Annotation of kernel/bsd/netinet/ip_mroute.c, revision 1.1.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.