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

Annotation of src/sys/netinet6/ip6_mroute.c, Revision 1.96

1.96    ! plunky      1: /*     $NetBSD: ip6_mroute.c,v 1.95 2008/06/24 10:35:14 gmcgarry Exp $ */
1.22      itojun      2: /*     $KAME: ip6_mroute.c,v 1.49 2001/07/25 09:21:18 jinmei Exp $     */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1998 WIDE Project.
                      6:  * All rights reserved.
1.12      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.12      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: /*     BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp     */
                     34:
                     35: /*
1.41      itojun     36:  * Copyright (c) 1992, 1993
                     37:  *      The Regents of the University of California.  All rights reserved.
                     38:  *
                     39:  * This code is derived from software contributed to Berkeley by
                     40:  * Stephen Deering of Stanford University.
                     41:  *
                     42:  * Redistribution and use in source and binary forms, with or without
                     43:  * modification, are permitted provided that the following conditions
                     44:  * are met:
                     45:  * 1. Redistributions of source code must retain the above copyright
                     46:  *    notice, this list of conditions and the following disclaimer.
                     47:  * 2. Redistributions in binary form must reproduce the above copyright
                     48:  *    notice, this list of conditions and the following disclaimer in the
                     49:  *    documentation and/or other materials provided with the distribution.
1.53      agc        50:  * 3. Neither the name of the University nor the names of its contributors
                     51:  *    may be used to endorse or promote products derived from this software
                     52:  *    without specific prior written permission.
                     53:  *
                     54:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     55:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     56:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     57:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     58:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     59:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     60:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     61:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     62:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     63:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     64:  * SUCH DAMAGE.
                     65:  *
                     66:  *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
                     67:  */
                     68:
                     69: /*
                     70:  * Copyright (c) 1989 Stephen Deering
                     71:  *
                     72:  * This code is derived from software contributed to Berkeley by
                     73:  * Stephen Deering of Stanford University.
                     74:  *
                     75:  * Redistribution and use in source and binary forms, with or without
                     76:  * modification, are permitted provided that the following conditions
                     77:  * are met:
                     78:  * 1. Redistributions of source code must retain the above copyright
                     79:  *    notice, this list of conditions and the following disclaimer.
                     80:  * 2. Redistributions in binary form must reproduce the above copyright
                     81:  *    notice, this list of conditions and the following disclaimer in the
                     82:  *    documentation and/or other materials provided with the distribution.
1.41      itojun     83:  * 3. All advertising materials mentioning features or use of this software
                     84:  *    must display the following acknowledgement:
                     85:  *      This product includes software developed by the University of
                     86:  *      California, Berkeley and its contributors.
                     87:  * 4. Neither the name of the University nor the names of its contributors
                     88:  *    may be used to endorse or promote products derived from this software
                     89:  *    without specific prior written permission.
                     90:  *
                     91:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     92:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     93:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     94:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     95:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     96:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     97:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     98:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     99:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                    100:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                    101:  * SUCH DAMAGE.
                    102:  *
                    103:  *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
                    104:  */
                    105:
                    106: /*
1.2       itojun    107:  * IP multicast forwarding procedures
                    108:  *
                    109:  * Written by David Waitzman, BBN Labs, August 1988.
                    110:  * Modified by Steve Deering, Stanford, February 1989.
                    111:  * Modified by Mark J. Steiglitz, Stanford, May, 1991
                    112:  * Modified by Van Jacobson, LBL, January 1993
                    113:  * Modified by Ajit Thyagarajan, PARC, August 1993
1.35      itojun    114:  * Modified by Bill Fenner, PARC, April 1994
1.2       itojun    115:  *
                    116:  * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support
                    117:  */
1.24      lukem     118:
                    119: #include <sys/cdefs.h>
1.96    ! plunky    120: __KERNEL_RCSID(0, "$NetBSD: ip6_mroute.c,v 1.95 2008/06/24 10:35:14 gmcgarry Exp $");
1.2       itojun    121:
                    122: #include "opt_inet.h"
1.48      martin    123: #include "opt_mrouting.h"
1.8       itojun    124:
1.2       itojun    125: #include <sys/param.h>
                    126: #include <sys/systm.h>
1.11      thorpej   127: #include <sys/callout.h>
1.2       itojun    128: #include <sys/mbuf.h>
                    129: #include <sys/socket.h>
                    130: #include <sys/socketvar.h>
                    131: #include <sys/sockio.h>
                    132: #include <sys/protosw.h>
                    133: #include <sys/errno.h>
                    134: #include <sys/time.h>
                    135: #include <sys/kernel.h>
                    136: #include <sys/ioctl.h>
1.65      rpaulo    137: #include <sys/sysctl.h>
1.2       itojun    138: #include <sys/syslog.h>
                    139:
                    140: #include <net/if.h>
                    141: #include <net/route.h>
                    142: #include <net/raw_cb.h>
1.91      thorpej   143: #include <net/net_stats.h>
1.2       itojun    144:
                    145: #include <netinet/in.h>
                    146: #include <netinet/in_var.h>
1.40      itojun    147: #include <netinet/icmp6.h>
1.2       itojun    148:
1.10      itojun    149: #include <netinet/ip6.h>
1.2       itojun    150: #include <netinet6/ip6_var.h>
1.89      thorpej   151: #include <netinet6/ip6_private.h>
1.2       itojun    152: #include <netinet6/ip6_mroute.h>
1.69      rpaulo    153: #include <netinet6/scope6_var.h>
1.2       itojun    154: #include <netinet6/pim6.h>
                    155: #include <netinet6/pim6_var.h>
1.29      itojun    156: #include <netinet6/nd6.h>
1.2       itojun    157:
1.13      itojun    158: #include <net/net_osdep.h>
                    159:
1.84      dyoung    160: static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
                    161: static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
1.2       itojun    162:
1.84      dyoung    163: static int set_pim6(int *);
                    164: static int socket_send(struct socket *, struct mbuf *,
                    165:            struct sockaddr_in6 *);
                    166: static int register_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
1.2       itojun    167:
                    168: /*
                    169:  * Globals.  All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
                    170:  * except for netstat or debugging purposes.
                    171:  */
1.30      itojun    172: struct socket  *ip6_mrouter = NULL;
1.12      itojun    173: int            ip6_mrouter_ver = 0;
1.2       itojun    174: int            ip6_mrtproto = IPPROTO_PIM;    /* for netstat only */
                    175: struct mrt6stat        mrt6stat;
                    176:
                    177: #define NO_RTE_FOUND   0x1
                    178: #define RTE_FOUND      0x2
                    179:
                    180: struct mf6c    *mf6ctable[MF6CTBLSIZ];
1.30      itojun    181: u_char         n6expire[MF6CTBLSIZ];
1.67      bouyer    182: struct mif6 mif6table[MAXMIFS];
1.2       itojun    183: #ifdef MRT6DEBUG
                    184: u_int          mrt6debug = 0;    /* debug level        */
1.52      itojun    185: #define DEBUG_MFC      0x02
                    186: #define DEBUG_FORWARD  0x04
                    187: #define DEBUG_EXPIRE   0x08
                    188: #define DEBUG_XMIT     0x10
                    189: #define DEBUG_REG      0x20
                    190: #define DEBUG_PIM      0x40
1.2       itojun    191: #endif
                    192:
1.84      dyoung    193: static void    expire_upcalls(void *);
1.52      itojun    194: #define        EXPIRE_TIMEOUT  (hz / 4)        /* 4x / second */
                    195: #define        UPCALL_EXPIRE   6               /* number of timeouts */
1.2       itojun    196:
                    197: #ifdef INET
                    198: #ifdef MROUTING
                    199: extern struct socket *ip_mrouter;
                    200: #endif
1.12      itojun    201: #endif
1.2       itojun    202:
                    203: /*
                    204:  * 'Interfaces' associated with decapsulator (so we can tell
                    205:  * packets that went through it from ones that get reflected
                    206:  * by a broken gateway).  These interfaces are never linked into
                    207:  * the system ifnet list & no routes point to them.  I.e., packets
                    208:  * can't be sent this way.  They only exist as a placeholder for
                    209:  * multicast source verification.
                    210:  */
1.66      rpaulo    211: struct ifnet multicast_register_if6;
1.2       itojun    212:
                    213: #define ENCAP_HOPS 64
                    214:
                    215: /*
                    216:  * Private variables.
                    217:  */
                    218: static mifi_t nummifs = 0;
                    219: static mifi_t reg_mif_num = (mifi_t)-1;
                    220:
1.90      thorpej   221: static percpu_t *pim6stat_percpu;
                    222:
1.91      thorpej   223: #define        PIM6_STATINC(x)         _NET_STATINC(pim6stat_percpu, x)
1.90      thorpej   224:
1.2       itojun    225: static int pim6;
                    226:
                    227: /*
                    228:  * Hash function for a source, group entry
                    229:  */
                    230: #define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
                    231:                                   (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
                    232:                                   (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \
                    233:                                   (g).s6_addr32[2] ^ (g).s6_addr32[3])
                    234:
                    235: /*
                    236:  * Find a route for a given origin IPv6 address and Multicast group address.
                    237:  * Quality of service parameter to be added in the future!!!
                    238:  */
                    239:
1.12      itojun    240: #define MF6CFIND(o, g, rt) do { \
1.15      itojun    241:        struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
1.2       itojun    242:        rt = NULL; \
                    243:        mrt6stat.mrt6s_mfc_lookups++; \
                    244:        while (_rt) { \
                    245:                if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \
                    246:                    IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \
                    247:                    (_rt->mf6c_stall == NULL)) { \
                    248:                        rt = _rt; \
                    249:                        break; \
                    250:                } \
                    251:                _rt = _rt->mf6c_next; \
                    252:        } \
                    253:        if (rt == NULL) { \
                    254:                mrt6stat.mrt6s_mfc_misses++; \
                    255:        } \
1.39      perry     256: } while (/*CONSTCOND*/ 0)
1.2       itojun    257:
                    258: /*
                    259:  * Macros to compute elapsed time efficiently
                    260:  * Borrowed from Van Jacobson's scheduling code
                    261:  */
1.12      itojun    262: #define TV_DELTA(a, b, delta) do { \
1.15      itojun    263:            int xxs; \
1.2       itojun    264:                \
                    265:            delta = (a).tv_usec - (b).tv_usec; \
                    266:            if ((xxs = (a).tv_sec - (b).tv_sec)) { \
                    267:               switch (xxs) { \
                    268:                      case 2: \
                    269:                          delta += 1000000; \
1.32      itojun    270:                              /* FALLTHROUGH */ \
1.2       itojun    271:                      case 1: \
                    272:                          delta += 1000000; \
                    273:                          break; \
                    274:                      default: \
                    275:                          delta += (1000000 * xxs); \
                    276:               } \
                    277:            } \
1.39      perry     278: } while (/*CONSTCOND*/ 0)
1.2       itojun    279:
                    280: #define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
                    281:              (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
                    282:
                    283: #ifdef UPCALL_TIMING
1.7       itojun    284: #define UPCALL_MAX     50
                    285: u_long upcall_data[UPCALL_MAX + 1];
1.2       itojun    286: static void collate();
                    287: #endif /* UPCALL_TIMING */
                    288:
1.84      dyoung    289: static int get_sg_cnt(struct sioc_sg_req6 *);
                    290: static int get_mif6_cnt(struct sioc_mif_req6 *);
                    291: static int ip6_mrouter_init(struct socket *, int, int);
                    292: static int add_m6if(struct mif6ctl *);
                    293: static int del_m6if(mifi_t *);
                    294: static int add_m6fc(struct mf6cctl *);
                    295: static int del_m6fc(struct mf6cctl *);
1.2       itojun    296:
1.83      ad        297: static callout_t expire_upcalls_ch;
1.11      thorpej   298:
1.90      thorpej   299: void
                    300: pim6_init(void)
                    301: {
                    302:
                    303:        pim6stat_percpu = percpu_alloc(sizeof(uint64_t) * PIM6_NSTATS);
                    304: }
                    305:
1.2       itojun    306: /*
                    307:  * Handle MRT setsockopt commands to modify the multicast routing tables.
                    308:  */
                    309: int
1.96    ! plunky    310: ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
1.2       itojun    311: {
1.96    ! plunky    312:        int error, optval;
        !           313:        struct mif6ctl mifc;
        !           314:        struct mf6cctl mfcc;
        !           315:        mifi_t mifi;
        !           316:
        !           317:        if (sopt->sopt_name != MRT6_INIT && so != ip6_mrouter)
1.59      itojun    318:                return (EACCES);
1.2       itojun    319:
1.96    ! plunky    320:        error = 0;
        !           321:
        !           322:        switch (sopt->sopt_name) {
1.59      itojun    323: #ifdef MRT6_OINIT
                    324:        case MRT6_OINIT:
                    325: #endif
                    326:        case MRT6_INIT:
1.96    ! plunky    327:                error = sockopt_getint(sopt, &optval);
        !           328:                if (error)
        !           329:                        break;
        !           330:                return (ip6_mrouter_init(so, optval, sopt->sopt_name));
1.59      itojun    331:        case MRT6_DONE:
                    332:                return (ip6_mrouter_done());
                    333:        case MRT6_ADD_MIF:
1.96    ! plunky    334:                error = sockopt_get(sopt, &mifc, sizeof(mifc));
        !           335:                if (error)
        !           336:                        break;
        !           337:                return (add_m6if(&mifc));
1.59      itojun    338:        case MRT6_DEL_MIF:
1.96    ! plunky    339:                error = sockopt_get(sopt, &mifi, sizeof(mifi));
        !           340:                if (error)
        !           341:                        break;
        !           342:                return (del_m6if(&mifi));
1.59      itojun    343:        case MRT6_ADD_MFC:
1.96    ! plunky    344:                error = sockopt_get(sopt, &mfcc, sizeof(mfcc));
        !           345:                if (error)
        !           346:                        break;
        !           347:                return (add_m6fc(&mfcc));
1.59      itojun    348:        case MRT6_DEL_MFC:
1.96    ! plunky    349:                error = sockopt_get(sopt, &mfcc, sizeof(mfcc));
        !           350:                if (error)
        !           351:                        break;
        !           352:                return (del_m6fc(&mfcc));
1.59      itojun    353:        case MRT6_PIM:
1.96    ! plunky    354:                error = sockopt_getint(sopt, &optval);
        !           355:                if (error)
        !           356:                        break;
        !           357:                return (set_pim6(&optval));
1.59      itojun    358:        default:
1.96    ! plunky    359:                error = EOPNOTSUPP;
1.2       itojun    360:        }
1.96    ! plunky    361:
        !           362:        return (error);
1.2       itojun    363: }
                    364:
                    365: /*
                    366:  * Handle MRT getsockopt commands
                    367:  */
                    368: int
1.96    ! plunky    369: ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
1.2       itojun    370: {
1.96    ! plunky    371:        int error;
1.2       itojun    372:
                    373:        if (so != ip6_mrouter) return EACCES;
                    374:
1.96    ! plunky    375:        error = 0;
1.2       itojun    376:
1.96    ! plunky    377:        switch (sopt->sopt_name) {
1.23      itojun    378:        case MRT6_PIM:
1.96    ! plunky    379:                error = sockopt_set(sopt, &pim6, sizeof(pim6));
        !           380:                break;
1.23      itojun    381:        default:
1.96    ! plunky    382:                error = EOPNOTSUPP;
        !           383:                break;
1.2       itojun    384:        }
1.96    ! plunky    385:
        !           386:        return (error);
1.2       itojun    387: }
                    388:
                    389: /*
                    390:  * Handle ioctl commands to obtain information from the cache
                    391:  */
                    392: int
1.95      gmcgarry  393: mrt6_ioctl(u_long cmd, void *data)
1.2       itojun    394: {
                    395:
1.23      itojun    396:        switch (cmd) {
                    397:        case SIOCGETSGCNT_IN6:
1.37      itojun    398:                return (get_sg_cnt((struct sioc_sg_req6 *)data));
1.23      itojun    399:        case SIOCGETMIFCNT_IN6:
1.37      itojun    400:                return (get_mif6_cnt((struct sioc_mif_req6 *)data));
1.23      itojun    401:        default:
                    402:                return (EINVAL);
                    403:        }
1.2       itojun    404: }
                    405:
                    406: /*
                    407:  * returns the packet, byte, rpf-failure count for the source group provided
                    408:  */
                    409: static int
1.81      christos  410: get_sg_cnt(struct sioc_sg_req6 *req)
1.2       itojun    411: {
1.15      itojun    412:        struct mf6c *rt;
1.2       itojun    413:        int s;
                    414:
1.4       itojun    415:        s = splsoftnet();
1.2       itojun    416:        MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
                    417:        splx(s);
                    418:        if (rt != NULL) {
                    419:                req->pktcnt = rt->mf6c_pkt_cnt;
                    420:                req->bytecnt = rt->mf6c_byte_cnt;
                    421:                req->wrong_if = rt->mf6c_wrong_if;
                    422:        } else
1.37      itojun    423:                return (ESRCH);
1.2       itojun    424: #if 0
                    425:                req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
1.12      itojun    426: #endif
1.2       itojun    427:
                    428:        return 0;
                    429: }
                    430:
                    431: /*
                    432:  * returns the input and output packet and byte counts on the mif provided
                    433:  */
                    434: static int
1.81      christos  435: get_mif6_cnt(struct sioc_mif_req6 *req)
1.2       itojun    436: {
1.15      itojun    437:        mifi_t mifi = req->mifi;
1.2       itojun    438:
                    439:        if (mifi >= nummifs)
                    440:                return EINVAL;
                    441:
                    442:        req->icount = mif6table[mifi].m6_pkt_in;
                    443:        req->ocount = mif6table[mifi].m6_pkt_out;
                    444:        req->ibytes = mif6table[mifi].m6_bytes_in;
                    445:        req->obytes = mif6table[mifi].m6_bytes_out;
                    446:
                    447:        return 0;
                    448: }
                    449:
                    450: static int
1.81      christos  451: set_pim6(int *i)
1.2       itojun    452: {
                    453:        if ((*i != 1) && (*i != 0))
                    454:                return EINVAL;
                    455:
                    456:        pim6 = *i;
                    457:
                    458:        return 0;
                    459: }
                    460:
                    461: /*
                    462:  * Enable multicast routing
                    463:  */
                    464: static int
1.81      christos  465: ip6_mrouter_init(struct socket *so, int v, int cmd)
1.2       itojun    466: {
                    467: #ifdef MRT6DEBUG
                    468:        if (mrt6debug)
                    469:                log(LOG_DEBUG,
                    470:                    "ip6_mrouter_init: so_type = %d, pr_protocol = %d\n",
                    471:                    so->so_type, so->so_proto->pr_protocol);
                    472: #endif
                    473:
                    474:        if (so->so_type != SOCK_RAW ||
                    475:            so->so_proto->pr_protocol != IPPROTO_ICMPV6)
1.59      itojun    476:                return (EOPNOTSUPP);
1.2       itojun    477:
1.59      itojun    478:        if (v != 1)
                    479:                return (ENOPROTOOPT);
1.2       itojun    480:
1.59      itojun    481:        if (ip6_mrouter != NULL)
                    482:                return (EADDRINUSE);
1.2       itojun    483:
                    484:        ip6_mrouter = so;
1.12      itojun    485:        ip6_mrouter_ver = cmd;
1.2       itojun    486:
1.79      christos  487:        bzero((void *)mf6ctable, sizeof(mf6ctable));
                    488:        bzero((void *)n6expire, sizeof(n6expire));
1.2       itojun    489:
                    490:        pim6 = 0;/* used for stubbing out/in pim stuff */
                    491:
1.92      ad        492:        callout_init(&expire_upcalls_ch, CALLOUT_MPSAFE);
1.11      thorpej   493:        callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
                    494:            expire_upcalls, NULL);
1.2       itojun    495:
                    496: #ifdef MRT6DEBUG
                    497:        if (mrt6debug)
                    498:                log(LOG_DEBUG, "ip6_mrouter_init\n");
                    499: #endif
                    500:
                    501:        return 0;
                    502: }
                    503:
                    504: /*
                    505:  * Disable multicast routing
                    506:  */
                    507: int
1.87      matt      508: ip6_mrouter_done(void)
1.2       itojun    509: {
                    510:        mifi_t mifi;
                    511:        int i;
                    512:        struct ifnet *ifp;
                    513:        struct in6_ifreq ifr;
                    514:        struct mf6c *rt;
                    515:        struct rtdetq *rte;
                    516:        int s;
                    517:
1.4       itojun    518:        s = splsoftnet();
1.2       itojun    519:
                    520:        /*
                    521:         * For each phyint in use, disable promiscuous reception of all IPv6
                    522:         * multicasts.
                    523:         */
                    524: #ifdef INET
                    525: #ifdef MROUTING
                    526:        /*
                    527:         * If there is still IPv4 multicast routing daemon,
                    528:         * we remain interfaces to receive all muliticasted packets.
                    529:         * XXX: there may be an interface in which the IPv4 multicast
                    530:         * daemon is not interested...
                    531:         */
                    532:        if (!ip_mrouter)
                    533: #endif
1.12      itojun    534: #endif
1.2       itojun    535:        {
                    536:                for (mifi = 0; mifi < nummifs; mifi++) {
                    537:                        if (mif6table[mifi].m6_ifp &&
                    538:                            !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
                    539:                                ifr.ifr_addr.sin6_family = AF_INET6;
                    540:                                ifr.ifr_addr.sin6_addr= in6addr_any;
                    541:                                ifp = mif6table[mifi].m6_ifp;
1.94      dyoung    542:                                (*ifp->if_ioctl)(ifp, SIOCDELMULTI, &ifr);
1.2       itojun    543:                        }
                    544:                }
                    545:        }
                    546: #ifdef notyet
1.79      christos  547:        bzero((void *)qtable, sizeof(qtable));
                    548:        bzero((void *)tbftable, sizeof(tbftable));
1.12      itojun    549: #endif
1.79      christos  550:        bzero((void *)mif6table, sizeof(mif6table));
1.2       itojun    551:        nummifs = 0;
                    552:
                    553:        pim6 = 0; /* used to stub out/in pim specific code */
                    554:
1.11      thorpej   555:        callout_stop(&expire_upcalls_ch);
1.2       itojun    556:
                    557:        /*
                    558:         * Free all multicast forwarding cache entries.
                    559:         */
                    560:        for (i = 0; i < MF6CTBLSIZ; i++) {
                    561:                rt = mf6ctable[i];
                    562:                while (rt) {
                    563:                        struct mf6c *frt;
                    564:
                    565:                        for (rte = rt->mf6c_stall; rte != NULL; ) {
                    566:                                struct rtdetq *n = rte->next;
                    567:
                    568:                                m_free(rte->m);
                    569:                                free(rte, M_MRTABLE);
                    570:                                rte = n;
                    571:                        }
                    572:                        frt = rt;
                    573:                        rt = rt->mf6c_next;
                    574:                        free(frt, M_MRTABLE);
                    575:                }
                    576:        }
                    577:
1.79      christos  578:        bzero((void *)mf6ctable, sizeof(mf6ctable));
1.2       itojun    579:
                    580:        /*
1.66      rpaulo    581:         * Reset register interface
1.2       itojun    582:         */
1.66      rpaulo    583:        if (reg_mif_num != (mifi_t)-1) {
                    584:                if_detach(&multicast_register_if6);
                    585:                reg_mif_num = (mifi_t)-1;
                    586:        }
                    587:
1.2       itojun    588:        ip6_mrouter = NULL;
1.12      itojun    589:        ip6_mrouter_ver = 0;
1.2       itojun    590:
                    591:        splx(s);
                    592:
                    593: #ifdef MRT6DEBUG
                    594:        if (mrt6debug)
                    595:                log(LOG_DEBUG, "ip6_mrouter_done\n");
                    596: #endif
                    597:
                    598:        return 0;
                    599: }
                    600:
1.50      itojun    601: void
1.81      christos  602: ip6_mrouter_detach(struct ifnet *ifp)
1.50      itojun    603: {
                    604:        struct rtdetq *rte;
                    605:        struct mf6c *mfc;
                    606:        mifi_t mifi;
                    607:        int i;
                    608:
1.71      rpaulo    609:        if (ip6_mrouter == NULL)
                    610:                return;
                    611:
1.50      itojun    612:        /*
                    613:         * Delete a mif which points to ifp.
                    614:         */
                    615:        for (mifi = 0; mifi < nummifs; mifi++)
                    616:                if (mif6table[mifi].m6_ifp == ifp)
                    617:                        del_m6if(&mifi);
                    618:
                    619:        /*
                    620:         * Clear rte->ifp of cache entries received on ifp.
                    621:         */
                    622:        for (i = 0; i < MF6CTBLSIZ; i++) {
                    623:                if (n6expire[i] == 0)
                    624:                        continue;
                    625:
                    626:                for (mfc = mf6ctable[i]; mfc != NULL; mfc = mfc->mf6c_next) {
                    627:                        for (rte = mfc->mf6c_stall; rte != NULL; rte = rte->next) {
                    628:                                if (rte->ifp == ifp)
                    629:                                        rte->ifp = NULL;
                    630:                        }
                    631:                }
                    632:        }
                    633: }
                    634:
1.2       itojun    635:
                    636: /*
                    637:  * Add a mif to the mif table
                    638:  */
                    639: static int
1.81      christos  640: add_m6if(struct mif6ctl *mifcp)
1.2       itojun    641: {
1.15      itojun    642:        struct mif6 *mifp;
1.2       itojun    643:        struct ifnet *ifp;
                    644:        struct in6_ifreq ifr;
                    645:        int error, s;
                    646: #ifdef notyet
                    647:        struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi;
1.12      itojun    648: #endif
1.2       itojun    649:
                    650:        if (mifcp->mif6c_mifi >= MAXMIFS)
                    651:                return EINVAL;
                    652:        mifp = mif6table + mifcp->mif6c_mifi;
                    653:        if (mifp->m6_ifp)
                    654:                return EADDRINUSE; /* XXX: is it appropriate? */
1.62      drochner  655:        if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi >= if_indexlim)
1.2       itojun    656:                return ENXIO;
1.22      itojun    657:        /*
                    658:         * XXX: some OSes can remove ifp and clear ifindex2ifnet[id]
                    659:         * even for id between 0 and if_index.
                    660:         */
                    661:        if ((ifp = ifindex2ifnet[mifcp->mif6c_pifi]) == NULL)
                    662:                return ENXIO;
1.2       itojun    663:
                    664:        if (mifcp->mif6c_flags & MIFF_REGISTER) {
1.66      rpaulo    665:                ifp = &multicast_register_if6;
                    666:
1.2       itojun    667:                if (reg_mif_num == (mifi_t)-1) {
1.66      rpaulo    668:                        strlcpy(ifp->if_xname, "register_mif",
                    669:                            sizeof(ifp->if_xname));
                    670:                        ifp->if_flags |= IFF_LOOPBACK;
                    671:                        ifp->if_index = mifcp->mif6c_mifi;
1.2       itojun    672:                        reg_mif_num = mifcp->mif6c_mifi;
1.66      rpaulo    673:                        if_attach(ifp);
1.2       itojun    674:                }
                    675:
                    676:        } /* if REGISTER */
                    677:        else {
                    678:                /* Make sure the interface supports multicast */
                    679:                if ((ifp->if_flags & IFF_MULTICAST) == 0)
                    680:                        return EOPNOTSUPP;
                    681:
1.8       itojun    682:                s = splsoftnet();
1.2       itojun    683:                /*
                    684:                 * Enable promiscuous reception of all IPv6 multicasts
1.8       itojun    685:                 * from the interface.
1.2       itojun    686:                 */
                    687:                ifr.ifr_addr.sin6_family = AF_INET6;
                    688:                ifr.ifr_addr.sin6_addr = in6addr_any;
1.94      dyoung    689:                error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, &ifr);
1.2       itojun    690:                splx(s);
                    691:                if (error)
                    692:                        return error;
                    693:        }
                    694:
1.4       itojun    695:        s = splsoftnet();
1.2       itojun    696:        mifp->m6_flags     = mifcp->mif6c_flags;
                    697:        mifp->m6_ifp       = ifp;
                    698: #ifdef notyet
                    699:        /* scaling up here allows division by 1024 in critical code */
                    700:        mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
1.12      itojun    701: #endif
1.2       itojun    702:        /* initialize per mif pkt counters */
                    703:        mifp->m6_pkt_in    = 0;
                    704:        mifp->m6_pkt_out   = 0;
                    705:        mifp->m6_bytes_in  = 0;
                    706:        mifp->m6_bytes_out = 0;
                    707:        splx(s);
                    708:
                    709:        /* Adjust nummifs up if the mifi is higher than nummifs */
                    710:        if (nummifs <= mifcp->mif6c_mifi)
                    711:                nummifs = mifcp->mif6c_mifi + 1;
                    712:
                    713: #ifdef MRT6DEBUG
                    714:        if (mrt6debug)
                    715:                log(LOG_DEBUG,
1.73      christos  716:                    "add_mif #%d, phyint %s\n",
                    717:                    mifcp->mif6c_mifi, ifp->if_xname);
1.2       itojun    718: #endif
                    719:
                    720:        return 0;
                    721: }
                    722:
                    723: /*
                    724:  * Delete a mif from the mif table
                    725:  */
                    726: static int
1.81      christos  727: del_m6if(mifi_t *mifip)
1.2       itojun    728: {
1.15      itojun    729:        struct mif6 *mifp = mif6table + *mifip;
                    730:        mifi_t mifi;
1.2       itojun    731:        struct ifnet *ifp;
                    732:        struct in6_ifreq ifr;
                    733:        int s;
                    734:
                    735:        if (*mifip >= nummifs)
                    736:                return EINVAL;
                    737:        if (mifp->m6_ifp == NULL)
                    738:                return EINVAL;
                    739:
1.4       itojun    740:        s = splsoftnet();
1.2       itojun    741:
                    742:        if (!(mifp->m6_flags & MIFF_REGISTER)) {
                    743:                /*
                    744:                 * XXX: what if there is yet IPv4 multicast daemon
                    745:                 *      using the interface?
                    746:                 */
1.8       itojun    747:                ifp = mifp->m6_ifp;
                    748:
1.2       itojun    749:                ifr.ifr_addr.sin6_family = AF_INET6;
                    750:                ifr.ifr_addr.sin6_addr = in6addr_any;
1.94      dyoung    751:                (*ifp->if_ioctl)(ifp, SIOCDELMULTI, &ifr);
1.66      rpaulo    752:        } else {
                    753:                if (reg_mif_num != (mifi_t)-1) {
                    754:                        if_detach(&multicast_register_if6);
                    755:                        reg_mif_num = (mifi_t)-1;
                    756:                }
1.2       itojun    757:        }
                    758:
                    759: #ifdef notyet
1.79      christos  760:        bzero((void *)qtable[*mifip], sizeof(qtable[*mifip]));
                    761:        bzero((void *)mifp->m6_tbf, sizeof(*(mifp->m6_tbf)));
1.12      itojun    762: #endif
1.79      christos  763:        bzero((void *)mifp, sizeof (*mifp));
1.2       itojun    764:
                    765:        /* Adjust nummifs down */
                    766:        for (mifi = nummifs; mifi > 0; mifi--)
                    767:                if (mif6table[mifi - 1].m6_ifp)
                    768:                        break;
                    769:        nummifs = mifi;
                    770:
                    771:        splx(s);
                    772:
                    773: #ifdef MRT6DEBUG
                    774:        if (mrt6debug)
                    775:                log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs);
                    776: #endif
                    777:
                    778:        return 0;
                    779: }
                    780:
                    781: /*
                    782:  * Add an mfc entry
                    783:  */
                    784: static int
1.81      christos  785: add_m6fc(struct mf6cctl *mfccp)
1.2       itojun    786: {
                    787:        struct mf6c *rt;
                    788:        u_long hash;
                    789:        struct rtdetq *rte;
1.15      itojun    790:        u_short nstl;
1.2       itojun    791:        int s;
                    792:
                    793:        MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
                    794:                 mfccp->mf6cc_mcastgrp.sin6_addr, rt);
                    795:
                    796:        /* If an entry already exists, just update the fields */
                    797:        if (rt) {
                    798: #ifdef MRT6DEBUG
                    799:                if (mrt6debug & DEBUG_MFC)
                    800:                        log(LOG_DEBUG,"add_m6fc update o %s g %s p %x\n",
                    801:                            ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
                    802:                            ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
                    803:                            mfccp->mf6cc_parent);
                    804: #endif
                    805:
1.4       itojun    806:                s = splsoftnet();
1.2       itojun    807:                rt->mf6c_parent = mfccp->mf6cc_parent;
                    808:                rt->mf6c_ifset = mfccp->mf6cc_ifset;
                    809:                splx(s);
                    810:                return 0;
                    811:        }
                    812:
1.12      itojun    813:        /*
1.2       itojun    814:         * Find the entry for which the upcall was made and update
                    815:         */
1.4       itojun    816:        s = splsoftnet();
1.2       itojun    817:        hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
                    818:                        mfccp->mf6cc_mcastgrp.sin6_addr);
                    819:        for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
                    820:                if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
                    821:                                       &mfccp->mf6cc_origin.sin6_addr) &&
                    822:                    IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
                    823:                                       &mfccp->mf6cc_mcastgrp.sin6_addr) &&
                    824:                    (rt->mf6c_stall != NULL)) {
                    825:
                    826:                        if (nstl++)
                    827:                                log(LOG_ERR,
1.5       itojun    828:                                    "add_m6fc: %s o %s g %s p %x dbx %p\n",
1.2       itojun    829:                                    "multiple kernel entries",
                    830:                                    ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
                    831:                                    ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
1.5       itojun    832:                                    mfccp->mf6cc_parent, rt->mf6c_stall);
1.2       itojun    833:
                    834: #ifdef MRT6DEBUG
                    835:                        if (mrt6debug & DEBUG_MFC)
                    836:                                log(LOG_DEBUG,
1.73      christos  837:                                    "add_m6fc o %s g %s p %x dbg %p\n",
1.2       itojun    838:                                    ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
                    839:                                    ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
                    840:                                    mfccp->mf6cc_parent, rt->mf6c_stall);
                    841: #endif
                    842:
                    843:                        rt->mf6c_origin     = mfccp->mf6cc_origin;
                    844:                        rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
                    845:                        rt->mf6c_parent     = mfccp->mf6cc_parent;
                    846:                        rt->mf6c_ifset      = mfccp->mf6cc_ifset;
                    847:                        /* initialize pkt counters per src-grp */
                    848:                        rt->mf6c_pkt_cnt    = 0;
                    849:                        rt->mf6c_byte_cnt   = 0;
                    850:                        rt->mf6c_wrong_if   = 0;
                    851:
                    852:                        rt->mf6c_expire = 0;    /* Don't clean this guy up */
1.30      itojun    853:                        n6expire[hash]--;
1.2       itojun    854:
                    855:                        /* free packets Qed at the end of this entry */
                    856:                        for (rte = rt->mf6c_stall; rte != NULL; ) {
                    857:                                struct rtdetq *n = rte->next;
1.50      itojun    858:                                if (rte->ifp) {
                    859:                                        ip6_mdq(rte->m, rte->ifp, rt);
                    860:                                }
1.2       itojun    861:                                m_freem(rte->m);
                    862: #ifdef UPCALL_TIMING
                    863:                                collate(&(rte->t));
                    864: #endif /* UPCALL_TIMING */
                    865:                                free(rte, M_MRTABLE);
                    866:                                rte = n;
                    867:                        }
                    868:                        rt->mf6c_stall = NULL;
                    869:                }
                    870:        }
                    871:
                    872:        /*
                    873:         * It is possible that an entry is being inserted without an upcall
                    874:         */
                    875:        if (nstl == 0) {
                    876: #ifdef MRT6DEBUG
                    877:                if (mrt6debug & DEBUG_MFC)
1.30      itojun    878:                        log(LOG_DEBUG,
1.73      christos  879:                            "add_mfc no upcall h %ld o %s g %s p %x\n",
1.2       itojun    880:                            hash,
                    881:                            ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
                    882:                            ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
                    883:                            mfccp->mf6cc_parent);
                    884: #endif
                    885:
                    886:                for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
1.26      sommerfe  887:
1.2       itojun    888:                        if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
                    889:                                               &mfccp->mf6cc_origin.sin6_addr)&&
                    890:                            IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
                    891:                                               &mfccp->mf6cc_mcastgrp.sin6_addr)) {
                    892:
                    893:                                rt->mf6c_origin     = mfccp->mf6cc_origin;
                    894:                                rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
                    895:                                rt->mf6c_parent     = mfccp->mf6cc_parent;
1.14      itojun    896:                                rt->mf6c_ifset      = mfccp->mf6cc_ifset;
1.2       itojun    897:                                /* initialize pkt counters per src-grp */
                    898:                                rt->mf6c_pkt_cnt    = 0;
                    899:                                rt->mf6c_byte_cnt   = 0;
                    900:                                rt->mf6c_wrong_if   = 0;
                    901:
                    902:                                if (rt->mf6c_expire)
1.30      itojun    903:                                        n6expire[hash]--;
1.2       itojun    904:                                rt->mf6c_expire    = 0;
                    905:                        }
                    906:                }
                    907:                if (rt == NULL) {
                    908:                        /* no upcall, so make a new entry */
                    909:                        rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
                    910:                                                  M_NOWAIT);
                    911:                        if (rt == NULL) {
                    912:                                splx(s);
                    913:                                return ENOBUFS;
                    914:                        }
1.26      sommerfe  915:
1.2       itojun    916:                        /* insert new entry at head of hash chain */
                    917:                        rt->mf6c_origin     = mfccp->mf6cc_origin;
                    918:                        rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
                    919:                        rt->mf6c_parent     = mfccp->mf6cc_parent;
1.14      itojun    920:                        rt->mf6c_ifset      = mfccp->mf6cc_ifset;
1.2       itojun    921:                        /* initialize pkt counters per src-grp */
                    922:                        rt->mf6c_pkt_cnt    = 0;
                    923:                        rt->mf6c_byte_cnt   = 0;
                    924:                        rt->mf6c_wrong_if   = 0;
                    925:                        rt->mf6c_expire     = 0;
                    926:                        rt->mf6c_stall = NULL;
1.26      sommerfe  927:
1.2       itojun    928:                        /* link into table */
                    929:                        rt->mf6c_next  = mf6ctable[hash];
                    930:                        mf6ctable[hash] = rt;
                    931:                }
                    932:        }
                    933:        splx(s);
                    934:        return 0;
                    935: }
                    936:
                    937: #ifdef UPCALL_TIMING
                    938: /*
1.12      itojun    939:  * collect delay statistics on the upcalls
1.2       itojun    940:  */
                    941: static void
1.81      christos  942: collate(struct timeval *t)
1.2       itojun    943: {
1.15      itojun    944:        u_long d;
                    945:        struct timeval tp;
                    946:        u_long delta;
1.12      itojun    947:
1.2       itojun    948:        GET_TIME(tp);
1.12      itojun    949:
1.2       itojun    950:        if (TV_LT(*t, tp))
                    951:        {
                    952:                TV_DELTA(tp, *t, delta);
1.26      sommerfe  953:
1.2       itojun    954:                d = delta >> 10;
1.7       itojun    955:                if (d > UPCALL_MAX)
                    956:                        d = UPCALL_MAX;
1.26      sommerfe  957:
1.2       itojun    958:                ++upcall_data[d];
                    959:        }
                    960: }
                    961: #endif /* UPCALL_TIMING */
                    962:
                    963: /*
                    964:  * Delete an mfc entry
                    965:  */
                    966: static int
1.81      christos  967: del_m6fc(struct mf6cctl *mfccp)
1.2       itojun    968: {
                    969:        struct sockaddr_in6     origin;
                    970:        struct sockaddr_in6     mcastgrp;
                    971:        struct mf6c             *rt;
                    972:        struct mf6c             **nptr;
                    973:        u_long          hash;
                    974:        int s;
                    975:
                    976:        origin = mfccp->mf6cc_origin;
                    977:        mcastgrp = mfccp->mf6cc_mcastgrp;
                    978:        hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);
                    979:
                    980: #ifdef MRT6DEBUG
                    981:        if (mrt6debug & DEBUG_MFC)
                    982:                log(LOG_DEBUG,"del_m6fc orig %s mcastgrp %s\n",
                    983:                    ip6_sprintf(&origin.sin6_addr),
                    984:                    ip6_sprintf(&mcastgrp.sin6_addr));
                    985: #endif
                    986:
1.4       itojun    987:        s = splsoftnet();
1.2       itojun    988:
                    989:        nptr = &mf6ctable[hash];
                    990:        while ((rt = *nptr) != NULL) {
                    991:                if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,
                    992:                                       &rt->mf6c_origin.sin6_addr) &&
                    993:                    IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr,
                    994:                                       &rt->mf6c_mcastgrp.sin6_addr) &&
                    995:                    rt->mf6c_stall == NULL)
                    996:                        break;
                    997:
                    998:                nptr = &rt->mf6c_next;
                    999:        }
                   1000:        if (rt == NULL) {
                   1001:                splx(s);
                   1002:                return EADDRNOTAVAIL;
                   1003:        }
                   1004:
                   1005:        *nptr = rt->mf6c_next;
                   1006:        free(rt, M_MRTABLE);
                   1007:
                   1008:        splx(s);
                   1009:
                   1010:        return 0;
                   1011: }
                   1012:
                   1013: static int
1.81      christos 1014: socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src)
1.2       itojun   1015: {
                   1016:        if (s) {
                   1017:                if (sbappendaddr(&s->so_rcv,
                   1018:                                 (struct sockaddr *)src,
                   1019:                                 mm, (struct mbuf *)0) != 0) {
                   1020:                        sorwakeup(s);
                   1021:                        return 0;
                   1022:                }
                   1023:        }
                   1024:        m_freem(mm);
                   1025:        return -1;
                   1026: }
                   1027:
                   1028: /*
                   1029:  * IPv6 multicast forwarding function. This function assumes that the packet
                   1030:  * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
                   1031:  * pointed to by "ifp", and the packet is to be relayed to other networks
                   1032:  * that have members of the packet's destination IPv6 multicast group.
                   1033:  *
                   1034:  * The packet is returned unscathed to the caller, unless it is
                   1035:  * erroneous, in which case a non-zero return value tells the caller to
                   1036:  * discard it.
                   1037:  */
                   1038:
                   1039: int
1.81      christos 1040: ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
1.2       itojun   1041: {
1.15      itojun   1042:        struct mf6c *rt;
                   1043:        struct mif6 *mifp;
                   1044:        struct mbuf *mm;
1.2       itojun   1045:        int s;
                   1046:        mifi_t mifi;
1.64      christos 1047:        struct sockaddr_in6 sin6;
1.2       itojun   1048:
                   1049: #ifdef MRT6DEBUG
                   1050:        if (mrt6debug & DEBUG_FORWARD)
                   1051:                log(LOG_DEBUG, "ip6_mforward: src %s, dst %s, ifindex %d\n",
                   1052:                    ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst),
                   1053:                    ifp->if_index);
                   1054: #endif
                   1055:
                   1056:        /*
                   1057:         * Don't forward a packet with Hop limit of zero or one,
                   1058:         * or a packet destined to a local-only group.
                   1059:         */
                   1060:        if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_NODELOCAL(&ip6->ip6_dst) ||
                   1061:            IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
                   1062:                return 0;
                   1063:        ip6->ip6_hlim--;
1.13      itojun   1064:
                   1065:        /*
                   1066:         * Source address check: do not forward packets with unspecified
                   1067:         * source. It was discussed in July 2000, on ipngwg mailing list.
                   1068:         * This is rather more serious than unicast cases, because some
                   1069:         * MLD packets can be sent with the unspecified source address
1.70      rpaulo   1070:         * (although such packets must normally set the hop limit field to 1).
1.13      itojun   1071:         */
                   1072:        if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1.89      thorpej  1073:                IP6_STATINC(IP6_STAT_CANTFORWARD);
1.72      kardel   1074:                if (ip6_log_time + ip6_log_interval < time_second) {
                   1075:                        ip6_log_time = time_second;
1.13      itojun   1076:                        log(LOG_DEBUG,
                   1077:                            "cannot forward "
                   1078:                            "from %s to %s nxt %d received on %s\n",
                   1079:                            ip6_sprintf(&ip6->ip6_src),
                   1080:                            ip6_sprintf(&ip6->ip6_dst),
                   1081:                            ip6->ip6_nxt,
1.25      itojun   1082:                            m->m_pkthdr.rcvif ?
                   1083:                            if_name(m->m_pkthdr.rcvif) : "?");
1.13      itojun   1084:                }
                   1085:                return 0;
                   1086:        }
1.2       itojun   1087:
                   1088:        /*
                   1089:         * Determine forwarding mifs from the forwarding cache table
                   1090:         */
1.4       itojun   1091:        s = splsoftnet();
1.2       itojun   1092:        MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
                   1093:
                   1094:        /* Entry exists, so forward if necessary */
                   1095:        if (rt) {
                   1096:                splx(s);
                   1097:                return (ip6_mdq(m, ifp, rt));
                   1098:        } else {
                   1099:                /*
                   1100:                 * If we don't have a route for packet's origin,
                   1101:                 * Make a copy of the packet &
                   1102:                 * send message to routing daemon
                   1103:                 */
                   1104:
1.15      itojun   1105:                struct mbuf *mb0;
                   1106:                struct rtdetq *rte;
                   1107:                u_long hash;
                   1108: /*             int i, npkts;*/
1.2       itojun   1109: #ifdef UPCALL_TIMING
                   1110:                struct timeval tp;
                   1111:
                   1112:                GET_TIME(tp);
                   1113: #endif /* UPCALL_TIMING */
                   1114:
                   1115:                mrt6stat.mrt6s_no_route++;
                   1116: #ifdef MRT6DEBUG
                   1117:                if (mrt6debug & (DEBUG_FORWARD | DEBUG_MFC))
                   1118:                        log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n",
                   1119:                            ip6_sprintf(&ip6->ip6_src),
                   1120:                            ip6_sprintf(&ip6->ip6_dst));
                   1121: #endif
                   1122:
                   1123:                /*
                   1124:                 * Allocate mbufs early so that we don't do extra work if we
                   1125:                 * are just going to fail anyway.
                   1126:                 */
                   1127:                rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE,
                   1128:                                              M_NOWAIT);
                   1129:                if (rte == NULL) {
                   1130:                        splx(s);
                   1131:                        return ENOBUFS;
                   1132:                }
                   1133:                mb0 = m_copy(m, 0, M_COPYALL);
                   1134:                /*
                   1135:                 * Pullup packet header if needed before storing it,
                   1136:                 * as other references may modify it in the meantime.
                   1137:                 */
                   1138:                if (mb0 &&
1.30      itojun   1139:                    (M_READONLY(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))
1.2       itojun   1140:                        mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
                   1141:                if (mb0 == NULL) {
                   1142:                        free(rte, M_MRTABLE);
                   1143:                        splx(s);
                   1144:                        return ENOBUFS;
                   1145:                }
1.26      sommerfe 1146:
1.2       itojun   1147:                /* is there an upcall waiting for this packet? */
                   1148:                hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
                   1149:                for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
                   1150:                        if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
                   1151:                                               &rt->mf6c_origin.sin6_addr) &&
                   1152:                            IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
                   1153:                                               &rt->mf6c_mcastgrp.sin6_addr) &&
                   1154:                            (rt->mf6c_stall != NULL))
                   1155:                                break;
                   1156:                }
                   1157:
                   1158:                if (rt == NULL) {
                   1159:                        struct mrt6msg *im;
1.12      itojun   1160:                        struct omrt6msg *oim;
1.2       itojun   1161:
                   1162:                        /* no upcall, so make a new entry */
                   1163:                        rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
                   1164:                                                  M_NOWAIT);
                   1165:                        if (rt == NULL) {
                   1166:                                free(rte, M_MRTABLE);
                   1167:                                m_freem(mb0);
                   1168:                                splx(s);
                   1169:                                return ENOBUFS;
                   1170:                        }
                   1171:                        /*
                   1172:                         * Make a copy of the header to send to the user
                   1173:                         * level process
                   1174:                         */
                   1175:                        mm = m_copy(mb0, 0, sizeof(struct ip6_hdr));
                   1176:
                   1177:                        if (mm == NULL) {
                   1178:                                free(rte, M_MRTABLE);
                   1179:                                m_freem(mb0);
                   1180:                                free(rt, M_MRTABLE);
                   1181:                                splx(s);
                   1182:                                return ENOBUFS;
                   1183:                        }
                   1184:
1.12      itojun   1185:                        /*
1.2       itojun   1186:                         * Send message to routing daemon
                   1187:                         */
1.85      dyoung   1188:                        sockaddr_in6_init(&sin6, &ip6->ip6_src, 0, 0, 0);
1.26      sommerfe 1189:
1.12      itojun   1190:                        im = NULL;
                   1191:                        oim = NULL;
                   1192:                        switch (ip6_mrouter_ver) {
                   1193:                        case MRT6_OINIT:
                   1194:                                oim = mtod(mm, struct omrt6msg *);
                   1195:                                oim->im6_msgtype = MRT6MSG_NOCACHE;
                   1196:                                oim->im6_mbz = 0;
                   1197:                                break;
                   1198:                        case MRT6_INIT:
                   1199:                                im = mtod(mm, struct mrt6msg *);
                   1200:                                im->im6_msgtype = MRT6MSG_NOCACHE;
                   1201:                                im->im6_mbz = 0;
                   1202:                                break;
                   1203:                        default:
                   1204:                                free(rte, M_MRTABLE);
                   1205:                                m_freem(mb0);
                   1206:                                free(rt, M_MRTABLE);
                   1207:                                splx(s);
                   1208:                                return EINVAL;
                   1209:                        }
1.2       itojun   1210:
                   1211: #ifdef MRT6DEBUG
                   1212:                        if (mrt6debug & DEBUG_FORWARD)
                   1213:                                log(LOG_DEBUG,
                   1214:                                    "getting the iif info in the kernel\n");
                   1215: #endif
                   1216:
                   1217:                        for (mifp = mif6table, mifi = 0;
                   1218:                             mifi < nummifs && mifp->m6_ifp != ifp;
                   1219:                             mifp++, mifi++)
                   1220:                                ;
                   1221:
1.12      itojun   1222:                        switch (ip6_mrouter_ver) {
                   1223:                        case MRT6_OINIT:
                   1224:                                oim->im6_mif = mifi;
                   1225:                                break;
                   1226:                        case MRT6_INIT:
                   1227:                                im->im6_mif = mifi;
                   1228:                                break;
                   1229:                        }
1.2       itojun   1230:
                   1231:                        if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
                   1232:                                log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
                   1233:                                    "socket queue full\n");
                   1234:                                mrt6stat.mrt6s_upq_sockfull++;
                   1235:                                free(rte, M_MRTABLE);
                   1236:                                m_freem(mb0);
                   1237:                                free(rt, M_MRTABLE);
                   1238:                                splx(s);
                   1239:                                return ENOBUFS;
                   1240:                        }
                   1241:
                   1242:                        mrt6stat.mrt6s_upcalls++;
                   1243:
                   1244:                        /* insert new entry at head of hash chain */
                   1245:                        bzero(rt, sizeof(*rt));
1.85      dyoung   1246:                        sockaddr_in6_init(&rt->mf6c_origin, &ip6->ip6_src,
                   1247:                            0, 0, 0);
                   1248:                        sockaddr_in6_init(&rt->mf6c_mcastgrp, &ip6->ip6_dst,
                   1249:                            0, 0, 0);
1.2       itojun   1250:                        rt->mf6c_expire = UPCALL_EXPIRE;
1.30      itojun   1251:                        n6expire[hash]++;
1.2       itojun   1252:                        rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;
                   1253:
                   1254:                        /* link into table */
                   1255:                        rt->mf6c_next  = mf6ctable[hash];
                   1256:                        mf6ctable[hash] = rt;
                   1257:                        /* Add this entry to the end of the queue */
                   1258:                        rt->mf6c_stall = rte;
                   1259:                } else {
                   1260:                        /* determine if q has overflowed */
                   1261:                        struct rtdetq **p;
1.15      itojun   1262:                        int npkts = 0;
1.2       itojun   1263:
                   1264:                        for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
                   1265:                                if (++npkts > MAX_UPQ6) {
                   1266:                                        mrt6stat.mrt6s_upq_ovflw++;
                   1267:                                        free(rte, M_MRTABLE);
                   1268:                                        m_freem(mb0);
                   1269:                                        splx(s);
                   1270:                                        return 0;
                   1271:                                }
                   1272:
                   1273:                        /* Add this entry to the end of the queue */
                   1274:                        *p = rte;
                   1275:                }
                   1276:
                   1277:                rte->next = NULL;
                   1278:                rte->m = mb0;
                   1279:                rte->ifp = ifp;
                   1280: #ifdef UPCALL_TIMING
                   1281:                rte->t = tp;
                   1282: #endif /* UPCALL_TIMING */
                   1283:
                   1284:                splx(s);
                   1285:
                   1286:                return 0;
                   1287:        }
                   1288: }
                   1289:
                   1290: /*
                   1291:  * Clean up cache entries if upcalls are not serviced
1.71      rpaulo   1292:  * Call from the Slow Timeout mechanism, every 0.25 seconds.
1.2       itojun   1293:  */
                   1294: static void
1.76      christos 1295: expire_upcalls(void *unused)
1.2       itojun   1296: {
                   1297:        struct rtdetq *rte;
                   1298:        struct mf6c *mfc, **nptr;
                   1299:        int i;
                   1300:
1.92      ad       1301:        mutex_enter(softnet_lock);
                   1302:        KERNEL_LOCK(1, NULL);
                   1303:
1.2       itojun   1304:        for (i = 0; i < MF6CTBLSIZ; i++) {
1.30      itojun   1305:                if (n6expire[i] == 0)
1.2       itojun   1306:                        continue;
                   1307:                nptr = &mf6ctable[i];
                   1308:                while ((mfc = *nptr) != NULL) {
                   1309:                        rte = mfc->mf6c_stall;
                   1310:                        /*
                   1311:                         * Skip real cache entries
                   1312:                         * Make sure it wasn't marked to not expire (shouldn't happen)
                   1313:                         * If it expires now
                   1314:                         */
                   1315:                        if (rte != NULL &&
                   1316:                            mfc->mf6c_expire != 0 &&
                   1317:                            --mfc->mf6c_expire == 0) {
                   1318: #ifdef MRT6DEBUG
                   1319:                                if (mrt6debug & DEBUG_EXPIRE)
                   1320:                                        log(LOG_DEBUG, "expire_upcalls: expiring (%s %s)\n",
                   1321:                                            ip6_sprintf(&mfc->mf6c_origin.sin6_addr),
                   1322:                                            ip6_sprintf(&mfc->mf6c_mcastgrp.sin6_addr));
                   1323: #endif
                   1324:                                /*
                   1325:                                 * drop all the packets
                   1326:                                 * free the mbuf with the pkt, if, timing info
                   1327:                                 */
                   1328:                                do {
                   1329:                                        struct rtdetq *n = rte->next;
                   1330:                                        m_freem(rte->m);
                   1331:                                        free(rte, M_MRTABLE);
                   1332:                                        rte = n;
                   1333:                                } while (rte != NULL);
                   1334:                                mrt6stat.mrt6s_cache_cleanups++;
1.30      itojun   1335:                                n6expire[i]--;
1.2       itojun   1336:
                   1337:                                *nptr = mfc->mf6c_next;
                   1338:                                free(mfc, M_MRTABLE);
                   1339:                        } else {
                   1340:                                nptr = &mfc->mf6c_next;
                   1341:                        }
                   1342:                }
                   1343:        }
1.11      thorpej  1344:        callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
                   1345:            expire_upcalls, NULL);
1.92      ad       1346:
                   1347:        KERNEL_UNLOCK_ONE(NULL);
                   1348:        mutex_exit(softnet_lock);
1.2       itojun   1349: }
                   1350:
                   1351: /*
                   1352:  * Packet forwarding routine once entry in the cache is made
                   1353:  */
                   1354: static int
1.81      christos 1355: ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
1.15      itojun   1356: {
                   1357:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
                   1358:        mifi_t mifi, iif;
                   1359:        struct mif6 *mifp;
                   1360:        int plen = m->m_pkthdr.len;
1.69      rpaulo   1361:        struct in6_addr src0, dst0; /* copies for local work */
                   1362:        u_int32_t iszone, idzone, oszone, odzone;
                   1363:        int error = 0;
1.2       itojun   1364:
                   1365: /*
                   1366:  * Macro to send packet on mif.  Since RSVP packets don't get counted on
                   1367:  * input, they shouldn't get counted on output, so statistics keeping is
1.21      wiz      1368:  * separate.
1.2       itojun   1369:  */
                   1370:
1.12      itojun   1371: #define MC6_SEND(ip6, mifp, m) do {                            \
1.43      itojun   1372:        if ((mifp)->m6_flags & MIFF_REGISTER)                   \
                   1373:                register_send((ip6), (mifp), (m));              \
                   1374:        else                                                    \
                   1375:                phyint_send((ip6), (mifp), (m));                \
1.39      perry    1376: } while (/*CONSTCOND*/ 0)
1.2       itojun   1377:
                   1378:        /*
                   1379:         * Don't forward if it didn't arrive from the parent mif
                   1380:         * for its origin.
                   1381:         */
                   1382:        mifi = rt->mf6c_parent;
                   1383:        if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) {
                   1384:                /* came in the wrong interface */
                   1385: #ifdef MRT6DEBUG
                   1386:                if (mrt6debug & DEBUG_FORWARD)
                   1387:                        log(LOG_DEBUG,
                   1388:                            "wrong if: ifid %d mifi %d mififid %x\n",
                   1389:                            ifp->if_index, mifi,
1.50      itojun   1390:                            mif6table[mifi].m6_ifp ?
1.63      perry    1391:                            mif6table[mifi].m6_ifp->if_index : -1);
1.2       itojun   1392: #endif
                   1393:                mrt6stat.mrt6s_wrong_if++;
                   1394:                rt->mf6c_wrong_if++;
                   1395:                /*
                   1396:                 * If we are doing PIM processing, and we are forwarding
                   1397:                 * packets on this interface, send a message to the
                   1398:                 * routing daemon.
                   1399:                 */
1.12      itojun   1400:                /* have to make sure this is a valid mif */
                   1401:                if (mifi < nummifs && mif6table[mifi].m6_ifp)
                   1402:                        if (pim6 && (m->m_flags & M_LOOP) == 0) {
                   1403:                                /*
                   1404:                                 * Check the M_LOOP flag to avoid an
                   1405:                                 * unnecessary PIM assert.
                   1406:                                 * XXX: M_LOOP is an ad-hoc hack...
                   1407:                                 */
1.64      christos 1408:                                struct sockaddr_in6 sin6;
1.2       itojun   1409:
1.15      itojun   1410:                                struct mbuf *mm;
1.12      itojun   1411:                                struct mrt6msg *im;
                   1412:                                struct omrt6msg *oim;
                   1413:
                   1414:                                mm = m_copy(m, 0, sizeof(struct ip6_hdr));
                   1415:                                if (mm &&
1.30      itojun   1416:                                    (M_READONLY(mm) ||
1.12      itojun   1417:                                     mm->m_len < sizeof(struct ip6_hdr)))
                   1418:                                        mm = m_pullup(mm, sizeof(struct ip6_hdr));
                   1419:                                if (mm == NULL)
                   1420:                                        return ENOBUFS;
1.26      sommerfe 1421:
1.12      itojun   1422:                                oim = NULL;
                   1423:                                im = NULL;
                   1424:                                switch (ip6_mrouter_ver) {
                   1425:                                case MRT6_OINIT:
                   1426:                                        oim = mtod(mm, struct omrt6msg *);
                   1427:                                        oim->im6_msgtype = MRT6MSG_WRONGMIF;
                   1428:                                        oim->im6_mbz = 0;
                   1429:                                        break;
                   1430:                                case MRT6_INIT:
1.2       itojun   1431:                                        im = mtod(mm, struct mrt6msg *);
1.12      itojun   1432:                                        im->im6_msgtype = MRT6MSG_WRONGMIF;
1.16      itojun   1433:                                        im->im6_mbz = 0;
1.12      itojun   1434:                                        break;
                   1435:                                default:
                   1436:                                        m_freem(mm);
                   1437:                                        return EINVAL;
                   1438:                                }
1.2       itojun   1439:
1.12      itojun   1440:                                for (mifp = mif6table, iif = 0;
                   1441:                                     iif < nummifs && mifp &&
                   1442:                                             mifp->m6_ifp != ifp;
                   1443:                                     mifp++, iif++)
                   1444:                                        ;
                   1445:
1.71      rpaulo   1446:                                bzero(&sin6, sizeof(sin6));
1.64      christos 1447:                                sin6.sin6_len = sizeof(sin6);
                   1448:                                sin6.sin6_family = AF_INET6;
1.12      itojun   1449:                                switch (ip6_mrouter_ver) {
                   1450:                                case MRT6_OINIT:
                   1451:                                        oim->im6_mif = iif;
                   1452:                                        sin6.sin6_addr = oim->im6_src;
                   1453:                                        break;
                   1454:                                case MRT6_INIT:
                   1455:                                        im->im6_mif = iif;
1.2       itojun   1456:                                        sin6.sin6_addr = im->im6_src;
1.12      itojun   1457:                                        break;
                   1458:                                }
1.2       itojun   1459:
1.12      itojun   1460:                                mrt6stat.mrt6s_upcalls++;
1.2       itojun   1461:
1.12      itojun   1462:                                if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1.2       itojun   1463: #ifdef MRT6DEBUG
1.12      itojun   1464:                                        if (mrt6debug)
                   1465:                                                log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
1.2       itojun   1466: #endif
1.12      itojun   1467:                                        ++mrt6stat.mrt6s_upq_sockfull;
                   1468:                                        return ENOBUFS;
                   1469:                                }       /* if socket Q full */
                   1470:                        }               /* if PIM */
1.2       itojun   1471:                return 0;
                   1472:        }                       /* if wrong iif */
                   1473:
                   1474:        /* If I sourced this packet, it counts as output, else it was input. */
                   1475:        if (m->m_pkthdr.rcvif == NULL) {
                   1476:                /* XXX: is rcvif really NULL when output?? */
                   1477:                mif6table[mifi].m6_pkt_out++;
                   1478:                mif6table[mifi].m6_bytes_out += plen;
                   1479:        } else {
                   1480:                mif6table[mifi].m6_pkt_in++;
                   1481:                mif6table[mifi].m6_bytes_in += plen;
                   1482:        }
                   1483:        rt->mf6c_pkt_cnt++;
                   1484:        rt->mf6c_byte_cnt += plen;
                   1485:
                   1486:        /*
                   1487:         * For each mif, forward a copy of the packet if there are group
                   1488:         * members downstream on the interface.
                   1489:         */
1.69      rpaulo   1490:        src0 = ip6->ip6_src;
                   1491:        dst0 = ip6->ip6_dst;
                   1492:        if ((error = in6_setscope(&src0, ifp, &iszone)) != 0 ||
                   1493:            (error = in6_setscope(&dst0, ifp, &idzone)) != 0) {
1.89      thorpej  1494:                IP6_STATINC(IP6_STAT_BADSCOPE);
1.69      rpaulo   1495:                return (error);
                   1496:        }
1.2       itojun   1497:        for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++)
                   1498:                if (IF_ISSET(mifi, &rt->mf6c_ifset)) {
1.47      itojun   1499:                        if (mif6table[mifi].m6_ifp == NULL)
                   1500:                                continue;
1.12      itojun   1501:                        /*
                   1502:                         * check if the outgoing packet is going to break
                   1503:                         * a scope boundary.
1.70      rpaulo   1504:                         * XXX: For packets through PIM register tunnel
                   1505:                         * interface, we believe the routing daemon.
1.12      itojun   1506:                         */
                   1507:                        if ((mif6table[rt->mf6c_parent].m6_flags &
                   1508:                             MIFF_REGISTER) == 0 &&
1.69      rpaulo   1509:                            (mif6table[mifi].m6_flags & MIFF_REGISTER) == 0) {
                   1510:                                if (in6_setscope(&src0, mif6table[mifi].m6_ifp,
                   1511:                                    &oszone) ||
                   1512:                                    in6_setscope(&dst0, mif6table[mifi].m6_ifp,
                   1513:                                    &odzone) ||
                   1514:                                    iszone != oszone || idzone != odzone) {
1.89      thorpej  1515:                                        IP6_STATINC(IP6_STAT_BADSCOPE);
1.69      rpaulo   1516:                                        continue;
                   1517:                                }
1.12      itojun   1518:                        }
                   1519:
1.2       itojun   1520:                        mifp->m6_pkt_out++;
                   1521:                        mifp->m6_bytes_out += plen;
                   1522:                        MC6_SEND(ip6, mifp, m);
                   1523:                }
                   1524:        return 0;
                   1525: }
                   1526:
                   1527: static void
1.81      christos 1528: phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
1.2       itojun   1529: {
1.15      itojun   1530:        struct mbuf *mb_copy;
1.2       itojun   1531:        struct ifnet *ifp = mifp->m6_ifp;
                   1532:        int error = 0;
1.77      dyoung   1533:        int s;
1.80      dyoung   1534:        static struct route ro;
1.71      rpaulo   1535:        struct in6_multi *in6m;
                   1536:        struct sockaddr_in6 dst6;
1.29      itojun   1537:        u_long linkmtu;
1.2       itojun   1538:
1.77      dyoung   1539:        s = splsoftnet();
1.2       itojun   1540:        /*
                   1541:         * Make a new reference to the packet; make sure that
                   1542:         * the IPv6 header is actually copied, not just referenced,
                   1543:         * so that ip6_output() only scribbles on the copy.
                   1544:         */
                   1545:        mb_copy = m_copy(m, 0, M_COPYALL);
                   1546:        if (mb_copy &&
1.30      itojun   1547:            (M_READONLY(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
1.2       itojun   1548:                mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
1.18      itojun   1549:        if (mb_copy == NULL) {
                   1550:                splx(s);
1.2       itojun   1551:                return;
1.18      itojun   1552:        }
1.2       itojun   1553:        /* set MCAST flag to the outgoing packet */
                   1554:        mb_copy->m_flags |= M_MCAST;
                   1555:
                   1556:        /*
1.71      rpaulo   1557:         * If we sourced the packet, call ip6_output since we may divide
1.2       itojun   1558:         * the packet into fragments when the packet is too big for the
                   1559:         * outgoing interface.
                   1560:         * Otherwise, we can simply send the packet to the interface
                   1561:         * sending queue.
                   1562:         */
                   1563:        if (m->m_pkthdr.rcvif == NULL) {
                   1564:                struct ip6_moptions im6o;
                   1565:
                   1566:                im6o.im6o_multicast_ifp = ifp;
                   1567:                /* XXX: ip6_output will override ip6->ip6_hlim */
                   1568:                im6o.im6o_multicast_hlim = ip6->ip6_hlim;
                   1569:                im6o.im6o_multicast_loop = 1;
1.54      jonathan 1570:                error = ip6_output(mb_copy, NULL, &ro, IPV6_FORWARDING,
1.77      dyoung   1571:                                   &im6o, NULL, NULL);
1.2       itojun   1572:
                   1573: #ifdef MRT6DEBUG
                   1574:                if (mrt6debug & DEBUG_XMIT)
                   1575:                        log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
                   1576:                            mifp - mif6table, error);
                   1577: #endif
                   1578:                splx(s);
                   1579:                return;
                   1580:        }
                   1581:
                   1582:        /*
                   1583:         * If we belong to the destination multicast group
                   1584:         * on the outgoing interface, loop back a copy.
                   1585:         */
1.71      rpaulo   1586:        /*
                   1587:         * Does not have to check source info, as it's alreay covered by
                   1588:         * ip6_input
                   1589:         */
1.85      dyoung   1590:        sockaddr_in6_init(&dst6, &ip6->ip6_dst, 0, 0, 0);
1.71      rpaulo   1591:
1.2       itojun   1592:        IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
1.78      dyoung   1593:        if (in6m != NULL) {
                   1594:                ip6_mloopback(ifp, m,
1.80      dyoung   1595:                    satocsin6(rtcache_getdst(&ro)));
1.78      dyoung   1596:        }
1.71      rpaulo   1597:
1.2       itojun   1598:        /*
1.12      itojun   1599:         * Put the packet into the sending queue of the outgoing interface
1.2       itojun   1600:         * if it would fit in the MTU of the interface.
                   1601:         */
1.29      itojun   1602:        linkmtu = IN6_LINKMTU(ifp);
1.36      itojun   1603:        if (mb_copy->m_pkthdr.len <= linkmtu || linkmtu < IPV6_MMTU) {
1.8       itojun   1604:                /*
1.71      rpaulo   1605:                 * We could call if_output directly here, but we use
                   1606:                 * nd6_output on purpose to see if IPv6 operation is allowed
                   1607:                 * on the interface.
1.8       itojun   1608:                 */
1.71      rpaulo   1609:                error = nd6_output(ifp, ifp, mb_copy, &dst6, NULL);
1.2       itojun   1610: #ifdef MRT6DEBUG
                   1611:                if (mrt6debug & DEBUG_XMIT)
                   1612:                        log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
                   1613:                            mifp - mif6table, error);
                   1614: #endif
1.20      itojun   1615:        } else {
1.71      rpaulo   1616:                /*
                   1617:                 * pMTU discovery is intentionally disabled by default, since
                   1618:                 * various router may notify pMTU in multicast, which can be
                   1619:                 * a DDoS to a router
                   1620:                 */
                   1621:                if (ip6_mcast_pmtu)
                   1622:                        icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, linkmtu);
                   1623:                else {
1.2       itojun   1624: #ifdef MRT6DEBUG
1.71      rpaulo   1625:                        if (mrt6debug & DEBUG_XMIT)
                   1626:                                log(LOG_DEBUG,
                   1627:                                    "phyint_send: packet too big on %s o %s g %s"
                   1628:                                    " size %d(discarded)\n",
                   1629:                                    if_name(ifp),
                   1630:                                    ip6_sprintf(&ip6->ip6_src),
                   1631:                                    ip6_sprintf(&ip6->ip6_dst),
                   1632:                                    mb_copy->m_pkthdr.len);
1.2       itojun   1633: #endif /* MRT6DEBUG */
1.71      rpaulo   1634:                        m_freem(mb_copy); /* simply discard the packet */
                   1635:                }
1.2       itojun   1636:        }
1.20      itojun   1637:
                   1638:        splx(s);
1.2       itojun   1639: }
                   1640:
1.12      itojun   1641: static int
1.82      christos 1642: register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
1.2       itojun   1643: {
1.15      itojun   1644:        struct mbuf *mm;
                   1645:        int i, len = m->m_pkthdr.len;
1.64      christos 1646:        struct sockaddr_in6 sin6;
1.2       itojun   1647:        struct mrt6msg *im6;
                   1648:
                   1649: #ifdef MRT6DEBUG
                   1650:        if (mrt6debug)
                   1651:                log(LOG_DEBUG, "** IPv6 register_send **\n src %s dst %s\n",
                   1652:                    ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst));
                   1653: #endif
1.90      thorpej  1654:        PIM6_STATINC(PIM6_STAT_SND_REGISTERS);
1.2       itojun   1655:
                   1656:        /* Make a copy of the packet to send to the user level process */
                   1657:        MGETHDR(mm, M_DONTWAIT, MT_HEADER);
                   1658:        if (mm == NULL)
                   1659:                return ENOBUFS;
                   1660:        mm->m_data += max_linkhdr;
                   1661:        mm->m_len = sizeof(struct ip6_hdr);
                   1662:
                   1663:        if ((mm->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {
                   1664:                m_freem(mm);
                   1665:                return ENOBUFS;
                   1666:        }
                   1667:        i = MHLEN - M_LEADINGSPACE(mm);
                   1668:        if (i > len)
                   1669:                i = len;
                   1670:        mm = m_pullup(mm, i);
1.27      itojun   1671:        if (mm == NULL)
1.2       itojun   1672:                return ENOBUFS;
                   1673: /* TODO: check it! */
                   1674:        mm->m_pkthdr.len = len + sizeof(struct ip6_hdr);
                   1675:
1.12      itojun   1676:        /*
1.2       itojun   1677:         * Send message to routing daemon
                   1678:         */
1.85      dyoung   1679:        sockaddr_in6_init(&sin6, &ip6->ip6_src, 0, 0, 0);
1.2       itojun   1680:
                   1681:        im6 = mtod(mm, struct mrt6msg *);
                   1682:        im6->im6_msgtype      = MRT6MSG_WHOLEPKT;
                   1683:        im6->im6_mbz          = 0;
                   1684:
                   1685:        im6->im6_mif = mif - mif6table;
                   1686:
                   1687:        /* iif info is not given for reg. encap.n */
                   1688:        mrt6stat.mrt6s_upcalls++;
                   1689:
                   1690:        if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
                   1691: #ifdef MRT6DEBUG
                   1692:                if (mrt6debug)
                   1693:                        log(LOG_WARNING,
1.33      itojun   1694:                            "register_send: ip6_mrouter socket queue full\n");
1.2       itojun   1695: #endif
1.15      itojun   1696:                ++mrt6stat.mrt6s_upq_sockfull;
                   1697:                return ENOBUFS;
1.2       itojun   1698:        }
                   1699:        return 0;
                   1700: }
1.12      itojun   1701:
1.2       itojun   1702: /*
                   1703:  * PIM sparse mode hook
                   1704:  * Receives the pim control messages, and passes them up to the listening
                   1705:  * socket, using rip6_input.
                   1706:  * The only message processed is the REGISTER pim message; the pim header
                   1707:  * is stripped off, and the inner packet is passed to register_mforward.
                   1708:  */
                   1709: int
1.81      christos 1710: pim6_input(struct mbuf **mp, int *offp, int proto)
1.2       itojun   1711: {
1.15      itojun   1712:        struct pim *pim; /* pointer to a pim struct */
                   1713:        struct ip6_hdr *ip6;
                   1714:        int pimlen;
1.2       itojun   1715:        struct mbuf *m = *mp;
1.15      itojun   1716:        int minlen;
1.2       itojun   1717:        int off = *offp;
                   1718:
1.90      thorpej  1719:        PIM6_STATINC(PIM6_STAT_RCV_TOTAL);
1.2       itojun   1720:
1.15      itojun   1721:        ip6 = mtod(m, struct ip6_hdr *);
                   1722:        pimlen = m->m_pkthdr.len - *offp;
1.2       itojun   1723:
1.15      itojun   1724:        /*
                   1725:         * Validate lengths
                   1726:         */
1.2       itojun   1727:        if (pimlen < PIM_MINLEN) {
1.90      thorpej  1728:                PIM6_STATINC(PIM6_STAT_RCV_TOOSHORT);
1.2       itojun   1729: #ifdef MRT6DEBUG
                   1730:                if (mrt6debug & DEBUG_PIM)
                   1731:                        log(LOG_DEBUG,"pim6_input: PIM packet too short\n");
                   1732: #endif
                   1733:                m_freem(m);
1.37      itojun   1734:                return (IPPROTO_DONE);
1.2       itojun   1735:        }
                   1736:
                   1737:        /*
                   1738:         * if the packet is at least as big as a REGISTER, go ahead
                   1739:         * and grab the PIM REGISTER header size, to avoid another
                   1740:         * possible m_pullup() later.
1.12      itojun   1741:         *
1.2       itojun   1742:         * PIM_MINLEN       == pimhdr + u_int32 == 8
                   1743:         * PIM6_REG_MINLEN   == pimhdr + reghdr + eip6hdr == 4 + 4 + 40
                   1744:         */
                   1745:        minlen = (pimlen >= PIM6_REG_MINLEN) ? PIM6_REG_MINLEN : PIM_MINLEN;
1.12      itojun   1746:
1.2       itojun   1747:        /*
                   1748:         * Make sure that the IP6 and PIM headers in contiguous memory, and
                   1749:         * possibly the PIM REGISTER header
                   1750:         */
1.8       itojun   1751:        IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen);
                   1752:        if (pim == NULL) {
1.90      thorpej  1753:                PIM6_STATINC(PIM6_STAT_RCV_TOOSHORT);
1.8       itojun   1754:                return IPPROTO_DONE;
                   1755:        }
1.2       itojun   1756:
1.45      itojun   1757:        /* PIM version check */
                   1758:        if (pim->pim_ver != PIM_VERSION) {
1.90      thorpej  1759:                PIM6_STATINC(PIM6_STAT_RCV_BADVERSION);
1.45      itojun   1760: #ifdef MRT6DEBUG
                   1761:                log(LOG_ERR,
                   1762:                    "pim6_input: incorrect version %d, expecting %d\n",
                   1763:                    pim->pim_ver, PIM_VERSION);
                   1764: #endif
                   1765:                m_freem(m);
                   1766:                return (IPPROTO_DONE);
                   1767:        }
                   1768:
1.2       itojun   1769: #define PIM6_CHECKSUM
                   1770: #ifdef PIM6_CHECKSUM
                   1771:        {
                   1772:                int cksumlen;
                   1773:
                   1774:                /*
                   1775:                 * Validate checksum.
                   1776:                 * If PIM REGISTER, exclude the data packet
                   1777:                 */
                   1778:                if (pim->pim_type == PIM_REGISTER)
                   1779:                        cksumlen = PIM_MINLEN;
                   1780:                else
                   1781:                        cksumlen = pimlen;
                   1782:
                   1783:                if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) {
1.90      thorpej  1784:                        PIM6_STATINC(PIM6_STAT_RCV_BADSUM);
1.2       itojun   1785: #ifdef MRT6DEBUG
                   1786:                        if (mrt6debug & DEBUG_PIM)
                   1787:                                log(LOG_DEBUG,
                   1788:                                    "pim6_input: invalid checksum\n");
1.12      itojun   1789: #endif
1.2       itojun   1790:                        m_freem(m);
1.37      itojun   1791:                        return (IPPROTO_DONE);
1.2       itojun   1792:                }
                   1793:        }
                   1794: #endif /* PIM_CHECKSUM */
                   1795:
                   1796:        if (pim->pim_type == PIM_REGISTER) {
                   1797:                /*
                   1798:                 * since this is a REGISTER, we'll make a copy of the register
1.7       itojun   1799:                 * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the
1.2       itojun   1800:                 * routing daemon.
                   1801:                 */
1.74      christos 1802:                static const struct sockaddr_in6 dst = {
                   1803:                        .sin6_len = sizeof(dst),
                   1804:                        .sin6_family = AF_INET6,
                   1805:                };
1.2       itojun   1806:
                   1807:                struct mbuf *mcp;
                   1808:                struct ip6_hdr *eip6;
1.7       itojun   1809:                u_int32_t *reghdr;
1.26      sommerfe 1810:
1.90      thorpej  1811:                PIM6_STATINC(PIM6_STAT_RCV_REGISTERS);
1.2       itojun   1812:
                   1813:                if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {
                   1814: #ifdef MRT6DEBUG
                   1815:                        if (mrt6debug & DEBUG_PIM)
                   1816:                                log(LOG_DEBUG,
                   1817:                                    "pim6_input: register mif not set: %d\n",
                   1818:                                    reg_mif_num);
                   1819: #endif
                   1820:                        m_freem(m);
1.37      itojun   1821:                        return (IPPROTO_DONE);
1.2       itojun   1822:                }
1.26      sommerfe 1823:
1.7       itojun   1824:                reghdr = (u_int32_t *)(pim + 1);
1.26      sommerfe 1825:
1.2       itojun   1826:                if ((ntohl(*reghdr) & PIM_NULL_REGISTER))
                   1827:                        goto pim6_input_to_daemon;
                   1828:
                   1829:                /*
                   1830:                 * Validate length
                   1831:                 */
                   1832:                if (pimlen < PIM6_REG_MINLEN) {
1.90      thorpej  1833:                        PIM6_STATINC(PIM6_STAT_RCV_TOOSHORT);
                   1834:                        PIM6_STATINC(PIM6_STAT_RCV_BADREGISTERS);
1.2       itojun   1835: #ifdef MRT6DEBUG
                   1836:                        log(LOG_ERR,
                   1837:                            "pim6_input: register packet size too "
                   1838:                            "small %d from %s\n",
                   1839:                            pimlen, ip6_sprintf(&ip6->ip6_src));
1.12      itojun   1840: #endif
1.2       itojun   1841:                        m_freem(m);
1.37      itojun   1842:                        return (IPPROTO_DONE);
1.2       itojun   1843:                }
1.26      sommerfe 1844:
1.2       itojun   1845:                eip6 = (struct ip6_hdr *) (reghdr + 1);
1.26      sommerfe 1846: #ifdef MRT6DEBUG
1.2       itojun   1847:                if (mrt6debug & DEBUG_PIM)
                   1848:                        log(LOG_DEBUG,
                   1849:                            "pim6_input[register], eip6: %s -> %s, "
                   1850:                            "eip6 plen %d\n",
                   1851:                            ip6_sprintf(&eip6->ip6_src),
                   1852:                            ip6_sprintf(&eip6->ip6_dst),
                   1853:                            ntohs(eip6->ip6_plen));
1.12      itojun   1854: #endif
1.14      itojun   1855:
                   1856:                /* verify the version number of the inner packet */
                   1857:                if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
1.90      thorpej  1858:                        PIM6_STATINC(PIM6_STAT_RCV_BADREGISTERS);
1.14      itojun   1859: #ifdef MRT6DEBUG
                   1860:                        log(LOG_DEBUG, "pim6_input: invalid IP version (%d) "
                   1861:                            "of the inner packet\n",
                   1862:                            (eip6->ip6_vfc & IPV6_VERSION));
                   1863: #endif
                   1864:                        m_freem(m);
1.37      itojun   1865:                        return (IPPROTO_NONE);
1.14      itojun   1866:                }
1.26      sommerfe 1867:
1.2       itojun   1868:                /* verify the inner packet is destined to a mcast group */
                   1869:                if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
1.90      thorpej  1870:                        PIM6_STATINC(PIM6_STAT_RCV_BADREGISTERS);
1.2       itojun   1871: #ifdef MRT6DEBUG
                   1872:                        if (mrt6debug & DEBUG_PIM)
                   1873:                                log(LOG_DEBUG,
                   1874:                                    "pim6_input: inner packet of register "
                   1875:                                    "is not multicast %s\n",
                   1876:                                    ip6_sprintf(&eip6->ip6_dst));
1.12      itojun   1877: #endif
1.2       itojun   1878:                        m_freem(m);
1.37      itojun   1879:                        return (IPPROTO_DONE);
1.2       itojun   1880:                }
1.26      sommerfe 1881:
1.2       itojun   1882:                /*
                   1883:                 * make a copy of the whole header to pass to the daemon later.
                   1884:                 */
                   1885:                mcp = m_copy(m, 0, off + PIM6_REG_MINLEN);
                   1886:                if (mcp == NULL) {
                   1887: #ifdef MRT6DEBUG
                   1888:                        log(LOG_ERR,
                   1889:                            "pim6_input: pim register: "
                   1890:                            "could not copy register head\n");
1.12      itojun   1891: #endif
1.2       itojun   1892:                        m_freem(m);
1.37      itojun   1893:                        return (IPPROTO_DONE);
1.2       itojun   1894:                }
1.26      sommerfe 1895:
1.2       itojun   1896:                /*
                   1897:                 * forward the inner ip6 packet; point m_data at the inner ip6.
                   1898:                 */
                   1899:                m_adj(m, off + PIM_MINLEN);
                   1900: #ifdef MRT6DEBUG
                   1901:                if (mrt6debug & DEBUG_PIM) {
                   1902:                        log(LOG_DEBUG,
                   1903:                            "pim6_input: forwarding decapsulated register: "
                   1904:                            "src %s, dst %s, mif %d\n",
                   1905:                            ip6_sprintf(&eip6->ip6_src),
                   1906:                            ip6_sprintf(&eip6->ip6_dst),
                   1907:                            reg_mif_num);
                   1908:                }
                   1909: #endif
                   1910:
1.58      simonb   1911:                looutput(mif6table[reg_mif_num].m6_ifp, m,
1.74      christos 1912:                              (struct sockaddr *)__UNCONST(&dst),
1.2       itojun   1913:                              (struct rtentry *) NULL);
1.26      sommerfe 1914:
1.2       itojun   1915:                /* prepare the register head to send to the mrouting daemon */
                   1916:                m = mcp;
                   1917:        }
1.12      itojun   1918:
1.2       itojun   1919:        /*
                   1920:         * Pass the PIM message up to the daemon; if it is a register message
                   1921:         * pass the 'head' only up to the daemon. This includes the
                   1922:         * encapsulator ip6 header, pim header, register header and the
                   1923:         * encapsulated ip6 header.
                   1924:         */
                   1925:   pim6_input_to_daemon:
                   1926:        rip6_input(&m, offp, proto);
1.37      itojun   1927:        return (IPPROTO_DONE);
1.2       itojun   1928: }
1.65      rpaulo   1929:
1.90      thorpej  1930: static int
                   1931: sysctl_net_inet6_pim6_stats(SYSCTLFN_ARGS)
                   1932: {
                   1933:
1.93      thorpej  1934:        return (NETSTAT_SYSCTL(pim6stat_percpu, PIM6_NSTATS));
1.90      thorpej  1935: }
                   1936:
1.65      rpaulo   1937: SYSCTL_SETUP(sysctl_net_inet6_pim6_setup, "sysctl net.inet6.pim6 subtree setup")
                   1938: {
                   1939:        sysctl_createv(clog, 0, NULL, NULL,
                   1940:                       CTLFLAG_PERMANENT,
                   1941:                       CTLTYPE_NODE, "net", NULL,
                   1942:                       NULL, 0, NULL, 0,
                   1943:                       CTL_NET, CTL_EOL);
                   1944:        sysctl_createv(clog, 0, NULL, NULL,
                   1945:                       CTLFLAG_PERMANENT,
                   1946:                       CTLTYPE_NODE, "inet6", NULL,
                   1947:                       NULL, 0, NULL, 0,
                   1948:                       CTL_NET, PF_INET6, CTL_EOL);
                   1949:        sysctl_createv(clog, 0, NULL, NULL,
                   1950:                       CTLFLAG_PERMANENT,
                   1951:                       CTLTYPE_NODE, "pim6",
                   1952:                       SYSCTL_DESCR("PIMv6 settings"),
                   1953:                       NULL, 0, NULL, 0,
                   1954:                       CTL_NET, PF_INET6, IPPROTO_PIM, CTL_EOL);
                   1955:
                   1956:        sysctl_createv(clog, 0, NULL, NULL,
                   1957:                       CTLFLAG_PERMANENT,
                   1958:                       CTLTYPE_STRUCT, "stats",
                   1959:                       SYSCTL_DESCR("PIMv6 statistics"),
1.90      thorpej  1960:                       sysctl_net_inet6_pim6_stats, 0, NULL, 0,
1.65      rpaulo   1961:                       CTL_NET, PF_INET6, IPPROTO_PIM, PIM6CTL_STATS,
                   1962:                       CTL_EOL);
                   1963: }

CVSweb <webmaster@jp.NetBSD.org>