[BACK]Return to ip_mroute.c CVS log [TXT][DIR] Up to [local] / sys / netinet

Annotation of sys/netinet/ip_mroute.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ip_mroute.c,v 1.48 2007/05/22 09:51:13 michele Exp $  */
        !             2: /*     $NetBSD: ip_mroute.c,v 1.85 2004/04/26 01:31:57 matt Exp $      */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1989 Stephen Deering
        !             6:  * Copyright (c) 1992, 1993
        !             7:  *      The Regents of the University of California.  All rights reserved.
        !             8:  *
        !             9:  * This code is derived from software contributed to Berkeley by
        !            10:  * Stephen Deering of Stanford University.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. Neither the name of the University nor the names of its contributors
        !            21:  *    may be used to endorse or promote products derived from this software
        !            22:  *    without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            34:  * SUCH DAMAGE.
        !            35:  *
        !            36:  *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
        !            37:  */
        !            38:
        !            39: /*
        !            40:  * IP multicast forwarding procedures
        !            41:  *
        !            42:  * Written by David Waitzman, BBN Labs, August 1988.
        !            43:  * Modified by Steve Deering, Stanford, February 1989.
        !            44:  * Modified by Mark J. Steiglitz, Stanford, May, 1991
        !            45:  * Modified by Van Jacobson, LBL, January 1993
        !            46:  * Modified by Ajit Thyagarajan, PARC, August 1993
        !            47:  * Modified by Bill Fenner, PARC, April 1994
        !            48:  * Modified by Charles M. Hannum, NetBSD, May 1995.
        !            49:  * Modified by Ahmed Helmy, SGI, June 1996
        !            50:  * Modified by George Edmond Eddy (Rusty), ISI, February 1998
        !            51:  * Modified by Pavlin Radoslavov, USC/ISI, May 1998, August 1999, October 2000
        !            52:  * Modified by Hitoshi Asaeda, WIDE, August 2000
        !            53:  * Modified by Pavlin Radoslavov, ICSI, October 2002
        !            54:  *
        !            55:  * MROUTING Revision: 1.2
        !            56:  * and PIM-SMv2 and PIM-DM support, advanced API support,
        !            57:  * bandwidth metering and signaling
        !            58:  */
        !            59:
        !            60: #ifdef PIM
        !            61: #define _PIM_VT 1
        !            62: #endif
        !            63:
        !            64: #include <sys/param.h>
        !            65: #include <sys/systm.h>
        !            66: #include <sys/mbuf.h>
        !            67: #include <sys/socket.h>
        !            68: #include <sys/socketvar.h>
        !            69: #include <sys/protosw.h>
        !            70: #include <sys/errno.h>
        !            71: #include <sys/time.h>
        !            72: #include <sys/kernel.h>
        !            73: #include <sys/ioctl.h>
        !            74: #include <sys/syslog.h>
        !            75: #include <sys/timeout.h>
        !            76:
        !            77: #include <net/if.h>
        !            78: #include <net/route.h>
        !            79: #include <net/raw_cb.h>
        !            80:
        !            81: #include <netinet/in.h>
        !            82: #include <netinet/in_var.h>
        !            83: #include <netinet/in_systm.h>
        !            84: #include <netinet/ip.h>
        !            85: #include <netinet/ip_var.h>
        !            86: #include <netinet/in_pcb.h>
        !            87: #include <netinet/udp.h>
        !            88: #include <netinet/igmp.h>
        !            89: #include <netinet/igmp_var.h>
        !            90: #include <netinet/ip_mroute.h>
        !            91: #ifdef PIM
        !            92: #include <netinet/pim.h>
        !            93: #include <netinet/pim_var.h>
        !            94: #endif
        !            95:
        !            96: #include <sys/stdarg.h>
        !            97:
        !            98: #define IP_MULTICASTOPTS 0
        !            99: #define        M_PULLUP(m, len)                                                 \
        !           100:        do {                                                             \
        !           101:                if ((m) && ((m)->m_flags & M_EXT || (m)->m_len < (len))) \
        !           102:                        (m) = m_pullup((m), (len));                      \
        !           103:        } while (/*CONSTCOND*/ 0)
        !           104:
        !           105: /*
        !           106:  * Globals.  All but ip_mrouter and ip_mrtproto could be static,
        !           107:  * except for netstat or debugging purposes.
        !           108:  */
        !           109: struct socket  *ip_mrouter  = NULL;
        !           110: int            ip_mrtproto = IGMP_DVMRP;    /* for netstat only */
        !           111:
        !           112: #define NO_RTE_FOUND   0x1
        !           113: #define RTE_FOUND      0x2
        !           114:
        !           115: #define        MFCHASH(a, g)                                                   \
        !           116:        ((((a).s_addr >> 20) ^ ((a).s_addr >> 10) ^ (a).s_addr ^        \
        !           117:            ((g).s_addr >> 20) ^ ((g).s_addr >> 10) ^ (g).s_addr) & mfchash)
        !           118: LIST_HEAD(mfchashhdr, mfc) *mfchashtbl;
        !           119: u_long mfchash;
        !           120:
        !           121: u_char         nexpire[MFCTBLSIZ];
        !           122: struct vif     viftable[MAXVIFS];
        !           123: struct mrtstat mrtstat;
        !           124: u_int          mrtdebug = 0;     /* debug level        */
        !           125: #define                DEBUG_MFC       0x02
        !           126: #define                DEBUG_FORWARD   0x04
        !           127: #define                DEBUG_EXPIRE    0x08
        !           128: #define                DEBUG_XMIT      0x10
        !           129: #define                DEBUG_PIM       0x20
        !           130:
        !           131: #define                VIFI_INVALID    ((vifi_t) -1)
        !           132:
        !           133: u_int          tbfdebug = 0;     /* tbf debug level    */
        !           134: #ifdef RSVP_ISI
        !           135: u_int          rsvpdebug = 0;    /* rsvp debug level   */
        !           136: extern struct socket *ip_rsvpd;
        !           137: extern int rsvp_on;
        !           138: #endif /* RSVP_ISI */
        !           139:
        !           140: #define                EXPIRE_TIMEOUT  (hz / 4)        /* 4x / second */
        !           141: #define                UPCALL_EXPIRE   6               /* number of timeouts */
        !           142: struct timeout expire_upcalls_ch;
        !           143:
        !           144: /*
        !           145:  * Define the token bucket filter structures
        !           146:  */
        !           147:
        !           148: #define                TBF_REPROCESS   (hz / 100)      /* 100x / second */
        !           149:
        !           150: static int get_sg_cnt(struct sioc_sg_req *);
        !           151: static int get_vif_cnt(struct sioc_vif_req *);
        !           152: static int ip_mrouter_init(struct socket *, struct mbuf *);
        !           153: static int get_version(struct mbuf *);
        !           154: static int set_assert(struct mbuf *);
        !           155: static int get_assert(struct mbuf *);
        !           156: static int add_vif(struct mbuf *);
        !           157: static int del_vif(struct mbuf *);
        !           158: static void update_mfc_params(struct mfc *, struct mfcctl2 *);
        !           159: static void init_mfc_params(struct mfc *, struct mfcctl2 *);
        !           160: static void expire_mfc(struct mfc *);
        !           161: static int add_mfc(struct mbuf *);
        !           162: #ifdef UPCALL_TIMING
        !           163: static void collate(struct timeval *);
        !           164: #endif
        !           165: static int del_mfc(struct mbuf *);
        !           166: static int set_api_config(struct mbuf *); /* chose API capabilities */
        !           167: static int get_api_support(struct mbuf *);
        !           168: static int get_api_config(struct mbuf *);
        !           169: static int socket_send(struct socket *, struct mbuf *,
        !           170:                            struct sockaddr_in *);
        !           171: static void expire_upcalls(void *);
        !           172: #ifdef RSVP_ISI
        !           173: static int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *, vifi_t);
        !           174: #else
        !           175: static int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *);
        !           176: #endif
        !           177: static void phyint_send(struct ip *, struct vif *, struct mbuf *);
        !           178: static void encap_send(struct ip *, struct vif *, struct mbuf *);
        !           179: static void tbf_control(struct vif *, struct mbuf *, struct ip *,
        !           180:                             u_int32_t);
        !           181: static void tbf_queue(struct vif *, struct mbuf *);
        !           182: static void tbf_process_q(struct vif *);
        !           183: static void tbf_reprocess_q(void *);
        !           184: static int tbf_dq_sel(struct vif *, struct ip *);
        !           185: static void tbf_send_packet(struct vif *, struct mbuf *);
        !           186: static void tbf_update_tokens(struct vif *);
        !           187: static int priority(struct vif *, struct ip *);
        !           188:
        !           189: /*
        !           190:  * Bandwidth monitoring
        !           191:  */
        !           192: static void free_bw_list(struct bw_meter *);
        !           193: static int add_bw_upcall(struct mbuf *);
        !           194: static int del_bw_upcall(struct mbuf *);
        !           195: static void bw_meter_receive_packet(struct bw_meter *, int , struct timeval *);
        !           196: static void bw_meter_prepare_upcall(struct bw_meter *, struct timeval *);
        !           197: static void bw_upcalls_send(void);
        !           198: static void schedule_bw_meter(struct bw_meter *, struct timeval *);
        !           199: static void unschedule_bw_meter(struct bw_meter *);
        !           200: static void bw_meter_process(void);
        !           201: static void expire_bw_upcalls_send(void *);
        !           202: static void expire_bw_meter_process(void *);
        !           203:
        !           204: #ifdef PIM
        !           205: static int pim_register_send(struct ip *, struct vif *,
        !           206:                struct mbuf *, struct mfc *);
        !           207: static int pim_register_send_rp(struct ip *, struct vif *,
        !           208:                struct mbuf *, struct mfc *);
        !           209: static int pim_register_send_upcall(struct ip *, struct vif *,
        !           210:                struct mbuf *, struct mfc *);
        !           211: static struct mbuf *pim_register_prepare(struct ip *, struct mbuf *);
        !           212: #endif
        !           213:
        !           214: /*
        !           215:  * 'Interfaces' associated with decapsulator (so we can tell
        !           216:  * packets that went through it from ones that get reflected
        !           217:  * by a broken gateway).  These interfaces are never linked into
        !           218:  * the system ifnet list & no routes point to them.  I.e., packets
        !           219:  * can't be sent this way.  They only exist as a placeholder for
        !           220:  * multicast source verification.
        !           221:  */
        !           222: #if 0
        !           223: struct ifnet multicast_decap_if[MAXVIFS];
        !           224: #endif
        !           225:
        !           226: #define        ENCAP_TTL       64
        !           227: #define        ENCAP_PROTO     IPPROTO_IPIP    /* 4 */
        !           228:
        !           229: /* prototype IP hdr for encapsulated packets */
        !           230: struct ip multicast_encap_iphdr = {
        !           231: #if BYTE_ORDER == LITTLE_ENDIAN
        !           232:        sizeof(struct ip) >> 2, IPVERSION,
        !           233: #else
        !           234:        IPVERSION, sizeof(struct ip) >> 2,
        !           235: #endif
        !           236:        0,                              /* tos */
        !           237:        sizeof(struct ip),              /* total length */
        !           238:        0,                              /* id */
        !           239:        0,                              /* frag offset */
        !           240:        ENCAP_TTL, ENCAP_PROTO,
        !           241:        0,                              /* checksum */
        !           242: };
        !           243:
        !           244: /*
        !           245:  * Bandwidth meter variables and constants
        !           246:  */
        !           247:
        !           248: /*
        !           249:  * Pending timeouts are stored in a hash table, the key being the
        !           250:  * expiration time. Periodically, the entries are analysed and processed.
        !           251:  */
        !           252: #define BW_METER_BUCKETS       1024
        !           253: static struct bw_meter *bw_meter_timers[BW_METER_BUCKETS];
        !           254: struct timeout bw_meter_ch;
        !           255: #define BW_METER_PERIOD (hz)           /* periodical handling of bw meters */
        !           256:
        !           257: /*
        !           258:  * Pending upcalls are stored in a vector which is flushed when
        !           259:  * full, or periodically
        !           260:  */
        !           261: static struct bw_upcall        bw_upcalls[BW_UPCALLS_MAX];
        !           262: static u_int   bw_upcalls_n; /* # of pending upcalls */
        !           263: struct timeout bw_upcalls_ch;
        !           264: #define BW_UPCALLS_PERIOD (hz)         /* periodical flush of bw upcalls */
        !           265:
        !           266: #ifdef PIM
        !           267: struct pimstat pimstat;
        !           268:
        !           269: /*
        !           270:  * Note: the PIM Register encapsulation adds the following in front of a
        !           271:  * data packet:
        !           272:  *
        !           273:  * struct pim_encap_hdr {
        !           274:  *    struct ip ip;
        !           275:  *    struct pim_encap_pimhdr  pim;
        !           276:  * }
        !           277:  *
        !           278:  */
        !           279:
        !           280: struct pim_encap_pimhdr {
        !           281:        struct pim pim;
        !           282:        uint32_t   flags;
        !           283: };
        !           284:
        !           285: static struct ip pim_encap_iphdr = {
        !           286: #if BYTE_ORDER == LITTLE_ENDIAN
        !           287:        sizeof(struct ip) >> 2,
        !           288:        IPVERSION,
        !           289: #else
        !           290:        IPVERSION,
        !           291:        sizeof(struct ip) >> 2,
        !           292: #endif
        !           293:        0,                      /* tos */
        !           294:        sizeof(struct ip),      /* total length */
        !           295:        0,                      /* id */
        !           296:        0,                      /* frag offset */
        !           297:        ENCAP_TTL,
        !           298:        IPPROTO_PIM,
        !           299:        0,                      /* checksum */
        !           300: };
        !           301:
        !           302: static struct pim_encap_pimhdr pim_encap_pimhdr = {
        !           303:     {
        !           304:        PIM_MAKE_VT(PIM_VERSION, PIM_REGISTER), /* PIM vers and message type */
        !           305:        0,                      /* reserved */
        !           306:        0,                      /* checksum */
        !           307:     },
        !           308:     0                          /* flags */
        !           309: };
        !           310:
        !           311: static struct ifnet multicast_register_if;
        !           312: static vifi_t reg_vif_num = VIFI_INVALID;
        !           313: #endif /* PIM */
        !           314:
        !           315:
        !           316: /*
        !           317:  * Private variables.
        !           318:  */
        !           319: static vifi_t     numvifs = 0;
        !           320: static int have_encap_tunnel = 0;
        !           321:
        !           322: /*
        !           323:  * whether or not special PIM assert processing is enabled.
        !           324:  */
        !           325: static int pim_assert;
        !           326: /*
        !           327:  * Rate limit for assert notification messages, in usec
        !           328:  */
        !           329: #define ASSERT_MSG_TIME                3000000
        !           330:
        !           331: /*
        !           332:  * Kernel multicast routing API capabilities and setup.
        !           333:  * If more API capabilities are added to the kernel, they should be
        !           334:  * recorded in `mrt_api_support'.
        !           335:  */
        !           336: static const u_int32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF |
        !           337:                                          MRT_MFC_FLAGS_BORDER_VIF |
        !           338:                                          MRT_MFC_RP |
        !           339:                                          MRT_MFC_BW_UPCALL);
        !           340: static u_int32_t mrt_api_config = 0;
        !           341:
        !           342: /*
        !           343:  * Find a route for a given origin IP address and Multicast group address
        !           344:  * Type of service parameter to be added in the future!!!
        !           345:  * Statistics are updated by the caller if needed
        !           346:  * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses)
        !           347:  */
        !           348: static struct mfc *
        !           349: mfc_find(struct in_addr *o, struct in_addr *g)
        !           350: {
        !           351:        struct mfc *rt;
        !           352:
        !           353:        LIST_FOREACH(rt, &mfchashtbl[MFCHASH(*o, *g)], mfc_hash) {
        !           354:                if (in_hosteq(rt->mfc_origin, *o) &&
        !           355:                    in_hosteq(rt->mfc_mcastgrp, *g) &&
        !           356:                    (rt->mfc_stall == NULL))
        !           357:                        break;
        !           358:        }
        !           359:
        !           360:        return (rt);
        !           361: }
        !           362:
        !           363: /*
        !           364:  * Macros to compute elapsed time efficiently
        !           365:  * Borrowed from Van Jacobson's scheduling code
        !           366:  */
        !           367: #define TV_DELTA(a, b, delta) do {                                     \
        !           368:        int xxs;                                                        \
        !           369:        delta = (a).tv_usec - (b).tv_usec;                              \
        !           370:        xxs = (a).tv_sec - (b).tv_sec;                                  \
        !           371:        switch (xxs) {                                                  \
        !           372:        case 2:                                                         \
        !           373:                delta += 1000000;                                       \
        !           374:                /* FALLTHROUGH */                                       \
        !           375:        case 1:                                                         \
        !           376:                delta += 1000000;                                       \
        !           377:                /* FALLTHROUGH */                                       \
        !           378:        case 0:                                                         \
        !           379:                break;                                                  \
        !           380:        default:                                                        \
        !           381:                delta += (1000000 * xxs);                               \
        !           382:                break;                                                  \
        !           383:        }                                                               \
        !           384: } while (/*CONSTCOND*/ 0)
        !           385:
        !           386: #ifdef UPCALL_TIMING
        !           387: u_int32_t upcall_data[51];
        !           388: #endif /* UPCALL_TIMING */
        !           389:
        !           390: /*
        !           391:  * Handle MRT setsockopt commands to modify the multicast routing tables.
        !           392:  */
        !           393: int
        !           394: ip_mrouter_set(struct socket *so, int optname, struct mbuf **m)
        !           395: {
        !           396:        int error;
        !           397:
        !           398:        if (optname != MRT_INIT && so != ip_mrouter)
        !           399:                error = ENOPROTOOPT;
        !           400:        else
        !           401:                switch (optname) {
        !           402:                case MRT_INIT:
        !           403:                        error = ip_mrouter_init(so, *m);
        !           404:                        break;
        !           405:                case MRT_DONE:
        !           406:                        error = ip_mrouter_done();
        !           407:                        break;
        !           408:                case MRT_ADD_VIF:
        !           409:                        error = add_vif(*m);
        !           410:                        break;
        !           411:                case MRT_DEL_VIF:
        !           412:                        error = del_vif(*m);
        !           413:                        break;
        !           414:                case MRT_ADD_MFC:
        !           415:                        error = add_mfc(*m);
        !           416:                        break;
        !           417:                case MRT_DEL_MFC:
        !           418:                        error = del_mfc(*m);
        !           419:                        break;
        !           420:                case MRT_ASSERT:
        !           421:                        error = set_assert(*m);
        !           422:                        break;
        !           423:                case MRT_API_CONFIG:
        !           424:                        error = set_api_config(*m);
        !           425:                        break;
        !           426:                case MRT_ADD_BW_UPCALL:
        !           427:                        error = add_bw_upcall(*m);
        !           428:                        break;
        !           429:                case MRT_DEL_BW_UPCALL:
        !           430:                        error = del_bw_upcall(*m);
        !           431:                        break;
        !           432:                default:
        !           433:                        error = ENOPROTOOPT;
        !           434:                        break;
        !           435:                }
        !           436:
        !           437:        if (*m)
        !           438:                m_free(*m);
        !           439:        return (error);
        !           440: }
        !           441:
        !           442: /*
        !           443:  * Handle MRT getsockopt commands
        !           444:  */
        !           445: int
        !           446: ip_mrouter_get(struct socket *so, int optname, struct mbuf **m)
        !           447: {
        !           448:        int error;
        !           449:
        !           450:        if (so != ip_mrouter)
        !           451:                error = ENOPROTOOPT;
        !           452:        else {
        !           453:                *m = m_get(M_WAIT, MT_SOOPTS);
        !           454:
        !           455:                switch (optname) {
        !           456:                case MRT_VERSION:
        !           457:                        error = get_version(*m);
        !           458:                        break;
        !           459:                case MRT_ASSERT:
        !           460:                        error = get_assert(*m);
        !           461:                        break;
        !           462:                case MRT_API_SUPPORT:
        !           463:                        error = get_api_support(*m);
        !           464:                        break;
        !           465:                case MRT_API_CONFIG:
        !           466:                        error = get_api_config(*m);
        !           467:                        break;
        !           468:                default:
        !           469:                        error = ENOPROTOOPT;
        !           470:                        break;
        !           471:                }
        !           472:
        !           473:                if (error)
        !           474:                        m_free(*m);
        !           475:        }
        !           476:
        !           477:        return (error);
        !           478: }
        !           479:
        !           480: /*
        !           481:  * Handle ioctl commands to obtain information from the cache
        !           482:  */
        !           483: int
        !           484: mrt_ioctl(struct socket *so, u_long cmd, caddr_t data)
        !           485: {
        !           486:        int error;
        !           487:
        !           488:        if (so != ip_mrouter)
        !           489:                error = EINVAL;
        !           490:        else
        !           491:                switch (cmd) {
        !           492:                case SIOCGETVIFCNT:
        !           493:                        error = get_vif_cnt((struct sioc_vif_req *)data);
        !           494:                        break;
        !           495:                case SIOCGETSGCNT:
        !           496:                        error = get_sg_cnt((struct sioc_sg_req *)data);
        !           497:                        break;
        !           498:                default:
        !           499:                        error = EINVAL;
        !           500:                        break;
        !           501:                }
        !           502:
        !           503:        return (error);
        !           504: }
        !           505:
        !           506: /*
        !           507:  * returns the packet, byte, rpf-failure count for the source group provided
        !           508:  */
        !           509: static int
        !           510: get_sg_cnt(struct sioc_sg_req *req)
        !           511: {
        !           512:        int s;
        !           513:        struct mfc *rt;
        !           514:
        !           515:        s = splsoftnet();
        !           516:        rt = mfc_find(&req->src, &req->grp);
        !           517:        if (rt == NULL) {
        !           518:                splx(s);
        !           519:                req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
        !           520:                return (EADDRNOTAVAIL);
        !           521:        }
        !           522:        req->pktcnt = rt->mfc_pkt_cnt;
        !           523:        req->bytecnt = rt->mfc_byte_cnt;
        !           524:        req->wrong_if = rt->mfc_wrong_if;
        !           525:        splx(s);
        !           526:
        !           527:        return (0);
        !           528: }
        !           529:
        !           530: /*
        !           531:  * returns the input and output packet and byte counts on the vif provided
        !           532:  */
        !           533: static int
        !           534: get_vif_cnt(struct sioc_vif_req *req)
        !           535: {
        !           536:        vifi_t vifi = req->vifi;
        !           537:
        !           538:        if (vifi >= numvifs)
        !           539:                return (EINVAL);
        !           540:
        !           541:        req->icount = viftable[vifi].v_pkt_in;
        !           542:        req->ocount = viftable[vifi].v_pkt_out;
        !           543:        req->ibytes = viftable[vifi].v_bytes_in;
        !           544:        req->obytes = viftable[vifi].v_bytes_out;
        !           545:
        !           546:        return (0);
        !           547: }
        !           548:
        !           549: /*
        !           550:  * Enable multicast routing
        !           551:  */
        !           552: static int
        !           553: ip_mrouter_init(struct socket *so, struct mbuf *m)
        !           554: {
        !           555:        int *v;
        !           556:
        !           557:        if (mrtdebug)
        !           558:                log(LOG_DEBUG,
        !           559:                    "ip_mrouter_init: so_type = %d, pr_protocol = %d\n",
        !           560:                    so->so_type, so->so_proto->pr_protocol);
        !           561:
        !           562:        if (so->so_type != SOCK_RAW ||
        !           563:            so->so_proto->pr_protocol != IPPROTO_IGMP)
        !           564:                return (EOPNOTSUPP);
        !           565:
        !           566:        if (m == NULL || m->m_len < sizeof(int))
        !           567:                return (EINVAL);
        !           568:
        !           569:        v = mtod(m, int *);
        !           570:        if (*v != 1)
        !           571:                return (EINVAL);
        !           572:
        !           573:        if (ip_mrouter != NULL)
        !           574:                return (EADDRINUSE);
        !           575:
        !           576:        ip_mrouter = so;
        !           577:
        !           578:        mfchashtbl = hashinit(MFCTBLSIZ, M_MRTABLE, M_WAITOK, &mfchash);
        !           579:        bzero((caddr_t)nexpire, sizeof(nexpire));
        !           580:
        !           581:        pim_assert = 0;
        !           582:
        !           583:        timeout_set(&expire_upcalls_ch, expire_upcalls, NULL);
        !           584:        timeout_add(&expire_upcalls_ch, EXPIRE_TIMEOUT);
        !           585:
        !           586:        timeout_set(&bw_upcalls_ch, expire_bw_upcalls_send, NULL);
        !           587:        timeout_add(&bw_upcalls_ch, BW_UPCALLS_PERIOD);
        !           588:
        !           589:        timeout_set(&bw_meter_ch, expire_bw_meter_process, NULL);
        !           590:        timeout_add(&bw_meter_ch, BW_METER_PERIOD);
        !           591:
        !           592:        if (mrtdebug)
        !           593:                log(LOG_DEBUG, "ip_mrouter_init\n");
        !           594:
        !           595:        return (0);
        !           596: }
        !           597:
        !           598: /*
        !           599:  * Disable multicast routing
        !           600:  */
        !           601: int
        !           602: ip_mrouter_done()
        !           603: {
        !           604:        vifi_t vifi;
        !           605:        struct vif *vifp;
        !           606:        int i;
        !           607:        int s;
        !           608:
        !           609:        s = splsoftnet();
        !           610:
        !           611:        /* Clear out all the vifs currently in use. */
        !           612:        for (vifi = 0; vifi < numvifs; vifi++) {
        !           613:                vifp = &viftable[vifi];
        !           614:                if (!in_nullhost(vifp->v_lcl_addr))
        !           615:                        reset_vif(vifp);
        !           616:        }
        !           617:
        !           618:        numvifs = 0;
        !           619:        pim_assert = 0;
        !           620:        mrt_api_config = 0;
        !           621:
        !           622:        timeout_del(&expire_upcalls_ch);
        !           623:        timeout_del(&bw_upcalls_ch);
        !           624:        timeout_del(&bw_meter_ch);
        !           625:
        !           626:        /*
        !           627:         * Free all multicast forwarding cache entries.
        !           628:         */
        !           629:        for (i = 0; i < MFCTBLSIZ; i++) {
        !           630:                struct mfc *rt, *nrt;
        !           631:
        !           632:                for (rt = LIST_FIRST(&mfchashtbl[i]); rt; rt = nrt) {
        !           633:                        nrt = LIST_NEXT(rt, mfc_hash);
        !           634:
        !           635:                        expire_mfc(rt);
        !           636:                }
        !           637:        }
        !           638:
        !           639:        bzero((caddr_t)nexpire, sizeof(nexpire));
        !           640:        free(mfchashtbl, M_MRTABLE);
        !           641:        mfchashtbl = NULL;
        !           642:
        !           643:        bw_upcalls_n = 0;
        !           644:        bzero(bw_meter_timers, sizeof(bw_meter_timers));
        !           645:
        !           646:        /* Reset de-encapsulation cache. */
        !           647:        have_encap_tunnel = 0;
        !           648:
        !           649:        ip_mrouter = NULL;
        !           650:
        !           651:        splx(s);
        !           652:
        !           653:        if (mrtdebug)
        !           654:                log(LOG_DEBUG, "ip_mrouter_done\n");
        !           655:
        !           656:        return (0);
        !           657: }
        !           658:
        !           659: void
        !           660: ip_mrouter_detach(struct ifnet *ifp)
        !           661: {
        !           662:        int vifi, i;
        !           663:        struct vif *vifp;
        !           664:        struct mfc *rt;
        !           665:        struct rtdetq *rte;
        !           666:
        !           667:        /* XXX not sure about side effect to userland routing daemon */
        !           668:        for (vifi = 0; vifi < numvifs; vifi++) {
        !           669:                vifp = &viftable[vifi];
        !           670:                if (vifp->v_ifp == ifp)
        !           671:                        reset_vif(vifp);
        !           672:        }
        !           673:        for (i = 0; i < MFCTBLSIZ; i++) {
        !           674:                if (nexpire[i] == 0)
        !           675:                        continue;
        !           676:                LIST_FOREACH(rt, &mfchashtbl[i], mfc_hash) {
        !           677:                        for (rte = rt->mfc_stall; rte; rte = rte->next) {
        !           678:                                if (rte->ifp == ifp)
        !           679:                                        rte->ifp = NULL;
        !           680:                        }
        !           681:                }
        !           682:        }
        !           683: }
        !           684:
        !           685: static int
        !           686: get_version(struct mbuf *m)
        !           687: {
        !           688:        int *v = mtod(m, int *);
        !           689:
        !           690:        *v = 0x0305;    /* XXX !!!! */
        !           691:        m->m_len = sizeof(int);
        !           692:        return (0);
        !           693: }
        !           694:
        !           695: /*
        !           696:  * Set PIM assert processing global
        !           697:  */
        !           698: static int
        !           699: set_assert(struct mbuf *m)
        !           700: {
        !           701:        int *i;
        !           702:
        !           703:        if (m == NULL || m->m_len < sizeof(int))
        !           704:                return (EINVAL);
        !           705:
        !           706:        i = mtod(m, int *);
        !           707:        pim_assert = !!*i;
        !           708:        return (0);
        !           709: }
        !           710:
        !           711: /*
        !           712:  * Get PIM assert processing global
        !           713:  */
        !           714: static int
        !           715: get_assert(struct mbuf *m)
        !           716: {
        !           717:        int *i = mtod(m, int *);
        !           718:
        !           719:        *i = pim_assert;
        !           720:        m->m_len = sizeof(int);
        !           721:        return (0);
        !           722: }
        !           723:
        !           724: /*
        !           725:  * Configure API capabilities
        !           726:  */
        !           727: static int
        !           728: set_api_config(struct mbuf *m)
        !           729: {
        !           730:        int i;
        !           731:        u_int32_t *apival;
        !           732:
        !           733:        if (m == NULL || m->m_len < sizeof(u_int32_t))
        !           734:                return (EINVAL);
        !           735:
        !           736:        apival = mtod(m, u_int32_t *);
        !           737:
        !           738:        /*
        !           739:         * We can set the API capabilities only if it is the first operation
        !           740:         * after MRT_INIT. I.e.:
        !           741:         *  - there are no vifs installed
        !           742:         *  - pim_assert is not enabled
        !           743:         *  - the MFC table is empty
        !           744:         */
        !           745:        if (numvifs > 0) {
        !           746:                *apival = 0;
        !           747:                return (EPERM);
        !           748:        }
        !           749:        if (pim_assert) {
        !           750:                *apival = 0;
        !           751:                return (EPERM);
        !           752:        }
        !           753:        for (i = 0; i < MFCTBLSIZ; i++) {
        !           754:                if (LIST_FIRST(&mfchashtbl[i]) != NULL) {
        !           755:                        *apival = 0;
        !           756:                        return (EPERM);
        !           757:                }
        !           758:        }
        !           759:
        !           760:        mrt_api_config = *apival & mrt_api_support;
        !           761:        *apival = mrt_api_config;
        !           762:
        !           763:        return (0);
        !           764: }
        !           765:
        !           766: /*
        !           767:  * Get API capabilities
        !           768:  */
        !           769: static int
        !           770: get_api_support(struct mbuf *m)
        !           771: {
        !           772:        u_int32_t *apival;
        !           773:
        !           774:        if (m == NULL || m->m_len < sizeof(u_int32_t))
        !           775:                return (EINVAL);
        !           776:
        !           777:        apival = mtod(m, u_int32_t *);
        !           778:
        !           779:        *apival = mrt_api_support;
        !           780:
        !           781:        return (0);
        !           782: }
        !           783:
        !           784: /*
        !           785:  * Get API configured capabilities
        !           786:  */
        !           787: static int
        !           788: get_api_config(struct mbuf *m)
        !           789: {
        !           790:        u_int32_t *apival;
        !           791:
        !           792:        if (m == NULL || m->m_len < sizeof(u_int32_t))
        !           793:                return (EINVAL);
        !           794:
        !           795:        apival = mtod(m, u_int32_t *);
        !           796:
        !           797:        *apival = mrt_api_config;
        !           798:
        !           799:        return (0);
        !           800: }
        !           801:
        !           802: static struct sockaddr_in sin = { sizeof(sin), AF_INET };
        !           803:
        !           804: /*
        !           805:  * Add a vif to the vif table
        !           806:  */
        !           807: static int
        !           808: add_vif(struct mbuf *m)
        !           809: {
        !           810:        struct vifctl *vifcp;
        !           811:        struct vif *vifp;
        !           812:        struct ifaddr *ifa;
        !           813:        struct ifnet *ifp;
        !           814:        struct ifreq ifr;
        !           815:        int error, s;
        !           816:
        !           817:        if (m == NULL || m->m_len < sizeof(struct vifctl))
        !           818:                return (EINVAL);
        !           819:
        !           820:        vifcp = mtod(m, struct vifctl *);
        !           821:        if (vifcp->vifc_vifi >= MAXVIFS)
        !           822:                return (EINVAL);
        !           823:        if (in_nullhost(vifcp->vifc_lcl_addr))
        !           824:                return (EADDRNOTAVAIL);
        !           825:
        !           826:        vifp = &viftable[vifcp->vifc_vifi];
        !           827:        if (!in_nullhost(vifp->v_lcl_addr))
        !           828:                return (EADDRINUSE);
        !           829:
        !           830:        /* Find the interface with an address in AF_INET family. */
        !           831: #ifdef PIM
        !           832:        if (vifcp->vifc_flags & VIFF_REGISTER) {
        !           833:                /*
        !           834:                 * XXX: Because VIFF_REGISTER does not really need a valid
        !           835:                 * local interface (e.g. it could be 127.0.0.2), we don't
        !           836:                 * check its address.
        !           837:                 */
        !           838:            ifp = NULL;
        !           839:        } else
        !           840: #endif
        !           841:        {
        !           842:                sin.sin_addr = vifcp->vifc_lcl_addr;
        !           843:                ifa = ifa_ifwithaddr(sintosa(&sin));
        !           844:                if (ifa == NULL)
        !           845:                        return (EADDRNOTAVAIL);
        !           846:                ifp = ifa->ifa_ifp;
        !           847:        }
        !           848:
        !           849:        if (vifcp->vifc_flags & VIFF_TUNNEL) {
        !           850:                /* tunnels are no longer supported use gif(4) instead */
        !           851:                return (EOPNOTSUPP);
        !           852: #ifdef PIM
        !           853:        } else if (vifcp->vifc_flags & VIFF_REGISTER) {
        !           854:                ifp = &multicast_register_if;
        !           855:                if (mrtdebug)
        !           856:                        log(LOG_DEBUG, "Adding a register vif, ifp: %p\n",
        !           857:                            (void *)ifp);
        !           858:                if (reg_vif_num == VIFI_INVALID) {
        !           859:                        bzero(ifp, sizeof(*ifp));
        !           860:                        snprintf(ifp->if_xname, sizeof ifp->if_xname,
        !           861:                                 "register_vif");
        !           862:                        ifp->if_flags = IFF_LOOPBACK;
        !           863:                        bzero(&vifp->v_route, sizeof(vifp->v_route));
        !           864:                        reg_vif_num = vifcp->vifc_vifi;
        !           865:                }
        !           866: #endif
        !           867:        } else {
        !           868:                /* Use the physical interface associated with the address. */
        !           869:                ifp = ifa->ifa_ifp;
        !           870:
        !           871:                /* Make sure the interface supports multicast. */
        !           872:                if ((ifp->if_flags & IFF_MULTICAST) == 0)
        !           873:                        return (EOPNOTSUPP);
        !           874:
        !           875:                /* Enable promiscuous reception of all IP multicasts. */
        !           876:                satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
        !           877:                satosin(&ifr.ifr_addr)->sin_family = AF_INET;
        !           878:                satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
        !           879:                error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
        !           880:                if (error)
        !           881:                        return (error);
        !           882:        }
        !           883:
        !           884:        s = splsoftnet();
        !           885:
        !           886:        /* Define parameters for the tbf structure. */
        !           887:        vifp->tbf_q = NULL;
        !           888:        vifp->tbf_t = &vifp->tbf_q;
        !           889:        microtime(&vifp->tbf_last_pkt_t);
        !           890:        vifp->tbf_n_tok = 0;
        !           891:        vifp->tbf_q_len = 0;
        !           892:        vifp->tbf_max_q_len = MAXQSIZE;
        !           893:
        !           894:        vifp->v_flags = vifcp->vifc_flags;
        !           895:        vifp->v_threshold = vifcp->vifc_threshold;
        !           896:        /* scaling up here allows division by 1024 in critical code */
        !           897:        vifp->v_rate_limit = vifcp->vifc_rate_limit * 1024 / 1000;
        !           898:        vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
        !           899:        vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
        !           900:        vifp->v_ifp = ifp;
        !           901:        /* Initialize per vif pkt counters. */
        !           902:        vifp->v_pkt_in = 0;
        !           903:        vifp->v_pkt_out = 0;
        !           904:        vifp->v_bytes_in = 0;
        !           905:        vifp->v_bytes_out = 0;
        !           906:
        !           907:        timeout_del(&vifp->v_repq_ch);
        !           908:
        !           909: #ifdef RSVP_ISI
        !           910:        vifp->v_rsvp_on = 0;
        !           911:        vifp->v_rsvpd = NULL;
        !           912: #endif /* RSVP_ISI */
        !           913:
        !           914:        splx(s);
        !           915:
        !           916:        /* Adjust numvifs up if the vifi is higher than numvifs. */
        !           917:        if (numvifs <= vifcp->vifc_vifi)
        !           918:                numvifs = vifcp->vifc_vifi + 1;
        !           919:
        !           920:        if (mrtdebug)
        !           921:                log(LOG_DEBUG, "add_vif #%d, lcladdr %x, %s %x, "
        !           922:                    "thresh %x, rate %d\n",
        !           923:                    vifcp->vifc_vifi,
        !           924:                    ntohl(vifcp->vifc_lcl_addr.s_addr),
        !           925:                    (vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask",
        !           926:                    ntohl(vifcp->vifc_rmt_addr.s_addr),
        !           927:                    vifcp->vifc_threshold,
        !           928:                    vifcp->vifc_rate_limit);
        !           929:
        !           930:        return (0);
        !           931: }
        !           932:
        !           933: void
        !           934: reset_vif(struct vif *vifp)
        !           935: {
        !           936:        struct mbuf *m, *n;
        !           937:        struct ifnet *ifp;
        !           938:        struct ifreq ifr;
        !           939:
        !           940:        timeout_set(&vifp->v_repq_ch, tbf_reprocess_q, vifp);
        !           941:
        !           942:        /*
        !           943:         * Free packets queued at the interface
        !           944:         */
        !           945:        for (m = vifp->tbf_q; m != NULL; m = n) {
        !           946:                n = m->m_nextpkt;
        !           947:                m_freem(m);
        !           948:        }
        !           949:
        !           950:        if (vifp->v_flags & VIFF_TUNNEL) {
        !           951:                /* empty */
        !           952:        } else if (vifp->v_flags & VIFF_REGISTER) {
        !           953: #ifdef PIM
        !           954:                reg_vif_num = VIFI_INVALID;
        !           955: #endif
        !           956:        } else {
        !           957:                satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
        !           958:                satosin(&ifr.ifr_addr)->sin_family = AF_INET;
        !           959:                satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
        !           960:                ifp = vifp->v_ifp;
        !           961:                (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
        !           962:        }
        !           963:        bzero((caddr_t)vifp, sizeof(*vifp));
        !           964: }
        !           965:
        !           966: /*
        !           967:  * Delete a vif from the vif table
        !           968:  */
        !           969: static int
        !           970: del_vif(struct mbuf *m)
        !           971: {
        !           972:        vifi_t *vifip;
        !           973:        struct vif *vifp;
        !           974:        vifi_t vifi;
        !           975:        int s;
        !           976:
        !           977:        if (m == NULL || m->m_len < sizeof(vifi_t))
        !           978:                return (EINVAL);
        !           979:
        !           980:        vifip = mtod(m, vifi_t *);
        !           981:        if (*vifip >= numvifs)
        !           982:                return (EINVAL);
        !           983:
        !           984:        vifp = &viftable[*vifip];
        !           985:        if (in_nullhost(vifp->v_lcl_addr))
        !           986:                return (EADDRNOTAVAIL);
        !           987:
        !           988:        s = splsoftnet();
        !           989:
        !           990:        reset_vif(vifp);
        !           991:
        !           992:        /* Adjust numvifs down */
        !           993:        for (vifi = numvifs; vifi > 0; vifi--)
        !           994:                if (!in_nullhost(viftable[vifi - 1].v_lcl_addr))
        !           995:                        break;
        !           996:        numvifs = vifi;
        !           997:
        !           998:        splx(s);
        !           999:
        !          1000:        if (mrtdebug)
        !          1001:                log(LOG_DEBUG, "del_vif %d, numvifs %d\n", *vifip, numvifs);
        !          1002:
        !          1003:        return (0);
        !          1004: }
        !          1005:
        !          1006: void
        !          1007: vif_delete(struct ifnet *ifp)
        !          1008: {
        !          1009:        int i;
        !          1010:        struct vif *vifp;
        !          1011:        struct mfc *rt;
        !          1012:        struct rtdetq *rte;
        !          1013:
        !          1014:        for (i = 0; i < numvifs; i++) {
        !          1015:                vifp = &viftable[i];
        !          1016:                if (vifp->v_ifp == ifp)
        !          1017:                        bzero((caddr_t)vifp, sizeof *vifp);
        !          1018:        }
        !          1019:
        !          1020:        for (i = numvifs; i > 0; i--)
        !          1021:                if (!in_nullhost(viftable[i - 1].v_lcl_addr))
        !          1022:                        break;
        !          1023:        numvifs = i;
        !          1024:
        !          1025:        for (i = 0; i < MFCTBLSIZ; i++) {
        !          1026:                if (nexpire[i] == 0)
        !          1027:                        continue;
        !          1028:                LIST_FOREACH(rt, &mfchashtbl[i], mfc_hash) {
        !          1029:                        for (rte = rt->mfc_stall; rte; rte = rte->next) {
        !          1030:                                if (rte->ifp == ifp)
        !          1031:                                        rte->ifp = NULL;
        !          1032:                        }
        !          1033:                }
        !          1034:        }
        !          1035: }
        !          1036:
        !          1037: /*
        !          1038:  * update an mfc entry without resetting counters and S,G addresses.
        !          1039:  */
        !          1040: static void
        !          1041: update_mfc_params(struct mfc *rt, struct mfcctl2 *mfccp)
        !          1042: {
        !          1043:        int i;
        !          1044:
        !          1045:        rt->mfc_parent = mfccp->mfcc_parent;
        !          1046:        for (i = 0; i < numvifs; i++) {
        !          1047:                rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
        !          1048:                rt->mfc_flags[i] = mfccp->mfcc_flags[i] & mrt_api_config &
        !          1049:                    MRT_MFC_FLAGS_ALL;
        !          1050:        }
        !          1051:        /* set the RP address */
        !          1052:        if (mrt_api_config & MRT_MFC_RP)
        !          1053:                rt->mfc_rp = mfccp->mfcc_rp;
        !          1054:        else
        !          1055:                rt->mfc_rp = zeroin_addr;
        !          1056: }
        !          1057:
        !          1058: /*
        !          1059:  * fully initialize an mfc entry from the parameter.
        !          1060:  */
        !          1061: static void
        !          1062: init_mfc_params(struct mfc *rt, struct mfcctl2 *mfccp)
        !          1063: {
        !          1064:        rt->mfc_origin     = mfccp->mfcc_origin;
        !          1065:        rt->mfc_mcastgrp   = mfccp->mfcc_mcastgrp;
        !          1066:
        !          1067:        update_mfc_params(rt, mfccp);
        !          1068:
        !          1069:        /* initialize pkt counters per src-grp */
        !          1070:        rt->mfc_pkt_cnt    = 0;
        !          1071:        rt->mfc_byte_cnt   = 0;
        !          1072:        rt->mfc_wrong_if   = 0;
        !          1073:        timerclear(&rt->mfc_last_assert);
        !          1074: }
        !          1075:
        !          1076: static void
        !          1077: expire_mfc(struct mfc *rt)
        !          1078: {
        !          1079:        struct rtdetq *rte, *nrte;
        !          1080:
        !          1081:        free_bw_list(rt->mfc_bw_meter);
        !          1082:
        !          1083:        for (rte = rt->mfc_stall; rte != NULL; rte = nrte) {
        !          1084:                nrte = rte->next;
        !          1085:                m_freem(rte->m);
        !          1086:                free(rte, M_MRTABLE);
        !          1087:        }
        !          1088:
        !          1089:        LIST_REMOVE(rt, mfc_hash);
        !          1090:        free(rt, M_MRTABLE);
        !          1091: }
        !          1092:
        !          1093: /*
        !          1094:  * Add an mfc entry
        !          1095:  */
        !          1096: static int
        !          1097: add_mfc(struct mbuf *m)
        !          1098: {
        !          1099:        struct mfcctl2 mfcctl2;
        !          1100:        struct mfcctl2 *mfccp;
        !          1101:        struct mfc *rt;
        !          1102:        u_int32_t hash = 0;
        !          1103:        struct rtdetq *rte, *nrte;
        !          1104:        u_short nstl;
        !          1105:        int s;
        !          1106:        int mfcctl_size = sizeof(struct mfcctl);
        !          1107:
        !          1108:        if (mrt_api_config & MRT_API_FLAGS_ALL)
        !          1109:                mfcctl_size = sizeof(struct mfcctl2);
        !          1110:
        !          1111:        if (m == NULL || m->m_len < mfcctl_size)
        !          1112:                return (EINVAL);
        !          1113:
        !          1114:        /*
        !          1115:         * select data size depending on API version.
        !          1116:         */
        !          1117:        if (mrt_api_config & MRT_API_FLAGS_ALL) {
        !          1118:                struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *);
        !          1119:                bcopy(mp2, (caddr_t)&mfcctl2, sizeof(*mp2));
        !          1120:        } else {
        !          1121:                struct mfcctl *mp = mtod(m, struct mfcctl *);
        !          1122:                bcopy(mp, (caddr_t)&mfcctl2, sizeof(*mp));
        !          1123:                bzero((caddr_t)&mfcctl2 + sizeof(struct mfcctl),
        !          1124:                    sizeof(mfcctl2) - sizeof(struct mfcctl));
        !          1125:        }
        !          1126:        mfccp = &mfcctl2;
        !          1127:
        !          1128:        s = splsoftnet();
        !          1129:        rt = mfc_find(&mfccp->mfcc_origin, &mfccp->mfcc_mcastgrp);
        !          1130:
        !          1131:        /* If an entry already exists, just update the fields */
        !          1132:        if (rt) {
        !          1133:                if (mrtdebug & DEBUG_MFC)
        !          1134:                        log(LOG_DEBUG, "add_mfc update o %x g %x p %x\n",
        !          1135:                            ntohl(mfccp->mfcc_origin.s_addr),
        !          1136:                            ntohl(mfccp->mfcc_mcastgrp.s_addr),
        !          1137:                            mfccp->mfcc_parent);
        !          1138:
        !          1139:                update_mfc_params(rt, mfccp);
        !          1140:
        !          1141:                splx(s);
        !          1142:                return (0);
        !          1143:        }
        !          1144:
        !          1145:        /*
        !          1146:         * Find the entry for which the upcall was made and update
        !          1147:         */
        !          1148:        nstl = 0;
        !          1149:        hash = MFCHASH(mfccp->mfcc_origin, mfccp->mfcc_mcastgrp);
        !          1150:        LIST_FOREACH(rt, &mfchashtbl[hash], mfc_hash) {
        !          1151:                if (in_hosteq(rt->mfc_origin, mfccp->mfcc_origin) &&
        !          1152:                    in_hosteq(rt->mfc_mcastgrp, mfccp->mfcc_mcastgrp) &&
        !          1153:                    rt->mfc_stall != NULL) {
        !          1154:                        if (nstl++)
        !          1155:                                log(LOG_ERR, "add_mfc %s o %x g %x "
        !          1156:                                    "p %x dbx %p\n",
        !          1157:                                    "multiple kernel entries",
        !          1158:                                    ntohl(mfccp->mfcc_origin.s_addr),
        !          1159:                                    ntohl(mfccp->mfcc_mcastgrp.s_addr),
        !          1160:                                    mfccp->mfcc_parent, rt->mfc_stall);
        !          1161:
        !          1162:                        if (mrtdebug & DEBUG_MFC)
        !          1163:                                log(LOG_DEBUG, "add_mfc o %x g %x "
        !          1164:                                    "p %x dbg %p\n",
        !          1165:                                    ntohl(mfccp->mfcc_origin.s_addr),
        !          1166:                                    ntohl(mfccp->mfcc_mcastgrp.s_addr),
        !          1167:                                    mfccp->mfcc_parent, rt->mfc_stall);
        !          1168:
        !          1169:                        rte = rt->mfc_stall;
        !          1170:                        init_mfc_params(rt, mfccp);
        !          1171:                        rt->mfc_stall = NULL;
        !          1172:
        !          1173:                        rt->mfc_expire = 0; /* Don't clean this guy up */
        !          1174:                        nexpire[hash]--;
        !          1175:
        !          1176:                        /* free packets Qed at the end of this entry */
        !          1177:                        for (; rte != NULL; rte = nrte) {
        !          1178:                                nrte = rte->next;
        !          1179:                                if (rte->ifp) {
        !          1180: #ifdef RSVP_ISI
        !          1181:                                        ip_mdq(rte->m, rte->ifp, rt, -1);
        !          1182: #else
        !          1183:                                        ip_mdq(rte->m, rte->ifp, rt);
        !          1184: #endif /* RSVP_ISI */
        !          1185:                                }
        !          1186:                                m_freem(rte->m);
        !          1187: #ifdef UPCALL_TIMING
        !          1188:                                collate(&rte->t);
        !          1189: #endif /* UPCALL_TIMING */
        !          1190:                                free(rte, M_MRTABLE);
        !          1191:                        }
        !          1192:                }
        !          1193:        }
        !          1194:
        !          1195:        /*
        !          1196:         * It is possible that an entry is being inserted without an upcall
        !          1197:         */
        !          1198:        if (nstl == 0) {
        !          1199:                /*
        !          1200:                 * No mfc; make a new one
        !          1201:                 */
        !          1202:                if (mrtdebug & DEBUG_MFC)
        !          1203:                        log(LOG_DEBUG, "add_mfc no upcall o %x g %x p %x\n",
        !          1204:                            ntohl(mfccp->mfcc_origin.s_addr),
        !          1205:                            ntohl(mfccp->mfcc_mcastgrp.s_addr),
        !          1206:                            mfccp->mfcc_parent);
        !          1207:
        !          1208:                LIST_FOREACH(rt, &mfchashtbl[hash], mfc_hash) {
        !          1209:                        if (in_hosteq(rt->mfc_origin, mfccp->mfcc_origin) &&
        !          1210:                            in_hosteq(rt->mfc_mcastgrp, mfccp->mfcc_mcastgrp)) {
        !          1211:                                init_mfc_params(rt, mfccp);
        !          1212:                                if (rt->mfc_expire)
        !          1213:                                        nexpire[hash]--;
        !          1214:                                rt->mfc_expire = 0;
        !          1215:                                break; /* XXX */
        !          1216:                        }
        !          1217:                }
        !          1218:                if (rt == NULL) {       /* no upcall, so make a new entry */
        !          1219:                        rt = (struct mfc *)malloc(sizeof(*rt), M_MRTABLE,
        !          1220:                            M_NOWAIT);
        !          1221:                        if (rt == NULL) {
        !          1222:                                splx(s);
        !          1223:                                return (ENOBUFS);
        !          1224:                        }
        !          1225:
        !          1226:                        init_mfc_params(rt, mfccp);
        !          1227:                        rt->mfc_expire  = 0;
        !          1228:                        rt->mfc_stall   = NULL;
        !          1229:                        rt->mfc_bw_meter = NULL;
        !          1230:
        !          1231:                        /* insert new entry at head of hash chain */
        !          1232:                        LIST_INSERT_HEAD(&mfchashtbl[hash], rt, mfc_hash);
        !          1233:                }
        !          1234:        }
        !          1235:
        !          1236:        splx(s);
        !          1237:        return (0);
        !          1238: }
        !          1239:
        !          1240: #ifdef UPCALL_TIMING
        !          1241: /*
        !          1242:  * collect delay statistics on the upcalls
        !          1243:  */
        !          1244: static void
        !          1245: collate(struct timeval *t)
        !          1246: {
        !          1247:        u_int32_t d;
        !          1248:        struct timeval tp;
        !          1249:        u_int32_t delta;
        !          1250:
        !          1251:        microtime(&tp);
        !          1252:
        !          1253:        if (timercmp(t, &tp, <)) {
        !          1254:                TV_DELTA(tp, *t, delta);
        !          1255:
        !          1256:                d = delta >> 10;
        !          1257:                if (d > 50)
        !          1258:                        d = 50;
        !          1259:
        !          1260:                ++upcall_data[d];
        !          1261:        }
        !          1262: }
        !          1263: #endif /* UPCALL_TIMING */
        !          1264:
        !          1265: /*
        !          1266:  * Delete an mfc entry
        !          1267:  */
        !          1268: static int
        !          1269: del_mfc(struct mbuf *m)
        !          1270: {
        !          1271:        struct mfcctl2 mfcctl2;
        !          1272:        struct mfcctl2 *mfccp;
        !          1273:        struct mfc *rt;
        !          1274:        int s;
        !          1275:        int mfcctl_size = sizeof(struct mfcctl);
        !          1276:        struct mfcctl *mp = mtod(m, struct mfcctl *);
        !          1277:
        !          1278:        /*
        !          1279:         * XXX: for deleting MFC entries the information in entries
        !          1280:         * of size "struct mfcctl" is sufficient.
        !          1281:         */
        !          1282:
        !          1283:        if (m == NULL || m->m_len < mfcctl_size)
        !          1284:                return (EINVAL);
        !          1285:
        !          1286:        bcopy(mp, (caddr_t)&mfcctl2, sizeof(*mp));
        !          1287:        bzero((caddr_t)&mfcctl2 + sizeof(struct mfcctl),
        !          1288:            sizeof(mfcctl2) - sizeof(struct mfcctl));
        !          1289:
        !          1290:        mfccp = &mfcctl2;
        !          1291:
        !          1292:        if (mrtdebug & DEBUG_MFC)
        !          1293:                log(LOG_DEBUG, "del_mfc origin %x mcastgrp %x\n",
        !          1294:                    ntohl(mfccp->mfcc_origin.s_addr),
        !          1295:                    ntohl(mfccp->mfcc_mcastgrp.s_addr));
        !          1296:
        !          1297:        s = splsoftnet();
        !          1298:
        !          1299:        rt = mfc_find(&mfccp->mfcc_origin, &mfccp->mfcc_mcastgrp);
        !          1300:        if (rt == NULL) {
        !          1301:                splx(s);
        !          1302:                return (EADDRNOTAVAIL);
        !          1303:        }
        !          1304:
        !          1305:        /*
        !          1306:         * free the bw_meter entries
        !          1307:         */
        !          1308:        free_bw_list(rt->mfc_bw_meter);
        !          1309:        rt->mfc_bw_meter = NULL;
        !          1310:
        !          1311:        LIST_REMOVE(rt, mfc_hash);
        !          1312:        free(rt, M_MRTABLE);
        !          1313:
        !          1314:        splx(s);
        !          1315:        return (0);
        !          1316: }
        !          1317:
        !          1318: static int
        !          1319: socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in *src)
        !          1320: {
        !          1321:        if (s != NULL) {
        !          1322:                if (sbappendaddr(&s->so_rcv, sintosa(src), mm,
        !          1323:                    (struct mbuf *)NULL) != 0) {
        !          1324:                        sorwakeup(s);
        !          1325:                        return (0);
        !          1326:                }
        !          1327:        }
        !          1328:        m_freem(mm);
        !          1329:        return (-1);
        !          1330: }
        !          1331:
        !          1332: /*
        !          1333:  * IP multicast forwarding function. This function assumes that the packet
        !          1334:  * pointed to by "ip" has arrived on (or is about to be sent to) the interface
        !          1335:  * pointed to by "ifp", and the packet is to be relayed to other networks
        !          1336:  * that have members of the packet's destination IP multicast group.
        !          1337:  *
        !          1338:  * The packet is returned unscathed to the caller, unless it is
        !          1339:  * erroneous, in which case a non-zero return value tells the caller to
        !          1340:  * discard it.
        !          1341:  */
        !          1342:
        !          1343: #define IP_HDR_LEN  20 /* # bytes of fixed IP header (excluding options) */
        !          1344: #define TUNNEL_LEN  12  /* # bytes of IP option for tunnel encapsulation  */
        !          1345:
        !          1346: int
        !          1347: #ifdef RSVP_ISI
        !          1348: ip_mforward(struct mbuf *m, struct ifnet *ifp, struct ip_moptions *imo)
        !          1349: #else
        !          1350: ip_mforward(struct mbuf *m, struct ifnet *ifp)
        !          1351: #endif /* RSVP_ISI */
        !          1352: {
        !          1353:        struct ip *ip = mtod(m, struct ip *);
        !          1354:        struct mfc *rt;
        !          1355:        static int srctun = 0;
        !          1356:        struct mbuf *mm;
        !          1357:        int s;
        !          1358:        vifi_t vifi;
        !          1359:
        !          1360:        if (mrtdebug & DEBUG_FORWARD)
        !          1361:                log(LOG_DEBUG, "ip_mforward: src %x, dst %x, ifp %p\n",
        !          1362:                    ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), ifp);
        !          1363:
        !          1364:        if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
        !          1365:            ((u_char *)(ip + 1))[1] != IPOPT_LSRR) {
        !          1366:                /*
        !          1367:                 * Packet arrived via a physical interface or
        !          1368:                 * an encapsulated tunnel or a register_vif.
        !          1369:                 */
        !          1370:        } else {
        !          1371:                /*
        !          1372:                 * Packet arrived through a source-route tunnel.
        !          1373:                 * Source-route tunnels are no longer supported.
        !          1374:                 */
        !          1375:                if ((srctun++ % 1000) == 0)
        !          1376:                        log(LOG_ERR, "ip_mforward: received source-routed "
        !          1377:                            "packet from %x\n", ntohl(ip->ip_src.s_addr));
        !          1378:
        !          1379:                return (1);
        !          1380:        }
        !          1381:
        !          1382: #ifdef RSVP_ISI
        !          1383:        if (imo && ((vifi = imo->imo_multicast_vif) < numvifs)) {
        !          1384:                if (ip->ip_ttl < 255) {
        !          1385:                        /* compensate for -1 in *_send routines */
        !          1386:                        ip->ip_ttl++;
        !          1387:                }
        !          1388:                if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
        !          1389:                        struct vif *vifp = viftable + vifi;
        !          1390:                        printf("Sending IPPROTO_RSVP from %x to %x on "
        !          1391:                            "vif %d (%s%s)\n",
        !          1392:                            ntohl(ip->ip_src), ntohl(ip->ip_dst), vifi,
        !          1393:                            (vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "",
        !          1394:                            vifp->v_ifp->if_xname);
        !          1395:                }
        !          1396:                return (ip_mdq(m, ifp, (struct mfc *)NULL, vifi));
        !          1397:        }
        !          1398:        if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
        !          1399:                printf("Warning: IPPROTO_RSVP from %x to %x without "
        !          1400:                    "vif option\n", ntohl(ip->ip_src), ntohl(ip->ip_dst));
        !          1401:        }
        !          1402: #endif /* RSVP_ISI */
        !          1403:
        !          1404:        /*
        !          1405:         * Don't forward a packet with time-to-live of zero or one,
        !          1406:         * or a packet destined to a local-only group.
        !          1407:         */
        !          1408:        if (ip->ip_ttl <= 1 || IN_LOCAL_GROUP(ip->ip_dst.s_addr))
        !          1409:                return (0);
        !          1410:
        !          1411:        /*
        !          1412:         * Determine forwarding vifs from the forwarding cache table
        !          1413:         */
        !          1414:        s = splsoftnet();
        !          1415:        ++mrtstat.mrts_mfc_lookups;
        !          1416:        rt = mfc_find(&ip->ip_src, &ip->ip_dst);
        !          1417:
        !          1418:        /* Entry exists, so forward if necessary */
        !          1419:        if (rt != NULL) {
        !          1420:                splx(s);
        !          1421: #ifdef RSVP_ISI
        !          1422:                return (ip_mdq(m, ifp, rt, -1));
        !          1423: #else
        !          1424:                return (ip_mdq(m, ifp, rt));
        !          1425: #endif /* RSVP_ISI */
        !          1426:        } else {
        !          1427:                /*
        !          1428:                 * If we don't have a route for packet's origin,
        !          1429:                 * Make a copy of the packet & send message to routing daemon
        !          1430:                 */
        !          1431:
        !          1432:                struct mbuf *mb0;
        !          1433:                struct rtdetq *rte;
        !          1434:                u_int32_t hash;
        !          1435:                int hlen = ip->ip_hl << 2;
        !          1436: #ifdef UPCALL_TIMING
        !          1437:                struct timeval tp;
        !          1438:
        !          1439:                microtime(&tp);
        !          1440: #endif /* UPCALL_TIMING */
        !          1441:
        !          1442:                ++mrtstat.mrts_mfc_misses;
        !          1443:
        !          1444:                mrtstat.mrts_no_route++;
        !          1445:                if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC))
        !          1446:                        log(LOG_DEBUG, "ip_mforward: no rte s %x g %x\n",
        !          1447:                            ntohl(ip->ip_src.s_addr),
        !          1448:                            ntohl(ip->ip_dst.s_addr));
        !          1449:
        !          1450:                /*
        !          1451:                 * Allocate mbufs early so that we don't do extra work if we are
        !          1452:                 * just going to fail anyway.  Make sure to pullup the header so
        !          1453:                 * that other people can't step on it.
        !          1454:                 */
        !          1455:                rte = (struct rtdetq *)malloc(sizeof(*rte),
        !          1456:                    M_MRTABLE, M_NOWAIT);
        !          1457:                if (rte == NULL) {
        !          1458:                        splx(s);
        !          1459:                        return (ENOBUFS);
        !          1460:                }
        !          1461:                mb0 = m_copy(m, 0, M_COPYALL);
        !          1462:                M_PULLUP(mb0, hlen);
        !          1463:                if (mb0 == NULL) {
        !          1464:                        free(rte, M_MRTABLE);
        !          1465:                        splx(s);
        !          1466:                        return (ENOBUFS);
        !          1467:                }
        !          1468:
        !          1469:                /* is there an upcall waiting for this flow? */
        !          1470:                hash = MFCHASH(ip->ip_src, ip->ip_dst);
        !          1471:                LIST_FOREACH(rt, &mfchashtbl[hash], mfc_hash) {
        !          1472:                        if (in_hosteq(ip->ip_src, rt->mfc_origin) &&
        !          1473:                            in_hosteq(ip->ip_dst, rt->mfc_mcastgrp) &&
        !          1474:                            rt->mfc_stall != NULL)
        !          1475:                                break;
        !          1476:                }
        !          1477:
        !          1478:                if (rt == NULL) {
        !          1479:                        int i;
        !          1480:                        struct igmpmsg *im;
        !          1481:
        !          1482:                        /*
        !          1483:                         * Locate the vifi for the incoming interface for
        !          1484:                         * this packet.
        !          1485:                         * If none found, drop packet.
        !          1486:                         */
        !          1487:                        for (vifi = 0; vifi < numvifs &&
        !          1488:                                 viftable[vifi].v_ifp != ifp; vifi++)
        !          1489:                                ;
        !          1490:                        if (vifi >= numvifs) /* vif not found, drop packet */
        !          1491:                                goto non_fatal;
        !          1492:
        !          1493:                        /* no upcall, so make a new entry */
        !          1494:                        rt = (struct mfc *)malloc(sizeof(*rt),
        !          1495:                            M_MRTABLE, M_NOWAIT);
        !          1496:                        if (rt == NULL)
        !          1497:                                goto fail;
        !          1498:                        /*
        !          1499:                         * Make a copy of the header to send to the user level
        !          1500:                         * process
        !          1501:                         */
        !          1502:                        mm = m_copy(m, 0, hlen);
        !          1503:                        M_PULLUP(mm, hlen);
        !          1504:                        if (mm == NULL)
        !          1505:                                goto fail1;
        !          1506:
        !          1507:                        /*
        !          1508:                         * Send message to routing daemon to install
        !          1509:                         * a route into the kernel table
        !          1510:                         */
        !          1511:
        !          1512:                        im = mtod(mm, struct igmpmsg *);
        !          1513:                        im->im_msgtype = IGMPMSG_NOCACHE;
        !          1514:                        im->im_mbz = 0;
        !          1515:                        im->im_vif = vifi;
        !          1516:
        !          1517:                        mrtstat.mrts_upcalls++;
        !          1518:
        !          1519:                        sin.sin_addr = ip->ip_src;
        !          1520:                        if (socket_send(ip_mrouter, mm, &sin) < 0) {
        !          1521:                                log(LOG_WARNING, "ip_mforward: ip_mrouter "
        !          1522:                                    "socket queue full\n");
        !          1523:                                ++mrtstat.mrts_upq_sockfull;
        !          1524:                        fail1:
        !          1525:                                free(rt, M_MRTABLE);
        !          1526:                        fail:
        !          1527:                                free(rte, M_MRTABLE);
        !          1528:                                m_freem(mb0);
        !          1529:                                splx(s);
        !          1530:                                return (ENOBUFS);
        !          1531:                        }
        !          1532:
        !          1533:                        /* insert new entry at head of hash chain */
        !          1534:                        rt->mfc_origin = ip->ip_src;
        !          1535:                        rt->mfc_mcastgrp = ip->ip_dst;
        !          1536:                        rt->mfc_pkt_cnt = 0;
        !          1537:                        rt->mfc_byte_cnt = 0;
        !          1538:                        rt->mfc_wrong_if = 0;
        !          1539:                        rt->mfc_expire = UPCALL_EXPIRE;
        !          1540:                        nexpire[hash]++;
        !          1541:                        for (i = 0; i < numvifs; i++) {
        !          1542:                                rt->mfc_ttls[i] = 0;
        !          1543:                                rt->mfc_flags[i] = 0;
        !          1544:                        }
        !          1545:                        rt->mfc_parent = -1;
        !          1546:
        !          1547:                        /* clear the RP address */
        !          1548:                        rt->mfc_rp = zeroin_addr;
        !          1549:
        !          1550:                        rt->mfc_bw_meter = NULL;
        !          1551:
        !          1552:                        /* link into table */
        !          1553:                        LIST_INSERT_HEAD(&mfchashtbl[hash], rt, mfc_hash);
        !          1554:                        /* Add this entry to the end of the queue */
        !          1555:                        rt->mfc_stall = rte;
        !          1556:                } else {
        !          1557:                        /* determine if q has overflowed */
        !          1558:                        struct rtdetq **p;
        !          1559:                        int npkts = 0;
        !          1560:
        !          1561:                        /*
        !          1562:                         * XXX ouch! we need to append to the list, but we
        !          1563:                         * only have a pointer to the front, so we have to
        !          1564:                         * scan the entire list every time.
        !          1565:                         */
        !          1566:                        for (p = &rt->mfc_stall; *p != NULL; p = &(*p)->next)
        !          1567:                                if (++npkts > MAX_UPQ) {
        !          1568:                                        mrtstat.mrts_upq_ovflw++;
        !          1569:                                non_fatal:
        !          1570:                                        free(rte, M_MRTABLE);
        !          1571:                                        m_freem(mb0);
        !          1572:                                        splx(s);
        !          1573:                                        return (0);
        !          1574:                                }
        !          1575:
        !          1576:                        /* Add this entry to the end of the queue */
        !          1577:                        *p = rte;
        !          1578:                }
        !          1579:
        !          1580:                rte->next = NULL;
        !          1581:                rte->m = mb0;
        !          1582:                rte->ifp = ifp;
        !          1583:        #ifdef UPCALL_TIMING
        !          1584:                rte->t = tp;
        !          1585:        #endif /* UPCALL_TIMING */
        !          1586:
        !          1587:                splx(s);
        !          1588:
        !          1589:                return (0);
        !          1590:        }
        !          1591: }
        !          1592:
        !          1593:
        !          1594: /*ARGSUSED*/
        !          1595: static void
        !          1596: expire_upcalls(void *v)
        !          1597: {
        !          1598:        int i;
        !          1599:        int s;
        !          1600:
        !          1601:        s = splsoftnet();
        !          1602:
        !          1603:        for (i = 0; i < MFCTBLSIZ; i++) {
        !          1604:                struct mfc *rt, *nrt;
        !          1605:
        !          1606:                if (nexpire[i] == 0)
        !          1607:                        continue;
        !          1608:
        !          1609:                for (rt = LIST_FIRST(&mfchashtbl[i]); rt; rt = nrt) {
        !          1610:                        nrt = LIST_NEXT(rt, mfc_hash);
        !          1611:
        !          1612:                        if (rt->mfc_expire == 0 || --rt->mfc_expire > 0)
        !          1613:                                continue;
        !          1614:                        nexpire[i]--;
        !          1615:
        !          1616:                        /*
        !          1617:                         * free the bw_meter entries
        !          1618:                         */
        !          1619:                        while (rt->mfc_bw_meter != NULL) {
        !          1620:                                struct bw_meter *x = rt->mfc_bw_meter;
        !          1621:
        !          1622:                                rt->mfc_bw_meter = x->bm_mfc_next;
        !          1623:                                free(x, M_BWMETER);
        !          1624:                        }
        !          1625:
        !          1626:                        ++mrtstat.mrts_cache_cleanups;
        !          1627:                        if (mrtdebug & DEBUG_EXPIRE)
        !          1628:                                log(LOG_DEBUG,
        !          1629:                                    "expire_upcalls: expiring (%x %x)\n",
        !          1630:                                    ntohl(rt->mfc_origin.s_addr),
        !          1631:                                    ntohl(rt->mfc_mcastgrp.s_addr));
        !          1632:
        !          1633:                        expire_mfc(rt);
        !          1634:                }
        !          1635:        }
        !          1636:
        !          1637:        splx(s);
        !          1638:        timeout_add(&expire_upcalls_ch, EXPIRE_TIMEOUT);
        !          1639: }
        !          1640:
        !          1641: /*
        !          1642:  * Packet forwarding routine once entry in the cache is made
        !          1643:  */
        !          1644: static int
        !          1645: #ifdef RSVP_ISI
        !          1646: ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif)
        !          1647: #else
        !          1648: ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt)
        !          1649: #endif /* RSVP_ISI */
        !          1650: {
        !          1651:        struct ip  *ip = mtod(m, struct ip *);
        !          1652:        vifi_t vifi;
        !          1653:        struct vif *vifp;
        !          1654:        int plen = ntohs(ip->ip_len) - (ip->ip_hl << 2);
        !          1655:
        !          1656: /*
        !          1657:  * Macro to send packet on vif.  Since RSVP packets don't get counted on
        !          1658:  * input, they shouldn't get counted on output, so statistics keeping is
        !          1659:  * separate.
        !          1660:  */
        !          1661: #define MC_SEND(ip, vifp, m) do {                                      \
        !          1662:        if ((vifp)->v_flags & VIFF_TUNNEL)                              \
        !          1663:                encap_send((ip), (vifp), (m));                          \
        !          1664:        else                                                            \
        !          1665:                phyint_send((ip), (vifp), (m));                         \
        !          1666: } while (/*CONSTCOND*/ 0)
        !          1667:
        !          1668: #ifdef RSVP_ISI
        !          1669:        /*
        !          1670:         * If xmt_vif is not -1, send on only the requested vif.
        !          1671:         *
        !          1672:         * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.
        !          1673:         */
        !          1674:        if (xmt_vif < numvifs) {
        !          1675: #ifdef PIM
        !          1676:                if (viftable[xmt_vif].v_flags & VIFF_REGISTER)
        !          1677:                        pim_register_send(ip, viftable + xmt_vif, m, rt);
        !          1678:                else
        !          1679: #endif
        !          1680:                MC_SEND(ip, viftable + xmt_vif, m);
        !          1681:                return (1);
        !          1682:        }
        !          1683: #endif /* RSVP_ISI */
        !          1684:
        !          1685:        /*
        !          1686:         * Don't forward if it didn't arrive from the parent vif for its origin.
        !          1687:         */
        !          1688:        vifi = rt->mfc_parent;
        !          1689:        if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) {
        !          1690:                /* came in the wrong interface */
        !          1691:                if (mrtdebug & DEBUG_FORWARD)
        !          1692:                        log(LOG_DEBUG, "wrong if: ifp %p vifi %d vififp %p\n",
        !          1693:                            ifp, vifi,
        !          1694:                            vifi >= numvifs ? 0 : viftable[vifi].v_ifp);
        !          1695:                ++mrtstat.mrts_wrong_if;
        !          1696:                ++rt->mfc_wrong_if;
        !          1697:                /*
        !          1698:                 * If we are doing PIM assert processing, send a message
        !          1699:                 * to the routing daemon.
        !          1700:                 *
        !          1701:                 * XXX: A PIM-SM router needs the WRONGVIF detection so it
        !          1702:                 * can complete the SPT switch, regardless of the type
        !          1703:                 * of interface (broadcast media, GRE tunnel, etc).
        !          1704:                 */
        !          1705:                if (pim_assert && (vifi < numvifs) && viftable[vifi].v_ifp) {
        !          1706:                        struct timeval now;
        !          1707:                        u_int32_t delta;
        !          1708:
        !          1709: #ifdef PIM
        !          1710:                        if (ifp == &multicast_register_if)
        !          1711:                                pimstat.pims_rcv_registers_wrongiif++;
        !          1712: #endif
        !          1713:
        !          1714:                        /* Get vifi for the incoming packet */
        !          1715:                        for (vifi = 0;
        !          1716:                             vifi < numvifs && viftable[vifi].v_ifp != ifp;
        !          1717:                             vifi++)
        !          1718:                            ;
        !          1719:                        if (vifi >= numvifs) {
        !          1720:                                /* The iif is not found: ignore the packet. */
        !          1721:                                return (0);
        !          1722:                        }
        !          1723:
        !          1724:                        if (rt->mfc_flags[vifi] &
        !          1725:                            MRT_MFC_FLAGS_DISABLE_WRONGVIF) {
        !          1726:                                /* WRONGVIF disabled: ignore the packet */
        !          1727:                                return (0);
        !          1728:                        }
        !          1729:
        !          1730:                        microtime(&now);
        !          1731:
        !          1732:                        TV_DELTA(rt->mfc_last_assert, now, delta);
        !          1733:
        !          1734:                        if (delta > ASSERT_MSG_TIME) {
        !          1735:                                struct igmpmsg *im;
        !          1736:                                int hlen = ip->ip_hl << 2;
        !          1737:                                struct mbuf *mm = m_copy(m, 0, hlen);
        !          1738:
        !          1739:                                M_PULLUP(mm, hlen);
        !          1740:                                if (mm == NULL)
        !          1741:                                        return (ENOBUFS);
        !          1742:
        !          1743:                                rt->mfc_last_assert = now;
        !          1744:
        !          1745:                                im = mtod(mm, struct igmpmsg *);
        !          1746:                                im->im_msgtype  = IGMPMSG_WRONGVIF;
        !          1747:                                im->im_mbz      = 0;
        !          1748:                                im->im_vif      = vifi;
        !          1749:
        !          1750:                                mrtstat.mrts_upcalls++;
        !          1751:
        !          1752:                                sin.sin_addr = im->im_src;
        !          1753:                                if (socket_send(ip_mrouter, mm, &sin) < 0) {
        !          1754:                                        log(LOG_WARNING, "ip_mforward: "
        !          1755:                                            "ip_mrouter socket queue full\n");
        !          1756:                                        ++mrtstat.mrts_upq_sockfull;
        !          1757:                                        return (ENOBUFS);
        !          1758:                                }
        !          1759:                        }
        !          1760:                }
        !          1761:                return (0);
        !          1762:        }
        !          1763:
        !          1764:        /* If I sourced this packet, it counts as output, else it was input. */
        !          1765:        if (in_hosteq(ip->ip_src, viftable[vifi].v_lcl_addr)) {
        !          1766:                viftable[vifi].v_pkt_out++;
        !          1767:                viftable[vifi].v_bytes_out += plen;
        !          1768:        } else {
        !          1769:                viftable[vifi].v_pkt_in++;
        !          1770:                viftable[vifi].v_bytes_in += plen;
        !          1771:        }
        !          1772:        rt->mfc_pkt_cnt++;
        !          1773:        rt->mfc_byte_cnt += plen;
        !          1774:
        !          1775:        /*
        !          1776:         * For each vif, decide if a copy of the packet should be forwarded.
        !          1777:         * Forward if:
        !          1778:         *              - the ttl exceeds the vif's threshold
        !          1779:         *              - there are group members downstream on interface
        !          1780:         */
        !          1781:        for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++)
        !          1782:                if ((rt->mfc_ttls[vifi] > 0) &&
        !          1783:                        (ip->ip_ttl > rt->mfc_ttls[vifi])) {
        !          1784:                        vifp->v_pkt_out++;
        !          1785:                        vifp->v_bytes_out += plen;
        !          1786: #ifdef PIM
        !          1787:                        if (vifp->v_flags & VIFF_REGISTER)
        !          1788:                                pim_register_send(ip, vifp, m, rt);
        !          1789:                        else
        !          1790: #endif
        !          1791:                        MC_SEND(ip, vifp, m);
        !          1792:                }
        !          1793:
        !          1794:        /*
        !          1795:         * Perform upcall-related bw measuring.
        !          1796:         */
        !          1797:        if (rt->mfc_bw_meter != NULL) {
        !          1798:                struct bw_meter *x;
        !          1799:                struct timeval now;
        !          1800:
        !          1801:                microtime(&now);
        !          1802:                for (x = rt->mfc_bw_meter; x != NULL; x = x->bm_mfc_next)
        !          1803:                        bw_meter_receive_packet(x, plen, &now);
        !          1804:        }
        !          1805:
        !          1806:        return (0);
        !          1807: }
        !          1808:
        !          1809: #ifdef RSVP_ISI
        !          1810: /*
        !          1811:  * check if a vif number is legal/ok. This is used by ip_output.
        !          1812:  */
        !          1813: int
        !          1814: legal_vif_num(int vif)
        !          1815: {
        !          1816:        if (vif >= 0 && vif < numvifs)
        !          1817:                return (1);
        !          1818:        else
        !          1819:                return (0);
        !          1820: }
        !          1821: #endif /* RSVP_ISI */
        !          1822:
        !          1823: static void
        !          1824: phyint_send(struct ip *ip, struct vif *vifp, struct mbuf *m)
        !          1825: {
        !          1826:        struct mbuf *mb_copy;
        !          1827:        int hlen = ip->ip_hl << 2;
        !          1828:
        !          1829:        /*
        !          1830:         * Make a new reference to the packet; make sure that
        !          1831:         * the IP header is actually copied, not just referenced,
        !          1832:         * so that ip_output() only scribbles on the copy.
        !          1833:         */
        !          1834:        mb_copy = m_copy(m, 0, M_COPYALL);
        !          1835:        M_PULLUP(mb_copy, hlen);
        !          1836:        if (mb_copy == NULL)
        !          1837:                return;
        !          1838:
        !          1839:        if (vifp->v_rate_limit <= 0)
        !          1840:                tbf_send_packet(vifp, mb_copy);
        !          1841:        else
        !          1842:                tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *),
        !          1843:                    ntohs(ip->ip_len));
        !          1844: }
        !          1845:
        !          1846: static void
        !          1847: encap_send(struct ip *ip, struct vif *vifp, struct mbuf *m)
        !          1848: {
        !          1849:        struct mbuf *mb_copy;
        !          1850:        struct ip *ip_copy;
        !          1851:        int i, len = ntohs(ip->ip_len) + sizeof(multicast_encap_iphdr);
        !          1852:
        !          1853:        /* Take care of delayed checksums */
        !          1854:        if (m->m_pkthdr.csum_flags & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) {
        !          1855:                in_delayed_cksum(m);
        !          1856:                m->m_pkthdr.csum_flags &=
        !          1857:                    ~(M_UDPV4_CSUM_OUT | M_TCPV4_CSUM_OUT);
        !          1858:        }
        !          1859:
        !          1860:        /*
        !          1861:         * copy the old packet & pullup its IP header into the
        !          1862:         * new mbuf so we can modify it.  Try to fill the new
        !          1863:         * mbuf since if we don't the ethernet driver will.
        !          1864:         */
        !          1865:        MGETHDR(mb_copy, M_DONTWAIT, MT_DATA);
        !          1866:        if (mb_copy == NULL)
        !          1867:                return;
        !          1868:        mb_copy->m_data += max_linkhdr;
        !          1869:        mb_copy->m_pkthdr.len = len;
        !          1870:        mb_copy->m_len = sizeof(multicast_encap_iphdr);
        !          1871:
        !          1872:        if ((mb_copy->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {
        !          1873:                m_freem(mb_copy);
        !          1874:                return;
        !          1875:        }
        !          1876:        i = MHLEN - max_linkhdr;
        !          1877:        if (i > len)
        !          1878:                i = len;
        !          1879:        mb_copy = m_pullup(mb_copy, i);
        !          1880:        if (mb_copy == NULL)
        !          1881:                return;
        !          1882:
        !          1883:        /*
        !          1884:         * fill in the encapsulating IP header.
        !          1885:         */
        !          1886:        ip_copy = mtod(mb_copy, struct ip *);
        !          1887:        *ip_copy = multicast_encap_iphdr;
        !          1888:        ip_copy->ip_id = htons(ip_randomid());
        !          1889:        ip_copy->ip_len = htons(len);
        !          1890:        ip_copy->ip_src = vifp->v_lcl_addr;
        !          1891:        ip_copy->ip_dst = vifp->v_rmt_addr;
        !          1892:
        !          1893:        /*
        !          1894:         * turn the encapsulated IP header back into a valid one.
        !          1895:         */
        !          1896:        ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr));
        !          1897:        --ip->ip_ttl;
        !          1898:        ip->ip_sum = 0;
        !          1899:        mb_copy->m_data += sizeof(multicast_encap_iphdr);
        !          1900:        ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2);
        !          1901:        mb_copy->m_data -= sizeof(multicast_encap_iphdr);
        !          1902:
        !          1903:        if (vifp->v_rate_limit <= 0)
        !          1904:                tbf_send_packet(vifp, mb_copy);
        !          1905:        else
        !          1906:                tbf_control(vifp, mb_copy, ip, ntohs(ip_copy->ip_len));
        !          1907: }
        !          1908:
        !          1909: /*
        !          1910:  * Token bucket filter module
        !          1911:  */
        !          1912: static void
        !          1913: tbf_control(struct vif *vifp, struct mbuf *m, struct ip *ip, u_int32_t len)
        !          1914: {
        !          1915:
        !          1916:        if (len > MAX_BKT_SIZE) {
        !          1917:                /* drop if packet is too large */
        !          1918:                mrtstat.mrts_pkt2large++;
        !          1919:                m_freem(m);
        !          1920:                return;
        !          1921:        }
        !          1922:
        !          1923:        tbf_update_tokens(vifp);
        !          1924:
        !          1925:        /*
        !          1926:         * If there are enough tokens, and the queue is empty, send this packet
        !          1927:         * out immediately.  Otherwise, try to insert it on this vif's queue.
        !          1928:         */
        !          1929:        if (vifp->tbf_q_len == 0) {
        !          1930:                if (len <= vifp->tbf_n_tok) {
        !          1931:                        vifp->tbf_n_tok -= len;
        !          1932:                        tbf_send_packet(vifp, m);
        !          1933:                } else {
        !          1934:                        /* queue packet and timeout till later */
        !          1935:                        tbf_queue(vifp, m);
        !          1936:                        timeout_add(&vifp->v_repq_ch, TBF_REPROCESS);
        !          1937:                }
        !          1938:        } else {
        !          1939:                if (vifp->tbf_q_len >= vifp->tbf_max_q_len &&
        !          1940:                    !tbf_dq_sel(vifp, ip)) {
        !          1941:                        /* queue full, and couldn't make room */
        !          1942:                        mrtstat.mrts_q_overflow++;
        !          1943:                        m_freem(m);
        !          1944:                } else {
        !          1945:                        /* queue length low enough, or made room */
        !          1946:                        tbf_queue(vifp, m);
        !          1947:                        tbf_process_q(vifp);
        !          1948:                }
        !          1949:        }
        !          1950: }
        !          1951:
        !          1952: /*
        !          1953:  * adds a packet to the queue at the interface
        !          1954:  */
        !          1955: static void
        !          1956: tbf_queue(struct vif *vifp, struct mbuf *m)
        !          1957: {
        !          1958:        int s = splsoftnet();
        !          1959:
        !          1960:        /* insert at tail */
        !          1961:        *vifp->tbf_t = m;
        !          1962:        vifp->tbf_t = &m->m_nextpkt;
        !          1963:        vifp->tbf_q_len++;
        !          1964:
        !          1965:        splx(s);
        !          1966: }
        !          1967:
        !          1968:
        !          1969: /*
        !          1970:  * processes the queue at the interface
        !          1971:  */
        !          1972: static void
        !          1973: tbf_process_q(struct vif *vifp)
        !          1974: {
        !          1975:        struct mbuf *m;
        !          1976:        int len;
        !          1977:        int s = splsoftnet();
        !          1978:
        !          1979:        /*
        !          1980:         * Loop through the queue at the interface and send as many packets
        !          1981:         * as possible.
        !          1982:         */
        !          1983:        for (m = vifp->tbf_q; m != NULL; m = vifp->tbf_q) {
        !          1984:                len = ntohs(mtod(m, struct ip *)->ip_len);
        !          1985:
        !          1986:                /* determine if the packet can be sent */
        !          1987:                if (len <= vifp->tbf_n_tok) {
        !          1988:                        /* if so,
        !          1989:                         * reduce no of tokens, dequeue the packet,
        !          1990:                         * send the packet.
        !          1991:                         */
        !          1992:                        if ((vifp->tbf_q = m->m_nextpkt) == NULL)
        !          1993:                                vifp->tbf_t = &vifp->tbf_q;
        !          1994:                        --vifp->tbf_q_len;
        !          1995:
        !          1996:                        m->m_nextpkt = NULL;
        !          1997:                        vifp->tbf_n_tok -= len;
        !          1998:                        tbf_send_packet(vifp, m);
        !          1999:                } else
        !          2000:                        break;
        !          2001:        }
        !          2002:        splx(s);
        !          2003: }
        !          2004:
        !          2005: static void
        !          2006: tbf_reprocess_q(void *arg)
        !          2007: {
        !          2008:        struct vif *vifp = arg;
        !          2009:
        !          2010:        if (ip_mrouter == NULL)
        !          2011:                return;
        !          2012:
        !          2013:        tbf_update_tokens(vifp);
        !          2014:        tbf_process_q(vifp);
        !          2015:
        !          2016:        if (vifp->tbf_q_len != 0)
        !          2017:                timeout_add(&vifp->v_repq_ch, TBF_REPROCESS);
        !          2018: }
        !          2019:
        !          2020: /* function that will selectively discard a member of the queue
        !          2021:  * based on the precedence value and the priority
        !          2022:  */
        !          2023: static int
        !          2024: tbf_dq_sel(struct vif *vifp, struct ip *ip)
        !          2025: {
        !          2026:        u_int p;
        !          2027:        struct mbuf **mp, *m;
        !          2028:        int s = splsoftnet();
        !          2029:
        !          2030:        p = priority(vifp, ip);
        !          2031:
        !          2032:        for (mp = &vifp->tbf_q, m = *mp;
        !          2033:            m != NULL;
        !          2034:            mp = &m->m_nextpkt, m = *mp) {
        !          2035:                if (p > priority(vifp, mtod(m, struct ip *))) {
        !          2036:                        if ((*mp = m->m_nextpkt) == NULL)
        !          2037:                                vifp->tbf_t = mp;
        !          2038:                        --vifp->tbf_q_len;
        !          2039:
        !          2040:                        m_freem(m);
        !          2041:                        mrtstat.mrts_drop_sel++;
        !          2042:                        splx(s);
        !          2043:                        return (1);
        !          2044:                }
        !          2045:        }
        !          2046:        splx(s);
        !          2047:        return (0);
        !          2048: }
        !          2049:
        !          2050: static void
        !          2051: tbf_send_packet(struct vif *vifp, struct mbuf *m)
        !          2052: {
        !          2053:        int error;
        !          2054:        int s = splsoftnet();
        !          2055:
        !          2056:        if (vifp->v_flags & VIFF_TUNNEL) {
        !          2057:                /* If tunnel options */
        !          2058:                ip_output(m, (struct mbuf *)NULL, &vifp->v_route,
        !          2059:                    IP_FORWARDING, (struct ip_moptions *)NULL,
        !          2060:                    (struct inpcb *)NULL);
        !          2061:        } else {
        !          2062:                /*
        !          2063:                 * if physical interface option, extract the options
        !          2064:                 * and then send
        !          2065:                 */
        !          2066:                struct ip_moptions imo;
        !          2067:
        !          2068:                imo.imo_multicast_ifp = vifp->v_ifp;
        !          2069:                imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1;
        !          2070:                imo.imo_multicast_loop = 1;
        !          2071: #ifdef RSVP_ISI
        !          2072:                imo.imo_multicast_vif = -1;
        !          2073: #endif
        !          2074:
        !          2075:                error = ip_output(m, (struct mbuf *)NULL, (struct route *)NULL,
        !          2076:                    IP_FORWARDING|IP_MULTICASTOPTS, &imo,
        !          2077:                    (struct inpcb *)NULL);
        !          2078:
        !          2079:                if (mrtdebug & DEBUG_XMIT)
        !          2080:                        log(LOG_DEBUG, "phyint_send on vif %ld err %d\n",
        !          2081:                            (long)(vifp - viftable), error);
        !          2082:        }
        !          2083:        splx(s);
        !          2084: }
        !          2085:
        !          2086: /* determine the current time and then
        !          2087:  * the elapsed time (between the last time and time now)
        !          2088:  * in milliseconds & update the no. of tokens in the bucket
        !          2089:  */
        !          2090: static void
        !          2091: tbf_update_tokens(struct vif *vifp)
        !          2092: {
        !          2093:        struct timeval tp;
        !          2094:        u_int32_t tm;
        !          2095:        int s = splsoftnet();
        !          2096:
        !          2097:        microtime(&tp);
        !          2098:
        !          2099:        TV_DELTA(tp, vifp->tbf_last_pkt_t, tm);
        !          2100:
        !          2101:        /*
        !          2102:         * This formula is actually
        !          2103:         * "time in seconds" * "bytes/second".
        !          2104:         *
        !          2105:         * (tm / 1000000) * (v_rate_limit * 1000 * (1000/1024) / 8)
        !          2106:         *
        !          2107:         * The (1000/1024) was introduced in add_vif to optimize
        !          2108:         * this divide into a shift.
        !          2109:         */
        !          2110:        vifp->tbf_n_tok += tm * vifp->v_rate_limit / 8192;
        !          2111:        vifp->tbf_last_pkt_t = tp;
        !          2112:
        !          2113:        if (vifp->tbf_n_tok > MAX_BKT_SIZE)
        !          2114:                vifp->tbf_n_tok = MAX_BKT_SIZE;
        !          2115:
        !          2116:        splx(s);
        !          2117: }
        !          2118:
        !          2119: static int
        !          2120: priority(struct vif *vifp, struct ip *ip)
        !          2121: {
        !          2122:        int prio = 50;  /* the lowest priority -- default case */
        !          2123:
        !          2124:        /* temporary hack; may add general packet classifier some day */
        !          2125:
        !          2126:        /*
        !          2127:         * The UDP port space is divided up into four priority ranges:
        !          2128:         * [0, 16384)     : unclassified - lowest priority
        !          2129:         * [16384, 32768) : audio - highest priority
        !          2130:         * [32768, 49152) : whiteboard - medium priority
        !          2131:         * [49152, 65536) : video - low priority
        !          2132:         */
        !          2133:        if (ip->ip_p == IPPROTO_UDP) {
        !          2134:                struct udphdr *udp =
        !          2135:                    (struct udphdr *)(((char *)ip) + (ip->ip_hl << 2));
        !          2136:
        !          2137:                switch (ntohs(udp->uh_dport) & 0xc000) {
        !          2138:                case 0x4000:
        !          2139:                        prio = 70;
        !          2140:                        break;
        !          2141:                case 0x8000:
        !          2142:                        prio = 60;
        !          2143:                        break;
        !          2144:                case 0xc000:
        !          2145:                        prio = 55;
        !          2146:                        break;
        !          2147:                }
        !          2148:
        !          2149:                if (tbfdebug > 1)
        !          2150:                        log(LOG_DEBUG, "port %x prio %d\n",
        !          2151:                            ntohs(udp->uh_dport), prio);
        !          2152:        }
        !          2153:
        !          2154:        return (prio);
        !          2155: }
        !          2156:
        !          2157: /*
        !          2158:  * End of token bucket filter modifications
        !          2159:  */
        !          2160: #ifdef RSVP_ISI
        !          2161: int
        !          2162: ip_rsvp_vif_init(struct socket *so, struct mbuf *m)
        !          2163: {
        !          2164:        int vifi, s;
        !          2165:
        !          2166:        if (rsvpdebug)
        !          2167:                printf("ip_rsvp_vif_init: so_type = %d, pr_protocol = %d\n",
        !          2168:                    so->so_type, so->so_proto->pr_protocol);
        !          2169:
        !          2170:        if (so->so_type != SOCK_RAW ||
        !          2171:            so->so_proto->pr_protocol != IPPROTO_RSVP)
        !          2172:                return (EOPNOTSUPP);
        !          2173:
        !          2174:        /* Check mbuf. */
        !          2175:        if (m == NULL || m->m_len != sizeof(int)) {
        !          2176:                return (EINVAL);
        !          2177:        }
        !          2178:        vifi = *(mtod(m, int *));
        !          2179:
        !          2180:        if (rsvpdebug)
        !          2181:                printf("ip_rsvp_vif_init: vif = %d rsvp_on = %d\n",
        !          2182:                    vifi, rsvp_on);
        !          2183:
        !          2184:        s = splsoftnet();
        !          2185:
        !          2186:        /* Check vif. */
        !          2187:        if (!legal_vif_num(vifi)) {
        !          2188:                splx(s);
        !          2189:                return (EADDRNOTAVAIL);
        !          2190:        }
        !          2191:
        !          2192:        /* Check if socket is available. */
        !          2193:        if (viftable[vifi].v_rsvpd != NULL) {
        !          2194:                splx(s);
        !          2195:                return (EADDRINUSE);
        !          2196:        }
        !          2197:
        !          2198:        viftable[vifi].v_rsvpd = so;
        !          2199:        /* This may seem silly, but we need to be sure we don't over-increment
        !          2200:         * the RSVP counter, in case something slips up.
        !          2201:         */
        !          2202:        if (!viftable[vifi].v_rsvp_on) {
        !          2203:                viftable[vifi].v_rsvp_on = 1;
        !          2204:                rsvp_on++;
        !          2205:        }
        !          2206:
        !          2207:        splx(s);
        !          2208:        return (0);
        !          2209: }
        !          2210:
        !          2211: int
        !          2212: ip_rsvp_vif_done(struct socket *so, struct mbuf *m)
        !          2213: {
        !          2214:        int vifi, s;
        !          2215:
        !          2216:        if (rsvpdebug)
        !          2217:                printf("ip_rsvp_vif_done: so_type = %d, pr_protocol = %d\n",
        !          2218:                    so->so_type, so->so_proto->pr_protocol);
        !          2219:
        !          2220:        if (so->so_type != SOCK_RAW ||
        !          2221:            so->so_proto->pr_protocol != IPPROTO_RSVP)
        !          2222:                return (EOPNOTSUPP);
        !          2223:
        !          2224:        /* Check mbuf. */
        !          2225:        if (m == NULL || m->m_len != sizeof(int)) {
        !          2226:                return (EINVAL);
        !          2227:        }
        !          2228:        vifi = *(mtod(m, int *));
        !          2229:
        !          2230:        s = splsoftnet();
        !          2231:
        !          2232:        /* Check vif. */
        !          2233:        if (!legal_vif_num(vifi)) {
        !          2234:                splx(s);
        !          2235:                return (EADDRNOTAVAIL);
        !          2236:        }
        !          2237:
        !          2238:        if (rsvpdebug)
        !          2239:                printf("ip_rsvp_vif_done: v_rsvpd = %x so = %x\n",
        !          2240:                    viftable[vifi].v_rsvpd, so);
        !          2241:
        !          2242:        viftable[vifi].v_rsvpd = NULL;
        !          2243:        /*
        !          2244:         * This may seem silly, but we need to be sure we don't over-decrement
        !          2245:         * the RSVP counter, in case something slips up.
        !          2246:         */
        !          2247:        if (viftable[vifi].v_rsvp_on) {
        !          2248:                viftable[vifi].v_rsvp_on = 0;
        !          2249:                rsvp_on--;
        !          2250:        }
        !          2251:
        !          2252:        splx(s);
        !          2253:        return (0);
        !          2254: }
        !          2255:
        !          2256: void
        !          2257: ip_rsvp_force_done(struct socket *so)
        !          2258: {
        !          2259:        int vifi, s;
        !          2260:
        !          2261:        /* Don't bother if it is not the right type of socket. */
        !          2262:        if (so->so_type != SOCK_RAW ||
        !          2263:            so->so_proto->pr_protocol != IPPROTO_RSVP)
        !          2264:                return;
        !          2265:
        !          2266:        s = splsoftnet();
        !          2267:
        !          2268:        /*
        !          2269:         * The socket may be attached to more than one vif...this
        !          2270:         * is perfectly legal.
        !          2271:         */
        !          2272:        for (vifi = 0; vifi < numvifs; vifi++) {
        !          2273:                if (viftable[vifi].v_rsvpd == so) {
        !          2274:                        viftable[vifi].v_rsvpd = NULL;
        !          2275:                        /*
        !          2276:                         * This may seem silly, but we need to be sure we don't
        !          2277:                         * over-decrement the RSVP counter, in case something
        !          2278:                         * slips up.
        !          2279:                         */
        !          2280:                        if (viftable[vifi].v_rsvp_on) {
        !          2281:                                viftable[vifi].v_rsvp_on = 0;
        !          2282:                                rsvp_on--;
        !          2283:                        }
        !          2284:                }
        !          2285:        }
        !          2286:
        !          2287:        splx(s);
        !          2288:        return;
        !          2289: }
        !          2290:
        !          2291: void
        !          2292: rsvp_input(struct mbuf *m, struct ifnet *ifp)
        !          2293: {
        !          2294:        int vifi, s;
        !          2295:        struct ip *ip = mtod(m, struct ip *);
        !          2296:        static struct sockaddr_in rsvp_src = { sizeof(sin), AF_INET };
        !          2297:
        !          2298:        if (rsvpdebug)
        !          2299:                printf("rsvp_input: rsvp_on %d\n", rsvp_on);
        !          2300:
        !          2301:        /*
        !          2302:         * Can still get packets with rsvp_on = 0 if there is a local member
        !          2303:         * of the group to which the RSVP packet is addressed.  But in this
        !          2304:         * case we want to throw the packet away.
        !          2305:         */
        !          2306:        if (!rsvp_on) {
        !          2307:                m_freem(m);
        !          2308:                return;
        !          2309:        }
        !          2310:
        !          2311:        /*
        !          2312:         * If the old-style non-vif-associated socket is set, then use
        !          2313:         * it and ignore the new ones.
        !          2314:         */
        !          2315:        if (ip_rsvpd != NULL) {
        !          2316:                if (rsvpdebug)
        !          2317:                        printf("rsvp_input: "
        !          2318:                            "Sending packet up old-style socket\n");
        !          2319:                rip_input(m, 0);        /*XXX*/
        !          2320:                return;
        !          2321:        }
        !          2322:
        !          2323:        s = splsoftnet();
        !          2324:
        !          2325:        if (rsvpdebug)
        !          2326:                printf("rsvp_input: check vifs\n");
        !          2327:
        !          2328:        /* Find which vif the packet arrived on. */
        !          2329:        for (vifi = 0; vifi < numvifs; vifi++) {
        !          2330:                if (viftable[vifi].v_ifp == ifp)
        !          2331:                        break;
        !          2332:        }
        !          2333:
        !          2334:        if (vifi == numvifs) {
        !          2335:                /* Can't find vif packet arrived on. Drop packet. */
        !          2336:                if (rsvpdebug)
        !          2337:                        printf("rsvp_input: "
        !          2338:                            "Can't find vif for packet...dropping it.\n");
        !          2339:                m_freem(m);
        !          2340:                splx(s);
        !          2341:                return;
        !          2342:        }
        !          2343:
        !          2344:        if (rsvpdebug)
        !          2345:                printf("rsvp_input: check socket\n");
        !          2346:
        !          2347:        if (viftable[vifi].v_rsvpd == NULL) {
        !          2348:                /*
        !          2349:                 * drop packet, since there is no specific socket for this
        !          2350:                 * interface
        !          2351:                 */
        !          2352:                if (rsvpdebug)
        !          2353:                        printf("rsvp_input: No socket defined for vif %d\n",
        !          2354:                            vifi);
        !          2355:                m_freem(m);
        !          2356:                splx(s);
        !          2357:                return;
        !          2358:        }
        !          2359:
        !          2360:        rsvp_src.sin_addr = ip->ip_src;
        !          2361:
        !          2362:        if (rsvpdebug && m)
        !          2363:                printf("rsvp_input: m->m_len = %d, sbspace() = %d\n",
        !          2364:                    m->m_len, sbspace(&viftable[vifi].v_rsvpd->so_rcv));
        !          2365:
        !          2366:        if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0)
        !          2367:                if (rsvpdebug)
        !          2368:                        printf("rsvp_input: Failed to append to socket\n");
        !          2369:        else
        !          2370:                if (rsvpdebug)
        !          2371:                        printf("rsvp_input: send packet up\n");
        !          2372:
        !          2373:        splx(s);
        !          2374: }
        !          2375: #endif /* RSVP_ISI */
        !          2376:
        !          2377: /*
        !          2378:  * Code for bandwidth monitors
        !          2379:  */
        !          2380:
        !          2381: /*
        !          2382:  * Define common interface for timeval-related methods
        !          2383:  */
        !          2384: #define        BW_TIMEVALCMP(tvp, uvp, cmp) timercmp((tvp), (uvp), cmp)
        !          2385: #define        BW_TIMEVALDECR(vvp, uvp) timersub((vvp), (uvp), (vvp))
        !          2386: #define        BW_TIMEVALADD(vvp, uvp) timeradd((vvp), (uvp), (vvp))
        !          2387:
        !          2388: static uint32_t
        !          2389: compute_bw_meter_flags(struct bw_upcall *req)
        !          2390: {
        !          2391:        uint32_t flags = 0;
        !          2392:
        !          2393:        if (req->bu_flags & BW_UPCALL_UNIT_PACKETS)
        !          2394:                flags |= BW_METER_UNIT_PACKETS;
        !          2395:        if (req->bu_flags & BW_UPCALL_UNIT_BYTES)
        !          2396:                flags |= BW_METER_UNIT_BYTES;
        !          2397:        if (req->bu_flags & BW_UPCALL_GEQ)
        !          2398:                flags |= BW_METER_GEQ;
        !          2399:        if (req->bu_flags & BW_UPCALL_LEQ)
        !          2400:                flags |= BW_METER_LEQ;
        !          2401:
        !          2402:        return (flags);
        !          2403: }
        !          2404:
        !          2405: /*
        !          2406:  * Add a bw_meter entry
        !          2407:  */
        !          2408: static int
        !          2409: add_bw_upcall(struct mbuf *m)
        !          2410: {
        !          2411:        int s;
        !          2412:        struct mfc *mfc;
        !          2413:        struct timeval delta = { BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC,
        !          2414:            BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC };
        !          2415:        struct timeval now;
        !          2416:        struct bw_meter *x;
        !          2417:        uint32_t flags;
        !          2418:        struct bw_upcall *req;
        !          2419:
        !          2420:        if (m == NULL || m->m_len < sizeof(struct bw_upcall))
        !          2421:                return (EINVAL);
        !          2422:
        !          2423:        req = mtod(m, struct bw_upcall *);
        !          2424:
        !          2425:        if (!(mrt_api_config & MRT_MFC_BW_UPCALL))
        !          2426:                return (EOPNOTSUPP);
        !          2427:
        !          2428:        /* Test if the flags are valid */
        !          2429:        if (!(req->bu_flags & (BW_UPCALL_UNIT_PACKETS | BW_UPCALL_UNIT_BYTES)))
        !          2430:                return (EINVAL);
        !          2431:        if (!(req->bu_flags & (BW_UPCALL_GEQ | BW_UPCALL_LEQ)))
        !          2432:                return (EINVAL);
        !          2433:        if ((req->bu_flags & (BW_UPCALL_GEQ | BW_UPCALL_LEQ))
        !          2434:            == (BW_UPCALL_GEQ | BW_UPCALL_LEQ))
        !          2435:                return (EINVAL);
        !          2436:
        !          2437:        /* Test if the threshold time interval is valid */
        !          2438:        if (BW_TIMEVALCMP(&req->bu_threshold.b_time, &delta, <))
        !          2439:                return (EINVAL);
        !          2440:
        !          2441:        flags = compute_bw_meter_flags(req);
        !          2442:
        !          2443:        /* Find if we have already same bw_meter entry */
        !          2444:        s = splsoftnet();
        !          2445:        mfc = mfc_find(&req->bu_src, &req->bu_dst);
        !          2446:        if (mfc == NULL) {
        !          2447:                splx(s);
        !          2448:                return (EADDRNOTAVAIL);
        !          2449:        }
        !          2450:        for (x = mfc->mfc_bw_meter; x != NULL; x = x->bm_mfc_next) {
        !          2451:                if ((BW_TIMEVALCMP(&x->bm_threshold.b_time,
        !          2452:                    &req->bu_threshold.b_time, ==)) &&
        !          2453:                    (x->bm_threshold.b_packets ==
        !          2454:                    req->bu_threshold.b_packets) &&
        !          2455:                    (x->bm_threshold.b_bytes == req->bu_threshold.b_bytes) &&
        !          2456:                    (x->bm_flags & BW_METER_USER_FLAGS) == flags)  {
        !          2457:                        splx(s);
        !          2458:                        return (0);     /* XXX Already installed */
        !          2459:                }
        !          2460:        }
        !          2461:
        !          2462:        /* Allocate the new bw_meter entry */
        !          2463:        x = (struct bw_meter *)malloc(sizeof(*x), M_BWMETER, M_NOWAIT);
        !          2464:        if (x == NULL) {
        !          2465:                splx(s);
        !          2466:                return (ENOBUFS);
        !          2467:        }
        !          2468:
        !          2469:        /* Set the new bw_meter entry */
        !          2470:        x->bm_threshold.b_time = req->bu_threshold.b_time;
        !          2471:        microtime(&now);
        !          2472:        x->bm_start_time = now;
        !          2473:        x->bm_threshold.b_packets = req->bu_threshold.b_packets;
        !          2474:        x->bm_threshold.b_bytes = req->bu_threshold.b_bytes;
        !          2475:        x->bm_measured.b_packets = 0;
        !          2476:        x->bm_measured.b_bytes = 0;
        !          2477:        x->bm_flags = flags;
        !          2478:        x->bm_time_next = NULL;
        !          2479:        x->bm_time_hash = BW_METER_BUCKETS;
        !          2480:
        !          2481:        /* Add the new bw_meter entry to the front of entries for this MFC */
        !          2482:        x->bm_mfc = mfc;
        !          2483:        x->bm_mfc_next = mfc->mfc_bw_meter;
        !          2484:        mfc->mfc_bw_meter = x;
        !          2485:        schedule_bw_meter(x, &now);
        !          2486:        splx(s);
        !          2487:
        !          2488:        return (0);
        !          2489: }
        !          2490:
        !          2491: static void
        !          2492: free_bw_list(struct bw_meter *list)
        !          2493: {
        !          2494:        while (list != NULL) {
        !          2495:                struct bw_meter *x = list;
        !          2496:
        !          2497:                list = list->bm_mfc_next;
        !          2498:                unschedule_bw_meter(x);
        !          2499:                free(x, M_BWMETER);
        !          2500:        }
        !          2501: }
        !          2502:
        !          2503: /*
        !          2504:  * Delete one or multiple bw_meter entries
        !          2505:  */
        !          2506: static int
        !          2507: del_bw_upcall(struct mbuf *m)
        !          2508: {
        !          2509:        int s;
        !          2510:        struct mfc *mfc;
        !          2511:        struct bw_meter *x;
        !          2512:        struct bw_upcall *req;
        !          2513:
        !          2514:        if (m == NULL || m->m_len < sizeof(struct bw_upcall))
        !          2515:                return (EINVAL);
        !          2516:
        !          2517:        req = mtod(m, struct bw_upcall *);
        !          2518:
        !          2519:        if (!(mrt_api_config & MRT_MFC_BW_UPCALL))
        !          2520:                return (EOPNOTSUPP);
        !          2521:
        !          2522:        s = splsoftnet();
        !          2523:        /* Find the corresponding MFC entry */
        !          2524:        mfc = mfc_find(&req->bu_src, &req->bu_dst);
        !          2525:        if (mfc == NULL) {
        !          2526:                splx(s);
        !          2527:                return (EADDRNOTAVAIL);
        !          2528:        } else if (req->bu_flags & BW_UPCALL_DELETE_ALL) {
        !          2529:                /* Delete all bw_meter entries for this mfc */
        !          2530:                struct bw_meter *list;
        !          2531:
        !          2532:                list = mfc->mfc_bw_meter;
        !          2533:                mfc->mfc_bw_meter = NULL;
        !          2534:                free_bw_list(list);
        !          2535:                splx(s);
        !          2536:                return (0);
        !          2537:        } else {        /* Delete a single bw_meter entry */
        !          2538:                struct bw_meter *prev;
        !          2539:                uint32_t flags = 0;
        !          2540:
        !          2541:                flags = compute_bw_meter_flags(req);
        !          2542:
        !          2543:                /* Find the bw_meter entry to delete */
        !          2544:                for (prev = NULL, x = mfc->mfc_bw_meter; x != NULL;
        !          2545:                    prev = x, x = x->bm_mfc_next) {
        !          2546:                        if ((BW_TIMEVALCMP(&x->bm_threshold.b_time,
        !          2547:                            &req->bu_threshold.b_time, ==)) &&
        !          2548:                            (x->bm_threshold.b_packets ==
        !          2549:                            req->bu_threshold.b_packets) &&
        !          2550:                            (x->bm_threshold.b_bytes ==
        !          2551:                            req->bu_threshold.b_bytes) &&
        !          2552:                            (x->bm_flags & BW_METER_USER_FLAGS) == flags)
        !          2553:                                break;
        !          2554:                }
        !          2555:                if (x != NULL) { /* Delete entry from the list for this MFC */
        !          2556:                        if (prev != NULL) {
        !          2557:                                /* remove from middle */
        !          2558:                                prev->bm_mfc_next = x->bm_mfc_next;
        !          2559:                        } else {
        !          2560:                                /* new head of list */
        !          2561:                                x->bm_mfc->mfc_bw_meter = x->bm_mfc_next;
        !          2562:                        }
        !          2563:
        !          2564:                        unschedule_bw_meter(x);
        !          2565:                        splx(s);
        !          2566:                        /* Free the bw_meter entry */
        !          2567:                        free(x, M_BWMETER);
        !          2568:                        return (0);
        !          2569:                } else {
        !          2570:                        splx(s);
        !          2571:                        return (EINVAL);
        !          2572:                }
        !          2573:        }
        !          2574:        /* NOTREACHED */
        !          2575: }
        !          2576:
        !          2577: /*
        !          2578:  * Perform bandwidth measurement processing that may result in an upcall
        !          2579:  */
        !          2580: static void
        !          2581: bw_meter_receive_packet(struct bw_meter *x, int plen, struct timeval *nowp)
        !          2582: {
        !          2583:        struct timeval delta;
        !          2584:
        !          2585:        delta = *nowp;
        !          2586:        BW_TIMEVALDECR(&delta, &x->bm_start_time);
        !          2587:
        !          2588:        if (x->bm_flags & BW_METER_GEQ) {
        !          2589:                /* Processing for ">=" type of bw_meter entry */
        !          2590:                if (BW_TIMEVALCMP(&delta, &x->bm_threshold.b_time, >)) {
        !          2591:                        /* Reset the bw_meter entry */
        !          2592:                        x->bm_start_time = *nowp;
        !          2593:                        x->bm_measured.b_packets = 0;
        !          2594:                        x->bm_measured.b_bytes = 0;
        !          2595:                        x->bm_flags &= ~BW_METER_UPCALL_DELIVERED;
        !          2596:                }
        !          2597:
        !          2598:                /* Record that a packet is received */
        !          2599:                x->bm_measured.b_packets++;
        !          2600:                x->bm_measured.b_bytes += plen;
        !          2601:
        !          2602:                /* Test if we should deliver an upcall */
        !          2603:                if (!(x->bm_flags & BW_METER_UPCALL_DELIVERED)) {
        !          2604:                        if (((x->bm_flags & BW_METER_UNIT_PACKETS) &&
        !          2605:                            (x->bm_measured.b_packets >=
        !          2606:                            x->bm_threshold.b_packets)) ||
        !          2607:                            ((x->bm_flags & BW_METER_UNIT_BYTES) &&
        !          2608:                            (x->bm_measured.b_bytes >=
        !          2609:                            x->bm_threshold.b_bytes))) {
        !          2610:                                /* Prepare an upcall for delivery */
        !          2611:                                bw_meter_prepare_upcall(x, nowp);
        !          2612:                                x->bm_flags |= BW_METER_UPCALL_DELIVERED;
        !          2613:                        }
        !          2614:                }
        !          2615:        } else if (x->bm_flags & BW_METER_LEQ) {
        !          2616:                /* Processing for "<=" type of bw_meter entry */
        !          2617:                if (BW_TIMEVALCMP(&delta, &x->bm_threshold.b_time, >)) {
        !          2618:                        /*
        !          2619:                         * We are behind time with the multicast forwarding
        !          2620:                         * table scanning for "<=" type of bw_meter entries,
        !          2621:                         * so test now if we should deliver an upcall.
        !          2622:                         */
        !          2623:                        if (((x->bm_flags & BW_METER_UNIT_PACKETS) &&
        !          2624:                            (x->bm_measured.b_packets <=
        !          2625:                            x->bm_threshold.b_packets)) ||
        !          2626:                            ((x->bm_flags & BW_METER_UNIT_BYTES) &&
        !          2627:                            (x->bm_measured.b_bytes <=
        !          2628:                            x->bm_threshold.b_bytes))) {
        !          2629:                                /* Prepare an upcall for delivery */
        !          2630:                                bw_meter_prepare_upcall(x, nowp);
        !          2631:                        }
        !          2632:                        /* Reschedule the bw_meter entry */
        !          2633:                        unschedule_bw_meter(x);
        !          2634:                        schedule_bw_meter(x, nowp);
        !          2635:                }
        !          2636:
        !          2637:                /* Record that a packet is received */
        !          2638:                x->bm_measured.b_packets++;
        !          2639:                x->bm_measured.b_bytes += plen;
        !          2640:
        !          2641:                /* Test if we should restart the measuring interval */
        !          2642:                if ((x->bm_flags & BW_METER_UNIT_PACKETS &&
        !          2643:                    x->bm_measured.b_packets <= x->bm_threshold.b_packets) ||
        !          2644:                    (x->bm_flags & BW_METER_UNIT_BYTES &&
        !          2645:                    x->bm_measured.b_bytes <= x->bm_threshold.b_bytes)) {
        !          2646:                        /* Don't restart the measuring interval */
        !          2647:                } else {
        !          2648:                        /* Do restart the measuring interval */
        !          2649:                        /*
        !          2650:                         * XXX: note that we don't unschedule and schedule,
        !          2651:                         * because this might be too much overhead per packet.
        !          2652:                         * Instead, when we process all entries for a given
        !          2653:                         * timer hash bin, we check whether it is really a
        !          2654:                         * timeout. If not, we reschedule at that time.
        !          2655:                         */
        !          2656:                        x->bm_start_time = *nowp;
        !          2657:                        x->bm_measured.b_packets = 0;
        !          2658:                        x->bm_measured.b_bytes = 0;
        !          2659:                        x->bm_flags &= ~BW_METER_UPCALL_DELIVERED;
        !          2660:                }
        !          2661:        }
        !          2662: }
        !          2663:
        !          2664: /*
        !          2665:  * Prepare a bandwidth-related upcall
        !          2666:  */
        !          2667: static void
        !          2668: bw_meter_prepare_upcall(struct bw_meter *x, struct timeval *nowp)
        !          2669: {
        !          2670:        struct timeval delta;
        !          2671:        struct bw_upcall *u;
        !          2672:
        !          2673:        /* Compute the measured time interval */
        !          2674:        delta = *nowp;
        !          2675:        BW_TIMEVALDECR(&delta, &x->bm_start_time);
        !          2676:
        !          2677:        /* If there are too many pending upcalls, deliver them now */
        !          2678:        if (bw_upcalls_n >= BW_UPCALLS_MAX)
        !          2679:                bw_upcalls_send();
        !          2680:
        !          2681:        /* Set the bw_upcall entry */
        !          2682:        u = &bw_upcalls[bw_upcalls_n++];
        !          2683:        u->bu_src = x->bm_mfc->mfc_origin;
        !          2684:        u->bu_dst = x->bm_mfc->mfc_mcastgrp;
        !          2685:        u->bu_threshold.b_time = x->bm_threshold.b_time;
        !          2686:        u->bu_threshold.b_packets = x->bm_threshold.b_packets;
        !          2687:        u->bu_threshold.b_bytes = x->bm_threshold.b_bytes;
        !          2688:        u->bu_measured.b_time = delta;
        !          2689:        u->bu_measured.b_packets = x->bm_measured.b_packets;
        !          2690:        u->bu_measured.b_bytes = x->bm_measured.b_bytes;
        !          2691:        u->bu_flags = 0;
        !          2692:        if (x->bm_flags & BW_METER_UNIT_PACKETS)
        !          2693:                u->bu_flags |= BW_UPCALL_UNIT_PACKETS;
        !          2694:        if (x->bm_flags & BW_METER_UNIT_BYTES)
        !          2695:                u->bu_flags |= BW_UPCALL_UNIT_BYTES;
        !          2696:        if (x->bm_flags & BW_METER_GEQ)
        !          2697:                u->bu_flags |= BW_UPCALL_GEQ;
        !          2698:        if (x->bm_flags & BW_METER_LEQ)
        !          2699:                u->bu_flags |= BW_UPCALL_LEQ;
        !          2700: }
        !          2701:
        !          2702: /*
        !          2703:  * Send the pending bandwidth-related upcalls
        !          2704:  */
        !          2705: static void
        !          2706: bw_upcalls_send(void)
        !          2707: {
        !          2708:        struct mbuf *m;
        !          2709:        int len = bw_upcalls_n * sizeof(bw_upcalls[0]);
        !          2710:        struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET };
        !          2711:        static struct igmpmsg igmpmsg = {
        !          2712:            0,                  /* unused1 */
        !          2713:            0,                  /* unused2 */
        !          2714:            IGMPMSG_BW_UPCALL,  /* im_msgtype */
        !          2715:            0,                  /* im_mbz  */
        !          2716:            0,                  /* im_vif  */
        !          2717:            0,                  /* unused3 */
        !          2718:            { 0 },              /* im_src  */
        !          2719:            { 0 } };            /* im_dst  */
        !          2720:
        !          2721:        if (bw_upcalls_n == 0)
        !          2722:                return;         /* No pending upcalls */
        !          2723:
        !          2724:        bw_upcalls_n = 0;
        !          2725:
        !          2726:        /*
        !          2727:         * Allocate a new mbuf, initialize it with the header and
        !          2728:         * the payload for the pending calls.
        !          2729:         */
        !          2730:        MGETHDR(m, M_DONTWAIT, MT_HEADER);
        !          2731:        if (m == NULL) {
        !          2732:                log(LOG_WARNING, "bw_upcalls_send: cannot allocate mbuf\n");
        !          2733:                return;
        !          2734:        }
        !          2735:
        !          2736:        m->m_len = m->m_pkthdr.len = 0;
        !          2737:        m_copyback(m, 0, sizeof(struct igmpmsg), (caddr_t)&igmpmsg);
        !          2738:        m_copyback(m, sizeof(struct igmpmsg), len, (caddr_t)&bw_upcalls[0]);
        !          2739:
        !          2740:        /*
        !          2741:         * Send the upcalls
        !          2742:         * XXX do we need to set the address in k_igmpsrc ?
        !          2743:         */
        !          2744:        mrtstat.mrts_upcalls++;
        !          2745:        if (socket_send(ip_mrouter, m, &k_igmpsrc) < 0) {
        !          2746:                log(LOG_WARNING,
        !          2747:                    "bw_upcalls_send: ip_mrouter socket queue full\n");
        !          2748:                ++mrtstat.mrts_upq_sockfull;
        !          2749:        }
        !          2750: }
        !          2751:
        !          2752: /*
        !          2753:  * Compute the timeout hash value for the bw_meter entries
        !          2754:  */
        !          2755: #define        BW_METER_TIMEHASH(bw_meter, hash) do {                          \
        !          2756:        struct timeval next_timeval = (bw_meter)->bm_start_time;        \
        !          2757:                                                                        \
        !          2758:        BW_TIMEVALADD(&next_timeval, &(bw_meter)->bm_threshold.b_time); \
        !          2759:        (hash) = next_timeval.tv_sec;                                   \
        !          2760:        if (next_timeval.tv_usec)                                       \
        !          2761:                (hash)++; /* XXX: make sure we don't timeout early */   \
        !          2762:        (hash) %= BW_METER_BUCKETS;                                     \
        !          2763: } while (/*CONSTCOND*/ 0)
        !          2764:
        !          2765: /*
        !          2766:  * Schedule a timer to process periodically bw_meter entry of type "<="
        !          2767:  * by linking the entry in the proper hash bucket.
        !          2768:  */
        !          2769: static void
        !          2770: schedule_bw_meter(struct bw_meter *x, struct timeval *nowp)
        !          2771: {
        !          2772:        int time_hash;
        !          2773:
        !          2774:        if (!(x->bm_flags & BW_METER_LEQ))
        !          2775:                return; /* XXX: we schedule timers only for "<=" entries */
        !          2776:
        !          2777:        /* Reset the bw_meter entry */
        !          2778:        x->bm_start_time = *nowp;
        !          2779:        x->bm_measured.b_packets = 0;
        !          2780:        x->bm_measured.b_bytes = 0;
        !          2781:        x->bm_flags &= ~BW_METER_UPCALL_DELIVERED;
        !          2782:
        !          2783:        /* Compute the timeout hash value and insert the entry */
        !          2784:        BW_METER_TIMEHASH(x, time_hash);
        !          2785:        x->bm_time_next = bw_meter_timers[time_hash];
        !          2786:        bw_meter_timers[time_hash] = x;
        !          2787:        x->bm_time_hash = time_hash;
        !          2788: }
        !          2789:
        !          2790: /*
        !          2791:  * Unschedule the periodic timer that processes bw_meter entry of type "<="
        !          2792:  * by removing the entry from the proper hash bucket.
        !          2793:  */
        !          2794: static void
        !          2795: unschedule_bw_meter(struct bw_meter *x)
        !          2796: {
        !          2797:        int time_hash;
        !          2798:        struct bw_meter *prev, *tmp;
        !          2799:
        !          2800:        if (!(x->bm_flags & BW_METER_LEQ))
        !          2801:                return; /* XXX: we schedule timers only for "<=" entries */
        !          2802:
        !          2803:        /* Compute the timeout hash value and delete the entry */
        !          2804:        time_hash = x->bm_time_hash;
        !          2805:        if (time_hash >= BW_METER_BUCKETS)
        !          2806:                return;         /* Entry was not scheduled */
        !          2807:
        !          2808:        for (prev = NULL, tmp = bw_meter_timers[time_hash];
        !          2809:            tmp != NULL; prev = tmp, tmp = tmp->bm_time_next)
        !          2810:                if (tmp == x)
        !          2811:                        break;
        !          2812:
        !          2813:        if (tmp == NULL)
        !          2814:                panic("unschedule_bw_meter: bw_meter entry not found");
        !          2815:
        !          2816:        if (prev != NULL)
        !          2817:                prev->bm_time_next = x->bm_time_next;
        !          2818:        else
        !          2819:                bw_meter_timers[time_hash] = x->bm_time_next;
        !          2820:
        !          2821:        x->bm_time_next = NULL;
        !          2822:        x->bm_time_hash = BW_METER_BUCKETS;
        !          2823: }
        !          2824:
        !          2825: /*
        !          2826:  * Process all "<=" type of bw_meter that should be processed now,
        !          2827:  * and for each entry prepare an upcall if necessary. Each processed
        !          2828:  * entry is rescheduled again for the (periodic) processing.
        !          2829:  *
        !          2830:  * This is run periodically (once per second normally). On each round,
        !          2831:  * all the potentially matching entries are in the hash slot that we are
        !          2832:  * looking at.
        !          2833:  */
        !          2834: static void
        !          2835: bw_meter_process()
        !          2836: {
        !          2837:        int s;
        !          2838:        static uint32_t last_tv_sec;    /* last time we processed this */
        !          2839:
        !          2840:        uint32_t loops;
        !          2841:        int i;
        !          2842:        struct timeval now, process_endtime;
        !          2843:
        !          2844:        microtime(&now);
        !          2845:        if (last_tv_sec == now.tv_sec)
        !          2846:                return;         /* nothing to do */
        !          2847:
        !          2848:        loops = now.tv_sec - last_tv_sec;
        !          2849:        last_tv_sec = now.tv_sec;
        !          2850:        if (loops > BW_METER_BUCKETS)
        !          2851:                loops = BW_METER_BUCKETS;
        !          2852:
        !          2853:        s = splsoftnet();
        !          2854:        /*
        !          2855:         * Process all bins of bw_meter entries from the one after the last
        !          2856:         * processed to the current one. On entry, i points to the last bucket
        !          2857:         * visited, so we need to increment i at the beginning of the loop.
        !          2858:         */
        !          2859:        for (i = (now.tv_sec - loops) % BW_METER_BUCKETS; loops > 0; loops--) {
        !          2860:                struct bw_meter *x, *tmp_list;
        !          2861:
        !          2862:                if (++i >= BW_METER_BUCKETS)
        !          2863:                        i = 0;
        !          2864:
        !          2865:                /* Disconnect the list of bw_meter entries from the bin */
        !          2866:                tmp_list = bw_meter_timers[i];
        !          2867:                bw_meter_timers[i] = NULL;
        !          2868:
        !          2869:                /* Process the list of bw_meter entries */
        !          2870:                while (tmp_list != NULL) {
        !          2871:                        x = tmp_list;
        !          2872:                        tmp_list = tmp_list->bm_time_next;
        !          2873:
        !          2874:                        /* Test if the time interval is over */
        !          2875:                        process_endtime = x->bm_start_time;
        !          2876:                        BW_TIMEVALADD(&process_endtime,
        !          2877:                            &x->bm_threshold.b_time);
        !          2878:                        if (BW_TIMEVALCMP(&process_endtime, &now, >)) {
        !          2879:                                /* Not yet: reschedule, but don't reset */
        !          2880:                                int time_hash;
        !          2881:
        !          2882:                                BW_METER_TIMEHASH(x, time_hash);
        !          2883:                                if (time_hash == i &&
        !          2884:                                    process_endtime.tv_sec == now.tv_sec) {
        !          2885:                                        /*
        !          2886:                                         * XXX: somehow the bin processing is
        !          2887:                                         * a bit ahead of time. Put the entry
        !          2888:                                         * in the next bin.
        !          2889:                                         */
        !          2890:                                        if (++time_hash >= BW_METER_BUCKETS)
        !          2891:                                                time_hash = 0;
        !          2892:                                }
        !          2893:                                x->bm_time_next = bw_meter_timers[time_hash];
        !          2894:                                bw_meter_timers[time_hash] = x;
        !          2895:                                x->bm_time_hash = time_hash;
        !          2896:
        !          2897:                                continue;
        !          2898:                        }
        !          2899:
        !          2900:                        /* Test if we should deliver an upcall */
        !          2901:                        if (((x->bm_flags & BW_METER_UNIT_PACKETS) &&
        !          2902:                            (x->bm_measured.b_packets <=
        !          2903:                            x->bm_threshold.b_packets)) ||
        !          2904:                            ((x->bm_flags & BW_METER_UNIT_BYTES) &&
        !          2905:                            (x->bm_measured.b_bytes <=
        !          2906:                            x->bm_threshold.b_bytes))) {
        !          2907:                                /* Prepare an upcall for delivery */
        !          2908:                                bw_meter_prepare_upcall(x, &now);
        !          2909:                        }
        !          2910:
        !          2911:                        /* Reschedule for next processing */
        !          2912:                        schedule_bw_meter(x, &now);
        !          2913:                }
        !          2914:        }
        !          2915:
        !          2916:        /* Send all upcalls that are pending delivery */
        !          2917:        bw_upcalls_send();
        !          2918:
        !          2919:        splx(s);
        !          2920: }
        !          2921:
        !          2922: /*
        !          2923:  * A periodic function for sending all upcalls that are pending delivery
        !          2924:  */
        !          2925: static void
        !          2926: expire_bw_upcalls_send(void *unused)
        !          2927: {
        !          2928:        int s;
        !          2929:
        !          2930:        s = splsoftnet();
        !          2931:        bw_upcalls_send();
        !          2932:        splx(s);
        !          2933:
        !          2934:        timeout_add(&bw_upcalls_ch, BW_UPCALLS_PERIOD);
        !          2935: }
        !          2936:
        !          2937: /*
        !          2938:  * A periodic function for periodic scanning of the multicast forwarding
        !          2939:  * table for processing all "<=" bw_meter entries.
        !          2940:  */
        !          2941: static void
        !          2942: expire_bw_meter_process(void *unused)
        !          2943: {
        !          2944:        if (mrt_api_config & MRT_MFC_BW_UPCALL)
        !          2945:                bw_meter_process();
        !          2946:
        !          2947:        timeout_add(&bw_meter_ch, BW_METER_PERIOD);
        !          2948: }
        !          2949:
        !          2950: /*
        !          2951:  * End of bandwidth monitoring code
        !          2952:  */
        !          2953:
        !          2954: #ifdef PIM
        !          2955: /*
        !          2956:  * Send the packet up to the user daemon, or eventually do kernel encapsulation
        !          2957:  */
        !          2958: static int
        !          2959: pim_register_send(struct ip *ip, struct vif *vifp,
        !          2960:        struct mbuf *m, struct mfc *rt)
        !          2961: {
        !          2962:        struct mbuf *mb_copy, *mm;
        !          2963:
        !          2964:        if (mrtdebug & DEBUG_PIM)
        !          2965:                log(LOG_DEBUG, "pim_register_send: ");
        !          2966:
        !          2967:        mb_copy = pim_register_prepare(ip, m);
        !          2968:        if (mb_copy == NULL)
        !          2969:                return (ENOBUFS);
        !          2970:
        !          2971:        /*
        !          2972:         * Send all the fragments. Note that the mbuf for each fragment
        !          2973:         * is freed by the sending machinery.
        !          2974:         */
        !          2975:        for (mm = mb_copy; mm; mm = mb_copy) {
        !          2976:                mb_copy = mm->m_nextpkt;
        !          2977:                mm->m_nextpkt = NULL;
        !          2978:                mm = m_pullup(mm, sizeof(struct ip));
        !          2979:                if (mm != NULL) {
        !          2980:                        ip = mtod(mm, struct ip *);
        !          2981:                        if ((mrt_api_config & MRT_MFC_RP) &&
        !          2982:                            !in_nullhost(rt->mfc_rp)) {
        !          2983:                                pim_register_send_rp(ip, vifp, mm, rt);
        !          2984:                        } else {
        !          2985:                                pim_register_send_upcall(ip, vifp, mm, rt);
        !          2986:                        }
        !          2987:                }
        !          2988:        }
        !          2989:
        !          2990:        return (0);
        !          2991: }
        !          2992:
        !          2993: /*
        !          2994:  * Return a copy of the data packet that is ready for PIM Register
        !          2995:  * encapsulation.
        !          2996:  * XXX: Note that in the returned copy the IP header is a valid one.
        !          2997:  */
        !          2998: static struct mbuf *
        !          2999: pim_register_prepare(struct ip *ip, struct mbuf *m)
        !          3000: {
        !          3001:        struct mbuf *mb_copy = NULL;
        !          3002:        int mtu;
        !          3003:
        !          3004:        /* Take care of delayed checksums */
        !          3005:        if (m->m_pkthdr.csum_flags & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) {
        !          3006:                in_delayed_cksum(m);
        !          3007:                m->m_pkthdr.csum_flags &=
        !          3008:                    ~(M_UDPV4_CSUM_OUT | M_TCPV4_CSUM_OUT);
        !          3009:        }
        !          3010:
        !          3011:        /*
        !          3012:         * Copy the old packet & pullup its IP header into the
        !          3013:         * new mbuf so we can modify it.
        !          3014:         */
        !          3015:        mb_copy = m_copy(m, 0, M_COPYALL);
        !          3016:        if (mb_copy == NULL)
        !          3017:                return (NULL);
        !          3018:        mb_copy = m_pullup(mb_copy, ip->ip_hl << 2);
        !          3019:        if (mb_copy == NULL)
        !          3020:                return (NULL);
        !          3021:
        !          3022:        /* take care of the TTL */
        !          3023:        ip = mtod(mb_copy, struct ip *);
        !          3024:        --ip->ip_ttl;
        !          3025:
        !          3026:        /* Compute the MTU after the PIM Register encapsulation */
        !          3027:        mtu = 0xffff - sizeof(pim_encap_iphdr) - sizeof(pim_encap_pimhdr);
        !          3028:
        !          3029:        if (ntohs(ip->ip_len) <= mtu) {
        !          3030:                /* Turn the IP header into a valid one */
        !          3031:                ip->ip_sum = 0;
        !          3032:                ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2);
        !          3033:        } else {
        !          3034:                /* Fragment the packet */
        !          3035:                if (ip_fragment(mb_copy, NULL, mtu) != 0) {
        !          3036:                        /* XXX: mb_copy was freed by ip_fragment() */
        !          3037:                        return (NULL);
        !          3038:                }
        !          3039:        }
        !          3040:        return (mb_copy);
        !          3041: }
        !          3042:
        !          3043: /*
        !          3044:  * Send an upcall with the data packet to the user-level process.
        !          3045:  */
        !          3046: static int
        !          3047: pim_register_send_upcall(struct ip *ip, struct vif *vifp,
        !          3048:        struct mbuf *mb_copy, struct mfc *rt)
        !          3049: {
        !          3050:        struct mbuf *mb_first;
        !          3051:        int len = ntohs(ip->ip_len);
        !          3052:        struct igmpmsg *im;
        !          3053:        struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET };
        !          3054:
        !          3055:        /* Add a new mbuf with an upcall header */
        !          3056:        MGETHDR(mb_first, M_DONTWAIT, MT_HEADER);
        !          3057:        if (mb_first == NULL) {
        !          3058:                m_freem(mb_copy);
        !          3059:                return (ENOBUFS);
        !          3060:        }
        !          3061:        mb_first->m_data += max_linkhdr;
        !          3062:        mb_first->m_pkthdr.len = len + sizeof(struct igmpmsg);
        !          3063:        mb_first->m_len = sizeof(struct igmpmsg);
        !          3064:        mb_first->m_next = mb_copy;
        !          3065:
        !          3066:        /* Send message to routing daemon */
        !          3067:        im = mtod(mb_first, struct igmpmsg *);
        !          3068:        im->im_msgtype = IGMPMSG_WHOLEPKT;
        !          3069:        im->im_mbz = 0;
        !          3070:        im->im_vif = vifp - viftable;
        !          3071:        im->im_src = ip->ip_src;
        !          3072:        im->im_dst = ip->ip_dst;
        !          3073:
        !          3074:        k_igmpsrc.sin_addr = ip->ip_src;
        !          3075:
        !          3076:        mrtstat.mrts_upcalls++;
        !          3077:
        !          3078:        if (socket_send(ip_mrouter, mb_first, &k_igmpsrc) < 0) {
        !          3079:                if (mrtdebug & DEBUG_PIM)
        !          3080:                        log(LOG_WARNING, "mcast: pim_register_send_upcall: "
        !          3081:                            "ip_mrouter socket queue full");
        !          3082:                ++mrtstat.mrts_upq_sockfull;
        !          3083:                return (ENOBUFS);
        !          3084:        }
        !          3085:
        !          3086:        /* Keep statistics */
        !          3087:        pimstat.pims_snd_registers_msgs++;
        !          3088:        pimstat.pims_snd_registers_bytes += len;
        !          3089:
        !          3090:        return (0);
        !          3091: }
        !          3092:
        !          3093: /*
        !          3094:  * Encapsulate the data packet in PIM Register message and send it to the RP.
        !          3095:  */
        !          3096: static int
        !          3097: pim_register_send_rp(struct ip *ip, struct vif *vifp,
        !          3098:        struct mbuf *mb_copy, struct mfc *rt)
        !          3099: {
        !          3100:        struct mbuf *mb_first;
        !          3101:        struct ip *ip_outer;
        !          3102:        struct pim_encap_pimhdr *pimhdr;
        !          3103:        int len = ntohs(ip->ip_len);
        !          3104:        vifi_t vifi = rt->mfc_parent;
        !          3105:
        !          3106:        if ((vifi >= numvifs) || in_nullhost(viftable[vifi].v_lcl_addr)) {
        !          3107:                m_freem(mb_copy);
        !          3108:                return (EADDRNOTAVAIL);         /* The iif vif is invalid */
        !          3109:        }
        !          3110:
        !          3111:        /* Add a new mbuf with the encapsulating header */
        !          3112:        MGETHDR(mb_first, M_DONTWAIT, MT_HEADER);
        !          3113:        if (mb_first == NULL) {
        !          3114:                m_freem(mb_copy);
        !          3115:                return (ENOBUFS);
        !          3116:        }
        !          3117:        mb_first->m_data += max_linkhdr;
        !          3118:        mb_first->m_len = sizeof(pim_encap_iphdr) + sizeof(pim_encap_pimhdr);
        !          3119:        mb_first->m_next = mb_copy;
        !          3120:
        !          3121:        mb_first->m_pkthdr.len = len + mb_first->m_len;
        !          3122:
        !          3123:        /* Fill in the encapsulating IP and PIM header */
        !          3124:        ip_outer = mtod(mb_first, struct ip *);
        !          3125:        *ip_outer = pim_encap_iphdr;
        !          3126:        ip_outer->ip_id = htons(ip_randomid());
        !          3127:        ip_outer->ip_len = htons(len + sizeof(pim_encap_iphdr) +
        !          3128:            sizeof(pim_encap_pimhdr));
        !          3129:        ip_outer->ip_src = viftable[vifi].v_lcl_addr;
        !          3130:        ip_outer->ip_dst = rt->mfc_rp;
        !          3131:        /*
        !          3132:         * Copy the inner header TOS to the outer header, and take care of the
        !          3133:         * IP_DF bit.
        !          3134:         */
        !          3135:        ip_outer->ip_tos = ip->ip_tos;
        !          3136:        if (ntohs(ip->ip_off) & IP_DF)
        !          3137:                ip_outer->ip_off |= htons(IP_DF);
        !          3138:        pimhdr = (struct pim_encap_pimhdr *)((caddr_t)ip_outer
        !          3139:            + sizeof(pim_encap_iphdr));
        !          3140:        *pimhdr = pim_encap_pimhdr;
        !          3141:        /* If the iif crosses a border, set the Border-bit */
        !          3142:        if (rt->mfc_flags[vifi] & MRT_MFC_FLAGS_BORDER_VIF & mrt_api_config)
        !          3143:                pimhdr->flags |= htonl(PIM_BORDER_REGISTER);
        !          3144:
        !          3145:        mb_first->m_data += sizeof(pim_encap_iphdr);
        !          3146:        pimhdr->pim.pim_cksum = in_cksum(mb_first, sizeof(pim_encap_pimhdr));
        !          3147:        mb_first->m_data -= sizeof(pim_encap_iphdr);
        !          3148:
        !          3149:        if (vifp->v_rate_limit == 0)
        !          3150:                tbf_send_packet(vifp, mb_first);
        !          3151:        else
        !          3152:                tbf_control(vifp, mb_first, ip, ntohs(ip_outer->ip_len));
        !          3153:
        !          3154:        /* Keep statistics */
        !          3155:        pimstat.pims_snd_registers_msgs++;
        !          3156:        pimstat.pims_snd_registers_bytes += len;
        !          3157:
        !          3158:        return (0);
        !          3159: }
        !          3160:
        !          3161: /*
        !          3162:  * PIM-SMv2 and PIM-DM messages processing.
        !          3163:  * Receives and verifies the PIM control messages, and passes them
        !          3164:  * up to the listening socket, using rip_input().
        !          3165:  * The only message with special processing is the PIM_REGISTER message
        !          3166:  * (used by PIM-SM): the PIM header is stripped off, and the inner packet
        !          3167:  * is passed to if_simloop().
        !          3168:  */
        !          3169: void
        !          3170: pim_input(struct mbuf *m, ...)
        !          3171: {
        !          3172:        struct ip *ip = mtod(m, struct ip *);
        !          3173:        struct pim *pim;
        !          3174:        int minlen;
        !          3175:        int datalen;
        !          3176:        int ip_tos;
        !          3177:        int iphlen;
        !          3178:        va_list ap;
        !          3179:
        !          3180:        va_start(ap, m);
        !          3181:        iphlen = va_arg(ap, int);
        !          3182:        va_end(ap);
        !          3183:
        !          3184:        datalen = ntohs(ip->ip_len) - iphlen;
        !          3185:
        !          3186:        /* Keep statistics */
        !          3187:        pimstat.pims_rcv_total_msgs++;
        !          3188:        pimstat.pims_rcv_total_bytes += datalen;
        !          3189:
        !          3190:        /* Validate lengths */
        !          3191:        if (datalen < PIM_MINLEN) {
        !          3192:                pimstat.pims_rcv_tooshort++;
        !          3193:                log(LOG_ERR, "pim_input: packet size too small %d from %lx\n",
        !          3194:                    datalen, (u_long)ip->ip_src.s_addr);
        !          3195:                m_freem(m);
        !          3196:                return;
        !          3197:        }
        !          3198:
        !          3199:        /*
        !          3200:         * If the packet is at least as big as a REGISTER, go agead
        !          3201:         * and grab the PIM REGISTER header size, to avoid another
        !          3202:         * possible m_pullup() later.
        !          3203:         *
        !          3204:         * PIM_MINLEN       == pimhdr + u_int32_t == 4 + 4 = 8
        !          3205:         * PIM_REG_MINLEN   == pimhdr + reghdr + encap_iphdr == 4 + 4 + 20 = 28
        !          3206:         */
        !          3207:        minlen = iphlen + (datalen >= PIM_REG_MINLEN ?
        !          3208:            PIM_REG_MINLEN : PIM_MINLEN);
        !          3209:        /*
        !          3210:         * Get the IP and PIM headers in contiguous memory, and
        !          3211:         * possibly the PIM REGISTER header.
        !          3212:         */
        !          3213:        if ((m->m_flags & M_EXT || m->m_len < minlen) &&
        !          3214:            (m = m_pullup(m, minlen)) == NULL) {
        !          3215:                log(LOG_ERR, "pim_input: m_pullup failure\n");
        !          3216:                return;
        !          3217:        }
        !          3218:        /* m_pullup() may have given us a new mbuf so reset ip. */
        !          3219:        ip = mtod(m, struct ip *);
        !          3220:        ip_tos = ip->ip_tos;
        !          3221:
        !          3222:        /* adjust mbuf to point to the PIM header */
        !          3223:        m->m_data += iphlen;
        !          3224:        m->m_len  -= iphlen;
        !          3225:        pim = mtod(m, struct pim *);
        !          3226:
        !          3227:        /*
        !          3228:         * Validate checksum. If PIM REGISTER, exclude the data packet.
        !          3229:         *
        !          3230:         * XXX: some older PIMv2 implementations don't make this distinction,
        !          3231:         * so for compatibility reason perform the checksum over part of the
        !          3232:         * message, and if error, then over the whole message.
        !          3233:         */
        !          3234:        if (PIM_VT_T(pim->pim_vt) == PIM_REGISTER &&
        !          3235:            in_cksum(m, PIM_MINLEN) == 0) {
        !          3236:                /* do nothing, checksum okay */
        !          3237:        } else if (in_cksum(m, datalen)) {
        !          3238:                pimstat.pims_rcv_badsum++;
        !          3239:                if (mrtdebug & DEBUG_PIM)
        !          3240:                        log(LOG_DEBUG, "pim_input: invalid checksum");
        !          3241:                m_freem(m);
        !          3242:                return;
        !          3243:        }
        !          3244:
        !          3245:        /* PIM version check */
        !          3246:        if (PIM_VT_V(pim->pim_vt) < PIM_VERSION) {
        !          3247:                pimstat.pims_rcv_badversion++;
        !          3248:                log(LOG_ERR, "pim_input: incorrect version %d, expecting %d\n",
        !          3249:                    PIM_VT_V(pim->pim_vt), PIM_VERSION);
        !          3250:                m_freem(m);
        !          3251:                return;
        !          3252:        }
        !          3253:
        !          3254:        /* restore mbuf back to the outer IP */
        !          3255:        m->m_data -= iphlen;
        !          3256:        m->m_len  += iphlen;
        !          3257:
        !          3258:        if (PIM_VT_T(pim->pim_vt) == PIM_REGISTER) {
        !          3259:                /*
        !          3260:                 * Since this is a REGISTER, we'll make a copy of the register
        !          3261:                 * headers ip + pim + u_int32 + encap_ip, to be passed up to the
        !          3262:                 * routing daemon.
        !          3263:                 */
        !          3264:                int s;
        !          3265:                struct sockaddr_in dst = { sizeof(dst), AF_INET };
        !          3266:                struct mbuf *mcp;
        !          3267:                struct ip *encap_ip;
        !          3268:                u_int32_t *reghdr;
        !          3269:                struct ifnet *vifp;
        !          3270:
        !          3271:                s = splsoftnet();
        !          3272:                if ((reg_vif_num >= numvifs) || (reg_vif_num == VIFI_INVALID)) {
        !          3273:                        splx(s);
        !          3274:                        if (mrtdebug & DEBUG_PIM)
        !          3275:                                log(LOG_DEBUG, "pim_input: register vif "
        !          3276:                                    "not set: %d\n", reg_vif_num);
        !          3277:                        m_freem(m);
        !          3278:                        return;
        !          3279:                }
        !          3280:                /* XXX need refcnt? */
        !          3281:                vifp = viftable[reg_vif_num].v_ifp;
        !          3282:                splx(s);
        !          3283:
        !          3284:                /* Validate length */
        !          3285:                if (datalen < PIM_REG_MINLEN) {
        !          3286:                        pimstat.pims_rcv_tooshort++;
        !          3287:                        pimstat.pims_rcv_badregisters++;
        !          3288:                        log(LOG_ERR, "pim_input: register packet size "
        !          3289:                            "too small %d from %lx\n",
        !          3290:                            datalen, (u_long)ip->ip_src.s_addr);
        !          3291:                        m_freem(m);
        !          3292:                        return;
        !          3293:                }
        !          3294:
        !          3295:                reghdr = (u_int32_t *)(pim + 1);
        !          3296:                encap_ip = (struct ip *)(reghdr + 1);
        !          3297:
        !          3298:                if (mrtdebug & DEBUG_PIM) {
        !          3299:                        log(LOG_DEBUG, "pim_input[register], encap_ip: "
        !          3300:                            "%lx -> %lx, encap_ip len %d\n",
        !          3301:                            (u_long)ntohl(encap_ip->ip_src.s_addr),
        !          3302:                            (u_long)ntohl(encap_ip->ip_dst.s_addr),
        !          3303:                            ntohs(encap_ip->ip_len));
        !          3304:                }
        !          3305:
        !          3306:                /* verify the version number of the inner packet */
        !          3307:                if (encap_ip->ip_v != IPVERSION) {
        !          3308:                        pimstat.pims_rcv_badregisters++;
        !          3309:                        if (mrtdebug & DEBUG_PIM) {
        !          3310:                                log(LOG_DEBUG, "pim_input: invalid IP version"
        !          3311:                                    " (%d) of the inner packet\n",
        !          3312:                                    encap_ip->ip_v);
        !          3313:                        }
        !          3314:                        m_freem(m);
        !          3315:                        return;
        !          3316:                }
        !          3317:
        !          3318:                /* verify the inner packet is destined to a mcast group */
        !          3319:                if (!IN_MULTICAST(encap_ip->ip_dst.s_addr)) {
        !          3320:                        pimstat.pims_rcv_badregisters++;
        !          3321:                        if (mrtdebug & DEBUG_PIM)
        !          3322:                                log(LOG_DEBUG,
        !          3323:                                    "pim_input: inner packet of register is"
        !          3324:                                    " not multicast %lx\n",
        !          3325:                                    (u_long)ntohl(encap_ip->ip_dst.s_addr));
        !          3326:                        m_freem(m);
        !          3327:                        return;
        !          3328:                }
        !          3329:
        !          3330:                /* If a NULL_REGISTER, pass it to the daemon */
        !          3331:                if ((ntohl(*reghdr) & PIM_NULL_REGISTER))
        !          3332:                        goto pim_input_to_daemon;
        !          3333:
        !          3334:                /*
        !          3335:                 * Copy the TOS from the outer IP header to the inner
        !          3336:                 * IP header.
        !          3337:                 */
        !          3338:                if (encap_ip->ip_tos != ip_tos) {
        !          3339:                        /* Outer TOS -> inner TOS */
        !          3340:                        encap_ip->ip_tos = ip_tos;
        !          3341:                        /* Recompute the inner header checksum. Sigh... */
        !          3342:
        !          3343:                        /* adjust mbuf to point to the inner IP header */
        !          3344:                        m->m_data += (iphlen + PIM_MINLEN);
        !          3345:                        m->m_len  -= (iphlen + PIM_MINLEN);
        !          3346:
        !          3347:                        encap_ip->ip_sum = 0;
        !          3348:                        encap_ip->ip_sum = in_cksum(m, encap_ip->ip_hl << 2);
        !          3349:
        !          3350:                        /* restore mbuf to point back to the outer IP header */
        !          3351:                        m->m_data -= (iphlen + PIM_MINLEN);
        !          3352:                        m->m_len  += (iphlen + PIM_MINLEN);
        !          3353:                }
        !          3354:
        !          3355:                /*
        !          3356:                 * Decapsulate the inner IP packet and loopback to forward it
        !          3357:                 * as a normal multicast packet. Also, make a copy of the
        !          3358:                 *     outer_iphdr + pimhdr + reghdr + encap_iphdr
        !          3359:                 * to pass to the daemon later, so it can take the appropriate
        !          3360:                 * actions (e.g., send back PIM_REGISTER_STOP).
        !          3361:                 * XXX: here m->m_data points to the outer IP header.
        !          3362:                 */
        !          3363:                mcp = m_copy(m, 0, iphlen + PIM_REG_MINLEN);
        !          3364:                if (mcp == NULL) {
        !          3365:                        log(LOG_ERR, "pim_input: pim register: could not "
        !          3366:                            "copy register head\n");
        !          3367:                        m_freem(m);
        !          3368:                        return;
        !          3369:                }
        !          3370:
        !          3371:                /* Keep statistics */
        !          3372:                /* XXX: registers_bytes include only the encap. mcast pkt */
        !          3373:                pimstat.pims_rcv_registers_msgs++;
        !          3374:                pimstat.pims_rcv_registers_bytes += ntohs(encap_ip->ip_len);
        !          3375:
        !          3376:                /* forward the inner ip packet; point m_data at the inner ip. */
        !          3377:                m_adj(m, iphlen + PIM_MINLEN);
        !          3378:
        !          3379:                if (mrtdebug & DEBUG_PIM) {
        !          3380:                        log(LOG_DEBUG,
        !          3381:                            "pim_input: forwarding decapsulated register: "
        !          3382:                            "src %lx, dst %lx, vif %d\n",
        !          3383:                            (u_long)ntohl(encap_ip->ip_src.s_addr),
        !          3384:                            (u_long)ntohl(encap_ip->ip_dst.s_addr),
        !          3385:                            reg_vif_num);
        !          3386:                }
        !          3387:                /* NB: vifp was collected above; can it change on us? */
        !          3388:                looutput(vifp, m, (struct sockaddr *)&dst,
        !          3389:                    (struct rtentry *)NULL);
        !          3390:
        !          3391:                /* prepare the register head to send to the mrouting daemon */
        !          3392:                m = mcp;
        !          3393:        }
        !          3394:
        !          3395: pim_input_to_daemon:
        !          3396:        /*
        !          3397:         * Pass the PIM message up to the daemon; if it is a Register message,
        !          3398:         * pass the 'head' only up to the daemon. This includes the
        !          3399:         * outer IP header, PIM header, PIM-Register header and the
        !          3400:         * inner IP header.
        !          3401:         * XXX: the outer IP header pkt size of a Register is not adjust to
        !          3402:         * reflect the fact that the inner multicast data is truncated.
        !          3403:         */
        !          3404:        rip_input(m);
        !          3405:
        !          3406:        return;
        !          3407: }
        !          3408: #endif /* PIM */

CVSweb