Annotation of XNU/bsd/net/bridge.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * Copyright (c) 1998 Luigi Rizzo
        !            24:  *
        !            25:  * Redistribution and use in source and binary forms, with or without
        !            26:  * modification, are permitted provided that the following conditions
        !            27:  * are met:
        !            28:  * 1. Redistributions of source code must retain the above copyright
        !            29:  *    notice, this list of conditions and the following disclaimer.
        !            30:  * 2. Redistributions in binary form must reproduce the above copyright
        !            31:  *    notice, this list of conditions and the following disclaimer in the
        !            32:  *    documentation and/or other materials provided with the distribution.
        !            33:  *
        !            34:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
        !            35:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            36:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            37:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            38:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            39:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            40:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            41:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            42:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            43:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            44:  * SUCH DAMAGE.
        !            45:  *
        !            46:  */
        !            47: 
        !            48: /*
        !            49:  * This code implements bridging in FreeBSD. It only acts on ethernet
        !            50:  * type of interfaces (others are still usable for routing).
        !            51:  * A bridging table holds the source MAC address/dest. interface for each
        !            52:  * known node. The table is indexed using an hash of the source address.
        !            53:  *
        !            54:  * Input packets are tapped near the end of the input routine in each
        !            55:  * driver (near the call to bpf_mtap, or before the call to ether_input)
        !            56:  * and analysed calling bridge_in(). Depending on the result, the packet
        !            57:  * can be forwarded to one or more output interfaces using bdg_forward(),
        !            58:  * and/or sent to the upper layer (e.g. in case of multicast).
        !            59:  *
        !            60:  * Output packets are intercepted near the end of ether_output(),
        !            61:  * the correct destination is selected calling bdg_dst_lookup(),
        !            62:  * and then forwarding is done using bdg_forward().
        !            63:  * Bridging is controlled by the sysctl variable net.link.ether.bridge
        !            64:  *
        !            65:  * The arp code is also modified to let a machine answer to requests
        !            66:  * irrespective of the port the request came from.
        !            67:  *
        !            68:  * In case of loops in the bridging topology, the bridge detects this
        !            69:  * event and temporarily mutes output bridging on one of the ports.
        !            70:  * Periodically, interfaces are unmuted by bdg_timeout(). (For the
        !            71:  * mute flag i am temporarily using IFF_LINK2 but this has to
        !            72:  * change.) Muting is only implemented as a safety measure, and also as
        !            73:  * a mechanism to support a user-space implementation of the spanning
        !            74:  * tree algorithm. In the final release, unmuting will only occur
        !            75:  * because of explicit action of the user-level daemon.
        !            76:  *
        !            77:  * To build a bridging kernel, use the following option
        !            78:  *    option BRIDGE
        !            79:  * and then at runtime set the sysctl variable to enable bridging.
        !            80:  *
        !            81:  * Only one interface is supposed to have addresses set (but
        !            82:  * there are no problems in practice if you set addresses for more
        !            83:  * than one interface).
        !            84:  * Bridging will act before routing, but nothing prevents a machine
        !            85:  * from doing both (modulo bugs in the implementation...).
        !            86:  *
        !            87:  * THINGS TO REMEMBER
        !            88:  *  - bridging requires some (small) modifications to the interface
        !            89:  *    driver. Currently (980911) the "ed", "de", "tx", "lnc" drivers
        !            90:  *    have been modified and tested. "fxp", "ep", "fe" have been
        !            91:  *    modified but not tested. See the "ed" and "de" drivers as
        !            92:  *    examples on how to operate.
        !            93:  *  - bridging is incompatible with multicast routing on the same
        !            94:  *    machine. There is not an easy fix to this.
        !            95:  *  - loop detection is still not very robust.
        !            96:  *  - the interface of bdg_forward() could be improved.
        !            97:  */
        !            98: 
        !            99: #include <sys/param.h>
        !           100: #include <sys/mbuf.h>
        !           101: #include <sys/malloc.h>
        !           102: #include <sys/systm.h>
        !           103: #include <sys/socket.h> /* for net/if.h */
        !           104: #include <sys/kernel.h>
        !           105: #include <sys/sysctl.h>
        !           106: 
        !           107: #include <net/if.h>
        !           108: #include <net/if_types.h>
        !           109: 
        !           110: #include <netinet/in.h> /* for struct arpcom */
        !           111: #include <netinet/in_systm.h>
        !           112: #include <netinet/in_var.h>
        !           113: #include <netinet/ip.h>
        !           114: #include <netinet/if_ether.h> /* for struct arpcom */
        !           115: 
        !           116: #include "opt_ipfw.h" 
        !           117: #include "opt_ipdn.h" 
        !           118: 
        !           119: #if defined(IPFIREWALL) && defined(DUMMYNET)
        !           120: #include <net/route.h>
        !           121: #include <netinet/ip_fw.h>
        !           122: #include <netinet/ip_dummynet.h>
        !           123: #endif
        !           124: 
        !           125: #include <net/bridge.h>
        !           126: 
        !           127: /*
        !           128:  * For debugging, you can use the following macros.
        !           129:  * remember, rdtsc() only works on Pentium-class machines
        !           130: 
        !           131:     quad_t ticks;
        !           132:     DDB(ticks = rdtsc();)
        !           133:     ... interesting code ...
        !           134:     DDB(bdg_fw_ticks += (u_long)(rdtsc() - ticks) ; bdg_fw_count++ ;)
        !           135: 
        !           136:  *
        !           137:  */
        !           138: 
        !           139: #define DDB(x) x
        !           140: #define DEB(x)
        !           141: 
        !           142: /*
        !           143:  * System initialization
        !           144:  */
        !           145: 
        !           146: static void bdginit(void *);
        !           147: static void flush_table(void);
        !           148: 
        !           149: SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, bdginit, NULL)
        !           150: 
        !           151: static int bdg_ipfw = 0 ;
        !           152: int do_bridge = 0;
        !           153: bdg_hash_table *bdg_table = NULL ;
        !           154: 
        !           155: /*
        !           156:  * we need additional info for the bridge. The bdg_ifp2sc[] array
        !           157:  * provides a pointer to this struct using the if_index.
        !           158:  * bdg_softc has a backpointer to the struct ifnet, the bridge
        !           159:  * flags, and a group (bridging occurs only between port of the
        !           160:  * same group).
        !           161:  */
        !           162: struct bdg_softc {
        !           163:     struct ifnet *ifp ;
        !           164:     /* ((struct arpcom *)ifp)->ac_enaddr is the eth. addr */
        !           165:     int flags ;
        !           166:     int group ;
        !           167: } ;
        !           168:     
        !           169: static struct bdg_softc **ifp2sc = NULL ;
        !           170: 
        !           171: #if 0 /* new code using ifp2sc */
        !           172: #define SAMEGROUP(ifp,src) (src == NULL || \
        !           173:     ifp2sc[ifp->if_index]->group == ifp2sc[src->if_index]->group )
        !           174: #define MUTED(ifp) (ifp2sc[ifp->if_index]->flags & IFF_MUTE)
        !           175: #define MUTE(ifp) ifp2sc[ifp->if_index]->flags |= IFF_MUTE
        !           176: #define UNMUTE(ifp) ifp2sc[ifp->if_index]->flags &= ~IFF_MUTE
        !           177: #else
        !           178: #define SAMEGROUP(a,b) 1
        !           179: #define MUTED(ifp) (ifp->if_flags & IFF_MUTE)
        !           180: #define MUTE(ifp) ifp->if_flags |= IFF_MUTE
        !           181: #define UNMUTE(ifp) ifp->if_flags &= ~IFF_MUTE
        !           182: #endif
        !           183: 
        !           184: static int
        !           185: sysctl_bdg SYSCTL_HANDLER_ARGS
        !           186: {
        !           187:     int error, oldval = do_bridge ;
        !           188: 
        !           189:     error = sysctl_handle_int(oidp,
        !           190:        oidp->oid_arg1, oidp->oid_arg2, req);
        !           191:     printf("called sysctl for bridge name %s arg2 %d val %d->%d\n",
        !           192:        oidp->oid_name, oidp->oid_arg2,
        !           193:        oldval, do_bridge);
        !           194:     if (bdg_table == NULL)
        !           195:        do_bridge = 0 ;
        !           196:     if (oldval != do_bridge) {
        !           197:        flush_table();
        !           198:     }
        !           199:     return error ;
        !           200: }
        !           201: 
        !           202: SYSCTL_DECL(_net_link_ether);
        !           203: SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge, CTLTYPE_INT|CTLFLAG_RW,
        !           204:            &do_bridge, 0, &sysctl_bdg, "I", "Bridging");
        !           205: 
        !           206: SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, &bdg_ipfw,0,"");
        !           207: #if 1 /* diagnostic vars */
        !           208: int bdg_in_count = 0 , bdg_in_ticks = 0 , bdg_fw_count = 0, bdg_fw_ticks = 0 ;
        !           209: SYSCTL_INT(_net_link_ether, OID_AUTO, bdginc, CTLFLAG_RW, &bdg_in_count,0,"");
        !           210: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgint, CTLFLAG_RW, &bdg_in_ticks,0,"");
        !           211: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgfwc, CTLFLAG_RW, &bdg_fw_count,0,"");
        !           212: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgfwt, CTLFLAG_RW, &bdg_fw_ticks,0,"");
        !           213: #endif
        !           214: static struct bdg_stats bdg_stats ;
        !           215: SYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats,
        !           216:         CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics");
        !           217: 
        !           218: static int bdg_loops ;
        !           219: 
        !           220: /*
        !           221:  * completely flush the bridge table.
        !           222:  */
        !           223: static void
        !           224: flush_table()
        !           225: {   
        !           226:     int s,i;
        !           227: 
        !           228:     if (bdg_table == NULL)
        !           229:        return ;
        !           230:     s = splimp();
        !           231:     for (i=0; i< HASH_SIZE; i++)
        !           232:         bdg_table[i].name= NULL; /* clear table */
        !           233:     splx(s);
        !           234: }
        !           235: 
        !           236: /*
        !           237:  * called periodically to flush entries etc.
        !           238:  */
        !           239: static void
        !           240: bdg_timeout(void *dummy)
        !           241: {
        !           242:     struct ifnet *ifp ;
        !           243:     int s ;
        !           244:     static int slowtimer = 0 ;
        !           245: 
        !           246:     if (do_bridge) {
        !           247:        static int age_index = 0 ; /* index of table position to age */
        !           248:        int l = age_index + HASH_SIZE/4 ;
        !           249:        /*
        !           250:         * age entries in the forwarding table.
        !           251:         */
        !           252:        if (l > HASH_SIZE)
        !           253:            l = HASH_SIZE ;
        !           254:        for (; age_index < l ; age_index++)
        !           255:            if (bdg_table[age_index].used)
        !           256:                bdg_table[age_index].used = 0 ;
        !           257:            else if (bdg_table[age_index].name) {
        !           258:                /* printf("xx flushing stale entry %d\n", age_index); */
        !           259:                bdg_table[age_index].name = NULL ;
        !           260:            }
        !           261:        if (age_index >= HASH_SIZE)
        !           262:            age_index = 0 ;
        !           263: 
        !           264:        if (--slowtimer <= 0 ) {
        !           265:            slowtimer = 5 ;
        !           266: 
        !           267:            for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
        !           268:                if (ifp->if_type != IFT_ETHER)
        !           269:                    continue ;
        !           270:                if ( 0 == ( ifp->if_flags & IFF_UP) ) {
        !           271:                    s = splimp();
        !           272:                    if_up(ifp);
        !           273:                    splx(s);
        !           274:                }
        !           275:                if ( 0 == ( ifp->if_flags & IFF_PROMISC) ) {
        !           276:                    int ret ;
        !           277:                    s = splimp();
        !           278:                    ret = ifpromisc(ifp, 1);
        !           279:                    splx(s);
        !           280:                    printf(">> now  %s%d flags 0x%x promisc %d\n",
        !           281:                        ifp->if_name, ifp->if_unit,
        !           282:                        ifp->if_flags, ret);
        !           283:                }
        !           284:                if (MUTED(ifp)) {
        !           285:                    printf(">> unmuting %s%d\n", ifp->if_name, ifp->if_unit);
        !           286:                    UNMUTE(ifp) ;
        !           287:                }
        !           288:            }
        !           289:            bdg_loops = 0 ;
        !           290:        }
        !           291:     }
        !           292:     timeout(bdg_timeout, (void *)0, 2*hz );
        !           293: }
        !           294: 
        !           295: /*
        !           296:  * local MAC addresses are held in a small array. This makes comparisons
        !           297:  * much faster.
        !           298:  */
        !           299: unsigned char bdg_addresses[6*BDG_MAX_PORTS];
        !           300: int bdg_ports ;
        !           301: 
        !           302: /*
        !           303:  * initialization of bridge code.
        !           304:  */
        !           305: static void
        !           306: bdginit(dummy)
        !           307:        void *dummy;
        !           308: {
        !           309:     int i ;
        !           310:     struct ifnet *ifp;
        !           311:     struct arpcom *ac ;
        !           312:     u_char *eth_addr ;
        !           313:     /*
        !           314:      * initialization of bridge code
        !           315:      */
        !           316:     if (bdg_table == NULL)
        !           317:        bdg_table = (struct hash_table *)
        !           318:                _MALLOC(HASH_SIZE * sizeof(struct hash_table),
        !           319:                    M_IFADDR, M_WAITOK);
        !           320:     flush_table();
        !           321: 
        !           322:     ifp2sc = _MALLOC(if_index * sizeof(struct bdg_softc *), M_IFADDR, M_WAITOK );
        !           323:     bzero(ifp2sc, if_index * sizeof(struct bdg_softc *) );
        !           324: 
        !           325:     bzero(&bdg_stats, sizeof(bdg_stats) );
        !           326:     bdg_ports = 0 ;
        !           327:     eth_addr = bdg_addresses ;
        !           328: 
        !           329:     printf("BRIDGE 981214, have %d interfaces\n", if_index);
        !           330:     for (i = 0 , ifp = ifnet.tqh_first ; i < if_index ;
        !           331:                i++, ifp = ifp->if_link.tqe_next)
        !           332:        if (ifp->if_type == IFT_ETHER) { /* ethernet ? */
        !           333:            ac = (struct arpcom *)ifp;
        !           334:        sprintf(bdg_stats.s[ifp->if_index].name,
        !           335:            "%s%d", ifp->if_name, ifp->if_unit);
        !           336:        printf("-- index %d %s type %d phy %d addrl %d addr %6D\n",
        !           337:            ifp->if_index,
        !           338:            bdg_stats.s[ifp->if_index].name,
        !           339:            (int)ifp->if_type, (int) ifp->if_physical,
        !           340:            (int)ifp->if_addrlen,
        !           341:            ac->ac_enaddr, "." );
        !           342:        bcopy(ac->ac_enaddr, eth_addr, 6);
        !           343:        eth_addr += 6 ;
        !           344: 
        !           345:        ifp2sc[bdg_ports] = _MALLOC(sizeof(struct bdg_softc),
        !           346:                M_IFADDR, M_WAITOK );
        !           347:        ifp2sc[bdg_ports]->ifp = ifp ;
        !           348:        ifp2sc[bdg_ports]->flags = 0 ;
        !           349:        ifp2sc[bdg_ports]->group = 0 ;
        !           350:        bdg_ports ++ ;
        !           351:     }
        !           352:     bdg_timeout(0);
        !           353:     do_bridge=0;
        !           354: }
        !           355: 
        !           356: /*
        !           357:  * bridge_in() is invoked to perform bridging decision on input packets.
        !           358:  * On Input:
        !           359:  *   m         packet to be bridged. The mbuf need not to hold the
        !           360:  *             whole packet, only the first 14 bytes suffice. We
        !           361:  *             assume them to be contiguous. No alignment assumptions
        !           362:  *             because they are not a problem on i386 class machines.
        !           363:  *
        !           364:  * On Return: destination of packet, one of
        !           365:  *   BDG_BCAST broadcast
        !           366:  *   BDG_MCAST  multicast
        !           367:  *   BDG_LOCAL  is only for a local address (do not forward)
        !           368:  *   BDG_DROP   drop the packet
        !           369:  *   ifp       ifp of the destination interface.
        !           370:  *
        !           371:  * Forwarding is not done directly to give a chance to some drivers
        !           372:  * to fetch more of the packet, or simply drop it completely.
        !           373:  */
        !           374: 
        !           375: 
        !           376: struct ifnet *
        !           377: bridge_in(struct mbuf *m)
        !           378: {
        !           379:     int index;
        !           380:     struct ifnet *ifp = m->m_pkthdr.rcvif,  *dst , *old ;
        !           381:     int dropit = MUTED(ifp) ;
        !           382:     struct ether_header *eh;
        !           383: 
        !           384:     eh = mtod(m, struct ether_header *);
        !           385: 
        !           386:     /*
        !           387:      * hash the source address
        !           388:      */
        !           389:     index= HASH_FN(eh->ether_shost);
        !           390:     bdg_table[index].used = 1 ;
        !           391:     old = bdg_table[index].name ;
        !           392:     if ( old ) { /* the entry is valid. */
        !           393:         if (!BDG_MATCH( eh->ether_shost, bdg_table[index].etheraddr) ) {
        !           394:            printf("collision at %d\n", index);
        !           395:            bdg_table[index].name = NULL ;
        !           396:         } else if (old != ifp) {
        !           397:            /*
        !           398:             * found a loop. Either a machine has moved, or there
        !           399:             * is a misconfiguration/reconfiguration of the network.
        !           400:             * First, do not forward this packet!
        !           401:             * Record the relocation anyways; then, if loops persist,
        !           402:             * suspect a reconfiguration and disable forwarding
        !           403:             * from the old interface.
        !           404:             */
        !           405:            bdg_table[index].name = ifp ; /* relocate address */
        !           406:            printf("-- loop (%d) %6D to %s%d from %s%d (%s)\n",
        !           407:                        bdg_loops, eh->ether_shost, ".",
        !           408:                        ifp->if_name, ifp->if_unit,
        !           409:                        old->if_name, old->if_unit,
        !           410:                        old->if_flags & IFF_MUTE ? "muted":"ignore");
        !           411:            dropit = 1 ;
        !           412:            if ( !MUTED(old) ) {
        !           413:                if (++bdg_loops > 10)
        !           414:                    MUTE(old) ;
        !           415:            }
        !           416:         }
        !           417:     }
        !           418: 
        !           419:     /*
        !           420:      * now write the source address into the table
        !           421:      */
        !           422:     if (bdg_table[index].name == NULL) {
        !           423:        DEB(printf("new addr %6D at %d for %s%d\n",
        !           424:            eh->ether_shost, ".", index, ifp->if_name, ifp->if_unit);)
        !           425:        bcopy(eh->ether_shost, bdg_table[index].etheraddr, 6);
        !           426:        bdg_table[index].name = ifp ;
        !           427:     }
        !           428:     dst = bridge_dst_lookup(m);
        !           429:     /* Return values:
        !           430:      *   BDG_BCAST, BDG_MCAST, BDG_LOCAL, BDG_UNKNOWN, BDG_DROP, ifp.
        !           431:      * For muted interfaces, the first 3 are changed in BDG_LOCAL,
        !           432:      * and others to BDG_DROP. Also, for incoming packets, ifp is changed
        !           433:      * to BDG_DROP in case ifp == src . These mods are not necessary
        !           434:      * for outgoing packets from ether_output().
        !           435:      */
        !           436:     BDG_STAT(ifp, BDG_IN);
        !           437:     switch ((int)dst) {
        !           438:     case (int)BDG_BCAST:
        !           439:     case (int)BDG_MCAST:
        !           440:     case (int)BDG_LOCAL:
        !           441:     case (int)BDG_UNKNOWN:
        !           442:     case (int)BDG_DROP:
        !           443:        BDG_STAT(ifp, dst);
        !           444:        break ;
        !           445:     default :
        !           446:        if (dst == ifp || dropit )
        !           447:            BDG_STAT(ifp, BDG_DROP);
        !           448:        else
        !           449:            BDG_STAT(ifp, BDG_FORWARD);
        !           450:        break ;
        !           451:     }
        !           452: 
        !           453:     if ( dropit ) {
        !           454:        if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_LOCAL)
        !           455:            return BDG_LOCAL ;
        !           456:        else
        !           457:            return BDG_DROP ;
        !           458:     } else {
        !           459:        return (dst == ifp ? BDG_DROP : dst ) ;
        !           460:     }
        !           461: }
        !           462: 
        !           463: /*
        !           464:  * Forward to dst, excluding src port and (if not a single interface)
        !           465:  * muted interfaces. The packet is freed if marked as such
        !           466:  * and not for a local destination.
        !           467:  * A cleaner implementation would be to make bdg_forward()
        !           468:  * always consume the packet, leaving to the caller the task
        !           469:  * to make a copy if it needs it. As it is now, bdg_forward()
        !           470:  * can keep a copy alive in some cases.
        !           471:  */
        !           472: int
        !           473: bdg_forward (struct mbuf **m0, struct ifnet *dst)
        !           474: {
        !           475:     struct ifnet *src = (*m0)->m_pkthdr.rcvif; /* could be NULL in output */
        !           476:     struct ifnet *ifp ;
        !           477:     struct ip *ip;
        !           478:     int error=0, s ;
        !           479:     int once = 0;      /* execute the loop only once */
        !           480:     int canfree = 1 ; /* can free the buf at the end */
        !           481:     struct mbuf *m ;
        !           482: 
        !           483:     struct ether_header *eh = mtod(*m0, struct ether_header *); /* XXX */
        !           484: 
        !           485:     if (dst == BDG_DROP) { /* this should not happen */
        !           486:        printf("xx bdg_forward for BDG_DROP)\n");
        !           487:        m_freem(*m0) ;
        !           488:        *m0 = NULL ;
        !           489:        return 0;
        !           490:     }
        !           491:     if (dst == BDG_LOCAL) { /* this should not happen as well */
        !           492:        printf("xx ouch, bdg_forward for local pkt\n");
        !           493:        return 0;
        !           494:     }
        !           495:     if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_UNKNOWN) {
        !           496:        ifp = ifnet.tqh_first ;
        !           497:        once = 0 ;
        !           498:        if (dst != BDG_UNKNOWN)
        !           499:            canfree = 0 ;
        !           500:     } else {
        !           501:        ifp = dst ;
        !           502:        once = 1 ; /* and also canfree */
        !           503:     }
        !           504: #if IPFIREWALL
        !           505:     /*
        !           506:      * do filtering in a very similar way to what is done
        !           507:      * in ip_output. Only for IP packets, and only pass/fail/dummynet
        !           508:      * is supported. The tricky thing is to make sure that enough of
        !           509:      * the packet (basically, Eth+IP+TCP/UDP headers) is contiguous
        !           510:      * so that calls to m_pullup in ip_fw_chk will not kill the
        !           511:      * ethernet header.
        !           512:      */
        !           513:     if (ip_fw_chk_ptr) {
        !           514:        u_int16_t dummy ;
        !           515:        struct ip_fw_chain *rule;
        !           516:        int off;
        !           517: 
        !           518:        m = *m0 ;
        !           519:        if (m->m_type == MT_DUMMYNET) {
        !           520:            /*
        !           521:             * the packet was already tagged, so part of the
        !           522:             * processing was already done, and we need to go down.
        !           523:             */
        !           524:            rule = (struct ip_fw_chain *)(m->m_data) ;
        !           525:            (*m0) = m = m->m_next ;
        !           526: 
        !           527:            src = m->m_pkthdr.rcvif; /* could be NULL in output */
        !           528:            eh = mtod(m, struct ether_header *); /* XXX */
        !           529:            canfree = 1 ; /* for sure, a copy is not needed later. */
        !           530:            goto forward; /* HACK! */
        !           531:        } else
        !           532:            rule = NULL ;
        !           533:        if (bdg_ipfw == 0)
        !           534:            goto forward ;
        !           535:        if (src == NULL)
        !           536:            goto forward ; /* do not apply to packets from ether_output */
        !           537:        if (canfree == 0 ) /* need to make a copy */
        !           538:            m = m_copypacket(*m0, M_DONTWAIT);
        !           539:        if (m == NULL) {
        !           540:            /* fail... */
        !           541:            return 0 ;
        !           542:        }
        !           543:        
        !           544:        dummy = 0 ;
        !           545:        /*
        !           546:         * before calling the firewall, swap fields the same as IP does.
        !           547:         * here we assume the pkt is an IP one and the header is contiguous
        !           548:         */
        !           549:        eh = mtod(m, struct ether_header *);
        !           550:        ip = (struct ip *)(eh + 1 ) ;
        !           551:        NTOHS(ip->ip_len);
        !           552:        NTOHS(ip->ip_id);
        !           553:        NTOHS(ip->ip_off);
        !           554: 
        !           555:        /*
        !           556:         * The third parameter to the firewall code is the dst.  interface.
        !           557:         * Since we apply checks only on input pkts we use NULL.
        !           558:         */
        !           559:        off = (*ip_fw_chk_ptr)(NULL, 0, NULL, &dummy, &m, &rule, NULL) ;
        !           560:        if (m == NULL) { /* pkt discarded by firewall */
        !           561:            if (canfree)
        !           562:                *m0 = NULL ;
        !           563:            return 0 ;
        !           564:        }
        !           565:        /*
        !           566:         * on return, the mbuf pointer might have changed. Restore
        !           567:         * *m0 (if it was the same as m), eh, ip and then
        !           568:         * restore original ordering.
        !           569:         */
        !           570:        eh = mtod(m, struct ether_header *);
        !           571:        ip = (struct ip *)(eh + 1 ) ;
        !           572:        if (canfree) /* m was a reference to *m0, so update *m0 */
        !           573:                *m0 = m ;
        !           574:        HTONS(ip->ip_len);
        !           575:        HTONS(ip->ip_id);
        !           576:        HTONS(ip->ip_off);
        !           577:        if (off == 0) {
        !           578:            if (canfree == 0)
        !           579:                m_freem(m);
        !           580:            goto forward ;
        !           581:        }
        !           582: #if DUMMYNET
        !           583:        if (off & 0x10000) {  
        !           584:            /*
        !           585:             * pass the pkt to dummynet. Need to include m, dst, rule.
        !           586:             * Dummynet consumes the packet in all cases.
        !           587:             */
        !           588:            dummynet_io((off & 0xffff), DN_TO_BDG_FWD, m, dst, NULL, 0, rule);
        !           589:            if (canfree) /* dummynet has consumed the original one */
        !           590:                *m0 = NULL ;
        !           591:            return 0 ;
        !           592:        }
        !           593: #endif
        !           594:        /* if none of the above matches, we have to drop the pkt */
        !           595:        if (m)
        !           596:            m_freem(m);
        !           597:        if (canfree && m != *m0) {
        !           598:            m_freem(*m0);
        !           599:            *m0 = NULL ;
        !           600:        }
        !           601:        return 0 ;
        !           602:     }
        !           603: forward:
        !           604: #endif /* COMPAT_IPFW */
        !           605:     if (canfree && once)
        !           606:        m = *m0 ;
        !           607:     else
        !           608:        m = NULL ;
        !           609: 
        !           610:     for ( ; ifp ; ifp = ifp->if_link.tqe_next ) {
        !           611:        if (ifp != src && ifp->if_type == IFT_ETHER &&
        !           612:            (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) &&
        !           613:            SAMEGROUP(ifp, src) && !MUTED(ifp) ) {
        !           614:            if (m == NULL) { /* do i need to make a copy ? */
        !           615:                if (canfree && ifp->if_link.tqe_next == NULL) /* last one! */
        !           616:                    m = *m0 ;
        !           617:                else /* on a P5-90, m_packetcopy takes 540 ticks */
        !           618:                    m = m_copypacket(*m0, M_DONTWAIT);
        !           619:                if (m == NULL) {
        !           620:                    printf("bdg_forward: sorry, m_copy failed!\n");
        !           621:                    return ENOBUFS ;
        !           622:                }
        !           623:            }
        !           624:            /*
        !           625:             * execute last part of ether_output.
        !           626:             */
        !           627:            s = splimp();
        !           628:            /*
        !           629:             * Queue message on interface, and start output if interface
        !           630:             * not yet active.
        !           631:             */
        !           632:            if (IF_QFULL(&ifp->if_snd)) {
        !           633:                IF_DROP(&ifp->if_snd);
        !           634:                MUTE(ifp); /* good measure... */
        !           635:                splx(s);
        !           636:                error = ENOBUFS ;
        !           637:            } else {
        !           638:                ifp->if_obytes += m->m_pkthdr.len ;
        !           639:                if (m->m_flags & M_MCAST)
        !           640:                    ifp->if_omcasts++;
        !           641:                IF_ENQUEUE(&ifp->if_snd, m);
        !           642:                if ((ifp->if_flags & IFF_OACTIVE) == 0)
        !           643:                    (*ifp->if_start)(ifp);
        !           644:                splx(s);
        !           645:                if (m == *m0)
        !           646:                    *m0 = NULL ; /* the packet is gone... */
        !           647:                m = NULL ;
        !           648:            }
        !           649:            BDG_STAT(ifp, BDG_OUT);
        !           650:        }
        !           651:        if (once)
        !           652:            break ;
        !           653:     }
        !           654: 
        !           655:     /* cleanup any mbuf leftover. */
        !           656:     if (m)
        !           657:        m_freem(m);
        !           658:     if (m == *m0)
        !           659:        *m0 = NULL ;
        !           660:     if (canfree && *m0) {
        !           661:        m_freem(*m0);
        !           662:        *m0 = NULL ;
        !           663:     }
        !           664:     return error ;
        !           665: }

unix.superglobalmegacorp.com

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