Annotation of XNU/bsd/net/bridge.c, revision 1.1.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.