Annotation of kernel/bsd/netinet/ip_mroute.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
        !            26: /*
        !            27:  * Copyright (c) 1989 Stephen Deering
        !            28:  * Copyright (c) 1992, 1993
        !            29:  *     The Regents of the University of California.  All rights reserved.
        !            30:  *
        !            31:  * This code is derived from software contributed to Berkeley by
        !            32:  * Stephen Deering of Stanford University.
        !            33:  *
        !            34:  * Redistribution and use in source and binary forms, with or without
        !            35:  * modification, are permitted provided that the following conditions
        !            36:  * are met:
        !            37:  * 1. Redistributions of source code must retain the above copyright
        !            38:  *    notice, this list of conditions and the following disclaimer.
        !            39:  * 2. Redistributions in binary form must reproduce the above copyright
        !            40:  *    notice, this list of conditions and the following disclaimer in the
        !            41:  *    documentation and/or other materials provided with the distribution.
        !            42:  * 3. All advertising materials mentioning features or use of this software
        !            43:  *    must display the following acknowledgement:
        !            44:  *     This product includes software developed by the University of
        !            45:  *     California, Berkeley and its contributors.
        !            46:  * 4. Neither the name of the University nor the names of its contributors
        !            47:  *    may be used to endorse or promote products derived from this software
        !            48:  *    without specific prior written permission.
        !            49:  *
        !            50:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            51:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            52:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            53:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            54:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            55:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            56:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            57:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            58:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            59:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            60:  * SUCH DAMAGE.
        !            61:  *
        !            62:  *     @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
        !            63:  */
        !            64: 
        !            65: /*
        !            66:  * Procedures for the kernel part of DVMRP,
        !            67:  * a Distance-Vector Multicast Routing Protocol.
        !            68:  * (See RFC-1075.)
        !            69:  *
        !            70:  * Written by David Waitzman, BBN Labs, August 1988.
        !            71:  * Modified by Steve Deering, Stanford, February 1989.
        !            72:  *
        !            73:  * MROUTING 1.1
        !            74:  */
        !            75: 
        !            76: #ifndef MROUTING
        !            77: int    ip_mrtproto;                            /* for netstat only */
        !            78: #else
        !            79: 
        !            80: #include <sys/param.h>
        !            81: #include <sys/errno.h>
        !            82: #include <sys/ioctl.h>
        !            83: #include <sys/malloc.h>
        !            84: #include <sys/mbuf.h>
        !            85: #include <sys/protosw.h>
        !            86: #include <sys/socket.h>
        !            87: #include <sys/socketvar.h>
        !            88: #include <sys/time.h>
        !            89: 
        !            90: #include <net/if.h>
        !            91: #include <net/route.h>
        !            92: #include <net/raw_cb.h>
        !            93: 
        !            94: #include <netinet/in.h>
        !            95: #include <netinet/in_systm.h>
        !            96: #include <netinet/ip.h>
        !            97: #include <netinet/in_pcb.h>
        !            98: #include <netinet/in_var.h>
        !            99: #include <netinet/ip_var.h>
        !           100: 
        !           101: #include <netinet/igmp.h>
        !           102: #include <netinet/igmp_var.h>
        !           103: #include <netinet/ip_mroute.h>
        !           104: 
        !           105: /* Static forwards */
        !           106: static int ip_mrouter_init __P((struct socket *));
        !           107: static int add_vif __P((struct vifctl *));
        !           108: static int del_vif __P((vifi_t *vifip));
        !           109: static int add_lgrp __P((struct lgrplctl *));
        !           110: static int del_lgrp __P((struct lgrplctl *));
        !           111: static int grplst_member __P((struct vif *, struct in_addr));
        !           112: static u_long nethash __P((struct in_addr in));
        !           113: static int add_mrt __P((struct mrtctl *));
        !           114: static int del_mrt __P((struct in_addr *));
        !           115: static struct mrt *mrtfind __P((struct in_addr));
        !           116: static void phyint_send __P((struct mbuf *, struct vif *));
        !           117: static void tunnel_send __P((struct mbuf *, struct vif *));
        !           118: 
        !           119: #define INSIZ sizeof(struct in_addr)
        !           120: #define        same(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0)
        !           121: #define        satosin(sa)     ((struct sockaddr_in *)(sa))
        !           122: 
        !           123: /*
        !           124:  * Globals.  All but ip_mrouter and ip_mrtproto could be static,
        !           125:  * except for netstat or debugging purposes.
        !           126:  */
        !           127: struct socket *ip_mrouter = NULL;
        !           128: int    ip_mrtproto = IGMP_DVMRP;               /* for netstat only */
        !           129: 
        !           130: struct mrt *mrttable[MRTHASHSIZ];
        !           131: struct vif viftable[MAXVIFS];
        !           132: struct mrtstat mrtstat;
        !           133: 
        !           134: /*
        !           135:  * Private variables.
        !           136:  */
        !           137: static vifi_t numvifs = 0;
        !           138: static struct mrt *cached_mrt = NULL;
        !           139: static u_long cached_origin;
        !           140: static u_long cached_originmask;
        !           141: 
        !           142: /*
        !           143:  * Handle DVMRP setsockopt commands to modify the multicast routing tables.
        !           144:  */
        !           145: int
        !           146: ip_mrouter_cmd(cmd, so, m)
        !           147:        register int cmd;
        !           148:        register struct socket *so;
        !           149:        register struct mbuf *m;
        !           150: {
        !           151:        register int error = 0;
        !           152: 
        !           153:        if (cmd != DVMRP_INIT && so != ip_mrouter)
        !           154:                error = EACCES;
        !           155:        else switch (cmd) {
        !           156: 
        !           157:        case DVMRP_INIT:
        !           158:                error = ip_mrouter_init(so);
        !           159:                break;
        !           160: 
        !           161:        case DVMRP_DONE:
        !           162:                error = ip_mrouter_done();
        !           163:                break;
        !           164: 
        !           165:        case DVMRP_ADD_VIF:
        !           166:                if (m == NULL || m->m_len < sizeof(struct vifctl))
        !           167:                        error = EINVAL;
        !           168:                else
        !           169:                        error = add_vif(mtod(m, struct vifctl *));
        !           170:                break;
        !           171: 
        !           172:        case DVMRP_DEL_VIF:
        !           173:                if (m == NULL || m->m_len < sizeof(short))
        !           174:                        error = EINVAL;
        !           175:                else
        !           176:                        error = del_vif(mtod(m, vifi_t *));
        !           177:                break;
        !           178: 
        !           179:        case DVMRP_ADD_LGRP:
        !           180:                if (m == NULL || m->m_len < sizeof(struct lgrplctl))
        !           181:                        error = EINVAL;
        !           182:                else
        !           183:                        error = add_lgrp(mtod(m, struct lgrplctl *));
        !           184:                break;
        !           185: 
        !           186:        case DVMRP_DEL_LGRP:
        !           187:                if (m == NULL || m->m_len < sizeof(struct lgrplctl))
        !           188:                        error = EINVAL;
        !           189:                else
        !           190:                        error = del_lgrp(mtod(m, struct lgrplctl *));
        !           191:                break;
        !           192: 
        !           193:        case DVMRP_ADD_MRT:
        !           194:                if (m == NULL || m->m_len < sizeof(struct mrtctl))
        !           195:                        error = EINVAL;
        !           196:                else
        !           197:                        error = add_mrt(mtod(m, struct mrtctl *));
        !           198:                break;
        !           199: 
        !           200:        case DVMRP_DEL_MRT:
        !           201:                if (m == NULL || m->m_len < sizeof(struct in_addr))
        !           202:                        error = EINVAL;
        !           203:                else
        !           204:                        error = del_mrt(mtod(m, struct in_addr *));
        !           205:                break;
        !           206: 
        !           207:        default:
        !           208:                error = EOPNOTSUPP;
        !           209:                break;
        !           210:        }
        !           211:        return (error);
        !           212: }
        !           213: 
        !           214: /*
        !           215:  * Enable multicast routing
        !           216:  */
        !           217: static int
        !           218: ip_mrouter_init(so)
        !           219:        register struct socket *so;
        !           220: {
        !           221:        if (so->so_type != SOCK_RAW ||
        !           222:            so->so_proto->pr_protocol != IPPROTO_IGMP)
        !           223:                return (EOPNOTSUPP);
        !           224: 
        !           225:        if (ip_mrouter != NULL)
        !           226:                return (EADDRINUSE);
        !           227: 
        !           228:        ip_mrouter = so;
        !           229: 
        !           230:        return (0);
        !           231: }
        !           232: 
        !           233: /*
        !           234:  * Disable multicast routing
        !           235:  */
        !           236: int
        !           237: ip_mrouter_done()
        !           238: {
        !           239:        register vifi_t vifi;
        !           240:        register int i;
        !           241:        register struct ifnet *ifp;
        !           242:        register int s;
        !           243:        struct ifreq ifr;
        !           244: 
        !           245:        s = splnet();
        !           246: 
        !           247:        /*
        !           248:         * For each phyint in use, free its local group list and
        !           249:         * disable promiscuous reception of all IP multicasts.
        !           250:         */
        !           251:        for (vifi = 0; vifi < numvifs; vifi++) {
        !           252:                if (viftable[vifi].v_lcl_addr.s_addr != 0 &&
        !           253:                    !(viftable[vifi].v_flags & VIFF_TUNNEL)) {
        !           254:                        if (viftable[vifi].v_lcl_grps)
        !           255:                                free(viftable[vifi].v_lcl_grps, M_MRTABLE);
        !           256:                        satosin(&ifr.ifr_addr)->sin_family = AF_INET;
        !           257:                        satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY;
        !           258:                        ifp = viftable[vifi].v_ifp;
        !           259:                        (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
        !           260:                }
        !           261:        }
        !           262:        bzero((caddr_t)viftable, sizeof(viftable));
        !           263:        numvifs = 0;
        !           264: 
        !           265:        /*
        !           266:         * Free any multicast route entries.
        !           267:         */
        !           268:        for (i = 0; i < MRTHASHSIZ; i++)
        !           269:                if (mrttable[i])
        !           270:                        free(mrttable[i], M_MRTABLE);
        !           271:        bzero((caddr_t)mrttable, sizeof(mrttable));
        !           272:        cached_mrt = NULL;
        !           273: 
        !           274:        ip_mrouter = NULL;
        !           275: 
        !           276:        splx(s);
        !           277:        return (0);
        !           278: }
        !           279: 
        !           280: /*
        !           281:  * Add a vif to the vif table
        !           282:  */
        !           283: static int
        !           284: add_vif(vifcp)
        !           285:        register struct vifctl *vifcp;
        !           286: {
        !           287:        register struct vif *vifp = viftable + vifcp->vifc_vifi;
        !           288:        register struct ifaddr *ifa;
        !           289:        register struct ifnet *ifp;
        !           290:        struct ifreq ifr;
        !           291:        register int error, s;
        !           292:        static struct sockaddr_in sin = { sizeof(sin), AF_INET };
        !           293: 
        !           294:        if (vifcp->vifc_vifi >= MAXVIFS)
        !           295:                return (EINVAL);
        !           296:        if (vifp->v_lcl_addr.s_addr != 0)
        !           297:                return (EADDRINUSE);
        !           298: 
        !           299:        /* Find the interface with an address in AF_INET family */
        !           300:        sin.sin_addr = vifcp->vifc_lcl_addr;
        !           301:        ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
        !           302:        if (ifa == 0)
        !           303:                return (EADDRNOTAVAIL);
        !           304: 
        !           305:        s = splnet();
        !           306: 
        !           307:        if (vifcp->vifc_flags & VIFF_TUNNEL)
        !           308:                vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
        !           309:        else {
        !           310:                /* Make sure the interface supports multicast */
        !           311:                ifp = ifa->ifa_ifp;
        !           312:                if ((ifp->if_flags & IFF_MULTICAST) == 0) {
        !           313:                        splx(s);
        !           314:                        return (EOPNOTSUPP);
        !           315:                }
        !           316:                /*
        !           317:                 * Enable promiscuous reception of all IP multicasts
        !           318:                 * from the interface.
        !           319:                 */
        !           320:                satosin(&ifr.ifr_addr)->sin_family = AF_INET;
        !           321:                satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY;
        !           322:                error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
        !           323:                if (error) {
        !           324:                        splx(s);
        !           325:                        return (error);
        !           326:                }
        !           327:        }
        !           328: 
        !           329:        vifp->v_flags = vifcp->vifc_flags;
        !           330:        vifp->v_threshold = vifcp->vifc_threshold;
        !           331:        vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
        !           332:        vifp->v_ifp = ifa->ifa_ifp;
        !           333: 
        !           334:        /* Adjust numvifs up if the vifi is higher than numvifs */
        !           335:        if (numvifs <= vifcp->vifc_vifi)
        !           336:                numvifs = vifcp->vifc_vifi + 1;
        !           337: 
        !           338:        splx(s);
        !           339:        return (0);
        !           340: }
        !           341: 
        !           342: /*
        !           343:  * Delete a vif from the vif table
        !           344:  */
        !           345: static int
        !           346: del_vif(vifip)
        !           347:        register vifi_t *vifip;
        !           348: {
        !           349:        register struct vif *vifp = viftable + *vifip;
        !           350:        register struct ifnet *ifp;
        !           351:        register int i, s;
        !           352:        struct ifreq ifr;
        !           353: 
        !           354:        if (*vifip >= numvifs)
        !           355:                return (EINVAL);
        !           356:        if (vifp->v_lcl_addr.s_addr == 0)
        !           357:                return (EADDRNOTAVAIL);
        !           358: 
        !           359:        s = splnet();
        !           360: 
        !           361:        if (!(vifp->v_flags & VIFF_TUNNEL)) {
        !           362:                if (vifp->v_lcl_grps)
        !           363:                        free(vifp->v_lcl_grps, M_MRTABLE);
        !           364:                satosin(&ifr.ifr_addr)->sin_family = AF_INET;
        !           365:                satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY;
        !           366:                ifp = vifp->v_ifp;
        !           367:                (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
        !           368:        }
        !           369: 
        !           370:        bzero((caddr_t)vifp, sizeof (*vifp));
        !           371: 
        !           372:        /* Adjust numvifs down */
        !           373:        for (i = numvifs - 1; i >= 0; i--)
        !           374:                if (viftable[i].v_lcl_addr.s_addr != 0)
        !           375:                        break;
        !           376:        numvifs = i + 1;
        !           377: 
        !           378:        splx(s);
        !           379:        return (0);
        !           380: }
        !           381: 
        !           382: /*
        !           383:  * Add the multicast group in the lgrpctl to the list of local multicast
        !           384:  * group memberships associated with the vif indexed by gcp->lgc_vifi.
        !           385:  */
        !           386: static int
        !           387: add_lgrp(gcp)
        !           388:        register struct lgrplctl *gcp;
        !           389: {
        !           390:        register struct vif *vifp;
        !           391:        register int s;
        !           392: 
        !           393:        if (gcp->lgc_vifi >= numvifs)
        !           394:                return (EINVAL);
        !           395: 
        !           396:        vifp = viftable + gcp->lgc_vifi;
        !           397:        if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL))
        !           398:                return (EADDRNOTAVAIL);
        !           399: 
        !           400:        /* If not enough space in existing list, allocate a larger one */
        !           401:        s = splnet();
        !           402:        if (vifp->v_lcl_grps_n + 1 >= vifp->v_lcl_grps_max) {
        !           403:                register int num;
        !           404:                register struct in_addr *ip;
        !           405: 
        !           406:                num = vifp->v_lcl_grps_max;
        !           407:                if (num <= 0)
        !           408:                        num = 32;       /* initial number */
        !           409:                else
        !           410:                        num += num;     /* double last number */
        !           411:                ip = (struct in_addr *)_MALLOC(num * sizeof(*ip),
        !           412:                        M_MRTABLE, M_NOWAIT);
        !           413:                if (ip == NULL) {
        !           414:                        splx(s);
        !           415:                        return (ENOBUFS);
        !           416:                }
        !           417: 
        !           418:                bzero((caddr_t)ip, num * sizeof(*ip));  /* XXX paranoid */
        !           419:                bcopy((caddr_t)vifp->v_lcl_grps, (caddr_t)ip,
        !           420:                    vifp->v_lcl_grps_n * sizeof(*ip));
        !           421: 
        !           422:                vifp->v_lcl_grps_max = num;
        !           423:                if (vifp->v_lcl_grps)
        !           424:                        free(vifp->v_lcl_grps, M_MRTABLE);
        !           425:                vifp->v_lcl_grps = ip;
        !           426:        }
        !           427: 
        !           428:        vifp->v_lcl_grps[vifp->v_lcl_grps_n++] = gcp->lgc_gaddr;
        !           429: 
        !           430:        if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group)
        !           431:                vifp->v_cached_result = 1;
        !           432: 
        !           433:        splx(s);
        !           434:        return (0);
        !           435: }
        !           436: 
        !           437: /*
        !           438:  * Delete the the local multicast group associated with the vif
        !           439:  * indexed by gcp->lgc_vifi.
        !           440:  */
        !           441: static int
        !           442: del_lgrp(gcp)
        !           443:        register struct lgrplctl *gcp;
        !           444: {
        !           445:        register struct vif *vifp;
        !           446:        register int i, error, s;
        !           447: 
        !           448:        if (gcp->lgc_vifi >= numvifs)
        !           449:                return (EINVAL);
        !           450:        vifp = viftable + gcp->lgc_vifi;
        !           451:        if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL))
        !           452:                return (EADDRNOTAVAIL);
        !           453: 
        !           454:        s = splnet();
        !           455: 
        !           456:        if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group)
        !           457:                vifp->v_cached_result = 0;
        !           458: 
        !           459:        error = EADDRNOTAVAIL;
        !           460:        for (i = 0; i < vifp->v_lcl_grps_n; ++i)
        !           461:                if (same(&gcp->lgc_gaddr, &vifp->v_lcl_grps[i])) {
        !           462:                        error = 0;
        !           463:                        vifp->v_lcl_grps_n--;
        !           464:                        bcopy((caddr_t)&vifp->v_lcl_grps[i + 1],
        !           465:                            (caddr_t)&vifp->v_lcl_grps[i],
        !           466:                            (vifp->v_lcl_grps_n - i) * sizeof(struct in_addr));
        !           467:                        error = 0;
        !           468:                        break;
        !           469:                }
        !           470: 
        !           471:        splx(s);
        !           472:        return (error);
        !           473: }
        !           474: 
        !           475: /*
        !           476:  * Return 1 if gaddr is a member of the local group list for vifp.
        !           477:  */
        !           478: static int
        !           479: grplst_member(vifp, gaddr)
        !           480:        register struct vif *vifp;
        !           481:        struct in_addr gaddr;
        !           482: {
        !           483:        register int i, s;
        !           484:        register u_long addr;
        !           485: 
        !           486:        mrtstat.mrts_grp_lookups++;
        !           487: 
        !           488:        addr = gaddr.s_addr;
        !           489:        if (addr == vifp->v_cached_group)
        !           490:                return (vifp->v_cached_result);
        !           491: 
        !           492:        mrtstat.mrts_grp_misses++;
        !           493: 
        !           494:        for (i = 0; i < vifp->v_lcl_grps_n; ++i)
        !           495:                if (addr == vifp->v_lcl_grps[i].s_addr) {
        !           496:                        s = splnet();
        !           497:                        vifp->v_cached_group = addr;
        !           498:                        vifp->v_cached_result = 1;
        !           499:                        splx(s);
        !           500:                        return (1);
        !           501:                }
        !           502:        s = splnet();
        !           503:        vifp->v_cached_group = addr;
        !           504:        vifp->v_cached_result = 0;
        !           505:        splx(s);
        !           506:        return (0);
        !           507: }
        !           508: 
        !           509: /*
        !           510:  * A simple hash function: returns MRTHASHMOD of the low-order octet of
        !           511:  * the argument's network or subnet number.
        !           512:  */
        !           513: static u_long
        !           514: nethash(in)
        !           515:        struct in_addr in;
        !           516: {
        !           517:        register u_long n;
        !           518: 
        !           519:        n = in_netof(in);
        !           520:        while ((n & 0xff) == 0)
        !           521:                n >>= 8;
        !           522:        return (MRTHASHMOD(n));
        !           523: }
        !           524: 
        !           525: /*
        !           526:  * Add an mrt entry
        !           527:  */
        !           528: static int
        !           529: add_mrt(mrtcp)
        !           530:        register struct mrtctl *mrtcp;
        !           531: {
        !           532:        struct mrt *rt;
        !           533:        u_long hash;
        !           534:        int s;
        !           535: 
        !           536:        if (rt = mrtfind(mrtcp->mrtc_origin)) {
        !           537:                /* Just update the route */
        !           538:                s = splnet();
        !           539:                rt->mrt_parent = mrtcp->mrtc_parent;
        !           540:                VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children);
        !           541:                VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves);
        !           542:                splx(s);
        !           543:                return (0);
        !           544:        }
        !           545: 
        !           546:        s = splnet();
        !           547: 
        !           548:        rt = (struct mrt *)_MALLOC(sizeof(*rt), M_MRTABLE, M_NOWAIT);
        !           549:        if (rt == NULL) {
        !           550:                splx(s);
        !           551:                return (ENOBUFS);
        !           552:        }
        !           553: 
        !           554:        /*
        !           555:         * insert new entry at head of hash chain
        !           556:         */
        !           557:        rt->mrt_origin = mrtcp->mrtc_origin;
        !           558:        rt->mrt_originmask = mrtcp->mrtc_originmask;
        !           559:        rt->mrt_parent = mrtcp->mrtc_parent;
        !           560:        VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children);
        !           561:        VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves);
        !           562:        /* link into table */
        !           563:        hash = nethash(mrtcp->mrtc_origin);
        !           564:        rt->mrt_next = mrttable[hash];
        !           565:        mrttable[hash] = rt;
        !           566: 
        !           567:        splx(s);
        !           568:        return (0);
        !           569: }
        !           570: 
        !           571: /*
        !           572:  * Delete an mrt entry
        !           573:  */
        !           574: static int
        !           575: del_mrt(origin)
        !           576:        register struct in_addr *origin;
        !           577: {
        !           578:        register struct mrt *rt, *prev_rt;
        !           579:        register u_long hash = nethash(*origin);
        !           580:        register int s;
        !           581: 
        !           582:        for (prev_rt = rt = mrttable[hash]; rt; prev_rt = rt, rt = rt->mrt_next)
        !           583:                if (origin->s_addr == rt->mrt_origin.s_addr)
        !           584:                        break;
        !           585:        if (!rt)
        !           586:                return (ESRCH);
        !           587: 
        !           588:        s = splnet();
        !           589: 
        !           590:        if (rt == cached_mrt)
        !           591:                cached_mrt = NULL;
        !           592: 
        !           593:        if (prev_rt == rt)
        !           594:                mrttable[hash] = rt->mrt_next;
        !           595:        else
        !           596:                prev_rt->mrt_next = rt->mrt_next;
        !           597:        free(rt, M_MRTABLE);
        !           598: 
        !           599:        splx(s);
        !           600:        return (0);
        !           601: }
        !           602: 
        !           603: /*
        !           604:  * Find a route for a given origin IP address.
        !           605:  */
        !           606: static struct mrt *
        !           607: mrtfind(origin)
        !           608:        struct in_addr origin;
        !           609: {
        !           610:        register struct mrt *rt;
        !           611:        register u_int hash;
        !           612:        register int s;
        !           613: 
        !           614:        mrtstat.mrts_mrt_lookups++;
        !           615: 
        !           616:        if (cached_mrt != NULL &&
        !           617:            (origin.s_addr & cached_originmask) == cached_origin)
        !           618:                return (cached_mrt);
        !           619: 
        !           620:        mrtstat.mrts_mrt_misses++;
        !           621: 
        !           622:        hash = nethash(origin);
        !           623:        for (rt = mrttable[hash]; rt; rt = rt->mrt_next)
        !           624:                if ((origin.s_addr & rt->mrt_originmask.s_addr) ==
        !           625:                    rt->mrt_origin.s_addr) {
        !           626:                        s = splnet();
        !           627:                        cached_mrt = rt;
        !           628:                        cached_origin = rt->mrt_origin.s_addr;
        !           629:                        cached_originmask = rt->mrt_originmask.s_addr;
        !           630:                        splx(s);
        !           631:                        return (rt);
        !           632:                }
        !           633:        return (NULL);
        !           634: }
        !           635: 
        !           636: /*
        !           637:  * IP multicast forwarding function. This function assumes that the packet
        !           638:  * pointed to by "ip" has arrived on (or is about to be sent to) the interface
        !           639:  * pointed to by "ifp", and the packet is to be relayed to other networks
        !           640:  * that have members of the packet's destination IP multicast group.
        !           641:  *
        !           642:  * The packet is returned unscathed to the caller, unless it is tunneled
        !           643:  * or erroneous, in which case a non-zero return value tells the caller to
        !           644:  * discard it.
        !           645:  */
        !           646: 
        !           647: #define IP_HDR_LEN  20 /* # bytes of fixed IP header (excluding options) */
        !           648: #define TUNNEL_LEN  12  /* # bytes of IP option for tunnel encapsulation  */
        !           649: 
        !           650: int
        !           651: ip_mforward(m, ifp)
        !           652:        register struct mbuf *m;
        !           653:        register struct ifnet *ifp;
        !           654: {
        !           655:        register struct ip *ip = mtod(m, struct ip *);
        !           656:        register struct mrt *rt;
        !           657:        register struct vif *vifp;
        !           658:        register int vifi;
        !           659:        register u_char *ipoptions;
        !           660:        u_long tunnel_src;
        !           661: 
        !           662:        if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
        !           663:            (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) {
        !           664:                /*
        !           665:                 * Packet arrived via a physical interface.
        !           666:                 */
        !           667:                tunnel_src = 0;
        !           668:        } else {
        !           669:                /*
        !           670:                 * Packet arrived through a tunnel.
        !           671:                 *
        !           672:                 * A tunneled packet has a single NOP option and a
        !           673:                 * two-element loose-source-and-record-route (LSRR)
        !           674:                 * option immediately following the fixed-size part of
        !           675:                 * the IP header.  At this point in processing, the IP
        !           676:                 * header should contain the following IP addresses:
        !           677:                 *
        !           678:                 * original source          - in the source address field
        !           679:                 * destination group        - in the destination address field
        !           680:                 * remote tunnel end-point  - in the first  element of LSRR
        !           681:                 * one of this host's addrs - in the second element of LSRR
        !           682:                 *
        !           683:                 * NOTE: RFC-1075 would have the original source and
        !           684:                 * remote tunnel end-point addresses swapped.  However,
        !           685:                 * that could cause delivery of ICMP error messages to
        !           686:                 * innocent applications on intermediate routing
        !           687:                 * hosts!  Therefore, we hereby change the spec.
        !           688:                 */
        !           689: 
        !           690:                /*
        !           691:                 * Verify that the tunnel options are well-formed.
        !           692:                 */
        !           693:                if (ipoptions[0] != IPOPT_NOP ||
        !           694:                    ipoptions[2] != 11 ||       /* LSRR option length   */
        !           695:                    ipoptions[3] != 12 ||       /* LSRR address pointer */
        !           696:                    (tunnel_src = *(u_long *)(&ipoptions[4])) == 0) {
        !           697:                        mrtstat.mrts_bad_tunnel++;
        !           698:                        return (1);
        !           699:                }
        !           700: 
        !           701:                /*
        !           702:                 * Delete the tunnel options from the packet.
        !           703:                 */
        !           704:                ovbcopy((caddr_t)(ipoptions + TUNNEL_LEN), (caddr_t)ipoptions,
        !           705:                    (unsigned)(m->m_len - (IP_HDR_LEN + TUNNEL_LEN)));
        !           706:                m->m_len -= TUNNEL_LEN;
        !           707:                ip->ip_len -= TUNNEL_LEN;
        !           708:                ip->ip_hl -= TUNNEL_LEN >> 2;
        !           709:        }
        !           710: 
        !           711:        /*
        !           712:         * Don't forward a packet with time-to-live of zero or one,
        !           713:         * or a packet destined to a local-only group.
        !           714:         */
        !           715:        if (ip->ip_ttl <= 1 ||
        !           716:            ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP)
        !           717:                return ((int)tunnel_src);
        !           718: 
        !           719:        /*
        !           720:         * Don't forward if we don't have a route for the packet's origin.
        !           721:         */
        !           722:        if (!(rt = mrtfind(ip->ip_src))) {
        !           723:                mrtstat.mrts_no_route++;
        !           724:                return ((int)tunnel_src);
        !           725:        }
        !           726: 
        !           727:        /*
        !           728:         * Don't forward if it didn't arrive from the parent vif for its origin.
        !           729:         */
        !           730:        vifi = rt->mrt_parent;
        !           731:        if (tunnel_src == 0 ) {
        !           732:                if ((viftable[vifi].v_flags & VIFF_TUNNEL) ||
        !           733:                    viftable[vifi].v_ifp != ifp )
        !           734:                        return ((int)tunnel_src);
        !           735:        } else {
        !           736:                if (!(viftable[vifi].v_flags & VIFF_TUNNEL) ||
        !           737:                    viftable[vifi].v_rmt_addr.s_addr != tunnel_src )
        !           738:                        return ((int)tunnel_src);
        !           739:        }
        !           740: 
        !           741:        /*
        !           742:         * For each vif, decide if a copy of the packet should be forwarded.
        !           743:         * Forward if:
        !           744:         *              - the ttl exceeds the vif's threshold AND
        !           745:         *              - the vif is a child in the origin's route AND
        !           746:         *              - ( the vif is not a leaf in the origin's route OR
        !           747:         *                  the destination group has members on the vif )
        !           748:         *
        !           749:         * (This might be speeded up with some sort of cache -- someday.)
        !           750:         */
        !           751:        for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) {
        !           752:                if (ip->ip_ttl > vifp->v_threshold &&
        !           753:                    VIFM_ISSET(vifi, rt->mrt_children) &&
        !           754:                    (!VIFM_ISSET(vifi, rt->mrt_leaves) ||
        !           755:                    grplst_member(vifp, ip->ip_dst))) {
        !           756:                        if (vifp->v_flags & VIFF_TUNNEL)
        !           757:                                tunnel_send(m, vifp);
        !           758:                        else
        !           759:                                phyint_send(m, vifp);
        !           760:                }
        !           761:        }
        !           762: 
        !           763:        return ((int)tunnel_src);
        !           764: }
        !           765: 
        !           766: static void
        !           767: phyint_send(m, vifp)
        !           768:        register struct mbuf *m;
        !           769:        register struct vif *vifp;
        !           770: {
        !           771:        register struct ip *ip = mtod(m, struct ip *);
        !           772:        register struct mbuf *mb_copy;
        !           773:        register struct ip_moptions *imo;
        !           774:        register int error;
        !           775:        struct ip_moptions simo;
        !           776: 
        !           777:        mb_copy = m_copy(m, 0, M_COPYALL);
        !           778:        if (mb_copy == NULL)
        !           779:                return;
        !           780: 
        !           781:        imo = &simo;
        !           782:        imo->imo_multicast_ifp = vifp->v_ifp;
        !           783:        imo->imo_multicast_ttl = ip->ip_ttl - 1;
        !           784:        imo->imo_multicast_loop = 1;
        !           785: 
        !           786:        error = ip_output(mb_copy, NULL, NULL, IP_FORWARDING, imo);
        !           787: }
        !           788: 
        !           789: static void
        !           790: tunnel_send(m, vifp)
        !           791:        register struct mbuf *m;
        !           792:        register struct vif *vifp;
        !           793: {
        !           794:        register struct ip *ip = mtod(m, struct ip *);
        !           795:        register struct mbuf *mb_copy, *mb_opts;
        !           796:        register struct ip *ip_copy;
        !           797:        register int error;
        !           798:        register u_char *cp;
        !           799: 
        !           800:        /*
        !           801:         * Make sure that adding the tunnel options won't exceed the
        !           802:         * maximum allowed number of option bytes.
        !           803:         */
        !           804:        if (ip->ip_hl > (60 - TUNNEL_LEN) >> 2) {
        !           805:                mrtstat.mrts_cant_tunnel++;
        !           806:                return;
        !           807:        }
        !           808: 
        !           809:        /* 
        !           810:         * Get a private copy of the IP header so that changes to some 
        !           811:         * of the IP fields don't damage the original header, which is
        !           812:         * examined later in ip_input.c.
        !           813:         */
        !           814:        mb_copy = m_copy(m, IP_HDR_LEN, M_COPYALL);
        !           815:        if (mb_copy == NULL)
        !           816:                return;
        !           817:        MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER);
        !           818:        if (mb_opts == NULL) {
        !           819:                m_freem(mb_copy);
        !           820:                return;
        !           821:        }
        !           822:        /*
        !           823:         * Make mb_opts be the new head of the packet chain.
        !           824:         * Any options of the packet were left in the old packet chain head
        !           825:         */
        !           826:        mb_opts->m_next = mb_copy;
        !           827:        mb_opts->m_len = IP_HDR_LEN + TUNNEL_LEN;
        !           828:        mb_opts->m_data += MSIZE - mb_opts->m_len;
        !           829: 
        !           830:        ip_copy = mtod(mb_opts, struct ip *);
        !           831:        /*
        !           832:         * Copy the base ip header to the new head mbuf.
        !           833:         */
        !           834:        *ip_copy = *ip;
        !           835:        ip_copy->ip_ttl--;
        !           836:        ip_copy->ip_dst = vifp->v_rmt_addr;     /* remote tunnel end-point */
        !           837:        /*
        !           838:         * Adjust the ip header length to account for the tunnel options.
        !           839:         */
        !           840:        ip_copy->ip_hl += TUNNEL_LEN >> 2;
        !           841:        ip_copy->ip_len += TUNNEL_LEN;
        !           842:        /*
        !           843:         * Add the NOP and LSRR after the base ip header
        !           844:         */
        !           845:        cp = (u_char *)(ip_copy + 1);
        !           846:        *cp++ = IPOPT_NOP;
        !           847:        *cp++ = IPOPT_LSRR;
        !           848:        *cp++ = 11;             /* LSRR option length */
        !           849:        *cp++ = 8;              /* LSSR pointer to second element */
        !           850:        *(u_long*)cp = vifp->v_lcl_addr.s_addr; /* local tunnel end-point */
        !           851:        cp += 4;
        !           852:        *(u_long*)cp = ip->ip_dst.s_addr;               /* destination group */
        !           853: 
        !           854:        error = ip_output(mb_opts, NULL, NULL, IP_FORWARDING, NULL);
        !           855: }
        !           856: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.