[BACK]Return to if_bridge.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/if_bridge.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: if_bridge.c,v 1.164 2007/05/28 17:16:39 henning Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            18:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            19:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
        !            20:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            21:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            22:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            24:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            25:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            26:  * POSSIBILITY OF SUCH DAMAGE.
        !            27:  *
        !            28:  * Effort sponsored in part by the Defense Advanced Research Projects
        !            29:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
        !            30:  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
        !            31:  *
        !            32:  */
        !            33:
        !            34: #include "bpfilter.h"
        !            35: #include "gif.h"
        !            36: #include "pf.h"
        !            37: #include "carp.h"
        !            38:
        !            39: #include <sys/param.h>
        !            40: #include <sys/proc.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/mbuf.h>
        !            43: #include <sys/socket.h>
        !            44: #include <sys/ioctl.h>
        !            45: #include <sys/errno.h>
        !            46: #include <sys/kernel.h>
        !            47: #include <machine/cpu.h>
        !            48:
        !            49: #include <net/if.h>
        !            50: #include <net/if_types.h>
        !            51: #include <net/if_llc.h>
        !            52: #include <net/route.h>
        !            53: #include <net/netisr.h>
        !            54:
        !            55: /* for arc4random() */
        !            56: #include <dev/rndvar.h>
        !            57:
        !            58: #ifdef INET
        !            59: #include <netinet/in.h>
        !            60: #include <netinet/in_systm.h>
        !            61: #include <netinet/in_var.h>
        !            62: #include <netinet/ip.h>
        !            63: #include <netinet/ip_var.h>
        !            64: #include <netinet/if_ether.h>
        !            65: #include <netinet/ip_icmp.h>
        !            66: #endif
        !            67:
        !            68: #ifdef IPSEC
        !            69: #include <netinet/ip_ipsp.h>
        !            70:
        !            71: #include <net/if_enc.h>
        !            72: #endif
        !            73:
        !            74: #ifdef INET6
        !            75: #include <netinet/ip6.h>
        !            76: #include <netinet6/ip6_var.h>
        !            77: #endif
        !            78:
        !            79: #if NPF > 0
        !            80: #include <net/pfvar.h>
        !            81: #define        BRIDGE_IN       PF_IN
        !            82: #define        BRIDGE_OUT      PF_OUT
        !            83: #else
        !            84: #define        BRIDGE_IN       0
        !            85: #define        BRIDGE_OUT      1
        !            86: #endif
        !            87:
        !            88: #if NBPFILTER > 0
        !            89: #include <net/bpf.h>
        !            90: #endif
        !            91:
        !            92: #include <net/if_vlan_var.h>
        !            93:
        !            94: #if NCARP > 0
        !            95: #include <netinet/ip_carp.h>
        !            96: #endif
        !            97:
        !            98: #include <net/if_bridge.h>
        !            99:
        !           100: /*
        !           101:  * Maximum number of addresses to cache
        !           102:  */
        !           103: #ifndef        BRIDGE_RTABLE_MAX
        !           104: #define        BRIDGE_RTABLE_MAX       100
        !           105: #endif
        !           106:
        !           107: /*
        !           108:  * Timeout (in seconds) for entries learned dynamically
        !           109:  */
        !           110: #ifndef        BRIDGE_RTABLE_TIMEOUT
        !           111: #define        BRIDGE_RTABLE_TIMEOUT   240
        !           112: #endif
        !           113:
        !           114: void   bridgeattach(int);
        !           115: int    bridge_ioctl(struct ifnet *, u_long, caddr_t);
        !           116: void   bridge_start(struct ifnet *);
        !           117: void   bridgeintr_frame(struct bridge_softc *, struct mbuf *);
        !           118: void   bridge_broadcast(struct bridge_softc *, struct ifnet *,
        !           119:     struct ether_header *, struct mbuf *);
        !           120: void   bridge_span(struct bridge_softc *, struct ether_header *,
        !           121:     struct mbuf *);
        !           122: void   bridge_stop(struct bridge_softc *);
        !           123: void   bridge_init(struct bridge_softc *);
        !           124: int    bridge_bifconf(struct bridge_softc *, struct ifbifconf *);
        !           125:
        !           126: void   bridge_timer(void *);
        !           127: int    bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
        !           128: void   bridge_rtage(struct bridge_softc *);
        !           129: void   bridge_rttrim(struct bridge_softc *);
        !           130: int    bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
        !           131: int    bridge_rtflush(struct bridge_softc *, int);
        !           132: struct ifnet * bridge_rtupdate(struct bridge_softc *,
        !           133:     struct ether_addr *, struct ifnet *ifp, int, u_int8_t);
        !           134: struct ifnet * bridge_rtlookup(struct bridge_softc *,
        !           135:     struct ether_addr *);
        !           136: u_int32_t      bridge_hash(struct bridge_softc *, struct ether_addr *);
        !           137: int bridge_blocknonip(struct ether_header *, struct mbuf *);
        !           138: int            bridge_addrule(struct bridge_iflist *,
        !           139:     struct ifbrlreq *, int out);
        !           140: int            bridge_flushrule(struct bridge_iflist *);
        !           141: int    bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
        !           142: u_int8_t bridge_filterrule(struct brl_head *, struct ether_header *,
        !           143:     struct mbuf *);
        !           144: #if NPF > 0
        !           145: struct mbuf *bridge_filter(struct bridge_softc *, int, struct ifnet *,
        !           146:     struct ether_header *, struct mbuf *m);
        !           147: #endif
        !           148: int    bridge_ifenqueue(struct bridge_softc *, struct ifnet *, struct mbuf *);
        !           149: void   bridge_fragment(struct bridge_softc *, struct ifnet *,
        !           150:     struct ether_header *, struct mbuf *);
        !           151: #ifdef INET
        !           152: void   bridge_send_icmp_err(struct bridge_softc *, struct ifnet *,
        !           153:     struct ether_header *, struct mbuf *, int, struct llc *, int, int, int);
        !           154: #endif
        !           155: #ifdef IPSEC
        !           156: int bridge_ipsec(struct bridge_softc *, struct ifnet *,
        !           157:     struct ether_header *, int, struct llc *,
        !           158:     int, int, int, struct mbuf *);
        !           159: #define ICMP_DEFLEN MHLEN
        !           160: #endif
        !           161: int     bridge_clone_create(struct if_clone *, int);
        !           162: int    bridge_clone_destroy(struct ifnet *ifp);
        !           163: int    bridge_delete(struct bridge_softc *, struct bridge_iflist *);
        !           164:
        !           165: #define        ETHERADDR_IS_IP_MCAST(a) \
        !           166:        /* struct etheraddr *a; */                              \
        !           167:        ((a)->ether_addr_octet[0] == 0x01 &&                    \
        !           168:         (a)->ether_addr_octet[1] == 0x00 &&                    \
        !           169:         (a)->ether_addr_octet[2] == 0x5e)
        !           170:
        !           171: LIST_HEAD(, bridge_softc) bridge_list;
        !           172:
        !           173: struct if_clone bridge_cloner =
        !           174:     IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy);
        !           175:
        !           176: /* ARGSUSED */
        !           177: void
        !           178: bridgeattach(int n)
        !           179: {
        !           180:        LIST_INIT(&bridge_list);
        !           181:        if_clone_attach(&bridge_cloner);
        !           182:        bstp_attach(n);
        !           183: }
        !           184:
        !           185: int
        !           186: bridge_clone_create(struct if_clone *ifc, int unit)
        !           187: {
        !           188:        struct bridge_softc *sc;
        !           189:        struct ifnet *ifp;
        !           190:        int i, s;
        !           191:
        !           192:        sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
        !           193:        if (!sc)
        !           194:                return (ENOMEM);
        !           195:        bzero(sc, sizeof(*sc));
        !           196:
        !           197:        sc->sc_stp = bstp_create(&sc->sc_if);
        !           198:        if (!sc->sc_stp) {
        !           199:                free(sc, M_DEVBUF);
        !           200:                return (ENOMEM);
        !           201:        }
        !           202:
        !           203:        sc->sc_brtmax = BRIDGE_RTABLE_MAX;
        !           204:        sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
        !           205:        timeout_set(&sc->sc_brtimeout, bridge_timer, sc);
        !           206:        LIST_INIT(&sc->sc_iflist);
        !           207:        LIST_INIT(&sc->sc_spanlist);
        !           208:        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++)
        !           209:                LIST_INIT(&sc->sc_rts[i]);
        !           210:        sc->sc_hashkey = arc4random();
        !           211:        ifp = &sc->sc_if;
        !           212:        snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
        !           213:            unit);
        !           214:        ifp->if_softc = sc;
        !           215:        ifp->if_mtu = ETHERMTU;
        !           216:        ifp->if_ioctl = bridge_ioctl;
        !           217:        ifp->if_output = bridge_output;
        !           218:        ifp->if_start = bridge_start;
        !           219:        ifp->if_type = IFT_BRIDGE;
        !           220:        ifp->if_hdrlen = ETHER_HDR_LEN;
        !           221:        IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
        !           222:        IFQ_SET_READY(&ifp->if_snd);
        !           223:
        !           224:        if_attach(ifp);
        !           225:        if_alloc_sadl(ifp);
        !           226:
        !           227: #if NBPFILTER > 0
        !           228:        bpfattach(&sc->sc_if.if_bpf, ifp,
        !           229:            DLT_EN10MB, ETHER_HDR_LEN);
        !           230: #endif
        !           231:
        !           232:        s = splnet();
        !           233:        LIST_INSERT_HEAD(&bridge_list, sc, sc_list);
        !           234:        splx(s);
        !           235:
        !           236:        return (0);
        !           237: }
        !           238:
        !           239: int
        !           240: bridge_clone_destroy(struct ifnet *ifp)
        !           241: {
        !           242:        struct bridge_softc *sc = ifp->if_softc;
        !           243:        struct bridge_iflist *bif;
        !           244:        int s;
        !           245:
        !           246:        bridge_stop(sc);
        !           247:        bridge_rtflush(sc, IFBF_FLUSHALL);
        !           248:        while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL)
        !           249:                bridge_delete(sc, bif);
        !           250:        while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) {
        !           251:                LIST_REMOVE(bif, next);
        !           252:                free(bif, M_DEVBUF);
        !           253:        }
        !           254:
        !           255:        s = splnet();
        !           256:        LIST_REMOVE(sc, sc_list);
        !           257:        splx(s);
        !           258:
        !           259:        bstp_destroy(sc->sc_stp);
        !           260:        if_detach(ifp);
        !           261:
        !           262:        free(sc, M_DEVBUF);
        !           263:        return (0);
        !           264: }
        !           265:
        !           266: int
        !           267: bridge_delete(struct bridge_softc *sc, struct bridge_iflist *p)
        !           268: {
        !           269:        int error;
        !           270:
        !           271:        if (p->bif_flags & IFBIF_STP)
        !           272:                bstp_delete(p->bif_stp);
        !           273:
        !           274:        p->ifp->if_bridge = NULL;
        !           275:        error = ifpromisc(p->ifp, 0);
        !           276:
        !           277:        LIST_REMOVE(p, next);
        !           278:        bridge_rtdelete(sc, p->ifp, 0);
        !           279:        bridge_flushrule(p);
        !           280:        free(p, M_DEVBUF);
        !           281:
        !           282:        return (error);
        !           283: }
        !           284:
        !           285: int
        !           286: bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        !           287: {
        !           288:        struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
        !           289:        struct ifbreq *req = (struct ifbreq *)data;
        !           290:        struct ifbareq *bareq = (struct ifbareq *)data;
        !           291:        struct ifbrparam *bparam = (struct ifbrparam *)data;
        !           292:        struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
        !           293:        struct ifbropreq *brop = (struct ifbropreq *)data;
        !           294:        struct ifnet *ifs;
        !           295:        struct bridge_iflist *p;
        !           296:        struct bstp_port *bp;
        !           297:        struct bstp_state *bs = sc->sc_stp;
        !           298:        int error = 0, s;
        !           299:
        !           300:        s = splnet();
        !           301:        switch (cmd) {
        !           302:        case SIOCBRDGADD:
        !           303:                if ((error = suser(curproc, 0)) != 0)
        !           304:                        break;
        !           305:
        !           306:                ifs = ifunit(req->ifbr_ifsname);
        !           307:                if (ifs == NULL) {                      /* no such interface */
        !           308:                        error = ENOENT;
        !           309:                        break;
        !           310:                }
        !           311:                if (ifs->if_bridge == (caddr_t)sc) {
        !           312:                        error = EEXIST;
        !           313:                        break;
        !           314:                }
        !           315:                if (ifs->if_bridge != NULL) {
        !           316:                        error = EBUSY;
        !           317:                        break;
        !           318:                }
        !           319:
        !           320:                /* If it's in the span list, it can't be a member. */
        !           321:                LIST_FOREACH(p, &sc->sc_spanlist, next)
        !           322:                        if (p->ifp == ifs)
        !           323:                                break;
        !           324:
        !           325:                if (p != LIST_END(&sc->sc_spanlist)) {
        !           326:                        error = EBUSY;
        !           327:                        break;
        !           328:                }
        !           329:
        !           330:                if (ifs->if_type == IFT_ETHER) {
        !           331:                        if ((ifs->if_flags & IFF_UP) == 0) {
        !           332:                                struct ifreq ifreq;
        !           333:
        !           334:                                /*
        !           335:                                 * Bring interface up long enough to set
        !           336:                                 * promiscuous flag, then shut it down again.
        !           337:                                 */
        !           338:                                strlcpy(ifreq.ifr_name, req->ifbr_ifsname,
        !           339:                                    IFNAMSIZ);
        !           340:                                ifs->if_flags |= IFF_UP;
        !           341:                                ifreq.ifr_flags = ifs->if_flags;
        !           342:                                error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
        !           343:                                    (caddr_t)&ifreq);
        !           344:                                if (error != 0)
        !           345:                                        break;
        !           346:
        !           347:                                error = ifpromisc(ifs, 1);
        !           348:                                if (error != 0)
        !           349:                                        break;
        !           350:
        !           351:                                strlcpy(ifreq.ifr_name, req->ifbr_ifsname,
        !           352:                                    IFNAMSIZ);
        !           353:                                ifs->if_flags &= ~IFF_UP;
        !           354:                                ifreq.ifr_flags = ifs->if_flags;
        !           355:                                error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
        !           356:                                    (caddr_t)&ifreq);
        !           357:                                if (error != 0) {
        !           358:                                        ifpromisc(ifs, 0);
        !           359:                                        break;
        !           360:                                }
        !           361:                        } else {
        !           362:                                error = ifpromisc(ifs, 1);
        !           363:                                if (error != 0)
        !           364:                                        break;
        !           365:                        }
        !           366:                }
        !           367: #if NGIF > 0
        !           368:                else if (ifs->if_type == IFT_GIF) {
        !           369:                        /* Nothing needed */
        !           370:                }
        !           371: #endif /* NGIF */
        !           372:                else {
        !           373:                        error = EINVAL;
        !           374:                        break;
        !           375:                }
        !           376:
        !           377:                p = (struct bridge_iflist *)malloc(
        !           378:                    sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);
        !           379:                if (p == NULL) {
        !           380:                        if (ifs->if_type == IFT_ETHER)
        !           381:                                ifpromisc(ifs, 0);
        !           382:                        error = ENOMEM;
        !           383:                        break;
        !           384:                }
        !           385:                bzero(p, sizeof(struct bridge_iflist));
        !           386:
        !           387:                p->ifp = ifs;
        !           388:                p->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
        !           389:                SIMPLEQ_INIT(&p->bif_brlin);
        !           390:                SIMPLEQ_INIT(&p->bif_brlout);
        !           391:                ifs->if_bridge = (caddr_t)sc;
        !           392:                LIST_INSERT_HEAD(&sc->sc_iflist, p, next);
        !           393:                break;
        !           394:        case SIOCBRDGDEL:
        !           395:                if ((error = suser(curproc, 0)) != 0)
        !           396:                        break;
        !           397:
        !           398:                LIST_FOREACH(p, &sc->sc_iflist, next) {
        !           399:                        if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,
        !           400:                            sizeof(p->ifp->if_xname)) == 0) {
        !           401:                                error = bridge_delete(sc, p);
        !           402:                                p = NULL;
        !           403:                                break;
        !           404:                        }
        !           405:                }
        !           406:                if (p != NULL && p == LIST_END(&sc->sc_iflist)) {
        !           407:                        error = ENOENT;
        !           408:                        break;
        !           409:                }
        !           410:                break;
        !           411:        case SIOCBRDGIFS:
        !           412:                error = bridge_bifconf(sc, (struct ifbifconf *)data);
        !           413:                break;
        !           414:        case SIOCBRDGADDS:
        !           415:                if ((error = suser(curproc, 0)) != 0)
        !           416:                        break;
        !           417:                ifs = ifunit(req->ifbr_ifsname);
        !           418:                if (ifs == NULL) {                      /* no such interface */
        !           419:                        error = ENOENT;
        !           420:                        break;
        !           421:                }
        !           422:                if (ifs->if_bridge == (caddr_t)sc) {
        !           423:                        error = EEXIST;
        !           424:                        break;
        !           425:                }
        !           426:                if (ifs->if_bridge != NULL) {
        !           427:                        error = EBUSY;
        !           428:                        break;
        !           429:                }
        !           430:                LIST_FOREACH(p, &sc->sc_spanlist, next) {
        !           431:                        if (p->ifp == ifs)
        !           432:                                break;
        !           433:                }
        !           434:                if (p != LIST_END(&sc->sc_spanlist)) {
        !           435:                        error = EBUSY;
        !           436:                        break;
        !           437:                }
        !           438:                p = (struct bridge_iflist *)malloc(
        !           439:                    sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);
        !           440:                if (p == NULL) {
        !           441:                        error = ENOMEM;
        !           442:                        break;
        !           443:                }
        !           444:                bzero(p, sizeof(struct bridge_iflist));
        !           445:                p->ifp = ifs;
        !           446:                p->bif_flags = IFBIF_SPAN;
        !           447:                SIMPLEQ_INIT(&p->bif_brlin);
        !           448:                SIMPLEQ_INIT(&p->bif_brlout);
        !           449:                LIST_INSERT_HEAD(&sc->sc_spanlist, p, next);
        !           450:                break;
        !           451:        case SIOCBRDGDELS:
        !           452:                if ((error = suser(curproc, 0)) != 0)
        !           453:                        break;
        !           454:                LIST_FOREACH(p, &sc->sc_spanlist, next) {
        !           455:                        if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,
        !           456:                            sizeof(p->ifp->if_xname)) == 0) {
        !           457:                                LIST_REMOVE(p, next);
        !           458:                                free(p, M_DEVBUF);
        !           459:                                break;
        !           460:                        }
        !           461:                }
        !           462:                if (p == LIST_END(&sc->sc_spanlist)) {
        !           463:                        error = ENOENT;
        !           464:                        break;
        !           465:                }
        !           466:                break;
        !           467:        case SIOCBRDGGIFFLGS:
        !           468:                ifs = ifunit(req->ifbr_ifsname);
        !           469:                if (ifs == NULL) {
        !           470:                        error = ENOENT;
        !           471:                        break;
        !           472:                }
        !           473:                if ((caddr_t)sc != ifs->if_bridge) {
        !           474:                        error = ESRCH;
        !           475:                        break;
        !           476:                }
        !           477:                LIST_FOREACH(p, &sc->sc_iflist, next) {
        !           478:                        if (p->ifp == ifs)
        !           479:                                break;
        !           480:                }
        !           481:                if (p == LIST_END(&sc->sc_iflist)) {
        !           482:                        error = ESRCH;
        !           483:                        break;
        !           484:                }
        !           485:                req->ifbr_ifsflags = p->bif_flags;
        !           486:                req->ifbr_portno = p->ifp->if_index & 0xfff;
        !           487:                if (p->bif_flags & IFBIF_STP) {
        !           488:                        bp = p->bif_stp;
        !           489:                        req->ifbr_state = bstp_getstate(bs, bp);
        !           490:                        req->ifbr_priority = bp->bp_priority;
        !           491:                        req->ifbr_path_cost = bp->bp_path_cost;
        !           492:                        req->ifbr_proto = bp->bp_protover;
        !           493:                        req->ifbr_role = bp->bp_role;
        !           494:                        req->ifbr_stpflags = bp->bp_flags;
        !           495:                        req->ifbr_fwd_trans = bp->bp_forward_transitions;
        !           496:                        req->ifbr_desg_bridge = bp->bp_desg_pv.pv_dbridge_id;
        !           497:                        req->ifbr_desg_port = bp->bp_desg_pv.pv_dport_id;
        !           498:                        req->ifbr_root_bridge = bp->bp_desg_pv.pv_root_id;
        !           499:                        req->ifbr_root_cost = bp->bp_desg_pv.pv_cost;
        !           500:                        req->ifbr_root_port = bp->bp_desg_pv.pv_port_id;
        !           501:
        !           502:                        /* Copy STP state options as flags */
        !           503:                        if (bp->bp_operedge)
        !           504:                                req->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
        !           505:                        if (bp->bp_flags & BSTP_PORT_AUTOEDGE)
        !           506:                                req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
        !           507:                        if (bp->bp_ptp_link)
        !           508:                                req->ifbr_ifsflags |= IFBIF_BSTP_PTP;
        !           509:                        if (bp->bp_flags & BSTP_PORT_AUTOPTP)
        !           510:                                req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
        !           511:                }
        !           512:                break;
        !           513:        case SIOCBRDGSIFFLGS:
        !           514:                if ((error = suser(curproc, 0)) != 0)
        !           515:                        break;
        !           516:                ifs = ifunit(req->ifbr_ifsname);
        !           517:                if (ifs == NULL) {
        !           518:                        error = ENOENT;
        !           519:                        break;
        !           520:                }
        !           521:                if ((caddr_t)sc != ifs->if_bridge) {
        !           522:                        error = ESRCH;
        !           523:                        break;
        !           524:                }
        !           525:                LIST_FOREACH(p, &sc->sc_iflist, next) {
        !           526:                        if (p->ifp == ifs)
        !           527:                                break;
        !           528:                }
        !           529:                if (p == LIST_END(&sc->sc_iflist)) {
        !           530:                        error = ESRCH;
        !           531:                        break;
        !           532:                }
        !           533:                if (req->ifbr_ifsflags & IFBIF_RO_MASK) {
        !           534:                        error = EINVAL;
        !           535:                        break;
        !           536:                }
        !           537:                if (req->ifbr_ifsflags & IFBIF_STP) {
        !           538:                        if ((p->bif_flags & IFBIF_STP) == 0) {
        !           539:                                /* Enable STP */
        !           540:                                if ((p->bif_stp = bstp_add(sc->sc_stp,
        !           541:                                    p->ifp)) == NULL) {
        !           542:                                        error = ENOMEM;
        !           543:                                        break;
        !           544:                                }
        !           545:                        } else {
        !           546:                                /* Update STP flags */
        !           547:                                bstp_ifsflags(p->bif_stp, req->ifbr_ifsflags);
        !           548:                        }
        !           549:                } else if (p->bif_flags & IFBIF_STP) {
        !           550:                        bstp_delete(p->bif_stp);
        !           551:                        p->bif_stp = NULL;
        !           552:                }
        !           553:                p->bif_flags = req->ifbr_ifsflags;
        !           554:                break;
        !           555:        case SIOCBRDGRTS:
        !           556:                error = bridge_rtfind(sc, (struct ifbaconf *)data);
        !           557:                break;
        !           558:        case SIOCBRDGFLUSH:
        !           559:                if ((error = suser(curproc, 0)) != 0)
        !           560:                        break;
        !           561:
        !           562:                error = bridge_rtflush(sc, req->ifbr_ifsflags);
        !           563:                break;
        !           564:        case SIOCBRDGSADDR:
        !           565:                if ((error = suser(curproc, 0)) != 0)
        !           566:                        break;
        !           567:
        !           568:                ifs = ifunit(bareq->ifba_ifsname);
        !           569:                if (ifs == NULL) {                      /* no such interface */
        !           570:                        error = ENOENT;
        !           571:                        break;
        !           572:                }
        !           573:
        !           574:                if (ifs->if_bridge == NULL ||
        !           575:                    ifs->if_bridge != (caddr_t)sc) {
        !           576:                        error = ESRCH;
        !           577:                        break;
        !           578:                }
        !           579:
        !           580:                ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
        !           581:                    bareq->ifba_flags);
        !           582:                if (ifs == NULL)
        !           583:                        error = ENOMEM;
        !           584:                break;
        !           585:        case SIOCBRDGDADDR:
        !           586:                if ((error = suser(curproc, 0)) != 0)
        !           587:                        break;
        !           588:                error = bridge_rtdaddr(sc, &bareq->ifba_dst);
        !           589:                break;
        !           590:        case SIOCBRDGGCACHE:
        !           591:                bparam->ifbrp_csize = sc->sc_brtmax;
        !           592:                break;
        !           593:        case SIOCBRDGSCACHE:
        !           594:                if ((error = suser(curproc, 0)) != 0)
        !           595:                        break;
        !           596:                sc->sc_brtmax = bparam->ifbrp_csize;
        !           597:                bridge_rttrim(sc);
        !           598:                break;
        !           599:        case SIOCBRDGSTO:
        !           600:                if ((error = suser(curproc, 0)) != 0)
        !           601:                        break;
        !           602:                if (bparam->ifbrp_ctime < 0 ||
        !           603:                    bparam->ifbrp_ctime > INT_MAX / hz) {
        !           604:                        error = EINVAL;
        !           605:                        break;
        !           606:                }
        !           607:                sc->sc_brttimeout = bparam->ifbrp_ctime;
        !           608:                timeout_del(&sc->sc_brtimeout);
        !           609:                if (bparam->ifbrp_ctime != 0)
        !           610:                        timeout_add(&sc->sc_brtimeout, sc->sc_brttimeout * hz);
        !           611:                break;
        !           612:        case SIOCBRDGGTO:
        !           613:                bparam->ifbrp_ctime = sc->sc_brttimeout;
        !           614:                break;
        !           615:        case SIOCSIFFLAGS:
        !           616:                if ((ifp->if_flags & IFF_UP) == IFF_UP)
        !           617:                        bridge_init(sc);
        !           618:
        !           619:                if ((ifp->if_flags & IFF_UP) == 0)
        !           620:                        bridge_stop(sc);
        !           621:
        !           622:                break;
        !           623:        case SIOCBRDGARL:
        !           624:                if ((error = suser(curproc, 0)) != 0)
        !           625:                        break;
        !           626:                ifs = ifunit(brlreq->ifbr_ifsname);
        !           627:                if (ifs == NULL) {
        !           628:                        error = ENOENT;
        !           629:                        break;
        !           630:                }
        !           631:                if (ifs->if_bridge == NULL ||
        !           632:                    ifs->if_bridge != (caddr_t)sc) {
        !           633:                        error = ESRCH;
        !           634:                        break;
        !           635:                }
        !           636:                LIST_FOREACH(p, &sc->sc_iflist, next) {
        !           637:                        if (p->ifp == ifs)
        !           638:                                break;
        !           639:                }
        !           640:                if (p == LIST_END(&sc->sc_iflist)) {
        !           641:                        error = ESRCH;
        !           642:                        break;
        !           643:                }
        !           644:                if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
        !           645:                    brlreq->ifbr_action != BRL_ACTION_PASS) ||
        !           646:                    (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
        !           647:                        error = EINVAL;
        !           648:                        break;
        !           649:                }
        !           650:                if (brlreq->ifbr_flags & BRL_FLAG_IN) {
        !           651:                        error = bridge_addrule(p, brlreq, 0);
        !           652:                        if (error)
        !           653:                                break;
        !           654:                }
        !           655:                if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
        !           656:                        error = bridge_addrule(p, brlreq, 1);
        !           657:                        if (error)
        !           658:                                break;
        !           659:                }
        !           660:                break;
        !           661:        case SIOCBRDGFRL:
        !           662:                if ((error = suser(curproc, 0)) != 0)
        !           663:                        break;
        !           664:                ifs = ifunit(brlreq->ifbr_ifsname);
        !           665:                if (ifs == NULL) {
        !           666:                        error = ENOENT;
        !           667:                        break;
        !           668:                }
        !           669:                if (ifs->if_bridge == NULL ||
        !           670:                    ifs->if_bridge != (caddr_t)sc) {
        !           671:                        error = ESRCH;
        !           672:                        break;
        !           673:                }
        !           674:                LIST_FOREACH(p, &sc->sc_iflist, next) {
        !           675:                        if (p->ifp == ifs)
        !           676:                                break;
        !           677:                }
        !           678:                if (p == LIST_END(&sc->sc_iflist)) {
        !           679:                        error = ESRCH;
        !           680:                        break;
        !           681:                }
        !           682:                error = bridge_flushrule(p);
        !           683:                break;
        !           684:        case SIOCBRDGGRL:
        !           685:                error = bridge_brlconf(sc, (struct ifbrlconf *)data);
        !           686:                break;
        !           687:        case SIOCBRDGGPARAM:
        !           688:                if ((bp = bs->bs_root_port) == NULL)
        !           689:                        brop->ifbop_root_port = 0;
        !           690:                else
        !           691:                        brop->ifbop_root_port = bp->bp_ifp->if_index;
        !           692:                brop->ifbop_maxage = bs->bs_bridge_max_age >> 8;
        !           693:                brop->ifbop_hellotime = bs->bs_bridge_htime >> 8;
        !           694:                brop->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8;
        !           695:                brop->ifbop_holdcount = bs->bs_txholdcount;
        !           696:                brop->ifbop_priority = bs->bs_bridge_priority;
        !           697:                brop->ifbop_protocol = bs->bs_protover;
        !           698:                brop->ifbop_root_bridge = bs->bs_root_pv.pv_root_id;
        !           699:                brop->ifbop_root_path_cost = bs->bs_root_pv.pv_cost;
        !           700:                brop->ifbop_root_port = bs->bs_root_pv.pv_port_id;
        !           701:                brop->ifbop_desg_bridge = bs->bs_root_pv.pv_dbridge_id;
        !           702:                brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
        !           703:                brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
        !           704:                break;
        !           705:        case SIOCBRDGGPRI:
        !           706:        case SIOCBRDGGMA:
        !           707:        case SIOCBRDGGHT:
        !           708:        case SIOCBRDGGFD:
        !           709:                break;
        !           710:        case SIOCBRDGSPRI:
        !           711:        case SIOCBRDGSFD:
        !           712:        case SIOCBRDGSMA:
        !           713:        case SIOCBRDGSHT:
        !           714:        case SIOCBRDGSTXHC:
        !           715:        case SIOCBRDGSPROTO:
        !           716:        case SIOCBRDGSIFPRIO:
        !           717:        case SIOCBRDGSIFCOST:
        !           718:                error = suser(curproc, 0);
        !           719:                break;
        !           720:        default:
        !           721:                error = EINVAL;
        !           722:                break;
        !           723:        }
        !           724:
        !           725:        if (!error)
        !           726:                error = bstp_ioctl(ifp, cmd, data);
        !           727:
        !           728:        splx(s);
        !           729:        return (error);
        !           730: }
        !           731:
        !           732: /* Detach an interface from a bridge.  */
        !           733: void
        !           734: bridge_ifdetach(struct ifnet *ifp)
        !           735: {
        !           736:        struct bridge_softc *sc = (struct bridge_softc *)ifp->if_bridge;
        !           737:        struct bridge_iflist *bif;
        !           738:
        !           739:        LIST_FOREACH(bif, &sc->sc_iflist, next)
        !           740:                if (bif->ifp == ifp) {
        !           741:                        LIST_REMOVE(bif, next);
        !           742:                        bridge_rtdelete(sc, ifp, 0);
        !           743:                        bridge_flushrule(bif);
        !           744:                        free(bif, M_DEVBUF);
        !           745:                        ifp->if_bridge = NULL;
        !           746:                        break;
        !           747:                }
        !           748: }
        !           749:
        !           750: void
        !           751: bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
        !           752: {
        !           753:        struct bridge_softc *sc = (struct bridge_softc *)ifp->if_bridge;
        !           754:        struct bridge_iflist *bif;
        !           755:        u_int8_t *addr;
        !           756:
        !           757:        addr = (u_int8_t *)ea;
        !           758:
        !           759:        LIST_FOREACH(bif, &sc->sc_iflist, next)
        !           760:                if (bif->ifp == ifp) {
        !           761:                        /*
        !           762:                         * Update the bridge interface if it is in
        !           763:                         * the learning state.
        !           764:                         */
        !           765:                        if ((bif->bif_flags & IFBIF_LEARNING) &&
        !           766:                            (ETHER_IS_MULTICAST(addr) == 0) &&
        !           767:                            !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
        !           768:                            addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
        !           769:                                /* Care must be taken with spanning tree */
        !           770:                                if ((bif->bif_flags & IFBIF_STP) &&
        !           771:                                    (bif->bif_state == BSTP_IFSTATE_DISCARDING))
        !           772:                                        return;
        !           773:
        !           774:                                /* Delete the address from the bridge */
        !           775:                                bridge_rtdaddr(sc, ea);
        !           776:
        !           777:                                if (!delete) {
        !           778:                                        /* Update the bridge table */
        !           779:                                        bridge_rtupdate(sc, ea, ifp, 0,
        !           780:                                            IFBAF_DYNAMIC);
        !           781:                                }
        !           782:                        }
        !           783:                        return;
        !           784:                }
        !           785: }
        !           786:
        !           787: int
        !           788: bridge_bifconf(struct bridge_softc *sc, struct ifbifconf *bifc)
        !           789: {
        !           790:        struct bridge_iflist *p;
        !           791:        struct bstp_port *bp;
        !           792:        struct bstp_state *bs = sc->sc_stp;
        !           793:        u_int32_t total = 0, i = 0;
        !           794:        int error = 0;
        !           795:        struct ifbreq *breq = NULL;
        !           796:
        !           797:        LIST_FOREACH(p, &sc->sc_iflist, next)
        !           798:                total++;
        !           799:
        !           800:        LIST_FOREACH(p, &sc->sc_spanlist, next)
        !           801:                total++;
        !           802:
        !           803:        if (bifc->ifbic_len == 0) {
        !           804:                i = total;
        !           805:                goto done;
        !           806:        }
        !           807:
        !           808:        if ((breq = (struct ifbreq *)
        !           809:            malloc(sizeof(*breq), M_DEVBUF, M_NOWAIT)) == NULL)
        !           810:                goto done;
        !           811:
        !           812:        LIST_FOREACH(p, &sc->sc_iflist, next) {
        !           813:                bzero(breq, sizeof(*breq));
        !           814:                if (bifc->ifbic_len < sizeof(*breq))
        !           815:                        break;
        !           816:                strlcpy(breq->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
        !           817:                strlcpy(breq->ifbr_ifsname, p->ifp->if_xname, IFNAMSIZ);
        !           818:                breq->ifbr_ifsflags = p->bif_flags;
        !           819:                breq->ifbr_portno = p->ifp->if_index & 0xfff;
        !           820:                if (p->bif_flags & IFBIF_STP) {
        !           821:                        bp = p->bif_stp;
        !           822:                        breq->ifbr_state = bstp_getstate(sc->sc_stp, bp);
        !           823:                        breq->ifbr_priority = bp->bp_priority;
        !           824:                        breq->ifbr_path_cost = bp->bp_path_cost;
        !           825:                        breq->ifbr_proto = bp->bp_protover;
        !           826:                        breq->ifbr_role = bp->bp_role;
        !           827:                        breq->ifbr_stpflags = bp->bp_flags;
        !           828:                        breq->ifbr_fwd_trans = bp->bp_forward_transitions;
        !           829:                        breq->ifbr_root_bridge = bs->bs_root_pv.pv_root_id;
        !           830:                        breq->ifbr_root_cost = bs->bs_root_pv.pv_cost;
        !           831:                        breq->ifbr_root_port = bs->bs_root_pv.pv_port_id;
        !           832:                        breq->ifbr_desg_bridge = bs->bs_root_pv.pv_dbridge_id;
        !           833:                        breq->ifbr_desg_port = bs->bs_root_pv.pv_dport_id;
        !           834:
        !           835:                        /* Copy STP state options as flags */
        !           836:                        if (bp->bp_operedge)
        !           837:                                breq->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
        !           838:                        if (bp->bp_flags & BSTP_PORT_AUTOEDGE)
        !           839:                                breq->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
        !           840:                        if (bp->bp_ptp_link)
        !           841:                                breq->ifbr_ifsflags |= IFBIF_BSTP_PTP;
        !           842:                        if (bp->bp_flags & BSTP_PORT_AUTOPTP)
        !           843:                                breq->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
        !           844:                }
        !           845:                error = copyout((caddr_t)breq,
        !           846:                    (caddr_t)(bifc->ifbic_req + i), sizeof(*breq));
        !           847:                if (error)
        !           848:                        goto done;
        !           849:                i++;
        !           850:                bifc->ifbic_len -= sizeof(*breq);
        !           851:        }
        !           852:        LIST_FOREACH(p, &sc->sc_spanlist, next) {
        !           853:                bzero(breq, sizeof(*breq));
        !           854:                if (bifc->ifbic_len < sizeof(*breq))
        !           855:                        break;
        !           856:                strlcpy(breq->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
        !           857:                strlcpy(breq->ifbr_ifsname, p->ifp->if_xname, IFNAMSIZ);
        !           858:                breq->ifbr_ifsflags = p->bif_flags | IFBIF_SPAN;
        !           859:                breq->ifbr_portno = p->ifp->if_index & 0xfff;
        !           860:                error = copyout((caddr_t)breq,
        !           861:                    (caddr_t)(bifc->ifbic_req + i), sizeof(*breq));
        !           862:                if (error)
        !           863:                        goto done;
        !           864:                i++;
        !           865:                bifc->ifbic_len -= sizeof(*breq);
        !           866:        }
        !           867:
        !           868: done:
        !           869:        if (breq != NULL)
        !           870:                free(breq, M_DEVBUF);
        !           871:        bifc->ifbic_len = i * sizeof(*breq);
        !           872:        return (error);
        !           873: }
        !           874:
        !           875: int
        !           876: bridge_brlconf(struct bridge_softc *sc, struct ifbrlconf *bc)
        !           877: {
        !           878:        struct ifnet *ifp;
        !           879:        struct bridge_iflist *ifl;
        !           880:        struct brl_node *n;
        !           881:        struct ifbrlreq req;
        !           882:        int error = 0;
        !           883:        u_int32_t i = 0, total = 0;
        !           884:
        !           885:        ifp = ifunit(bc->ifbrl_ifsname);
        !           886:        if (ifp == NULL)
        !           887:                return (ENOENT);
        !           888:        if (ifp->if_bridge == NULL || ifp->if_bridge != (caddr_t)sc)
        !           889:                return (ESRCH);
        !           890:        LIST_FOREACH(ifl, &sc->sc_iflist, next) {
        !           891:                if (ifl->ifp == ifp)
        !           892:                        break;
        !           893:        }
        !           894:        if (ifl == LIST_END(&sc->sc_iflist))
        !           895:                return (ESRCH);
        !           896:
        !           897:        SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
        !           898:                total++;
        !           899:        }
        !           900:        SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
        !           901:                total++;
        !           902:        }
        !           903:
        !           904:        if (bc->ifbrl_len == 0) {
        !           905:                i = total;
        !           906:                goto done;
        !           907:        }
        !           908:
        !           909:        SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
        !           910:                bzero(&req, sizeof req);
        !           911:                if (bc->ifbrl_len < sizeof(req))
        !           912:                        goto done;
        !           913:                strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
        !           914:                strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
        !           915:                req.ifbr_action = n->brl_action;
        !           916:                req.ifbr_flags = n->brl_flags;
        !           917:                req.ifbr_src = n->brl_src;
        !           918:                req.ifbr_dst = n->brl_dst;
        !           919: #if NPF > 0
        !           920:                req.ifbr_tagname[0] = '\0';
        !           921:                if (n->brl_tag)
        !           922:                        pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
        !           923: #endif
        !           924:                error = copyout((caddr_t)&req,
        !           925:                    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
        !           926:                if (error)
        !           927:                        goto done;
        !           928:                i++;
        !           929:                bc->ifbrl_len -= sizeof(req);
        !           930:        }
        !           931:
        !           932:        SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
        !           933:                bzero(&req, sizeof req);
        !           934:                if (bc->ifbrl_len < sizeof(req))
        !           935:                        goto done;
        !           936:                strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
        !           937:                strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
        !           938:                req.ifbr_action = n->brl_action;
        !           939:                req.ifbr_flags = n->brl_flags;
        !           940:                req.ifbr_src = n->brl_src;
        !           941:                req.ifbr_dst = n->brl_dst;
        !           942: #if NPF > 0
        !           943:                req.ifbr_tagname[0] = '\0';
        !           944:                if (n->brl_tag)
        !           945:                        pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
        !           946: #endif
        !           947:                error = copyout((caddr_t)&req,
        !           948:                    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
        !           949:                if (error)
        !           950:                        goto done;
        !           951:                i++;
        !           952:                bc->ifbrl_len -= sizeof(req);
        !           953:        }
        !           954:
        !           955: done:
        !           956:        bc->ifbrl_len = i * sizeof(req);
        !           957:        return (error);
        !           958: }
        !           959:
        !           960: void
        !           961: bridge_init(struct bridge_softc *sc)
        !           962: {
        !           963:        struct ifnet *ifp = &sc->sc_if;
        !           964:
        !           965:        if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING)
        !           966:                return;
        !           967:
        !           968:        ifp->if_flags |= IFF_RUNNING;
        !           969:        bstp_initialization(sc->sc_stp);
        !           970:
        !           971:        if (sc->sc_brttimeout != 0)
        !           972:                timeout_add(&sc->sc_brtimeout, sc->sc_brttimeout * hz);
        !           973: }
        !           974:
        !           975: /*
        !           976:  * Stop the bridge and deallocate the routing table.
        !           977:  */
        !           978: void
        !           979: bridge_stop(struct bridge_softc *sc)
        !           980: {
        !           981:        struct ifnet *ifp = &sc->sc_if;
        !           982:
        !           983:        /*
        !           984:         * If we're not running, there's nothing to do.
        !           985:         */
        !           986:        if ((ifp->if_flags & IFF_RUNNING) == 0)
        !           987:                return;
        !           988:
        !           989:        timeout_del(&sc->sc_brtimeout);
        !           990:
        !           991:        bridge_rtflush(sc, IFBF_FLUSHDYN);
        !           992:
        !           993:        ifp->if_flags &= ~IFF_RUNNING;
        !           994: }
        !           995:
        !           996: /*
        !           997:  * Send output from the bridge.  The mbuf has the ethernet header
        !           998:  * already attached.  We must enqueue or free the mbuf before exiting.
        !           999:  */
        !          1000: int
        !          1001: bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
        !          1002:     struct rtentry *rt)
        !          1003: {
        !          1004:        struct ether_header *eh;
        !          1005:        struct ifnet *dst_if;
        !          1006:        struct ether_addr *src, *dst;
        !          1007:        struct bridge_softc *sc;
        !          1008:        int s, error, len;
        !          1009: #ifdef IPSEC
        !          1010:        struct m_tag *mtag;
        !          1011: #endif /* IPSEC */
        !          1012:
        !          1013:        /* ifp must be a member interface of the bridge. */
        !          1014:        sc = (struct bridge_softc *)ifp->if_bridge;
        !          1015:        if (sc == NULL) {
        !          1016:                m_freem(m);
        !          1017:                return (EINVAL);
        !          1018:        }
        !          1019:
        !          1020:        if (m->m_len < sizeof(*eh)) {
        !          1021:                m = m_pullup(m, sizeof(*eh));
        !          1022:                if (m == NULL)
        !          1023:                        return (ENOBUFS);
        !          1024:        }
        !          1025:        eh = mtod(m, struct ether_header *);
        !          1026:        dst = (struct ether_addr *)&eh->ether_dhost[0];
        !          1027:        src = (struct ether_addr *)&eh->ether_shost[0];
        !          1028:
        !          1029:        s = splnet();
        !          1030:
        !          1031:        /*
        !          1032:         * If bridge is down, but original output interface is up,
        !          1033:         * go ahead and send out that interface.  Otherwise the packet
        !          1034:         * is dropped below.
        !          1035:         */
        !          1036:        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
        !          1037:                dst_if = ifp;
        !          1038:                goto sendunicast;
        !          1039:        }
        !          1040:
        !          1041:        /*
        !          1042:         * If the packet is a broadcast or we don't know a better way to
        !          1043:         * get there, send to all interfaces.
        !          1044:         */
        !          1045:        dst_if = bridge_rtlookup(sc, dst);
        !          1046:        if (dst_if == NULL || ETHER_IS_MULTICAST(eh->ether_dhost)) {
        !          1047:                struct bridge_iflist *p;
        !          1048:                struct mbuf *mc;
        !          1049:                int used = 0;
        !          1050:
        !          1051: #ifdef IPSEC
        !          1052:                /*
        !          1053:                 * Don't send out the packet if IPsec is needed, and
        !          1054:                 * notify IPsec to do its own crypto for now.
        !          1055:                 */
        !          1056:                if ((mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED,
        !          1057:                    NULL)) != NULL) {
        !          1058:                        ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
        !          1059:                        m_freem(m);
        !          1060:                        splx(s);
        !          1061:                        return (0);
        !          1062:                }
        !          1063: #endif /* IPSEC */
        !          1064:
        !          1065:                /* Catch packets that need TCP/UDP/IP hardware checksumming */
        !          1066:                if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT ||
        !          1067:                    m->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT ||
        !          1068:                    m->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
        !          1069:                        m_freem(m);
        !          1070:                        splx(s);
        !          1071:                        return (0);
        !          1072:                }
        !          1073:
        !          1074:                bridge_span(sc, NULL, m);
        !          1075:
        !          1076:                LIST_FOREACH(p, &sc->sc_iflist, next) {
        !          1077:                        dst_if = p->ifp;
        !          1078:                        if ((dst_if->if_flags & IFF_RUNNING) == 0)
        !          1079:                                continue;
        !          1080:
        !          1081:                        /*
        !          1082:                         * If this is not the original output interface,
        !          1083:                         * and the interface is participating in spanning
        !          1084:                         * tree, make sure the port is in a state that
        !          1085:                         * allows forwarding.
        !          1086:                         */
        !          1087:                        if (dst_if != ifp &&
        !          1088:                            (p->bif_flags & IFBIF_STP) &&
        !          1089:                            (p->bif_state == BSTP_IFSTATE_DISCARDING))
        !          1090:                                continue;
        !          1091:
        !          1092:                        if ((p->bif_flags & IFBIF_DISCOVER) == 0 &&
        !          1093:                            (m->m_flags & (M_BCAST | M_MCAST)) == 0)
        !          1094:                                continue;
        !          1095:
        !          1096: #ifdef ALTQ
        !          1097:                        if (ALTQ_IS_ENABLED(&dst_if->if_snd) == 0)
        !          1098: #endif
        !          1099:                        if (IF_QFULL(&dst_if->if_snd)) {
        !          1100:                                IF_DROP(&dst_if->if_snd);
        !          1101:                                sc->sc_if.if_oerrors++;
        !          1102:                                continue;
        !          1103:                        }
        !          1104:                        if (LIST_NEXT(p, next) == LIST_END(&sc->sc_iflist)) {
        !          1105:                                used = 1;
        !          1106:                                mc = m;
        !          1107:                        } else {
        !          1108:                                struct mbuf *m1, *m2, *mx;
        !          1109:
        !          1110:                                m1 = m_copym2(m, 0, ETHER_HDR_LEN,
        !          1111:                                    M_DONTWAIT);
        !          1112:                                if (m1 == NULL) {
        !          1113:                                        sc->sc_if.if_oerrors++;
        !          1114:                                        continue;
        !          1115:                                }
        !          1116:                                m2 = m_copym2(m, ETHER_HDR_LEN,
        !          1117:                                    M_COPYALL, M_DONTWAIT);
        !          1118:                                if (m2 == NULL) {
        !          1119:                                        m_freem(m1);
        !          1120:                                        sc->sc_if.if_oerrors++;
        !          1121:                                        continue;
        !          1122:                                }
        !          1123:
        !          1124:                                for (mx = m1; mx->m_next != NULL; mx = mx->m_next)
        !          1125:                                        /*EMPTY*/;
        !          1126:                                mx->m_next = m2;
        !          1127:
        !          1128:                                if (m1->m_flags & M_PKTHDR) {
        !          1129:                                        len = 0;
        !          1130:                                        for (mx = m1; mx != NULL; mx = mx->m_next)
        !          1131:                                                len += mx->m_len;
        !          1132:                                        m1->m_pkthdr.len = len;
        !          1133:                                }
        !          1134:                                mc = m1;
        !          1135:                        }
        !          1136:
        !          1137:                        error = bridge_ifenqueue(sc, dst_if, mc);
        !          1138:                        if (error)
        !          1139:                                continue;
        !          1140:                }
        !          1141:                if (!used)
        !          1142:                        m_freem(m);
        !          1143:                splx(s);
        !          1144:                return (0);
        !          1145:        }
        !          1146:
        !          1147: sendunicast:
        !          1148:        bridge_span(sc, NULL, m);
        !          1149:        if ((dst_if->if_flags & IFF_RUNNING) == 0) {
        !          1150:                m_freem(m);
        !          1151:                splx(s);
        !          1152:                return (ENETDOWN);
        !          1153:        }
        !          1154:        bridge_ifenqueue(sc, dst_if, m);
        !          1155:        splx(s);
        !          1156:        return (0);
        !          1157: }
        !          1158:
        !          1159: /*
        !          1160:  * Start output on the bridge.  This function should never be called.
        !          1161:  */
        !          1162: void
        !          1163: bridge_start(struct ifnet *ifp)
        !          1164: {
        !          1165: }
        !          1166:
        !          1167: /*
        !          1168:  * Loop through each bridge interface and process their input queues.
        !          1169:  */
        !          1170: void
        !          1171: bridgeintr(void)
        !          1172: {
        !          1173:        struct bridge_softc *sc;
        !          1174:        struct mbuf *m;
        !          1175:        int s;
        !          1176:
        !          1177:        LIST_FOREACH(sc, &bridge_list, sc_list) {
        !          1178:                while (sc->sc_if.if_snd.ifq_head) {
        !          1179:                        s = splnet();
        !          1180:                        IF_DEQUEUE(&sc->sc_if.if_snd, m);
        !          1181:                        splx(s);
        !          1182:                        if (m == NULL)
        !          1183:                                break;
        !          1184:                        bridgeintr_frame(sc, m);
        !          1185:                }
        !          1186:        }
        !          1187: }
        !          1188:
        !          1189: /*
        !          1190:  * Process a single frame.  Frame must be freed or queued before returning.
        !          1191:  */
        !          1192: void
        !          1193: bridgeintr_frame(struct bridge_softc *sc, struct mbuf *m)
        !          1194: {
        !          1195:        int s, len;
        !          1196:        struct ifnet *src_if, *dst_if;
        !          1197:        struct bridge_iflist *ifl;
        !          1198:        struct ether_addr *dst, *src;
        !          1199:        struct ether_header eh;
        !          1200:
        !          1201:        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
        !          1202:                m_freem(m);
        !          1203:                return;
        !          1204:        }
        !          1205:
        !          1206:        src_if = m->m_pkthdr.rcvif;
        !          1207:
        !          1208: #if NBPFILTER > 0
        !          1209:        if (sc->sc_if.if_bpf)
        !          1210:                bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN);
        !          1211: #endif
        !          1212:
        !          1213:        sc->sc_if.if_ipackets++;
        !          1214:        sc->sc_if.if_ibytes += m->m_pkthdr.len;
        !          1215:
        !          1216:        LIST_FOREACH(ifl, &sc->sc_iflist, next)
        !          1217:                if (ifl->ifp == src_if)
        !          1218:                        break;
        !          1219:
        !          1220:        if (ifl == LIST_END(&sc->sc_iflist)) {
        !          1221:                m_freem(m);
        !          1222:                return;
        !          1223:        }
        !          1224:
        !          1225:        if ((ifl->bif_flags & IFBIF_STP) &&
        !          1226:            (ifl->bif_state == BSTP_IFSTATE_DISCARDING)) {
        !          1227:                m_freem(m);
        !          1228:                return;
        !          1229:        }
        !          1230:
        !          1231:        if (m->m_pkthdr.len < sizeof(eh)) {
        !          1232:                m_freem(m);
        !          1233:                return;
        !          1234:        }
        !          1235:        m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&eh);
        !          1236:        dst = (struct ether_addr *)&eh.ether_dhost[0];
        !          1237:        src = (struct ether_addr *)&eh.ether_shost[0];
        !          1238:
        !          1239:        /*
        !          1240:         * If interface is learning, and if source address
        !          1241:         * is not broadcast or multicast, record its address.
        !          1242:         */
        !          1243:        if ((ifl->bif_flags & IFBIF_LEARNING) &&
        !          1244:            (eh.ether_shost[0] & 1) == 0 &&
        !          1245:            !(eh.ether_shost[0] == 0 && eh.ether_shost[1] == 0 &&
        !          1246:            eh.ether_shost[2] == 0 && eh.ether_shost[3] == 0 &&
        !          1247:            eh.ether_shost[4] == 0 && eh.ether_shost[5] == 0))
        !          1248:                bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC);
        !          1249:
        !          1250:        if ((ifl->bif_flags & IFBIF_STP) &&
        !          1251:            (ifl->bif_state == BSTP_IFSTATE_LEARNING)) {
        !          1252:                m_freem(m);
        !          1253:                return;
        !          1254:        }
        !          1255:
        !          1256:        /*
        !          1257:         * At this point, the port either doesn't participate in stp or
        !          1258:         * it's in the forwarding state
        !          1259:         */
        !          1260:
        !          1261:        /*
        !          1262:         * If packet is unicast, destined for someone on "this"
        !          1263:         * side of the bridge, drop it.
        !          1264:         */
        !          1265:        if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) {
        !          1266:                dst_if = bridge_rtlookup(sc, dst);
        !          1267:                if (dst_if == src_if) {
        !          1268:                        m_freem(m);
        !          1269:                        return;
        !          1270:                }
        !          1271:        } else
        !          1272:                dst_if = NULL;
        !          1273:
        !          1274:        /*
        !          1275:         * Multicast packets get handled a little differently:
        !          1276:         * If interface is:
        !          1277:         *      -link0,-link1   (default) Forward all multicast
        !          1278:         *                      as broadcast.
        !          1279:         *      -link0,link1    Drop non-IP multicast, forward
        !          1280:         *                      as broadcast IP multicast.
        !          1281:         *      link0,-link1    Drop IP multicast, forward as
        !          1282:         *                      broadcast non-IP multicast.
        !          1283:         *      link0,link1     Drop all multicast.
        !          1284:         */
        !          1285:        if (m->m_flags & M_MCAST) {
        !          1286:                if ((sc->sc_if.if_flags &
        !          1287:                    (IFF_LINK0 | IFF_LINK1)) ==
        !          1288:                    (IFF_LINK0 | IFF_LINK1)) {
        !          1289:                        m_freem(m);
        !          1290:                        return;
        !          1291:                }
        !          1292:                if (sc->sc_if.if_flags & IFF_LINK0 &&
        !          1293:                    ETHERADDR_IS_IP_MCAST(dst)) {
        !          1294:                        m_freem(m);
        !          1295:                        return;
        !          1296:                }
        !          1297:                if (sc->sc_if.if_flags & IFF_LINK1 &&
        !          1298:                    !ETHERADDR_IS_IP_MCAST(dst)) {
        !          1299:                        m_freem(m);
        !          1300:                        return;
        !          1301:                }
        !          1302:        }
        !          1303:
        !          1304:        if (ifl->bif_flags & IFBIF_BLOCKNONIP && bridge_blocknonip(&eh, m)) {
        !          1305:                m_freem(m);
        !          1306:                return;
        !          1307:        }
        !          1308:
        !          1309:        if (bridge_filterrule(&ifl->bif_brlin, &eh, m) == BRL_ACTION_BLOCK) {
        !          1310:                m_freem(m);
        !          1311:                return;
        !          1312:        }
        !          1313: #if NPF > 0
        !          1314:        m = bridge_filter(sc, BRIDGE_IN, src_if, &eh, m);
        !          1315:        if (m == NULL)
        !          1316:                return;
        !          1317: #endif
        !          1318:        /*
        !          1319:         * If the packet is a multicast or broadcast OR if we don't
        !          1320:         * know any better, forward it to all interfaces.
        !          1321:         */
        !          1322:        if ((m->m_flags & (M_BCAST | M_MCAST)) || dst_if == NULL) {
        !          1323:                sc->sc_if.if_imcasts++;
        !          1324:                s = splnet();
        !          1325:                bridge_broadcast(sc, src_if, &eh, m);
        !          1326:                splx(s);
        !          1327:                return;
        !          1328:        }
        !          1329:
        !          1330:        /*
        !          1331:         * At this point, we're dealing with a unicast frame going to a
        !          1332:         * different interface
        !          1333:         */
        !          1334:        if ((dst_if->if_flags & IFF_RUNNING) == 0) {
        !          1335:                m_freem(m);
        !          1336:                return;
        !          1337:        }
        !          1338:        LIST_FOREACH(ifl, &sc->sc_iflist, next) {
        !          1339:                if (ifl->ifp == dst_if)
        !          1340:                        break;
        !          1341:        }
        !          1342:        if (ifl == LIST_END(&sc->sc_iflist)) {
        !          1343:                m_freem(m);
        !          1344:                return;
        !          1345:        }
        !          1346:        if ((ifl->bif_flags & IFBIF_STP) &&
        !          1347:            (ifl->bif_state == BSTP_IFSTATE_DISCARDING)) {
        !          1348:                m_freem(m);
        !          1349:                return;
        !          1350:        }
        !          1351:        if (bridge_filterrule(&ifl->bif_brlout, &eh, m) == BRL_ACTION_BLOCK) {
        !          1352:                m_freem(m);
        !          1353:                return;
        !          1354:        }
        !          1355: #if NPF > 0
        !          1356:        m = bridge_filter(sc, BRIDGE_OUT, dst_if, &eh, m);
        !          1357:        if (m == NULL)
        !          1358:                return;
        !          1359: #endif
        !          1360:
        !          1361:        len = m->m_pkthdr.len;
        !          1362:        if ((len - ETHER_HDR_LEN) > dst_if->if_mtu)
        !          1363:                bridge_fragment(sc, dst_if, &eh, m);
        !          1364:        else {
        !          1365:                s = splnet();
        !          1366:                bridge_ifenqueue(sc, dst_if, m);
        !          1367:                splx(s);
        !          1368:        }
        !          1369: }
        !          1370:
        !          1371: /*
        !          1372:  * Receive input from an interface.  Queue the packet for bridging if its
        !          1373:  * not for us, and schedule an interrupt.
        !          1374:  */
        !          1375: struct mbuf *
        !          1376: bridge_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
        !          1377: {
        !          1378:        struct bridge_softc *sc;
        !          1379:        int s;
        !          1380:        struct bridge_iflist *ifl, *srcifl;
        !          1381:        struct arpcom *ac;
        !          1382:        struct mbuf *mc;
        !          1383:
        !          1384:        /*
        !          1385:         * Make sure this interface is a bridge member.
        !          1386:         */
        !          1387:        if (ifp == NULL || ifp->if_bridge == NULL || m == NULL)
        !          1388:                return (m);
        !          1389:
        !          1390:        if ((m->m_flags & M_PKTHDR) == 0)
        !          1391:                panic("bridge_input(): no HDR");
        !          1392:
        !          1393:        m->m_flags &= ~M_PROTO1;        /* Loop prevention */
        !          1394:
        !          1395:        sc = (struct bridge_softc *)ifp->if_bridge;
        !          1396:        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)
        !          1397:                return (m);
        !          1398:
        !          1399:        LIST_FOREACH(ifl, &sc->sc_iflist, next) {
        !          1400:                if (ifl->ifp == ifp)
        !          1401:                        break;
        !          1402:        }
        !          1403:        if (ifl == LIST_END(&sc->sc_iflist))
        !          1404:                return (m);
        !          1405:
        !          1406:        bridge_span(sc, eh, m);
        !          1407:
        !          1408:        if (m->m_flags & (M_BCAST | M_MCAST)) {
        !          1409:                /* Tap off 802.1D packets, they do not get forwarded */
        !          1410:                if (bcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0) {
        !          1411:                        m = bstp_input(sc->sc_stp, ifl->bif_stp, eh, m);
        !          1412:                        if (m == NULL)
        !          1413:                                return (NULL);
        !          1414:                }
        !          1415:
        !          1416:                /*
        !          1417:                 * No need to queue frames for ifs in the discarding state
        !          1418:                 */
        !          1419:                if ((ifl->bif_flags & IFBIF_STP) &&
        !          1420:                    (ifl->bif_state == BSTP_IFSTATE_DISCARDING))
        !          1421:                        return (m);
        !          1422:
        !          1423:                /*
        !          1424:                 * make a copy of 'm' with 'eh' tacked on to the
        !          1425:                 * beginning.  Return 'm' for local processing
        !          1426:                 * and enqueue the copy.  Schedule netisr.
        !          1427:                 */
        !          1428:                mc = m_copym2(m, 0, M_COPYALL, M_NOWAIT);
        !          1429:                if (mc == NULL)
        !          1430:                        return (m);
        !          1431:                M_PREPEND(mc, ETHER_HDR_LEN, M_DONTWAIT);
        !          1432:                if (mc == NULL)
        !          1433:                        return (m);
        !          1434:                bcopy(eh, mtod(mc, caddr_t), ETHER_HDR_LEN);
        !          1435:                s = splnet();
        !          1436:                if (IF_QFULL(&sc->sc_if.if_snd)) {
        !          1437:                        m_freem(mc);
        !          1438:                        splx(s);
        !          1439:                        return (m);
        !          1440:                }
        !          1441:                IF_ENQUEUE(&sc->sc_if.if_snd, mc);
        !          1442:                splx(s);
        !          1443:                schednetisr(NETISR_BRIDGE);
        !          1444:                if (ifp->if_type == IFT_GIF) {
        !          1445:                        LIST_FOREACH(ifl, &sc->sc_iflist, next) {
        !          1446:                                if (ifl->ifp->if_type == IFT_ETHER)
        !          1447:                                        break;
        !          1448:                        }
        !          1449:                        if (ifl != LIST_END(&sc->sc_iflist)) {
        !          1450:                                m->m_flags |= M_PROTO1;
        !          1451:                                m->m_pkthdr.rcvif = ifl->ifp;
        !          1452:                                ether_input(ifl->ifp, eh, m);
        !          1453:                                m = NULL;
        !          1454:                        }
        !          1455:                }
        !          1456:                return (m);
        !          1457:        }
        !          1458:
        !          1459:        /*
        !          1460:         * No need to queue frames for ifs in the discarding state
        !          1461:         */
        !          1462:        if ((ifl->bif_flags & IFBIF_STP) &&
        !          1463:            (ifl->bif_state == BSTP_IFSTATE_DISCARDING))
        !          1464:                return (m);
        !          1465:
        !          1466:        /*
        !          1467:         * Unicast, make sure it's not for us.
        !          1468:         */
        !          1469:        srcifl = ifl;
        !          1470:        LIST_FOREACH(ifl, &sc->sc_iflist, next) {
        !          1471:                if (ifl->ifp->if_type != IFT_ETHER)
        !          1472:                        continue;
        !          1473:                ac = (struct arpcom *)ifl->ifp;
        !          1474:                if (bcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN) == 0
        !          1475: #if NCARP > 0
        !          1476:                    || (ifl->ifp->if_carp && carp_ourether(ifl->ifp->if_carp,
        !          1477:                        eh, IFT_ETHER, 0) != NULL)
        !          1478: #endif
        !          1479:                    ) {
        !          1480:                        if (srcifl->bif_flags & IFBIF_LEARNING)
        !          1481:                                bridge_rtupdate(sc,
        !          1482:                                    (struct ether_addr *)&eh->ether_shost,
        !          1483:                                    ifp, 0, IFBAF_DYNAMIC);
        !          1484:                        if (bridge_filterrule(&srcifl->bif_brlin, eh, m) ==
        !          1485:                            BRL_ACTION_BLOCK) {
        !          1486:                                m_freem(m);
        !          1487:                                return (NULL);
        !          1488:                        }
        !          1489:                        m->m_pkthdr.rcvif = ifl->ifp;
        !          1490:                        if (ifp->if_type == IFT_GIF) {
        !          1491:                                m->m_flags |= M_PROTO1;
        !          1492:                                ether_input(ifl->ifp, eh, m);
        !          1493:                                m = NULL;
        !          1494:                        }
        !          1495:                        return (m);
        !          1496:                }
        !          1497:                if (bcmp(ac->ac_enaddr, eh->ether_shost, ETHER_ADDR_LEN) == 0
        !          1498: #if NCARP > 0
        !          1499:                    || (ifl->ifp->if_carp && carp_ourether(ifl->ifp->if_carp,
        !          1500:                        eh, IFT_ETHER, 1) != NULL)
        !          1501: #endif
        !          1502:                    ) {
        !          1503:                        m_freem(m);
        !          1504:                        return (NULL);
        !          1505:                }
        !          1506:        }
        !          1507:        M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
        !          1508:        if (m == NULL)
        !          1509:                return (NULL);
        !          1510:        bcopy(eh, mtod(m, caddr_t), ETHER_HDR_LEN);
        !          1511:        s = splnet();
        !          1512:        if (IF_QFULL(&sc->sc_if.if_snd)) {
        !          1513:                m_freem(m);
        !          1514:                splx(s);
        !          1515:                return (NULL);
        !          1516:        }
        !          1517:        IF_ENQUEUE(&sc->sc_if.if_snd, m);
        !          1518:        splx(s);
        !          1519:        schednetisr(NETISR_BRIDGE);
        !          1520:        return (NULL);
        !          1521: }
        !          1522:
        !          1523: /*
        !          1524:  * Send a frame to all interfaces that are members of the bridge
        !          1525:  * (except the one it came in on).  This code assumes that it is
        !          1526:  * running at splnet or higher.
        !          1527:  */
        !          1528: void
        !          1529: bridge_broadcast(struct bridge_softc *sc, struct ifnet *ifp,
        !          1530:     struct ether_header *eh, struct mbuf *m)
        !          1531: {
        !          1532:        struct bridge_iflist *p;
        !          1533:        struct mbuf *mc;
        !          1534:        struct ifnet *dst_if;
        !          1535:        int len = m->m_pkthdr.len, used = 0;
        !          1536:
        !          1537:        splassert(IPL_NET);
        !          1538:
        !          1539:        LIST_FOREACH(p, &sc->sc_iflist, next) {
        !          1540:                /*
        !          1541:                 * Don't retransmit out of the same interface where
        !          1542:                 * the packet was received from.
        !          1543:                 */
        !          1544:                dst_if = p->ifp;
        !          1545:                if (dst_if->if_index == ifp->if_index)
        !          1546:                        continue;
        !          1547:
        !          1548:                if ((p->bif_flags & IFBIF_STP) &&
        !          1549:                    (p->bif_state == BSTP_IFSTATE_DISCARDING))
        !          1550:                        continue;
        !          1551:
        !          1552:                if ((p->bif_flags & IFBIF_DISCOVER) == 0 &&
        !          1553:                    (m->m_flags & (M_BCAST | M_MCAST)) == 0)
        !          1554:                        continue;
        !          1555:
        !          1556:                if ((dst_if->if_flags & IFF_RUNNING) == 0)
        !          1557:                        continue;
        !          1558:
        !          1559: #ifdef ALTQ
        !          1560:                if (ALTQ_IS_ENABLED(&dst_if->if_snd) == 0)
        !          1561: #endif
        !          1562:                if (IF_QFULL(&dst_if->if_snd)) {
        !          1563:                        IF_DROP(&dst_if->if_snd);
        !          1564:                        sc->sc_if.if_oerrors++;
        !          1565:                        continue;
        !          1566:                }
        !          1567:
        !          1568:                /* Drop non-IP frames if the appropriate flag is set. */
        !          1569:                if (p->bif_flags & IFBIF_BLOCKNONIP &&
        !          1570:                    bridge_blocknonip(eh, m))
        !          1571:                        continue;
        !          1572:
        !          1573:                if (bridge_filterrule(&p->bif_brlout, eh, m) == BRL_ACTION_BLOCK)
        !          1574:                        continue;
        !          1575:
        !          1576:                /* If last one, reuse the passed-in mbuf */
        !          1577:                if (LIST_NEXT(p, next) == LIST_END(&sc->sc_iflist)) {
        !          1578:                        mc = m;
        !          1579:                        used = 1;
        !          1580:                } else {
        !          1581:                        struct mbuf *m1, *m2, *mx;
        !          1582:
        !          1583:                        m1 = m_copym2(m, 0, ETHER_HDR_LEN,
        !          1584:                            M_DONTWAIT);
        !          1585:                        if (m1 == NULL) {
        !          1586:                                sc->sc_if.if_oerrors++;
        !          1587:                                continue;
        !          1588:                        }
        !          1589:                        m2 = m_copym2(m, ETHER_HDR_LEN,
        !          1590:                            M_COPYALL, M_DONTWAIT);
        !          1591:                        if (m2 == NULL) {
        !          1592:                                m_freem(m1);
        !          1593:                                sc->sc_if.if_oerrors++;
        !          1594:                                continue;
        !          1595:                        }
        !          1596:
        !          1597:                        for (mx = m1; mx->m_next != NULL; mx = mx->m_next)
        !          1598:                                /*EMPTY*/;
        !          1599:                        mx->m_next = m2;
        !          1600:
        !          1601:                        if (m1->m_flags & M_PKTHDR) {
        !          1602:                                int len = 0;
        !          1603:
        !          1604:                                for (mx = m1; mx != NULL; mx = mx->m_next)
        !          1605:                                        len += mx->m_len;
        !          1606:                                m1->m_pkthdr.len = len;
        !          1607:                        }
        !          1608:                        mc = m1;
        !          1609:                }
        !          1610:
        !          1611: #if NPF > 0
        !          1612:                mc = bridge_filter(sc, BRIDGE_OUT, dst_if, eh, mc);
        !          1613:                if (mc == NULL)
        !          1614:                        continue;
        !          1615: #endif
        !          1616:
        !          1617:                if ((len - ETHER_HDR_LEN) > dst_if->if_mtu)
        !          1618:                        bridge_fragment(sc, dst_if, eh, mc);
        !          1619:                else {
        !          1620:                        bridge_ifenqueue(sc, dst_if, mc);
        !          1621:                }
        !          1622:        }
        !          1623:
        !          1624:        if (!used)
        !          1625:                m_freem(m);
        !          1626: }
        !          1627:
        !          1628: void
        !          1629: bridge_span(struct bridge_softc *sc, struct ether_header *eh,
        !          1630:     struct mbuf *morig)
        !          1631: {
        !          1632:        struct bridge_iflist *p;
        !          1633:        struct ifnet *ifp;
        !          1634:        struct mbuf *mc, *m;
        !          1635:        int error;
        !          1636:
        !          1637:        if (LIST_EMPTY(&sc->sc_spanlist))
        !          1638:                return;
        !          1639:
        !          1640:        m = m_copym2(morig, 0, M_COPYALL, M_NOWAIT);
        !          1641:        if (m == NULL)
        !          1642:                return;
        !          1643:        if (eh != NULL) {
        !          1644:                M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
        !          1645:                if (m == NULL)
        !          1646:                        return;
        !          1647:                bcopy(eh, mtod(m, caddr_t), ETHER_HDR_LEN);
        !          1648:        }
        !          1649:
        !          1650:        LIST_FOREACH(p, &sc->sc_spanlist, next) {
        !          1651:                ifp = p->ifp;
        !          1652:
        !          1653:                if ((ifp->if_flags & IFF_RUNNING) == 0)
        !          1654:                        continue;
        !          1655:
        !          1656: #ifdef ALTQ
        !          1657:                if (ALTQ_IS_ENABLED(&ifp->if_snd) == 0)
        !          1658: #endif
        !          1659:                        if (IF_QFULL(&ifp->if_snd)) {
        !          1660:                                IF_DROP(&ifp->if_snd);
        !          1661:                                sc->sc_if.if_oerrors++;
        !          1662:                                continue;
        !          1663:                        }
        !          1664:
        !          1665:                mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
        !          1666:                if (mc == NULL) {
        !          1667:                        sc->sc_if.if_oerrors++;
        !          1668:                        continue;
        !          1669:                }
        !          1670:
        !          1671:                error = bridge_ifenqueue(sc, ifp, mc);
        !          1672:                if (error)
        !          1673:                        continue;
        !          1674:        }
        !          1675:        m_freem(m);
        !          1676: }
        !          1677:
        !          1678: struct ifnet *
        !          1679: bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
        !          1680:     struct ifnet *ifp, int setflags, u_int8_t flags)
        !          1681: {
        !          1682:        struct bridge_rtnode *p, *q;
        !          1683:        u_int32_t h;
        !          1684:        int dir;
        !          1685:
        !          1686:        h = bridge_hash(sc, ea);
        !          1687:        p = LIST_FIRST(&sc->sc_rts[h]);
        !          1688:        if (p == LIST_END(&sc->sc_rts[h])) {
        !          1689:                if (sc->sc_brtcnt >= sc->sc_brtmax)
        !          1690:                        goto done;
        !          1691:                p = (struct bridge_rtnode *)malloc(
        !          1692:                    sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
        !          1693:                if (p == NULL)
        !          1694:                        goto done;
        !          1695:
        !          1696:                bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
        !          1697:                p->brt_if = ifp;
        !          1698:                p->brt_age = 1;
        !          1699:
        !          1700:                if (setflags)
        !          1701:                        p->brt_flags = flags;
        !          1702:                else
        !          1703:                        p->brt_flags = IFBAF_DYNAMIC;
        !          1704:
        !          1705:                LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
        !          1706:                sc->sc_brtcnt++;
        !          1707:                goto want;
        !          1708:        }
        !          1709:
        !          1710:        do {
        !          1711:                q = p;
        !          1712:                p = LIST_NEXT(p, brt_next);
        !          1713:
        !          1714:                dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
        !          1715:                if (dir == 0) {
        !          1716:                        if (setflags) {
        !          1717:                                q->brt_if = ifp;
        !          1718:                                q->brt_flags = flags;
        !          1719:                        } else if (!(q->brt_flags & IFBAF_STATIC))
        !          1720:                                q->brt_if = ifp;
        !          1721:
        !          1722:                        if (q->brt_if == ifp)
        !          1723:                                q->brt_age = 1;
        !          1724:                        ifp = q->brt_if;
        !          1725:                        goto want;
        !          1726:                }
        !          1727:
        !          1728:                if (dir > 0) {
        !          1729:                        if (sc->sc_brtcnt >= sc->sc_brtmax)
        !          1730:                                goto done;
        !          1731:                        p = (struct bridge_rtnode *)malloc(
        !          1732:                            sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
        !          1733:                        if (p == NULL)
        !          1734:                                goto done;
        !          1735:
        !          1736:                        bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
        !          1737:                        p->brt_if = ifp;
        !          1738:                        p->brt_age = 1;
        !          1739:
        !          1740:                        if (setflags)
        !          1741:                                p->brt_flags = flags;
        !          1742:                        else
        !          1743:                                p->brt_flags = IFBAF_DYNAMIC;
        !          1744:
        !          1745:                        LIST_INSERT_BEFORE(q, p, brt_next);
        !          1746:                        sc->sc_brtcnt++;
        !          1747:                        goto want;
        !          1748:                }
        !          1749:
        !          1750:                if (p == LIST_END(&sc->sc_rts[h])) {
        !          1751:                        if (sc->sc_brtcnt >= sc->sc_brtmax)
        !          1752:                                goto done;
        !          1753:                        p = (struct bridge_rtnode *)malloc(
        !          1754:                            sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
        !          1755:                        if (p == NULL)
        !          1756:                                goto done;
        !          1757:
        !          1758:                        bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
        !          1759:                        p->brt_if = ifp;
        !          1760:                        p->brt_age = 1;
        !          1761:
        !          1762:                        if (setflags)
        !          1763:                                p->brt_flags = flags;
        !          1764:                        else
        !          1765:                                p->brt_flags = IFBAF_DYNAMIC;
        !          1766:                        LIST_INSERT_AFTER(q, p, brt_next);
        !          1767:                        sc->sc_brtcnt++;
        !          1768:                        goto want;
        !          1769:                }
        !          1770:        } while (p != LIST_END(&sc->sc_rts[h]));
        !          1771:
        !          1772: done:
        !          1773:        ifp = NULL;
        !          1774: want:
        !          1775:        return (ifp);
        !          1776: }
        !          1777:
        !          1778: struct ifnet *
        !          1779: bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
        !          1780: {
        !          1781:        struct bridge_rtnode *p;
        !          1782:        u_int32_t h;
        !          1783:        int dir;
        !          1784:
        !          1785:        h = bridge_hash(sc, ea);
        !          1786:        LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
        !          1787:                dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
        !          1788:                if (dir == 0)
        !          1789:                        return (p->brt_if);
        !          1790:                if (dir > 0)
        !          1791:                        goto fail;
        !          1792:        }
        !          1793: fail:
        !          1794:        return (NULL);
        !          1795: }
        !          1796:
        !          1797: /*
        !          1798:  * The following hash function is adapted from 'Hash Functions' by Bob Jenkins
        !          1799:  * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
        !          1800:  * "You may use this code any way you wish, private, educational, or
        !          1801:  *  commercial.  It's free."
        !          1802:  */
        !          1803: #define        mix(a,b,c) \
        !          1804:        do {                                            \
        !          1805:                a -= b; a -= c; a ^= (c >> 13);         \
        !          1806:                b -= c; b -= a; b ^= (a << 8);          \
        !          1807:                c -= a; c -= b; c ^= (b >> 13);         \
        !          1808:                a -= b; a -= c; a ^= (c >> 12);         \
        !          1809:                b -= c; b -= a; b ^= (a << 16);         \
        !          1810:                c -= a; c -= b; c ^= (b >> 5);          \
        !          1811:                a -= b; a -= c; a ^= (c >> 3);          \
        !          1812:                b -= c; b -= a; b ^= (a << 10);         \
        !          1813:                c -= a; c -= b; c ^= (b >> 15);         \
        !          1814:        } while (0)
        !          1815:
        !          1816: u_int32_t
        !          1817: bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
        !          1818: {
        !          1819:        u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_hashkey;
        !          1820:
        !          1821:        b += addr->ether_addr_octet[5] << 8;
        !          1822:        b += addr->ether_addr_octet[4];
        !          1823:        a += addr->ether_addr_octet[3] << 24;
        !          1824:        a += addr->ether_addr_octet[2] << 16;
        !          1825:        a += addr->ether_addr_octet[1] << 8;
        !          1826:        a += addr->ether_addr_octet[0];
        !          1827:
        !          1828:        mix(a, b, c);
        !          1829:        return (c & BRIDGE_RTABLE_MASK);
        !          1830: }
        !          1831:
        !          1832: /*
        !          1833:  * Trim the routing table so that we've got a number of routes
        !          1834:  * less than or equal to the maximum.
        !          1835:  */
        !          1836: void
        !          1837: bridge_rttrim(struct bridge_softc *sc)
        !          1838: {
        !          1839:        struct bridge_rtnode *n, *p;
        !          1840:        int i;
        !          1841:
        !          1842:        /*
        !          1843:         * Make sure we have to trim the address table
        !          1844:         */
        !          1845:        if (sc->sc_brtcnt <= sc->sc_brtmax)
        !          1846:                return;
        !          1847:
        !          1848:        /*
        !          1849:         * Force an aging cycle, this might trim enough addresses.
        !          1850:         */
        !          1851:        bridge_rtage(sc);
        !          1852:
        !          1853:        if (sc->sc_brtcnt <= sc->sc_brtmax)
        !          1854:                return;
        !          1855:
        !          1856:        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        !          1857:                n = LIST_FIRST(&sc->sc_rts[i]);
        !          1858:                while (n != LIST_END(&sc->sc_rts[i])) {
        !          1859:                        p = LIST_NEXT(n, brt_next);
        !          1860:                        if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
        !          1861:                                LIST_REMOVE(n, brt_next);
        !          1862:                                sc->sc_brtcnt--;
        !          1863:                                free(n, M_DEVBUF);
        !          1864:                                n = p;
        !          1865:                                if (sc->sc_brtcnt <= sc->sc_brtmax)
        !          1866:                                        return;
        !          1867:                        }
        !          1868:                }
        !          1869:        }
        !          1870: }
        !          1871:
        !          1872: void
        !          1873: bridge_timer(void *vsc)
        !          1874: {
        !          1875:        struct bridge_softc *sc = vsc;
        !          1876:        int s;
        !          1877:
        !          1878:        s = splsoftnet();
        !          1879:        bridge_rtage(sc);
        !          1880:        splx(s);
        !          1881: }
        !          1882:
        !          1883: /*
        !          1884:  * Perform an aging cycle
        !          1885:  */
        !          1886: void
        !          1887: bridge_rtage(struct bridge_softc *sc)
        !          1888: {
        !          1889:        struct bridge_rtnode *n, *p;
        !          1890:        int i;
        !          1891:
        !          1892:        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        !          1893:                n = LIST_FIRST(&sc->sc_rts[i]);
        !          1894:                while (n != LIST_END(&sc->sc_rts[i])) {
        !          1895:                        if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
        !          1896:                                n->brt_age = !n->brt_age;
        !          1897:                                if (n->brt_age)
        !          1898:                                        n->brt_age = 0;
        !          1899:                                n = LIST_NEXT(n, brt_next);
        !          1900:                        } else if (n->brt_age) {
        !          1901:                                n->brt_age = 0;
        !          1902:                                n = LIST_NEXT(n, brt_next);
        !          1903:                        } else {
        !          1904:                                p = LIST_NEXT(n, brt_next);
        !          1905:                                LIST_REMOVE(n, brt_next);
        !          1906:                                sc->sc_brtcnt--;
        !          1907:                                free(n, M_DEVBUF);
        !          1908:                                n = p;
        !          1909:                        }
        !          1910:                }
        !          1911:        }
        !          1912:
        !          1913:        if (sc->sc_brttimeout != 0)
        !          1914:                timeout_add(&sc->sc_brtimeout, sc->sc_brttimeout * hz);
        !          1915: }
        !          1916:
        !          1917: void
        !          1918: bridge_rtagenode(struct ifnet *ifp, int age)
        !          1919: {
        !          1920:        struct bridge_softc *sc = (struct bridge_softc *)ifp->if_bridge;
        !          1921:        struct bridge_rtnode *n;
        !          1922:        int i;
        !          1923:
        !          1924:        if (sc == NULL)
        !          1925:                return;
        !          1926:
        !          1927:        /*
        !          1928:         * If the age is zero then flush, otherwise set all the expiry times to
        !          1929:         * age for the interface
        !          1930:         */
        !          1931:        if (age == 0)
        !          1932:                bridge_rtdelete(sc, ifp, 1);
        !          1933:        else {
        !          1934:                for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        !          1935:                        n = LIST_FIRST(&sc->sc_rts[i]);
        !          1936:                        while (n != LIST_END(&sc->sc_rts[i])) {
        !          1937:                                /* Cap the expiry time to 'age' */
        !          1938:                                if (n->brt_if == ifp &&
        !          1939:                                    n->brt_age > time_uptime + age &&
        !          1940:                                    (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
        !          1941:                                        n->brt_age = time_uptime + age;
        !          1942:                        }
        !          1943:                }
        !          1944:        }
        !          1945: }
        !          1946:
        !          1947:
        !          1948:
        !          1949: /*
        !          1950:  * Remove all dynamic addresses from the cache
        !          1951:  */
        !          1952: int
        !          1953: bridge_rtflush(struct bridge_softc *sc, int full)
        !          1954: {
        !          1955:        int i;
        !          1956:        struct bridge_rtnode *p, *n;
        !          1957:
        !          1958:        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        !          1959:                n = LIST_FIRST(&sc->sc_rts[i]);
        !          1960:                while (n != LIST_END(&sc->sc_rts[i])) {
        !          1961:                        if (full ||
        !          1962:                            (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
        !          1963:                                p = LIST_NEXT(n, brt_next);
        !          1964:                                LIST_REMOVE(n, brt_next);
        !          1965:                                sc->sc_brtcnt--;
        !          1966:                                free(n, M_DEVBUF);
        !          1967:                                n = p;
        !          1968:                        } else
        !          1969:                                n = LIST_NEXT(n, brt_next);
        !          1970:                }
        !          1971:        }
        !          1972:
        !          1973:        return (0);
        !          1974: }
        !          1975:
        !          1976: /*
        !          1977:  * Remove an address from the cache
        !          1978:  */
        !          1979: int
        !          1980: bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
        !          1981: {
        !          1982:        int h;
        !          1983:        struct bridge_rtnode *p;
        !          1984:
        !          1985:        h = bridge_hash(sc, ea);
        !          1986:        LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
        !          1987:                if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
        !          1988:                        LIST_REMOVE(p, brt_next);
        !          1989:                        sc->sc_brtcnt--;
        !          1990:                        free(p, M_DEVBUF);
        !          1991:                        return (0);
        !          1992:                }
        !          1993:        }
        !          1994:
        !          1995:        return (ENOENT);
        !          1996: }
        !          1997: /*
        !          1998:  * Delete routes to a specific interface member.
        !          1999:  */
        !          2000: void
        !          2001: bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
        !          2002: {
        !          2003:        int i;
        !          2004:        struct bridge_rtnode *n, *p;
        !          2005:
        !          2006:        /*
        !          2007:         * Loop through all of the hash buckets and traverse each
        !          2008:         * chain looking for routes to this interface.
        !          2009:         */
        !          2010:        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        !          2011:                n = LIST_FIRST(&sc->sc_rts[i]);
        !          2012:                while (n != LIST_END(&sc->sc_rts[i])) {
        !          2013:                        if (n->brt_if != ifp) {
        !          2014:                                /* Not ours */
        !          2015:                                n = LIST_NEXT(n, brt_next);
        !          2016:                                continue;
        !          2017:                        }
        !          2018:                        if (dynonly &&
        !          2019:                            (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
        !          2020:                                /* only deleting dynamics */
        !          2021:                                n = LIST_NEXT(n, brt_next);
        !          2022:                                continue;
        !          2023:                        }
        !          2024:                        p = LIST_NEXT(n, brt_next);
        !          2025:                        LIST_REMOVE(n, brt_next);
        !          2026:                        sc->sc_brtcnt--;
        !          2027:                        free(n, M_DEVBUF);
        !          2028:                        n = p;
        !          2029:                }
        !          2030:        }
        !          2031: }
        !          2032:
        !          2033: /*
        !          2034:  * Gather all of the routes for this interface.
        !          2035:  */
        !          2036: int
        !          2037: bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
        !          2038: {
        !          2039:        int i, error = 0, onlycnt = 0;
        !          2040:        u_int32_t cnt = 0;
        !          2041:        struct bridge_rtnode *n;
        !          2042:        struct ifbareq bareq;
        !          2043:
        !          2044:        if (baconf->ifbac_len == 0)
        !          2045:                onlycnt = 1;
        !          2046:
        !          2047:        for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        !          2048:                LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
        !          2049:                        if (!onlycnt) {
        !          2050:                                if (baconf->ifbac_len < sizeof(struct ifbareq))
        !          2051:                                        goto done;
        !          2052:                                bcopy(sc->sc_if.if_xname, bareq.ifba_name,
        !          2053:                                    sizeof(bareq.ifba_name));
        !          2054:                                bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
        !          2055:                                    sizeof(bareq.ifba_ifsname));
        !          2056:                                bcopy(&n->brt_addr, &bareq.ifba_dst,
        !          2057:                                    sizeof(bareq.ifba_dst));
        !          2058:                                bareq.ifba_age = n->brt_age;
        !          2059:                                bareq.ifba_flags = n->brt_flags;
        !          2060:                                error = copyout((caddr_t)&bareq,
        !          2061:                                    (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
        !          2062:                                if (error)
        !          2063:                                        goto done;
        !          2064:                                baconf->ifbac_len -= sizeof(struct ifbareq);
        !          2065:                        }
        !          2066:                        cnt++;
        !          2067:                }
        !          2068:        }
        !          2069: done:
        !          2070:        baconf->ifbac_len = cnt * sizeof(struct ifbareq);
        !          2071:        return (error);
        !          2072: }
        !          2073:
        !          2074: /*
        !          2075:  * Block non-ip frames:
        !          2076:  * Returns 0 if frame is ip, and 1 if it should be dropped.
        !          2077:  */
        !          2078: int
        !          2079: bridge_blocknonip(struct ether_header *eh, struct mbuf *m)
        !          2080: {
        !          2081:        struct llc llc;
        !          2082:        u_int16_t etype;
        !          2083:
        !          2084:        if (m->m_pkthdr.len < ETHER_HDR_LEN)
        !          2085:                return (1);
        !          2086:
        !          2087:        etype = ntohs(eh->ether_type);
        !          2088:        switch (etype) {
        !          2089:        case ETHERTYPE_ARP:
        !          2090:        case ETHERTYPE_REVARP:
        !          2091:        case ETHERTYPE_IP:
        !          2092:        case ETHERTYPE_IPV6:
        !          2093:                return (0);
        !          2094:        }
        !          2095:
        !          2096:        if (etype > ETHERMTU)
        !          2097:                return (1);
        !          2098:
        !          2099:        if (m->m_pkthdr.len <
        !          2100:            (ETHER_HDR_LEN + LLC_SNAPFRAMELEN))
        !          2101:                return (1);
        !          2102:
        !          2103:        m_copydata(m, ETHER_HDR_LEN, LLC_SNAPFRAMELEN,
        !          2104:            (caddr_t)&llc);
        !          2105:
        !          2106:        etype = ntohs(llc.llc_snap.ether_type);
        !          2107:        if (llc.llc_dsap == LLC_SNAP_LSAP &&
        !          2108:            llc.llc_ssap == LLC_SNAP_LSAP &&
        !          2109:            llc.llc_control == LLC_UI &&
        !          2110:            llc.llc_snap.org_code[0] == 0 &&
        !          2111:            llc.llc_snap.org_code[1] == 0 &&
        !          2112:            llc.llc_snap.org_code[2] == 0 &&
        !          2113:            (etype == ETHERTYPE_ARP || etype == ETHERTYPE_REVARP ||
        !          2114:            etype == ETHERTYPE_IP || etype == ETHERTYPE_IPV6)) {
        !          2115:                return (0);
        !          2116:        }
        !          2117:
        !          2118:        return (1);
        !          2119: }
        !          2120:
        !          2121: u_int8_t
        !          2122: bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
        !          2123: {
        !          2124:        struct brl_node *n;
        !          2125:        u_int8_t flags;
        !          2126:
        !          2127:        SIMPLEQ_FOREACH(n, h, brl_next) {
        !          2128:                flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
        !          2129:                if (flags == 0)
        !          2130:                        goto return_action;
        !          2131:                if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
        !          2132:                        if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
        !          2133:                                continue;
        !          2134:                        if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
        !          2135:                                continue;
        !          2136:                        goto return_action;
        !          2137:                }
        !          2138:                if (flags == BRL_FLAG_SRCVALID) {
        !          2139:                        if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
        !          2140:                                continue;
        !          2141:                        goto return_action;
        !          2142:                }
        !          2143:                if (flags == BRL_FLAG_DSTVALID) {
        !          2144:                        if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
        !          2145:                                continue;
        !          2146:                        goto return_action;
        !          2147:                }
        !          2148:        }
        !          2149:        return (BRL_ACTION_PASS);
        !          2150:
        !          2151: return_action:
        !          2152: #if NPF > 0
        !          2153:        pf_tag_packet(m, n->brl_tag, -1);
        !          2154: #endif
        !          2155:        return (n->brl_action);
        !          2156: }
        !          2157:
        !          2158: int
        !          2159: bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
        !          2160: {
        !          2161:        struct brl_node *n;
        !          2162:
        !          2163:        n = (struct brl_node *)malloc(sizeof(struct brl_node), M_DEVBUF, M_NOWAIT);
        !          2164:        if (n == NULL)
        !          2165:                return (ENOMEM);
        !          2166:        bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
        !          2167:        bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
        !          2168:        n->brl_action = req->ifbr_action;
        !          2169:        n->brl_flags = req->ifbr_flags;
        !          2170: #if NPF > 0
        !          2171:        if (req->ifbr_tagname[0])
        !          2172:                n->brl_tag = pf_tagname2tag(req->ifbr_tagname);
        !          2173:        else
        !          2174:                n->brl_tag = 0;
        !          2175: #endif
        !          2176:        if (out) {
        !          2177:                n->brl_flags &= ~BRL_FLAG_IN;
        !          2178:                n->brl_flags |= BRL_FLAG_OUT;
        !          2179:                SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
        !          2180:        } else {
        !          2181:                n->brl_flags &= ~BRL_FLAG_OUT;
        !          2182:                n->brl_flags |= BRL_FLAG_IN;
        !          2183:                SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
        !          2184:        }
        !          2185:        return (0);
        !          2186: }
        !          2187:
        !          2188: int
        !          2189: bridge_flushrule(struct bridge_iflist *bif)
        !          2190: {
        !          2191:        struct brl_node *p;
        !          2192:
        !          2193:        while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
        !          2194:                p = SIMPLEQ_FIRST(&bif->bif_brlin);
        !          2195:                SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
        !          2196: #if NPF > 0
        !          2197:                pf_tag_unref(p->brl_tag);
        !          2198: #endif
        !          2199:                free(p, M_DEVBUF);
        !          2200:        }
        !          2201:        while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
        !          2202:                p = SIMPLEQ_FIRST(&bif->bif_brlout);
        !          2203:                SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
        !          2204: #if NPF > 0
        !          2205:                pf_tag_unref(p->brl_tag);
        !          2206: #endif
        !          2207:                free(p, M_DEVBUF);
        !          2208:        }
        !          2209:        return (0);
        !          2210: }
        !          2211:
        !          2212: #ifdef IPSEC
        !          2213: int
        !          2214: bridge_ipsec(struct bridge_softc *sc, struct ifnet *ifp,
        !          2215:     struct ether_header *eh, int hassnap, struct llc *llc,
        !          2216:     int dir, int af, int hlen, struct mbuf *m)
        !          2217: {
        !          2218:        union sockaddr_union dst;
        !          2219:        struct timeval tv;
        !          2220:        struct tdb *tdb;
        !          2221:        u_int32_t spi;
        !          2222:        u_int16_t cpi;
        !          2223:        int error, off, s;
        !          2224:        u_int8_t proto = 0;
        !          2225: #ifdef INET
        !          2226:        struct ip *ip;
        !          2227: #endif /* INET */
        !          2228: #ifdef INET6
        !          2229:        struct ip6_hdr *ip6;
        !          2230: #endif /* INET6 */
        !          2231:
        !          2232:        if (dir == BRIDGE_IN) {
        !          2233:                switch (af) {
        !          2234: #ifdef INET
        !          2235:                case AF_INET:
        !          2236:                        if (m->m_pkthdr.len - hlen < 2 * sizeof(u_int32_t))
        !          2237:                                break;
        !          2238:
        !          2239:                        ip = mtod(m, struct ip *);
        !          2240:                        proto = ip->ip_p;
        !          2241:                        off = offsetof(struct ip, ip_p);
        !          2242:
        !          2243:                        if (proto != IPPROTO_ESP && proto != IPPROTO_AH &&
        !          2244:                            proto != IPPROTO_IPCOMP)
        !          2245:                                goto skiplookup;
        !          2246:
        !          2247:                        bzero(&dst, sizeof(union sockaddr_union));
        !          2248:                        dst.sa.sa_family = AF_INET;
        !          2249:                        dst.sin.sin_len = sizeof(struct sockaddr_in);
        !          2250:                        m_copydata(m, offsetof(struct ip, ip_dst),
        !          2251:                            sizeof(struct in_addr),
        !          2252:                            (caddr_t)&dst.sin.sin_addr);
        !          2253:
        !          2254:                        if (ip->ip_p == IPPROTO_ESP)
        !          2255:                                m_copydata(m, hlen, sizeof(u_int32_t),
        !          2256:                                    (caddr_t)&spi);
        !          2257:                        else if (ip->ip_p == IPPROTO_AH)
        !          2258:                                m_copydata(m, hlen + sizeof(u_int32_t),
        !          2259:                                    sizeof(u_int32_t), (caddr_t)&spi);
        !          2260:                        else if (ip->ip_p == IPPROTO_IPCOMP) {
        !          2261:                                m_copydata(m, hlen + sizeof(u_int16_t),
        !          2262:                                    sizeof(u_int16_t), (caddr_t)&cpi);
        !          2263:                                spi = ntohl(htons(cpi));
        !          2264:                        }
        !          2265:                        break;
        !          2266: #endif /* INET */
        !          2267: #ifdef INET6
        !          2268:                case AF_INET6:
        !          2269:                        if (m->m_pkthdr.len - hlen < 2 * sizeof(u_int32_t))
        !          2270:                                break;
        !          2271:
        !          2272:                        ip6 = mtod(m, struct ip6_hdr *);
        !          2273:
        !          2274:                        /* XXX We should chase down the header chain */
        !          2275:                        proto = ip6->ip6_nxt;
        !          2276:                        off = offsetof(struct ip6_hdr, ip6_nxt);
        !          2277:
        !          2278:                        if (proto != IPPROTO_ESP && proto != IPPROTO_AH &&
        !          2279:                            proto != IPPROTO_IPCOMP)
        !          2280:                                goto skiplookup;
        !          2281:
        !          2282:                        bzero(&dst, sizeof(union sockaddr_union));
        !          2283:                        dst.sa.sa_family = AF_INET6;
        !          2284:                        dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
        !          2285:                        m_copydata(m, offsetof(struct ip6_hdr, ip6_nxt),
        !          2286:                            sizeof(struct in6_addr),
        !          2287:                            (caddr_t)&dst.sin6.sin6_addr);
        !          2288:
        !          2289:                        if (proto == IPPROTO_ESP)
        !          2290:                                m_copydata(m, hlen, sizeof(u_int32_t),
        !          2291:                                    (caddr_t)&spi);
        !          2292:                        else if (proto == IPPROTO_AH)
        !          2293:                                m_copydata(m, hlen + sizeof(u_int32_t),
        !          2294:                                    sizeof(u_int32_t), (caddr_t)&spi);
        !          2295:                        else if (proto == IPPROTO_IPCOMP) {
        !          2296:                                m_copydata(m, hlen + sizeof(u_int16_t),
        !          2297:                                    sizeof(u_int16_t), (caddr_t)&cpi);
        !          2298:                                spi = ntohl(htons(cpi));
        !          2299:                        }
        !          2300:                        break;
        !          2301: #endif /* INET6 */
        !          2302:                default:
        !          2303:                        return (0);
        !          2304:                }
        !          2305:
        !          2306:                if (proto == 0)
        !          2307:                        goto skiplookup;
        !          2308:
        !          2309:                s = spltdb();
        !          2310:
        !          2311:                tdb = gettdb(spi, &dst, proto);
        !          2312:                if (tdb != NULL && (tdb->tdb_flags & TDBF_INVALID) == 0 &&
        !          2313:                    tdb->tdb_xform != NULL) {
        !          2314:                        if (tdb->tdb_first_use == 0) {
        !          2315:                                tdb->tdb_first_use = time_second;
        !          2316:
        !          2317:                                tv.tv_usec = 0;
        !          2318:
        !          2319:                                /* Check for wrap-around. */
        !          2320:                                if (tdb->tdb_exp_first_use + tdb->tdb_first_use
        !          2321:                                    < tdb->tdb_first_use)
        !          2322:                                        tv.tv_sec = ((unsigned long)-1) / 2;
        !          2323:                                else
        !          2324:                                        tv.tv_sec = tdb->tdb_exp_first_use +
        !          2325:                                            tdb->tdb_first_use;
        !          2326:
        !          2327:                                if (tdb->tdb_flags & TDBF_FIRSTUSE)
        !          2328:                                        timeout_add(&tdb->tdb_first_tmo,
        !          2329:                                            hzto(&tv));
        !          2330:
        !          2331:                                /* Check for wrap-around. */
        !          2332:                                if (tdb->tdb_first_use +
        !          2333:                                    tdb->tdb_soft_first_use
        !          2334:                                    < tdb->tdb_first_use)
        !          2335:                                        tv.tv_sec = ((unsigned long)-1) / 2;
        !          2336:                                else
        !          2337:                                        tv.tv_sec = tdb->tdb_first_use +
        !          2338:                                            tdb->tdb_soft_first_use;
        !          2339:
        !          2340:                                if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
        !          2341:                                        timeout_add(&tdb->tdb_sfirst_tmo,
        !          2342:                                            hzto(&tv));
        !          2343:                        }
        !          2344:
        !          2345:                        (*(tdb->tdb_xform->xf_input))(m, tdb, hlen, off);
        !          2346:                        splx(s);
        !          2347:                        return (1);
        !          2348:                } else {
        !          2349:                        splx(s);
        !          2350:  skiplookup:
        !          2351:                        /* XXX do an input policy lookup */
        !          2352:                        return (0);
        !          2353:                }
        !          2354:        } else { /* Outgoing from the bridge. */
        !          2355:                tdb = ipsp_spd_lookup(m, af, hlen, &error,
        !          2356:                    IPSP_DIRECTION_OUT, NULL, NULL);
        !          2357:                if (tdb != NULL) {
        !          2358:                        /*
        !          2359:                         * We don't need to do loop detection, the
        !          2360:                         * bridge will do that for us.
        !          2361:                         */
        !          2362: #if NPF > 0
        !          2363:                        switch (af) {
        !          2364: #ifdef INET
        !          2365:                        case AF_INET:
        !          2366:                                if (pf_test(dir, &encif[0].sc_if,
        !          2367:                                    &m, NULL) != PF_PASS) {
        !          2368:                                        m_freem(m);
        !          2369:                                        return (1);
        !          2370:                                }
        !          2371:                                break;
        !          2372: #endif /* INET */
        !          2373: #ifdef INET6
        !          2374:                        case AF_INET6:
        !          2375:                                if (pf_test6(dir, &encif[0].sc_if,
        !          2376:                                    &m, NULL) != PF_PASS) {
        !          2377:                                        m_freem(m);
        !          2378:                                        return (1);
        !          2379:                                }
        !          2380:                                break;
        !          2381: #endif /* INET6 */
        !          2382:                        }
        !          2383:                        if (m == NULL)
        !          2384:                                return (1);
        !          2385: #endif /* NPF */
        !          2386:
        !          2387:                        ip = mtod(m, struct ip *);
        !          2388:                        if ((af == AF_INET) &&
        !          2389:                            ip_mtudisc && (ip->ip_off & htons(IP_DF)) &&
        !          2390:                            tdb->tdb_mtu && ntohs(ip->ip_len) > tdb->tdb_mtu &&
        !          2391:                            tdb->tdb_mtutimeout > time_second)
        !          2392:                                bridge_send_icmp_err(sc, ifp, eh, m,
        !          2393:                                    hassnap, llc, tdb->tdb_mtu,
        !          2394:                                    ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG);
        !          2395:                        else
        !          2396:                                error = ipsp_process_packet(m, tdb, af, 0);
        !          2397:                        return (1);
        !          2398:                } else
        !          2399:                        return (0);
        !          2400:        }
        !          2401:
        !          2402:        return (0);
        !          2403: }
        !          2404: #endif /* IPSEC */
        !          2405:
        !          2406: #if NPF > 0
        !          2407: /*
        !          2408:  * Filter IP packets by peeking into the ethernet frame.  This violates
        !          2409:  * the ISO model, but allows us to act as a IP filter at the data link
        !          2410:  * layer.  As a result, most of this code will look familiar to those
        !          2411:  * who've read net/if_ethersubr.c and netinet/ip_input.c
        !          2412:  */
        !          2413: struct mbuf *
        !          2414: bridge_filter(struct bridge_softc *sc, int dir, struct ifnet *ifp,
        !          2415:     struct ether_header *eh, struct mbuf *m)
        !          2416: {
        !          2417:        struct llc llc;
        !          2418:        int hassnap = 0;
        !          2419:        struct ip *ip;
        !          2420:        int hlen;
        !          2421:        u_int16_t etype;
        !          2422:
        !          2423:        etype = ntohs(eh->ether_type);
        !          2424:
        !          2425:        if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6) {
        !          2426:                if (etype > ETHERMTU ||
        !          2427:                    m->m_pkthdr.len < (LLC_SNAPFRAMELEN +
        !          2428:                    ETHER_HDR_LEN))
        !          2429:                        return (m);
        !          2430:
        !          2431:                m_copydata(m, ETHER_HDR_LEN,
        !          2432:                    LLC_SNAPFRAMELEN, (caddr_t)&llc);
        !          2433:
        !          2434:                if (llc.llc_dsap != LLC_SNAP_LSAP ||
        !          2435:                    llc.llc_ssap != LLC_SNAP_LSAP ||
        !          2436:                    llc.llc_control != LLC_UI ||
        !          2437:                    llc.llc_snap.org_code[0] ||
        !          2438:                    llc.llc_snap.org_code[1] ||
        !          2439:                    llc.llc_snap.org_code[2])
        !          2440:                        return (m);
        !          2441:
        !          2442:                etype = ntohs(llc.llc_snap.ether_type);
        !          2443:                if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6)
        !          2444:                        return (m);
        !          2445:                hassnap = 1;
        !          2446:        }
        !          2447:
        !          2448:        m_adj(m, ETHER_HDR_LEN);
        !          2449:        if (hassnap)
        !          2450:                m_adj(m, LLC_SNAPFRAMELEN);
        !          2451:
        !          2452:        switch (etype) {
        !          2453:
        !          2454:        case ETHERTYPE_IP:
        !          2455:                if (m->m_pkthdr.len < sizeof(struct ip))
        !          2456:                        goto dropit;
        !          2457:
        !          2458:                /* Copy minimal header, and drop invalids */
        !          2459:                if (m->m_len < sizeof(struct ip) &&
        !          2460:                    (m = m_pullup(m, sizeof(struct ip))) == NULL) {
        !          2461:                        ipstat.ips_toosmall++;
        !          2462:                        return (NULL);
        !          2463:                }
        !          2464:                ip = mtod(m, struct ip *);
        !          2465:
        !          2466:                if (ip->ip_v != IPVERSION) {
        !          2467:                        ipstat.ips_badvers++;
        !          2468:                        goto dropit;
        !          2469:                }
        !          2470:
        !          2471:                hlen = ip->ip_hl << 2;  /* get whole header length */
        !          2472:                if (hlen < sizeof(struct ip)) {
        !          2473:                        ipstat.ips_badhlen++;
        !          2474:                        goto dropit;
        !          2475:                }
        !          2476:
        !          2477:                if (hlen > m->m_len) {
        !          2478:                        if ((m = m_pullup(m, hlen)) == NULL) {
        !          2479:                                ipstat.ips_badhlen++;
        !          2480:                                return (NULL);
        !          2481:                        }
        !          2482:                        ip = mtod(m, struct ip *);
        !          2483:                }
        !          2484:
        !          2485:                if ((ip->ip_sum = in_cksum(m, hlen)) != 0) {
        !          2486:                        ipstat.ips_badsum++;
        !          2487:                        goto dropit;
        !          2488:                }
        !          2489:
        !          2490:                if (ntohs(ip->ip_len) < hlen)
        !          2491:                        goto dropit;
        !          2492:
        !          2493:                if (m->m_pkthdr.len < ntohs(ip->ip_len))
        !          2494:                        goto dropit;
        !          2495:                if (m->m_pkthdr.len > ntohs(ip->ip_len)) {
        !          2496:                        if (m->m_len == m->m_pkthdr.len) {
        !          2497:                                m->m_len = ntohs(ip->ip_len);
        !          2498:                                m->m_pkthdr.len = ntohs(ip->ip_len);
        !          2499:                        } else
        !          2500:                                m_adj(m, ntohs(ip->ip_len) - m->m_pkthdr.len);
        !          2501:                }
        !          2502:
        !          2503: #ifdef IPSEC
        !          2504:                if ((sc->sc_if.if_flags & IFF_LINK2) == IFF_LINK2 &&
        !          2505:                    bridge_ipsec(sc, ifp, eh, hassnap, &llc,
        !          2506:                    dir, AF_INET, hlen, m))
        !          2507:                        return (NULL);
        !          2508: #endif /* IPSEC */
        !          2509:
        !          2510:                /* Finally, we get to filter the packet! */
        !          2511:                m->m_pkthdr.rcvif = ifp;
        !          2512:                if (pf_test(dir, ifp, &m, eh) != PF_PASS)
        !          2513:                        goto dropit;
        !          2514:                if (m == NULL)
        !          2515:                        goto dropit;
        !          2516:
        !          2517:                /* Rebuild the IP header */
        !          2518:                if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
        !          2519:                        return (NULL);
        !          2520:                if (m->m_len < sizeof(struct ip))
        !          2521:                        goto dropit;
        !          2522:                ip = mtod(m, struct ip *);
        !          2523:                ip->ip_sum = 0;
        !          2524:                ip->ip_sum = in_cksum(m, hlen);
        !          2525:
        !          2526:                break;
        !          2527:
        !          2528: #ifdef INET6
        !          2529:        case ETHERTYPE_IPV6: {
        !          2530:                struct ip6_hdr *ip6;
        !          2531:
        !          2532:                if (m->m_len < sizeof(struct ip6_hdr)) {
        !          2533:                        if ((m = m_pullup(m, sizeof(struct ip6_hdr)))
        !          2534:                            == NULL) {
        !          2535:                                ip6stat.ip6s_toosmall++;
        !          2536:                                return (NULL);
        !          2537:                        }
        !          2538:                }
        !          2539:
        !          2540:                ip6 = mtod(m, struct ip6_hdr *);
        !          2541:
        !          2542:                if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
        !          2543:                        ip6stat.ip6s_badvers++;
        !          2544:                        in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
        !          2545:                        goto dropit;
        !          2546:                }
        !          2547:
        !          2548: #ifdef IPSEC
        !          2549:                hlen = sizeof(struct ip6_hdr);
        !          2550:
        !          2551:                if ((sc->sc_if.if_flags & IFF_LINK2) == IFF_LINK2 &&
        !          2552:                    bridge_ipsec(sc, ifp, eh, hassnap, &llc,
        !          2553:                    dir, AF_INET6, hlen, m))
        !          2554:                        return (NULL);
        !          2555: #endif /* IPSEC */
        !          2556:
        !          2557:                if (pf_test6(dir, ifp, &m, eh) != PF_PASS)
        !          2558:                        goto dropit;
        !          2559:                if (m == NULL)
        !          2560:                        return (NULL);
        !          2561:
        !          2562:                break;
        !          2563:        }
        !          2564: #endif /* INET6 */
        !          2565:
        !          2566:        default:
        !          2567:                goto dropit;
        !          2568:                break;
        !          2569:        }
        !          2570:
        !          2571:        /* Reattach SNAP header */
        !          2572:        if (hassnap) {
        !          2573:                M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
        !          2574:                if (m == NULL)
        !          2575:                        goto dropit;
        !          2576:                bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
        !          2577:        }
        !          2578:
        !          2579:        /* Reattach ethernet header */
        !          2580:        M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
        !          2581:        if (m == NULL)
        !          2582:                goto dropit;
        !          2583:        bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
        !          2584:
        !          2585:        return (m);
        !          2586:
        !          2587: dropit:
        !          2588:        if (m != NULL)
        !          2589:                m_freem(m);
        !          2590:        return (NULL);
        !          2591: }
        !          2592: #endif /* NPF > 0 */
        !          2593:
        !          2594: void
        !          2595: bridge_fragment(struct bridge_softc *sc, struct ifnet *ifp,
        !          2596:     struct ether_header *eh, struct mbuf *m)
        !          2597: {
        !          2598:        struct llc llc;
        !          2599:        struct mbuf *m0;
        !          2600:        int s, len, error = 0;
        !          2601:        int hassnap = 0;
        !          2602: #ifdef INET
        !          2603:        u_int16_t etype;
        !          2604:        struct ip *ip;
        !          2605: #endif
        !          2606:
        !          2607: #ifndef INET
        !          2608:        goto dropit;
        !          2609: #else
        !          2610:        etype = ntohs(eh->ether_type);
        !          2611:        if (etype == ETHERTYPE_VLAN &&
        !          2612:            (ifp->if_capabilities & IFCAP_VLAN_MTU) &&
        !          2613:            ((m->m_pkthdr.len - sizeof(struct ether_vlan_header)) <=
        !          2614:            ifp->if_mtu)) {
        !          2615:                s = splnet();
        !          2616:                bridge_ifenqueue(sc, ifp, m);
        !          2617:                splx(s);
        !          2618:                return;
        !          2619:        }
        !          2620:        if (etype != ETHERTYPE_IP) {
        !          2621:                if (etype > ETHERMTU ||
        !          2622:                    m->m_pkthdr.len < (LLC_SNAPFRAMELEN +
        !          2623:                    ETHER_HDR_LEN))
        !          2624:                        goto dropit;
        !          2625:
        !          2626:                m_copydata(m, ETHER_HDR_LEN,
        !          2627:                    LLC_SNAPFRAMELEN, (caddr_t)&llc);
        !          2628:
        !          2629:                if (llc.llc_dsap != LLC_SNAP_LSAP ||
        !          2630:                    llc.llc_ssap != LLC_SNAP_LSAP ||
        !          2631:                    llc.llc_control != LLC_UI ||
        !          2632:                    llc.llc_snap.org_code[0] ||
        !          2633:                    llc.llc_snap.org_code[1] ||
        !          2634:                    llc.llc_snap.org_code[2] ||
        !          2635:                    llc.llc_snap.ether_type != htons(ETHERTYPE_IP))
        !          2636:                        goto dropit;
        !          2637:
        !          2638:                hassnap = 1;
        !          2639:        }
        !          2640:
        !          2641:        m_adj(m, ETHER_HDR_LEN);
        !          2642:        if (hassnap)
        !          2643:                m_adj(m, LLC_SNAPFRAMELEN);
        !          2644:
        !          2645:        if (m->m_len < sizeof(struct ip) &&
        !          2646:            (m = m_pullup(m, sizeof(struct ip))) == NULL)
        !          2647:                goto dropit;
        !          2648:        ip = mtod(m, struct ip *);
        !          2649:
        !          2650:        /* Respect IP_DF, return a ICMP_UNREACH_NEEDFRAG. */
        !          2651:        if (ip->ip_off & htons(IP_DF)) {
        !          2652:                bridge_send_icmp_err(sc, ifp, eh, m, hassnap, &llc,
        !          2653:                    ifp->if_mtu, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG);
        !          2654:                return;
        !          2655:        }
        !          2656:
        !          2657:        error = ip_fragment(m, ifp, ifp->if_mtu);
        !          2658:        if (error) {
        !          2659:                m = NULL;
        !          2660:                goto dropit;
        !          2661:        }
        !          2662:
        !          2663:        for (; m; m = m0) {
        !          2664:                m0 = m->m_nextpkt;
        !          2665:                m->m_nextpkt = NULL;
        !          2666:                if (error == 0) {
        !          2667:                        if (hassnap) {
        !          2668:                                M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
        !          2669:                                if (m == NULL) {
        !          2670:                                        error = ENOBUFS;
        !          2671:                                        continue;
        !          2672:                                }
        !          2673:                                bcopy(&llc, mtod(m, caddr_t),
        !          2674:                                    LLC_SNAPFRAMELEN);
        !          2675:                        }
        !          2676:                        M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
        !          2677:                        if (m == NULL) {
        !          2678:                                error = ENOBUFS;
        !          2679:                                continue;
        !          2680:                        }
        !          2681:                        len = m->m_pkthdr.len;
        !          2682:                        bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
        !          2683:                        s = splnet();
        !          2684:                        error = bridge_ifenqueue(sc, ifp, m);
        !          2685:                        if (error) {
        !          2686:                                splx(s);
        !          2687:                                continue;
        !          2688:                        }
        !          2689:                        splx(s);
        !          2690:                } else
        !          2691:                        m_freem(m);
        !          2692:        }
        !          2693:
        !          2694:        if (error == 0)
        !          2695:                ipstat.ips_fragmented++;
        !          2696:
        !          2697:        return;
        !          2698: #endif /* INET */
        !          2699:  dropit:
        !          2700:        if (m != NULL)
        !          2701:                m_freem(m);
        !          2702: }
        !          2703:
        !          2704: int
        !          2705: bridge_ifenqueue(struct bridge_softc *sc, struct ifnet *ifp, struct mbuf *m)
        !          2706: {
        !          2707:        int error, len;
        !          2708:        short mflags;
        !          2709:
        !          2710: #if NGIF > 0
        !          2711:        /* Packet needs etherip encapsulation. */
        !          2712:        if (ifp->if_type == IFT_GIF)
        !          2713:                m->m_flags |= M_PROTO1;
        !          2714: #endif
        !          2715:        len = m->m_pkthdr.len;
        !          2716:        mflags = m->m_flags;
        !          2717:        IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
        !          2718:        if (error) {
        !          2719:                sc->sc_if.if_oerrors++;
        !          2720:                return (error);
        !          2721:        }
        !          2722:        sc->sc_if.if_opackets++;
        !          2723:        sc->sc_if.if_obytes += len;
        !          2724:        ifp->if_obytes += len;
        !          2725:        if (mflags & M_MCAST)
        !          2726:                ifp->if_omcasts++;
        !          2727:        if ((ifp->if_flags & IFF_OACTIVE) == 0)
        !          2728:                (*ifp->if_start)(ifp);
        !          2729:
        !          2730:        return (0);
        !          2731: }
        !          2732:
        !          2733: #ifdef INET
        !          2734: void
        !          2735: bridge_send_icmp_err(struct bridge_softc *sc, struct ifnet *ifp,
        !          2736:     struct ether_header *eh, struct mbuf *n, int hassnap, struct llc *llc,
        !          2737:     int mtu, int type, int code)
        !          2738: {
        !          2739:        struct ip *ip;
        !          2740:        struct icmp *icp;
        !          2741:        struct in_addr t;
        !          2742:        struct mbuf *m, *n2;
        !          2743:        int hlen;
        !          2744:        u_int8_t ether_tmp[ETHER_ADDR_LEN];
        !          2745:
        !          2746:        n2 = m_copym(n, 0, M_COPYALL, M_DONTWAIT);
        !          2747:        if (!n2) {
        !          2748:                m_freem(n);
        !          2749:                return;
        !          2750:        }
        !          2751:        m = icmp_do_error(n, type, code, 0, mtu);
        !          2752:        if (m == NULL) {
        !          2753:                m_freem(n2);
        !          2754:                return;
        !          2755:        }
        !          2756:
        !          2757:        n = n2;
        !          2758:
        !          2759:        ip = mtod(m, struct ip *);
        !          2760:        hlen = ip->ip_hl << 2;
        !          2761:        t = ip->ip_dst;
        !          2762:        ip->ip_dst = ip->ip_src;
        !          2763:        ip->ip_src = t;
        !          2764:
        !          2765:        m->m_data += hlen;
        !          2766:        m->m_len -= hlen;
        !          2767:        icp = mtod(m, struct icmp *);
        !          2768:        icp->icmp_cksum = 0;
        !          2769:        icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen);
        !          2770:        m->m_data -= hlen;
        !          2771:        m->m_len += hlen;
        !          2772:
        !          2773:        ip->ip_v = IPVERSION;
        !          2774:        ip->ip_off &= htons(IP_DF);
        !          2775:        ip->ip_id = htons(ip_randomid());
        !          2776:        ip->ip_ttl = MAXTTL;
        !          2777:        ip->ip_sum = 0;
        !          2778:        ip->ip_sum = in_cksum(m, hlen);
        !          2779:
        !          2780:        /* Swap ethernet addresses */
        !          2781:        bcopy(&eh->ether_dhost, &ether_tmp, sizeof(ether_tmp));
        !          2782:        bcopy(&eh->ether_shost, &eh->ether_dhost, sizeof(ether_tmp));
        !          2783:        bcopy(&ether_tmp, &eh->ether_shost, sizeof(ether_tmp));
        !          2784:
        !          2785:        /* Reattach SNAP header */
        !          2786:        if (hassnap) {
        !          2787:                M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
        !          2788:                if (m == NULL)
        !          2789:                        goto dropit;
        !          2790:                bcopy(llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
        !          2791:        }
        !          2792:
        !          2793:        /* Reattach ethernet header */
        !          2794:        M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
        !          2795:        if (m == NULL)
        !          2796:                goto dropit;
        !          2797:        bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
        !          2798:
        !          2799:        bridge_output(ifp, m, NULL, NULL);
        !          2800:        m_freem(n);
        !          2801:        return;
        !          2802:
        !          2803:  dropit:
        !          2804:        m_freem(n);
        !          2805: }
        !          2806: #endif

CVSweb