123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772 |
- /* $OpenBSD: if_bridge.c,v 1.257 2015/07/20 22:54:29 mpi Exp $ */
- /*
- * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * Effort sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F30602-01-2-0537.
- *
- */
- #include "bpfilter.h"
- #include "gif.h"
- #include "pf.h"
- #include "carp.h"
- #include "vlan.h"
- #include "mpw.h"
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/mbuf.h>
- #include <sys/socket.h>
- #include <sys/timeout.h>
- #include <sys/ioctl.h>
- #include <sys/errno.h>
- #include <sys/kernel.h>
- #include <crypto/siphash.h>
- #include <net/if.h>
- #include <net/if_types.h>
- #include <net/if_llc.h>
- #include <net/netisr.h>
- #include <netinet/in.h>
- #include <netinet/ip.h>
- #include <netinet/ip_var.h>
- #include <netinet/if_ether.h>
- #include <netinet/ip_icmp.h>
- #ifdef IPSEC
- #include <netinet/ip_ipsp.h>
- #include <net/if_enc.h>
- #endif
- #ifdef INET6
- #include <netinet6/in6_var.h>
- #include <netinet/ip6.h>
- #include <netinet6/ip6_var.h>
- #endif
- #if NPF > 0
- #include <net/pfvar.h>
- #define BRIDGE_IN PF_IN
- #define BRIDGE_OUT PF_OUT
- #else
- #define BRIDGE_IN 0
- #define BRIDGE_OUT 1
- #endif
- #if NBPFILTER > 0
- #include <net/bpf.h>
- #endif
- #if NCARP > 0
- #include <netinet/ip_carp.h>
- #endif
- #if NVLAN > 0
- #include <net/if_vlan_var.h>
- #endif
- #if NGIF > 0
- #include <net/if_gif.h>
- #endif
- #include <net/if_bridge.h>
- /*
- * Maximum number of addresses to cache
- */
- #ifndef BRIDGE_RTABLE_MAX
- #define BRIDGE_RTABLE_MAX 100
- #endif
- /*
- * Timeout (in seconds) for entries learned dynamically
- */
- #ifndef BRIDGE_RTABLE_TIMEOUT
- #define BRIDGE_RTABLE_TIMEOUT 240
- #endif
- void bridgeattach(int);
- int bridge_ioctl(struct ifnet *, u_long, caddr_t);
- void bridge_start(struct ifnet *);
- void bridgeintr_frame(struct bridge_softc *, struct mbuf *);
- void bridge_broadcast(struct bridge_softc *, struct ifnet *,
- struct ether_header *, struct mbuf *);
- void bridge_localbroadcast(struct bridge_softc *, struct ifnet *,
- struct ether_header *, struct mbuf *);
- void bridge_span(struct bridge_softc *, struct mbuf *);
- void bridge_stop(struct bridge_softc *);
- void bridge_init(struct bridge_softc *);
- int bridge_bifconf(struct bridge_softc *, struct ifbifconf *);
- void bridge_timer(void *);
- int bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
- void bridge_rtage(struct bridge_softc *);
- int bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
- void bridge_rtflush(struct bridge_softc *, int);
- struct ifnet *bridge_rtupdate(struct bridge_softc *,
- struct ether_addr *, struct ifnet *ifp, int, u_int8_t, struct mbuf *);
- struct bridge_rtnode *bridge_rtlookup(struct bridge_softc *,
- struct ether_addr *);
- u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
- int bridge_blocknonip(struct ether_header *, struct mbuf *);
- int bridge_addrule(struct bridge_iflist *,
- struct ifbrlreq *, int out);
- void bridge_flushrule(struct bridge_iflist *);
- int bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
- u_int8_t bridge_filterrule(struct brl_head *, struct ether_header *,
- struct mbuf *);
- struct mbuf *bridge_ip(struct bridge_softc *, int, struct ifnet *,
- struct ether_header *, struct mbuf *m);
- int bridge_ifenqueue(struct bridge_softc *, struct ifnet *, struct mbuf *);
- void bridge_fragment(struct bridge_softc *, struct ifnet *,
- struct ether_header *, struct mbuf *);
- void bridge_send_icmp_err(struct bridge_softc *, struct ifnet *,
- struct ether_header *, struct mbuf *, int, struct llc *, int, int, int);
- #ifdef IPSEC
- int bridge_ipsec(struct bridge_softc *, struct ifnet *,
- struct ether_header *, int, struct llc *,
- int, int, int, struct mbuf *);
- #endif
- int bridge_clone_create(struct if_clone *, int);
- int bridge_clone_destroy(struct ifnet *ifp);
- int bridge_delete(struct bridge_softc *, struct bridge_iflist *);
- void bridge_copyaddr(struct sockaddr *, struct sockaddr *);
- struct mbuf *bridge_m_dup(struct mbuf *);
- #define ETHERADDR_IS_IP_MCAST(a) \
- /* struct etheraddr *a; */ \
- ((a)->ether_addr_octet[0] == 0x01 && \
- (a)->ether_addr_octet[1] == 0x00 && \
- (a)->ether_addr_octet[2] == 0x5e)
- LIST_HEAD(, bridge_softc) bridge_list;
- struct if_clone bridge_cloner =
- IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy);
- /* ARGSUSED */
- void
- bridgeattach(int n)
- {
- LIST_INIT(&bridge_list);
- if_clone_attach(&bridge_cloner);
- }
- int
- bridge_clone_create(struct if_clone *ifc, int unit)
- {
- struct bridge_softc *sc;
- struct ifih *bridge_ifih;
- struct ifnet *ifp;
- int i, s;
- sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO);
- if (!sc)
- return (ENOMEM);
- bridge_ifih = malloc(sizeof(*bridge_ifih), M_DEVBUF, M_NOWAIT);
- if (bridge_ifih == NULL) {
- free(sc, M_DEVBUF, 0);
- return (ENOMEM);
- }
- sc->sc_stp = bstp_create(&sc->sc_if);
- if (!sc->sc_stp) {
- free(bridge_ifih, M_DEVBUF, sizeof(*bridge_ifih));
- free(sc, M_DEVBUF, 0);
- return (ENOMEM);
- }
- sc->sc_brtmax = BRIDGE_RTABLE_MAX;
- sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
- timeout_set(&sc->sc_brtimeout, bridge_timer, sc);
- TAILQ_INIT(&sc->sc_iflist);
- TAILQ_INIT(&sc->sc_spanlist);
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++)
- LIST_INIT(&sc->sc_rts[i]);
- arc4random_buf(&sc->sc_hashkey, sizeof(sc->sc_hashkey));
- ifp = &sc->sc_if;
- snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
- unit);
- ifp->if_softc = sc;
- ifp->if_mtu = ETHERMTU;
- ifp->if_ioctl = bridge_ioctl;
- ifp->if_output = bridge_output;
- ifp->if_start = bridge_start;
- ifp->if_type = IFT_BRIDGE;
- ifp->if_hdrlen = ETHER_HDR_LEN;
- IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
- IFQ_SET_READY(&ifp->if_snd);
- if_attach(ifp);
- if_alloc_sadl(ifp);
- #if NBPFILTER > 0
- bpfattach(&sc->sc_if.if_bpf, ifp,
- DLT_EN10MB, ETHER_HDR_LEN);
- #endif
- bridge_ifih->ifih_input = ether_input;
- SLIST_INSERT_HEAD(&ifp->if_inputs, bridge_ifih, ifih_next);
- s = splnet();
- LIST_INSERT_HEAD(&bridge_list, sc, sc_list);
- splx(s);
- return (0);
- }
- int
- bridge_clone_destroy(struct ifnet *ifp)
- {
- struct bridge_softc *sc = ifp->if_softc;
- struct bridge_iflist *bif;
- struct ifih *bridge_ifih;
- int s;
- bridge_stop(sc);
- bridge_rtflush(sc, IFBF_FLUSHALL);
- while ((bif = TAILQ_FIRST(&sc->sc_iflist)) != NULL)
- bridge_delete(sc, bif);
- while ((bif = TAILQ_FIRST(&sc->sc_spanlist)) != NULL) {
- TAILQ_REMOVE(&sc->sc_spanlist, bif, next);
- free(bif, M_DEVBUF, 0);
- }
- s = splnet();
- LIST_REMOVE(sc, sc_list);
- splx(s);
- bstp_destroy(sc->sc_stp);
- /* Undo pseudo-driver changes. */
- if_deactivate(ifp);
- bridge_ifih = SLIST_FIRST(&ifp->if_inputs);
- SLIST_REMOVE_HEAD(&ifp->if_inputs, ifih_next);
- KASSERT(SLIST_EMPTY(&ifp->if_inputs));
- free(bridge_ifih, M_DEVBUF, sizeof(*bridge_ifih));
- if_detach(ifp);
- free(sc, M_DEVBUF, 0);
- return (0);
- }
- int
- bridge_delete(struct bridge_softc *sc, struct bridge_iflist *p)
- {
- int error;
- if (p->bif_flags & IFBIF_STP)
- bstp_delete(p->bif_stp);
- p->ifp->if_bridgeport = NULL;
- error = ifpromisc(p->ifp, 0);
- TAILQ_REMOVE(&sc->sc_iflist, p, next);
- bridge_rtdelete(sc, p->ifp, 0);
- bridge_flushrule(p);
- free(p, M_DEVBUF, 0);
- return (error);
- }
- int
- bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
- {
- struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
- struct ifbreq *req = (struct ifbreq *)data;
- struct ifbareq *bareq = (struct ifbareq *)data;
- struct ifbrparam *bparam = (struct ifbrparam *)data;
- struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
- struct ifbropreq *brop = (struct ifbropreq *)data;
- struct ifnet *ifs;
- struct bridge_iflist *p;
- struct bstp_port *bp;
- struct bstp_state *bs = sc->sc_stp;
- int error = 0, s;
- s = splnet();
- switch (cmd) {
- case SIOCBRDGADD:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(req->ifbr_ifsname);
- if (ifs == NULL) { /* no such interface */
- error = ENOENT;
- break;
- }
- if (ifs->if_bridgeport != NULL) {
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p->bridge_sc == sc)
- error = EEXIST;
- else
- error = EBUSY;
- break;
- }
- /* If it's in the span list, it can't be a member. */
- TAILQ_FOREACH(p, &sc->sc_spanlist, next)
- if (p->ifp == ifs)
- break;
- if (p != NULL) {
- error = EBUSY;
- break;
- }
- if (ifs->if_type == IFT_ETHER) {
- if ((ifs->if_flags & IFF_UP) == 0) {
- struct ifreq ifreq;
- /*
- * Bring interface up long enough to set
- * promiscuous flag, then shut it down again.
- */
- strlcpy(ifreq.ifr_name, req->ifbr_ifsname,
- IFNAMSIZ);
- ifs->if_flags |= IFF_UP;
- ifreq.ifr_flags = ifs->if_flags;
- error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
- (caddr_t)&ifreq);
- if (error != 0)
- break;
- error = ifpromisc(ifs, 1);
- if (error != 0)
- break;
- strlcpy(ifreq.ifr_name, req->ifbr_ifsname,
- IFNAMSIZ);
- ifs->if_flags &= ~IFF_UP;
- ifreq.ifr_flags = ifs->if_flags;
- error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
- (caddr_t)&ifreq);
- if (error != 0) {
- ifpromisc(ifs, 0);
- break;
- }
- } else {
- error = ifpromisc(ifs, 1);
- if (error != 0)
- break;
- }
- }
- #if NGIF > 0
- else if (ifs->if_type == IFT_GIF) {
- /* Nothing needed */
- }
- #endif /* NGIF */
- #if NMPW > 0
- else if (ifs->if_type == IFT_MPLSTUNNEL) {
- /* Nothing needed */
- }
- #endif /* NMPW */
- else {
- error = EINVAL;
- break;
- }
- p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT|M_ZERO);
- if (p == NULL) {
- if (ifs->if_type == IFT_ETHER)
- ifpromisc(ifs, 0);
- error = ENOMEM;
- break;
- }
- p->bridge_sc = sc;
- p->ifp = ifs;
- p->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
- SIMPLEQ_INIT(&p->bif_brlin);
- SIMPLEQ_INIT(&p->bif_brlout);
- ifs->if_bridgeport = (caddr_t)p;
- TAILQ_INSERT_TAIL(&sc->sc_iflist, p, next);
- break;
- case SIOCBRDGDEL:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(req->ifbr_ifsname);
- if (ifs == NULL) {
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- error = ESRCH;
- break;
- }
- error = bridge_delete(sc, p);
- break;
- case SIOCBRDGIFS:
- error = bridge_bifconf(sc, (struct ifbifconf *)data);
- break;
- case SIOCBRDGADDS:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(req->ifbr_ifsname);
- if (ifs == NULL) { /* no such interface */
- error = ENOENT;
- break;
- }
- if (ifs->if_bridgeport != NULL) {
- error = EBUSY;
- break;
- }
- TAILQ_FOREACH(p, &sc->sc_spanlist, next) {
- if (p->ifp == ifs)
- break;
- }
- if (p != NULL) {
- error = EEXIST;
- break;
- }
- p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT|M_ZERO);
- if (p == NULL) {
- error = ENOMEM;
- break;
- }
- p->ifp = ifs;
- p->bif_flags = IFBIF_SPAN;
- SIMPLEQ_INIT(&p->bif_brlin);
- SIMPLEQ_INIT(&p->bif_brlout);
- TAILQ_INSERT_TAIL(&sc->sc_spanlist, p, next);
- break;
- case SIOCBRDGDELS:
- if ((error = suser(curproc, 0)) != 0)
- break;
- TAILQ_FOREACH(p, &sc->sc_spanlist, next) {
- if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,
- sizeof(p->ifp->if_xname)) == 0) {
- TAILQ_REMOVE(&sc->sc_spanlist, p, next);
- free(p, M_DEVBUF, 0);
- break;
- }
- }
- if (p == NULL) {
- error = ENOENT;
- break;
- }
- break;
- case SIOCBRDGGIFFLGS:
- ifs = ifunit(req->ifbr_ifsname);
- if (ifs == NULL) {
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- error = ESRCH;
- break;
- }
- req->ifbr_ifsflags = p->bif_flags;
- req->ifbr_portno = p->ifp->if_index & 0xfff;
- if (p->bif_flags & IFBIF_STP) {
- bp = p->bif_stp;
- req->ifbr_state = bstp_getstate(bs, bp);
- req->ifbr_priority = bp->bp_priority;
- req->ifbr_path_cost = bp->bp_path_cost;
- req->ifbr_proto = bp->bp_protover;
- req->ifbr_role = bp->bp_role;
- req->ifbr_stpflags = bp->bp_flags;
- req->ifbr_fwd_trans = bp->bp_forward_transitions;
- req->ifbr_desg_bridge = bp->bp_desg_pv.pv_dbridge_id;
- req->ifbr_desg_port = bp->bp_desg_pv.pv_dport_id;
- req->ifbr_root_bridge = bp->bp_desg_pv.pv_root_id;
- req->ifbr_root_cost = bp->bp_desg_pv.pv_cost;
- req->ifbr_root_port = bp->bp_desg_pv.pv_port_id;
- /* Copy STP state options as flags */
- if (bp->bp_operedge)
- req->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
- if (bp->bp_flags & BSTP_PORT_AUTOEDGE)
- req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
- if (bp->bp_ptp_link)
- req->ifbr_ifsflags |= IFBIF_BSTP_PTP;
- if (bp->bp_flags & BSTP_PORT_AUTOPTP)
- req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
- }
- break;
- case SIOCBRDGSIFFLGS:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(req->ifbr_ifsname);
- if (ifs == NULL) {
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- error = ESRCH;
- break;
- }
- if (req->ifbr_ifsflags & IFBIF_RO_MASK) {
- error = EINVAL;
- break;
- }
- if (req->ifbr_ifsflags & IFBIF_STP) {
- if ((p->bif_flags & IFBIF_STP) == 0) {
- /* Enable STP */
- if ((p->bif_stp = bstp_add(sc->sc_stp,
- p->ifp)) == NULL) {
- error = ENOMEM;
- break;
- }
- } else {
- /* Update STP flags */
- bstp_ifsflags(p->bif_stp, req->ifbr_ifsflags);
- }
- } else if (p->bif_flags & IFBIF_STP) {
- bstp_delete(p->bif_stp);
- p->bif_stp = NULL;
- }
- p->bif_flags = req->ifbr_ifsflags;
- break;
- case SIOCBRDGRTS:
- error = bridge_rtfind(sc, (struct ifbaconf *)data);
- break;
- case SIOCBRDGFLUSH:
- if ((error = suser(curproc, 0)) != 0)
- break;
- bridge_rtflush(sc, req->ifbr_ifsflags);
- break;
- case SIOCBRDGSADDR:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(bareq->ifba_ifsname);
- if (ifs == NULL) { /* no such interface */
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- error = ESRCH;
- break;
- }
- ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
- bareq->ifba_flags, NULL);
- if (ifs == NULL)
- error = ENOMEM;
- break;
- case SIOCBRDGDADDR:
- if ((error = suser(curproc, 0)) != 0)
- break;
- error = bridge_rtdaddr(sc, &bareq->ifba_dst);
- break;
- case SIOCBRDGGCACHE:
- bparam->ifbrp_csize = sc->sc_brtmax;
- break;
- case SIOCBRDGSCACHE:
- if ((error = suser(curproc, 0)) != 0)
- break;
- sc->sc_brtmax = bparam->ifbrp_csize;
- break;
- case SIOCBRDGSTO:
- if ((error = suser(curproc, 0)) != 0)
- break;
- if (bparam->ifbrp_ctime < 0 ||
- bparam->ifbrp_ctime > INT_MAX / hz) {
- error = EINVAL;
- break;
- }
- sc->sc_brttimeout = bparam->ifbrp_ctime;
- if (bparam->ifbrp_ctime != 0)
- timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
- else
- timeout_del(&sc->sc_brtimeout);
- break;
- case SIOCBRDGGTO:
- bparam->ifbrp_ctime = sc->sc_brttimeout;
- break;
- case SIOCSIFFLAGS:
- if ((ifp->if_flags & IFF_UP) == IFF_UP)
- bridge_init(sc);
- if ((ifp->if_flags & IFF_UP) == 0)
- bridge_stop(sc);
- break;
- case SIOCBRDGARL:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(brlreq->ifbr_ifsname);
- if (ifs == NULL) {
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- error = ESRCH;
- break;
- }
- if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
- brlreq->ifbr_action != BRL_ACTION_PASS) ||
- (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
- error = EINVAL;
- break;
- }
- if (brlreq->ifbr_flags & BRL_FLAG_IN) {
- error = bridge_addrule(p, brlreq, 0);
- if (error)
- break;
- }
- if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
- error = bridge_addrule(p, brlreq, 1);
- if (error)
- break;
- }
- break;
- case SIOCBRDGFRL:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(brlreq->ifbr_ifsname);
- if (ifs == NULL) {
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- error = ESRCH;
- break;
- }
- bridge_flushrule(p);
- break;
- case SIOCBRDGGRL:
- error = bridge_brlconf(sc, (struct ifbrlconf *)data);
- break;
- case SIOCBRDGGPARAM:
- if ((bp = bs->bs_root_port) == NULL)
- brop->ifbop_root_port = 0;
- else
- brop->ifbop_root_port = bp->bp_ifp->if_index;
- brop->ifbop_maxage = bs->bs_bridge_max_age >> 8;
- brop->ifbop_hellotime = bs->bs_bridge_htime >> 8;
- brop->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8;
- brop->ifbop_holdcount = bs->bs_txholdcount;
- brop->ifbop_priority = bs->bs_bridge_priority;
- brop->ifbop_protocol = bs->bs_protover;
- brop->ifbop_root_bridge = bs->bs_root_pv.pv_root_id;
- brop->ifbop_root_path_cost = bs->bs_root_pv.pv_cost;
- brop->ifbop_root_port = bs->bs_root_pv.pv_port_id;
- brop->ifbop_desg_bridge = bs->bs_root_pv.pv_dbridge_id;
- brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
- brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
- break;
- case SIOCBRDGGPRI:
- case SIOCBRDGGMA:
- case SIOCBRDGGHT:
- case SIOCBRDGGFD:
- break;
- case SIOCBRDGSPRI:
- case SIOCBRDGSFD:
- case SIOCBRDGSMA:
- case SIOCBRDGSHT:
- case SIOCBRDGSTXHC:
- case SIOCBRDGSPROTO:
- case SIOCBRDGSIFPRIO:
- case SIOCBRDGSIFCOST:
- error = suser(curproc, 0);
- break;
- default:
- error = ENOTTY;
- break;
- }
- if (!error)
- error = bstp_ioctl(ifp, cmd, data);
- splx(s);
- return (error);
- }
- /* Detach an interface from a bridge. */
- void
- bridge_ifdetach(struct ifnet *ifp)
- {
- struct bridge_softc *sc;
- struct bridge_iflist *bif;
- bif = (struct bridge_iflist *)ifp->if_bridgeport;
- sc = bif->bridge_sc;
- bridge_delete(sc, bif);
- }
- void
- bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
- {
- struct bridge_softc *sc;
- struct bridge_iflist *bif;
- u_int8_t *addr;
- addr = (u_int8_t *)ea;
- bif = (struct bridge_iflist *)ifp->if_bridgeport;
- sc = bif->bridge_sc;
- /*
- * Update the bridge interface if it is in
- * the learning state.
- */
- if ((bif->bif_flags & IFBIF_LEARNING) &&
- (ETHER_IS_MULTICAST(addr) == 0) &&
- !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
- addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
- /* Care must be taken with spanning tree */
- if ((bif->bif_flags & IFBIF_STP) &&
- (bif->bif_state == BSTP_IFSTATE_DISCARDING))
- return;
- /* Delete the address from the bridge */
- bridge_rtdaddr(sc, ea);
- if (!delete) {
- /* Update the bridge table */
- bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL);
- }
- }
- }
- int
- bridge_bifconf(struct bridge_softc *sc, struct ifbifconf *bifc)
- {
- struct bridge_iflist *p;
- struct bstp_port *bp;
- struct bstp_state *bs = sc->sc_stp;
- u_int32_t total = 0, i = 0;
- int error = 0;
- struct ifbreq *breq = NULL;
- TAILQ_FOREACH(p, &sc->sc_iflist, next)
- total++;
- TAILQ_FOREACH(p, &sc->sc_spanlist, next)
- total++;
- if (bifc->ifbic_len == 0) {
- i = total;
- goto done;
- }
- if ((breq = (struct ifbreq *)
- malloc(sizeof(*breq), M_DEVBUF, M_NOWAIT)) == NULL)
- goto done;
- TAILQ_FOREACH(p, &sc->sc_iflist, next) {
- bzero(breq, sizeof(*breq));
- if (bifc->ifbic_len < sizeof(*breq))
- break;
- strlcpy(breq->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
- strlcpy(breq->ifbr_ifsname, p->ifp->if_xname, IFNAMSIZ);
- breq->ifbr_ifsflags = p->bif_flags;
- breq->ifbr_portno = p->ifp->if_index & 0xfff;
- if (p->bif_flags & IFBIF_STP) {
- bp = p->bif_stp;
- breq->ifbr_state = bstp_getstate(sc->sc_stp, bp);
- breq->ifbr_priority = bp->bp_priority;
- breq->ifbr_path_cost = bp->bp_path_cost;
- breq->ifbr_proto = bp->bp_protover;
- breq->ifbr_role = bp->bp_role;
- breq->ifbr_stpflags = bp->bp_flags;
- breq->ifbr_fwd_trans = bp->bp_forward_transitions;
- breq->ifbr_root_bridge = bs->bs_root_pv.pv_root_id;
- breq->ifbr_root_cost = bs->bs_root_pv.pv_cost;
- breq->ifbr_root_port = bs->bs_root_pv.pv_port_id;
- breq->ifbr_desg_bridge = bs->bs_root_pv.pv_dbridge_id;
- breq->ifbr_desg_port = bs->bs_root_pv.pv_dport_id;
- /* Copy STP state options as flags */
- if (bp->bp_operedge)
- breq->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
- if (bp->bp_flags & BSTP_PORT_AUTOEDGE)
- breq->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
- if (bp->bp_ptp_link)
- breq->ifbr_ifsflags |= IFBIF_BSTP_PTP;
- if (bp->bp_flags & BSTP_PORT_AUTOPTP)
- breq->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
- }
- error = copyout((caddr_t)breq,
- (caddr_t)(bifc->ifbic_req + i), sizeof(*breq));
- if (error)
- goto done;
- i++;
- bifc->ifbic_len -= sizeof(*breq);
- }
- TAILQ_FOREACH(p, &sc->sc_spanlist, next) {
- bzero(breq, sizeof(*breq));
- if (bifc->ifbic_len < sizeof(*breq))
- break;
- strlcpy(breq->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
- strlcpy(breq->ifbr_ifsname, p->ifp->if_xname, IFNAMSIZ);
- breq->ifbr_ifsflags = p->bif_flags | IFBIF_SPAN;
- breq->ifbr_portno = p->ifp->if_index & 0xfff;
- error = copyout((caddr_t)breq,
- (caddr_t)(bifc->ifbic_req + i), sizeof(*breq));
- if (error)
- goto done;
- i++;
- bifc->ifbic_len -= sizeof(*breq);
- }
- done:
- if (breq != NULL)
- free(breq, M_DEVBUF, 0);
- bifc->ifbic_len = i * sizeof(*breq);
- return (error);
- }
- int
- bridge_brlconf(struct bridge_softc *sc, struct ifbrlconf *bc)
- {
- struct ifnet *ifp;
- struct bridge_iflist *ifl;
- struct brl_node *n;
- struct ifbrlreq req;
- int error = 0;
- u_int32_t i = 0, total = 0;
- ifp = ifunit(bc->ifbrl_ifsname);
- if (ifp == NULL)
- return (ENOENT);
- ifl = (struct bridge_iflist *)ifp->if_bridgeport;
- if (ifl == NULL || ifl->bridge_sc != sc)
- return (ESRCH);
- SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
- total++;
- }
- SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
- total++;
- }
- if (bc->ifbrl_len == 0) {
- i = total;
- goto done;
- }
- SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
- bzero(&req, sizeof req);
- if (bc->ifbrl_len < sizeof(req))
- goto done;
- strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
- strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
- req.ifbr_action = n->brl_action;
- req.ifbr_flags = n->brl_flags;
- req.ifbr_src = n->brl_src;
- req.ifbr_dst = n->brl_dst;
- #if NPF > 0
- req.ifbr_tagname[0] = '\0';
- if (n->brl_tag)
- pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
- #endif
- error = copyout((caddr_t)&req,
- (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
- if (error)
- goto done;
- i++;
- bc->ifbrl_len -= sizeof(req);
- }
- SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
- bzero(&req, sizeof req);
- if (bc->ifbrl_len < sizeof(req))
- goto done;
- strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
- strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
- req.ifbr_action = n->brl_action;
- req.ifbr_flags = n->brl_flags;
- req.ifbr_src = n->brl_src;
- req.ifbr_dst = n->brl_dst;
- #if NPF > 0
- req.ifbr_tagname[0] = '\0';
- if (n->brl_tag)
- pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
- #endif
- error = copyout((caddr_t)&req,
- (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
- if (error)
- goto done;
- i++;
- bc->ifbrl_len -= sizeof(req);
- }
- done:
- bc->ifbrl_len = i * sizeof(req);
- return (error);
- }
- void
- bridge_init(struct bridge_softc *sc)
- {
- struct ifnet *ifp = &sc->sc_if;
- if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING)
- return;
- ifp->if_flags |= IFF_RUNNING;
- bstp_initialization(sc->sc_stp);
- if (sc->sc_brttimeout != 0)
- timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
- }
- /*
- * Stop the bridge and deallocate the routing table.
- */
- void
- bridge_stop(struct bridge_softc *sc)
- {
- struct ifnet *ifp = &sc->sc_if;
- /*
- * If we're not running, there's nothing to do.
- */
- if ((ifp->if_flags & IFF_RUNNING) == 0)
- return;
- timeout_del(&sc->sc_brtimeout);
- bridge_rtflush(sc, IFBF_FLUSHDYN);
- ifp->if_flags &= ~IFF_RUNNING;
- }
- /*
- * Send output from the bridge. The mbuf has the ethernet header
- * already attached. We must enqueue or free the mbuf before exiting.
- */
- int
- bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
- struct rtentry *rt)
- {
- struct ether_header *eh;
- struct ifnet *dst_if = NULL;
- struct bridge_rtnode *dst_p = NULL;
- struct ether_addr *dst;
- struct bridge_softc *sc;
- int error;
- /* ifp must be a member interface of the bridge. */
- if (ifp->if_bridgeport == NULL) {
- m_freem(m);
- return (EINVAL);
- }
- sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
- if (m->m_len < sizeof(*eh)) {
- m = m_pullup(m, sizeof(*eh));
- if (m == NULL)
- return (ENOBUFS);
- }
- eh = mtod(m, struct ether_header *);
- dst = (struct ether_addr *)&eh->ether_dhost[0];
- /*
- * If bridge is down, but original output interface is up,
- * go ahead and send out that interface. Otherwise the packet
- * is dropped below.
- */
- if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
- dst_if = ifp;
- goto sendunicast;
- }
- #if NBPFILTER > 0
- if (sc->sc_if.if_bpf)
- bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
- #endif
- ifp->if_opackets++;
- ifp->if_obytes += m->m_pkthdr.len;
- /*
- * If the packet is a broadcast or we don't know a better way to
- * get there, send to all interfaces.
- */
- if ((dst_p = bridge_rtlookup(sc, dst)) != NULL)
- dst_if = dst_p->brt_if;
- if (dst_if == NULL || ETHER_IS_MULTICAST(eh->ether_dhost)) {
- struct bridge_iflist *p;
- struct mbuf *mc;
- int used = 0;
- bridge_span(sc, m);
- TAILQ_FOREACH(p, &sc->sc_iflist, next) {
- dst_if = p->ifp;
- if ((dst_if->if_flags & IFF_RUNNING) == 0)
- continue;
- /*
- * If this is not the original output interface,
- * and the interface is participating in spanning
- * tree, make sure the port is in a state that
- * allows forwarding.
- */
- if (dst_if != ifp &&
- (p->bif_flags & IFBIF_STP) &&
- (p->bif_state == BSTP_IFSTATE_DISCARDING))
- continue;
- #if NMPW > 0
- /*
- * Split horizon: avoid broadcasting messages from
- * wire to another wire.
- */
- if (ifp->if_type == IFT_MPLSTUNNEL &&
- dst_if->if_type == IFT_MPLSTUNNEL)
- continue;
- #endif /* NMPW */
- if ((p->bif_flags & IFBIF_DISCOVER) == 0 &&
- (m->m_flags & (M_BCAST | M_MCAST)) == 0)
- continue;
- if (IF_QFULL(&dst_if->if_snd)) {
- IF_DROP(&dst_if->if_snd);
- sc->sc_if.if_oerrors++;
- continue;
- }
- if (TAILQ_NEXT(p, next) == NULL) {
- used = 1;
- mc = m;
- } else {
- mc = bridge_m_dup(m);
- if (mc == NULL) {
- sc->sc_if.if_oerrors++;
- continue;
- }
- }
- error = bridge_ifenqueue(sc, dst_if, mc);
- if (error)
- continue;
- }
- if (!used)
- m_freem(m);
- return (0);
- }
- sendunicast:
- if (dst_p != NULL && dst_p->brt_tunnel.sa.sa_family != AF_UNSPEC &&
- (sa = bridge_tunneltag(m, dst_p->brt_tunnel.sa.sa_family)) != NULL)
- memcpy(sa, &dst_p->brt_tunnel.sa, dst_p->brt_tunnel.sa.sa_len);
- bridge_span(sc, m);
- if ((dst_if->if_flags & IFF_RUNNING) == 0) {
- m_freem(m);
- return (ENETDOWN);
- }
- bridge_ifenqueue(sc, dst_if, m);
- return (0);
- }
- /*
- * Start output on the bridge. This function should never be called.
- */
- void
- bridge_start(struct ifnet *ifp)
- {
- }
- /*
- * Loop through each bridge interface and process their input queues.
- */
- void
- bridgeintr(void)
- {
- struct bridge_softc *sc;
- struct mbuf *m;
- int s;
- LIST_FOREACH(sc, &bridge_list, sc_list) {
- for (;;) {
- s = splnet();
- IF_DEQUEUE(&sc->sc_if.if_snd, m);
- splx(s);
- if (m == NULL)
- break;
- bridgeintr_frame(sc, m);
- }
- }
- }
- /*
- * Process a single frame. Frame must be freed or queued before returning.
- */
- void
- bridgeintr_frame(struct bridge_softc *sc, struct mbuf *m)
- {
- struct ifnet *src_if, *dst_if;
- struct bridge_iflist *ifl;
- struct bridge_rtnode *dst_p;
- struct ether_addr *dst, *src;
- struct ether_header eh;
- int len;
- if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
- m_freem(m);
- return;
- }
- src_if = if_get(m->m_pkthdr.ph_ifidx);
- if (src_if == NULL) {
- m_freem(m);
- return;
- }
- sc->sc_if.if_ipackets++;
- sc->sc_if.if_ibytes += m->m_pkthdr.len;
- ifl = (struct bridge_iflist *)src_if->if_bridgeport;
- if (ifl == NULL) {
- m_freem(m);
- return;
- }
- if ((ifl->bif_flags & IFBIF_STP) &&
- (ifl->bif_state == BSTP_IFSTATE_DISCARDING)) {
- m_freem(m);
- return;
- }
- if (m->m_pkthdr.len < sizeof(eh)) {
- m_freem(m);
- return;
- }
- m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&eh);
- dst = (struct ether_addr *)&eh.ether_dhost[0];
- src = (struct ether_addr *)&eh.ether_shost[0];
- /*
- * If interface is learning, and if source address
- * is not broadcast or multicast, record its address.
- */
- if ((ifl->bif_flags & IFBIF_LEARNING) &&
- (eh.ether_shost[0] & 1) == 0 &&
- !(eh.ether_shost[0] == 0 && eh.ether_shost[1] == 0 &&
- eh.ether_shost[2] == 0 && eh.ether_shost[3] == 0 &&
- eh.ether_shost[4] == 0 && eh.ether_shost[5] == 0))
- bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC, m);
- if ((ifl->bif_flags & IFBIF_STP) &&
- (ifl->bif_state == BSTP_IFSTATE_LEARNING)) {
- m_freem(m);
- return;
- }
- /*
- * At this point, the port either doesn't participate in stp or
- * it's in the forwarding state
- */
- /*
- * If packet is unicast, destined for someone on "this"
- * side of the bridge, drop it.
- */
- if (!ETHER_IS_MULTICAST(eh.ether_dhost)) {
- if ((dst_p = bridge_rtlookup(sc, dst)) != NULL)
- dst_if = dst_p->brt_if;
- else
- dst_if = NULL;
- if (dst_if == src_if) {
- m_freem(m);
- return;
- }
- } else {
- if (memcmp(etherbroadcastaddr, eh.ether_dhost,
- sizeof(etherbroadcastaddr)) == 0)
- m->m_flags |= M_BCAST;
- else
- m->m_flags |= M_MCAST;
- dst_if = NULL;
- }
- /*
- * Multicast packets get handled a little differently:
- * If interface is:
- * -link0,-link1 (default) Forward all multicast
- * as broadcast.
- * -link0,link1 Drop non-IP multicast, forward
- * as broadcast IP multicast.
- * link0,-link1 Drop IP multicast, forward as
- * broadcast non-IP multicast.
- * link0,link1 Drop all multicast.
- */
- if (m->m_flags & M_MCAST) {
- if ((sc->sc_if.if_flags &
- (IFF_LINK0 | IFF_LINK1)) ==
- (IFF_LINK0 | IFF_LINK1)) {
- m_freem(m);
- return;
- }
- if (sc->sc_if.if_flags & IFF_LINK0 &&
- ETHERADDR_IS_IP_MCAST(dst)) {
- m_freem(m);
- return;
- }
- if (sc->sc_if.if_flags & IFF_LINK1 &&
- !ETHERADDR_IS_IP_MCAST(dst)) {
- m_freem(m);
- return;
- }
- }
- if (ifl->bif_flags & IFBIF_BLOCKNONIP && bridge_blocknonip(&eh, m)) {
- m_freem(m);
- return;
- }
- if (bridge_filterrule(&ifl->bif_brlin, &eh, m) == BRL_ACTION_BLOCK) {
- m_freem(m);
- return;
- }
- m = bridge_ip(sc, BRIDGE_IN, src_if, &eh, m);
- if (m == NULL)
- return;
- /*
- * If the packet is a multicast or broadcast OR if we don't
- * know any better, forward it to all interfaces.
- */
- if ((m->m_flags & (M_BCAST | M_MCAST)) || dst_if == NULL) {
- sc->sc_if.if_imcasts++;
- bridge_broadcast(sc, src_if, &eh, m);
- return;
- }
- /*
- * At this point, we're dealing with a unicast frame going to a
- * different interface
- */
- if ((dst_if->if_flags & IFF_RUNNING) == 0) {
- m_freem(m);
- return;
- }
- ifl = (struct bridge_iflist *)dst_if->if_bridgeport;
- if ((ifl->bif_flags & IFBIF_STP) &&
- (ifl->bif_state == BSTP_IFSTATE_DISCARDING)) {
- m_freem(m);
- return;
- }
- if (bridge_filterrule(&ifl->bif_brlout, &eh, m) == BRL_ACTION_BLOCK) {
- m_freem(m);
- return;
- }
- m = bridge_ip(sc, BRIDGE_OUT, dst_if, &eh, m);
- if (m == NULL)
- return;
- len = m->m_pkthdr.len;
- #if NVLAN > 0
- if ((m->m_flags & M_VLANTAG) &&
- (dst_if->if_capabilities & IFCAP_VLAN_HWTAGGING) == 0)
- len += ETHER_VLAN_ENCAP_LEN;
- #endif
- if ((len - ETHER_HDR_LEN) > dst_if->if_mtu)
- bridge_fragment(sc, dst_if, &eh, m);
- else {
- bridge_ifenqueue(sc, dst_if, m);
- }
- }
- /*
- * Receive input from an interface. Queue the packet for bridging if its
- * not for us, and schedule an interrupt.
- */
- struct mbuf *
- bridge_input(struct ifnet *ifp, struct mbuf *m)
- {
- struct bridge_softc *sc;
- struct bridge_iflist *ifl;
- struct bridge_iflist *srcifl;
- struct ether_header *eh;
- struct arpcom *ac;
- struct mbuf_list ml = MBUF_LIST_INITIALIZER();
- struct mbuf *mc;
- int s;
- if ((m->m_flags & M_PKTHDR) == 0)
- panic("bridge_input(): no HDR");
- ifl = (struct bridge_iflist *)ifp->if_bridgeport;
- if (ifl == NULL)
- return (m);
- sc = ifl->bridge_sc;
- if ((sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
- return (m);
- #if NBPFILTER > 0
- if (sc->sc_if.if_bpf)
- bpf_mtap_ether(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN);
- #endif
- bridge_span(sc, m);
- eh = mtod(m, struct ether_header *);
- if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
- /*
- * Reserved destination MAC addresses (01:80:C2:00:00:0x)
- * should not be forwarded to bridge members according to
- * section 7.12.6 of the 802.1D-2004 specification. The
- * STP destination address (as stored in bstp_etheraddr)
- * is the first of these.
- */
- if (bcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN - 1)
- == 0) {
- if (eh->ether_dhost[ETHER_ADDR_LEN - 1] == 0) {
- /* STP traffic */
- if ((m = bstp_input(sc->sc_stp, ifl->bif_stp,
- eh, m)) == NULL)
- return (NULL);
- } else if (eh->ether_dhost[ETHER_ADDR_LEN - 1] <= 0xf) {
- m_freem(m);
- return (NULL);
- }
- }
- /*
- * No need to queue frames for ifs in the discarding state
- */
- if ((ifl->bif_flags & IFBIF_STP) &&
- (ifl->bif_state == BSTP_IFSTATE_DISCARDING))
- return (m);
- mc = bridge_m_dup(m);
- if (mc == NULL)
- return (m);
- s = splnet();
- if (IF_QFULL(&sc->sc_if.if_snd)) {
- m_freem(mc);
- splx(s);
- return (m);
- }
- IF_ENQUEUE(&sc->sc_if.if_snd, mc);
- splx(s);
- schednetisr(NETISR_BRIDGE);
- #if NGIF > 0
- if (ifp->if_type == IFT_GIF) {
- TAILQ_FOREACH(ifl, &sc->sc_iflist, next) {
- if (ifl->ifp->if_type != IFT_ETHER)
- continue;
- m->m_flags |= M_PROTO1;
- ml_enqueue(&ml, m);
- if_input(ifl->ifp, &ml);
- return (NULL);
- }
- }
- #endif /* NGIF */
- return (m);
- }
- /*
- * No need to queue frames for ifs in the discarding state
- */
- if ((ifl->bif_flags & IFBIF_STP) &&
- (ifl->bif_state == BSTP_IFSTATE_DISCARDING))
- return (m);
- /*
- * Unicast, make sure it's not for us.
- */
- srcifl = ifl;
- TAILQ_FOREACH(ifl, &sc->sc_iflist, next) {
- if (ifl->ifp->if_type != IFT_ETHER)
- continue;
- ac = (struct arpcom *)ifl->ifp;
- if (bcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN) == 0
- #if NCARP > 0
- || (ifl->ifp->if_carp && carp_ourether(ifl->ifp->if_carp,
- (u_int8_t *)&eh->ether_dhost) != NULL)
- #endif
- ) {
- if (srcifl->bif_flags & IFBIF_LEARNING)
- bridge_rtupdate(sc,
- (struct ether_addr *)&eh->ether_shost,
- ifp, 0, IFBAF_DYNAMIC, m);
- if (bridge_filterrule(&srcifl->bif_brlin, eh, m) ==
- BRL_ACTION_BLOCK) {
- m_freem(m);
- return (NULL);
- }
- /* Count for the bridge */
- sc->sc_if.if_ipackets++;
- sc->sc_if.if_ibytes += m->m_pkthdr.len;
- m->m_flags |= M_PROTO1;
- ml_enqueue(&ml, m);
- if_input(ifl->ifp, &ml);
- return (NULL);
- }
- if (bcmp(ac->ac_enaddr, eh->ether_shost, ETHER_ADDR_LEN) == 0
- #if NCARP > 0
- || (ifl->ifp->if_carp && carp_ourether(ifl->ifp->if_carp,
- (u_int8_t *)&eh->ether_shost) != NULL)
- #endif
- ) {
- m_freem(m);
- return (NULL);
- }
- }
- s = splnet();
- if (IF_QFULL(&sc->sc_if.if_snd)) {
- m_freem(m);
- splx(s);
- return (NULL);
- }
- IF_ENQUEUE(&sc->sc_if.if_snd, m);
- splx(s);
- schednetisr(NETISR_BRIDGE);
- return (NULL);
- }
- /*
- * Send a frame to all interfaces that are members of the bridge
- * (except the one it came in on).
- */
- void
- bridge_broadcast(struct bridge_softc *sc, struct ifnet *ifp,
- struct ether_header *eh, struct mbuf *m)
- {
- struct bridge_iflist *p;
- struct mbuf *mc;
- struct ifnet *dst_if;
- int len, used = 0;
- TAILQ_FOREACH(p, &sc->sc_iflist, next) {
- dst_if = p->ifp;
- if ((dst_if->if_flags & IFF_RUNNING) == 0)
- continue;
- if ((p->bif_flags & IFBIF_STP) &&
- (p->bif_state == BSTP_IFSTATE_DISCARDING))
- continue;
- if ((p->bif_flags & IFBIF_DISCOVER) == 0 &&
- (m->m_flags & (M_BCAST | M_MCAST)) == 0)
- continue;
- /* Drop non-IP frames if the appropriate flag is set. */
- if (p->bif_flags & IFBIF_BLOCKNONIP &&
- bridge_blocknonip(eh, m))
- continue;
- if (bridge_filterrule(&p->bif_brlout, eh, m) == BRL_ACTION_BLOCK)
- continue;
- bridge_localbroadcast(sc, dst_if, eh, m);
- /*
- * Don't retransmit out of the same interface where
- * the packet was received from.
- */
- if (dst_if->if_index == ifp->if_index)
- continue;
- #if NMPW > 0
- /*
- * Split horizon: avoid broadcasting messages from wire to
- * another wire.
- */
- if (ifp->if_type == IFT_MPLSTUNNEL &&
- dst_if->if_type == IFT_MPLSTUNNEL)
- continue;
- #endif /* NMPW */
- if (IF_QFULL(&dst_if->if_snd)) {
- IF_DROP(&dst_if->if_snd);
- sc->sc_if.if_oerrors++;
- continue;
- }
- /* If last one, reuse the passed-in mbuf */
- if (TAILQ_NEXT(p, next) == NULL) {
- mc = m;
- used = 1;
- } else {
- mc = bridge_m_dup(m);
- if (mc == NULL) {
- sc->sc_if.if_oerrors++;
- continue;
- }
- }
- mc = bridge_ip(sc, BRIDGE_OUT, dst_if, eh, mc);
- if (mc == NULL)
- continue;
- len = mc->m_pkthdr.len;
- #if NVLAN > 0
- if ((mc->m_flags & M_VLANTAG) &&
- (dst_if->if_capabilities & IFCAP_VLAN_HWTAGGING) == 0)
- len += ETHER_VLAN_ENCAP_LEN;
- #endif
- if ((len - ETHER_HDR_LEN) > dst_if->if_mtu)
- bridge_fragment(sc, dst_if, eh, mc);
- else {
- bridge_ifenqueue(sc, dst_if, mc);
- }
- }
- if (!used)
- m_freem(m);
- }
- void
- bridge_localbroadcast(struct bridge_softc *sc, struct ifnet *ifp,
- struct ether_header *eh, struct mbuf *m)
- {
- struct mbuf_list ml = MBUF_LIST_INITIALIZER();
- struct mbuf *m1;
- u_int16_t etype;
- /*
- * quick optimisation, don't send packets up the stack if no
- * corresponding address has been specified.
- */
- etype = ntohs(eh->ether_type);
- if (!(m->m_flags & M_VLANTAG) && etype == ETHERTYPE_IP) {
- struct ifaddr *ifa;
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
- if (ifa->ifa_addr->sa_family == AF_INET)
- break;
- }
- if (ifa == NULL)
- return;
- }
- m1 = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
- if (m1 == NULL) {
- sc->sc_if.if_oerrors++;
- return;
- }
- m1->m_flags |= M_PROTO1;
- ml_enqueue(&ml, m1);
- if_input(ifp, &ml);
- }
- void
- bridge_span(struct bridge_softc *sc, struct mbuf *m)
- {
- struct bridge_iflist *p;
- struct ifnet *ifp;
- struct mbuf *mc;
- int error;
- TAILQ_FOREACH(p, &sc->sc_spanlist, next) {
- ifp = p->ifp;
- if ((ifp->if_flags & IFF_RUNNING) == 0)
- continue;
- if (IF_QFULL(&ifp->if_snd)) {
- IF_DROP(&ifp->if_snd);
- sc->sc_if.if_oerrors++;
- continue;
- }
- mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
- if (mc == NULL) {
- sc->sc_if.if_oerrors++;
- continue;
- }
- error = bridge_ifenqueue(sc, ifp, mc);
- if (error)
- continue;
- }
- }
- struct ifnet *
- bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
- struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
- {
- struct bridge_rtnode *p, *q;
- struct sockaddr *sa = NULL;
- u_int32_t h;
- int dir;
- if (m != NULL) {
- /* Check if the mbuf was tagged with a tunnel endpoint addr */
- sa = bridge_tunnel(m);
- }
- h = bridge_hash(sc, ea);
- p = LIST_FIRST(&sc->sc_rts[h]);
- if (p == NULL) {
- if (sc->sc_brtcnt >= sc->sc_brtmax)
- goto done;
- p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
- if (p == NULL)
- goto done;
- bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
- p->brt_if = ifp;
- p->brt_age = 1;
- bridge_copyaddr(sa, (struct sockaddr *)&p->brt_tunnel);
- if (setflags)
- p->brt_flags = flags;
- else
- p->brt_flags = IFBAF_DYNAMIC;
- LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
- sc->sc_brtcnt++;
- goto want;
- }
- do {
- q = p;
- p = LIST_NEXT(p, brt_next);
- dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
- if (dir == 0) {
- if (setflags) {
- q->brt_if = ifp;
- q->brt_flags = flags;
- } else if (!(q->brt_flags & IFBAF_STATIC))
- q->brt_if = ifp;
- if (q->brt_if == ifp)
- q->brt_age = 1;
- ifp = q->brt_if;
- bridge_copyaddr(sa,
- (struct sockaddr *)&q->brt_tunnel);
- goto want;
- }
- if (dir > 0) {
- if (sc->sc_brtcnt >= sc->sc_brtmax)
- goto done;
- p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
- if (p == NULL)
- goto done;
- bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
- p->brt_if = ifp;
- p->brt_age = 1;
- bridge_copyaddr(sa,
- (struct sockaddr *)&p->brt_tunnel);
- if (setflags)
- p->brt_flags = flags;
- else
- p->brt_flags = IFBAF_DYNAMIC;
- LIST_INSERT_BEFORE(q, p, brt_next);
- sc->sc_brtcnt++;
- goto want;
- }
- if (p == NULL) {
- if (sc->sc_brtcnt >= sc->sc_brtmax)
- goto done;
- p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
- if (p == NULL)
- goto done;
- bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
- p->brt_if = ifp;
- p->brt_age = 1;
- bridge_copyaddr(sa,
- (struct sockaddr *)&p->brt_tunnel);
- if (setflags)
- p->brt_flags = flags;
- else
- p->brt_flags = IFBAF_DYNAMIC;
- LIST_INSERT_AFTER(q, p, brt_next);
- sc->sc_brtcnt++;
- goto want;
- }
- } while (p != NULL);
- done:
- ifp = NULL;
- want:
- return (ifp);
- }
- struct bridge_rtnode *
- bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
- {
- struct bridge_rtnode *p;
- u_int32_t h;
- int dir;
- h = bridge_hash(sc, ea);
- LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
- dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
- if (dir == 0)
- return (p);
- if (dir > 0)
- goto fail;
- }
- fail:
- return (NULL);
- }
- u_int32_t
- bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
- {
- return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
- BRIDGE_RTABLE_MASK;
- }
- void
- bridge_timer(void *vsc)
- {
- struct bridge_softc *sc = vsc;
- int s;
- s = splsoftnet();
- bridge_rtage(sc);
- splx(s);
- }
- /*
- * Perform an aging cycle
- */
- void
- bridge_rtage(struct bridge_softc *sc)
- {
- struct bridge_rtnode *n, *p;
- int i;
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- n = LIST_FIRST(&sc->sc_rts[i]);
- while (n != NULL) {
- if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
- n->brt_age = !n->brt_age;
- if (n->brt_age)
- n->brt_age = 0;
- n = LIST_NEXT(n, brt_next);
- } else if (n->brt_age) {
- n->brt_age = 0;
- n = LIST_NEXT(n, brt_next);
- } else {
- p = LIST_NEXT(n, brt_next);
- LIST_REMOVE(n, brt_next);
- sc->sc_brtcnt--;
- free(n, M_DEVBUF, 0);
- n = p;
- }
- }
- }
- if (sc->sc_brttimeout != 0)
- timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
- }
- void
- bridge_rtagenode(struct ifnet *ifp, int age)
- {
- struct bridge_softc *sc;
- struct bridge_rtnode *n;
- int i;
- sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
- if (sc == NULL)
- return;
- /*
- * If the age is zero then flush, otherwise set all the expiry times to
- * age for the interface
- */
- if (age == 0)
- bridge_rtdelete(sc, ifp, 1);
- else {
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
- /* Cap the expiry time to 'age' */
- if (n->brt_if == ifp &&
- n->brt_age > time_uptime + age &&
- (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
- n->brt_age = time_uptime + age;
- }
- }
- }
- }
- /*
- * Remove all dynamic addresses from the cache
- */
- void
- bridge_rtflush(struct bridge_softc *sc, int full)
- {
- int i;
- struct bridge_rtnode *p, *n;
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- n = LIST_FIRST(&sc->sc_rts[i]);
- while (n != NULL) {
- if (full ||
- (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
- p = LIST_NEXT(n, brt_next);
- LIST_REMOVE(n, brt_next);
- sc->sc_brtcnt--;
- free(n, M_DEVBUF, 0);
- n = p;
- } else
- n = LIST_NEXT(n, brt_next);
- }
- }
- }
- /*
- * Remove an address from the cache
- */
- int
- bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
- {
- int h;
- struct bridge_rtnode *p;
- h = bridge_hash(sc, ea);
- LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
- if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
- LIST_REMOVE(p, brt_next);
- sc->sc_brtcnt--;
- free(p, M_DEVBUF, 0);
- return (0);
- }
- }
- return (ENOENT);
- }
- /*
- * Delete routes to a specific interface member.
- */
- void
- bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
- {
- int i;
- struct bridge_rtnode *n, *p;
- /*
- * Loop through all of the hash buckets and traverse each
- * chain looking for routes to this interface.
- */
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- n = LIST_FIRST(&sc->sc_rts[i]);
- while (n != NULL) {
- if (n->brt_if != ifp) {
- /* Not ours */
- n = LIST_NEXT(n, brt_next);
- continue;
- }
- if (dynonly &&
- (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
- /* only deleting dynamics */
- n = LIST_NEXT(n, brt_next);
- continue;
- }
- p = LIST_NEXT(n, brt_next);
- LIST_REMOVE(n, brt_next);
- sc->sc_brtcnt--;
- free(n, M_DEVBUF, 0);
- n = p;
- }
- }
- }
- /*
- * Gather all of the routes for this interface.
- */
- int
- bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
- {
- int i, error = 0, onlycnt = 0;
- u_int32_t cnt = 0;
- struct bridge_rtnode *n;
- struct ifbareq bareq;
- if (baconf->ifbac_len == 0)
- onlycnt = 1;
- for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
- if (!onlycnt) {
- if (baconf->ifbac_len < sizeof(struct ifbareq))
- goto done;
- bcopy(sc->sc_if.if_xname, bareq.ifba_name,
- sizeof(bareq.ifba_name));
- bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
- sizeof(bareq.ifba_ifsname));
- bcopy(&n->brt_addr, &bareq.ifba_dst,
- sizeof(bareq.ifba_dst));
- bridge_copyaddr(&n->brt_tunnel.sa,
- (struct sockaddr *)&bareq.ifba_dstsa);
- bareq.ifba_age = n->brt_age;
- bareq.ifba_flags = n->brt_flags;
- error = copyout((caddr_t)&bareq,
- (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
- if (error)
- goto done;
- baconf->ifbac_len -= sizeof(struct ifbareq);
- }
- cnt++;
- }
- }
- done:
- baconf->ifbac_len = cnt * sizeof(struct ifbareq);
- return (error);
- }
- /*
- * Block non-ip frames:
- * Returns 0 if frame is ip, and 1 if it should be dropped.
- */
- int
- bridge_blocknonip(struct ether_header *eh, struct mbuf *m)
- {
- struct llc llc;
- u_int16_t etype;
- if (m->m_pkthdr.len < ETHER_HDR_LEN)
- return (1);
- #if NVLAN > 0
- if (m->m_flags & M_VLANTAG)
- return (1);
- #endif
- etype = ntohs(eh->ether_type);
- switch (etype) {
- case ETHERTYPE_ARP:
- case ETHERTYPE_REVARP:
- case ETHERTYPE_IP:
- case ETHERTYPE_IPV6:
- return (0);
- }
- if (etype > ETHERMTU)
- return (1);
- if (m->m_pkthdr.len <
- (ETHER_HDR_LEN + LLC_SNAPFRAMELEN))
- return (1);
- m_copydata(m, ETHER_HDR_LEN, LLC_SNAPFRAMELEN,
- (caddr_t)&llc);
- etype = ntohs(llc.llc_snap.ether_type);
- if (llc.llc_dsap == LLC_SNAP_LSAP &&
- llc.llc_ssap == LLC_SNAP_LSAP &&
- llc.llc_control == LLC_UI &&
- llc.llc_snap.org_code[0] == 0 &&
- llc.llc_snap.org_code[1] == 0 &&
- llc.llc_snap.org_code[2] == 0 &&
- (etype == ETHERTYPE_ARP || etype == ETHERTYPE_REVARP ||
- etype == ETHERTYPE_IP || etype == ETHERTYPE_IPV6)) {
- return (0);
- }
- return (1);
- }
- u_int8_t
- bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
- {
- struct brl_node *n;
- u_int8_t flags;
- SIMPLEQ_FOREACH(n, h, brl_next) {
- flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
- if (flags == 0)
- goto return_action;
- if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
- if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
- continue;
- if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
- continue;
- goto return_action;
- }
- if (flags == BRL_FLAG_SRCVALID) {
- if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
- continue;
- goto return_action;
- }
- if (flags == BRL_FLAG_DSTVALID) {
- if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
- continue;
- goto return_action;
- }
- }
- return (BRL_ACTION_PASS);
- return_action:
- #if NPF > 0
- pf_tag_packet(m, n->brl_tag, -1);
- #endif
- return (n->brl_action);
- }
- int
- bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
- {
- struct brl_node *n;
- n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT);
- if (n == NULL)
- return (ENOMEM);
- bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
- bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
- n->brl_action = req->ifbr_action;
- n->brl_flags = req->ifbr_flags;
- #if NPF > 0
- if (req->ifbr_tagname[0])
- n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
- else
- n->brl_tag = 0;
- #endif
- if (out) {
- n->brl_flags &= ~BRL_FLAG_IN;
- n->brl_flags |= BRL_FLAG_OUT;
- SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
- } else {
- n->brl_flags &= ~BRL_FLAG_OUT;
- n->brl_flags |= BRL_FLAG_IN;
- SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
- }
- return (0);
- }
- void
- bridge_flushrule(struct bridge_iflist *bif)
- {
- struct brl_node *p;
- while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
- p = SIMPLEQ_FIRST(&bif->bif_brlin);
- SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
- #if NPF > 0
- pf_tag_unref(p->brl_tag);
- #endif
- free(p, M_DEVBUF, 0);
- }
- while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
- p = SIMPLEQ_FIRST(&bif->bif_brlout);
- SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
- #if NPF > 0
- pf_tag_unref(p->brl_tag);
- #endif
- free(p, M_DEVBUF, 0);
- }
- }
- #ifdef IPSEC
- int
- bridge_ipsec(struct bridge_softc *sc, struct ifnet *ifp,
- struct ether_header *eh, int hassnap, struct llc *llc,
- int dir, int af, int hlen, struct mbuf *m)
- {
- union sockaddr_union dst;
- struct tdb *tdb;
- u_int32_t spi;
- u_int16_t cpi;
- int error, off, s;
- u_int8_t proto = 0;
- struct ip *ip;
- #ifdef INET6
- struct ip6_hdr *ip6;
- #endif /* INET6 */
- #if NPF > 0
- struct ifnet *encif;
- #endif
- if (dir == BRIDGE_IN) {
- switch (af) {
- case AF_INET:
- if (m->m_pkthdr.len - hlen < 2 * sizeof(u_int32_t))
- break;
- ip = mtod(m, struct ip *);
- proto = ip->ip_p;
- off = offsetof(struct ip, ip_p);
- if (proto != IPPROTO_ESP && proto != IPPROTO_AH &&
- proto != IPPROTO_IPCOMP)
- goto skiplookup;
- bzero(&dst, sizeof(union sockaddr_union));
- dst.sa.sa_family = AF_INET;
- dst.sin.sin_len = sizeof(struct sockaddr_in);
- m_copydata(m, offsetof(struct ip, ip_dst),
- sizeof(struct in_addr),
- (caddr_t)&dst.sin.sin_addr);
- if (ip->ip_p == IPPROTO_ESP)
- m_copydata(m, hlen, sizeof(u_int32_t),
- (caddr_t)&spi);
- else if (ip->ip_p == IPPROTO_AH)
- m_copydata(m, hlen + sizeof(u_int32_t),
- sizeof(u_int32_t), (caddr_t)&spi);
- else if (ip->ip_p == IPPROTO_IPCOMP) {
- m_copydata(m, hlen + sizeof(u_int16_t),
- sizeof(u_int16_t), (caddr_t)&cpi);
- spi = ntohl(htons(cpi));
- }
- break;
- #ifdef INET6
- case AF_INET6:
- if (m->m_pkthdr.len - hlen < 2 * sizeof(u_int32_t))
- break;
- ip6 = mtod(m, struct ip6_hdr *);
- /* XXX We should chase down the header chain */
- proto = ip6->ip6_nxt;
- off = offsetof(struct ip6_hdr, ip6_nxt);
- if (proto != IPPROTO_ESP && proto != IPPROTO_AH &&
- proto != IPPROTO_IPCOMP)
- goto skiplookup;
- bzero(&dst, sizeof(union sockaddr_union));
- dst.sa.sa_family = AF_INET6;
- dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
- m_copydata(m, offsetof(struct ip6_hdr, ip6_nxt),
- sizeof(struct in6_addr),
- (caddr_t)&dst.sin6.sin6_addr);
- if (proto == IPPROTO_ESP)
- m_copydata(m, hlen, sizeof(u_int32_t),
- (caddr_t)&spi);
- else if (proto == IPPROTO_AH)
- m_copydata(m, hlen + sizeof(u_int32_t),
- sizeof(u_int32_t), (caddr_t)&spi);
- else if (proto == IPPROTO_IPCOMP) {
- m_copydata(m, hlen + sizeof(u_int16_t),
- sizeof(u_int16_t), (caddr_t)&cpi);
- spi = ntohl(htons(cpi));
- }
- break;
- #endif /* INET6 */
- default:
- return (0);
- }
- if (proto == 0)
- goto skiplookup;
- s = splsoftnet();
- tdb = gettdb(ifp->if_rdomain, spi, &dst, proto);
- if (tdb != NULL && (tdb->tdb_flags & TDBF_INVALID) == 0 &&
- tdb->tdb_xform != NULL) {
- if (tdb->tdb_first_use == 0) {
- tdb->tdb_first_use = time_second;
- if (tdb->tdb_flags & TDBF_FIRSTUSE)
- timeout_add_sec(&tdb->tdb_first_tmo,
- tdb->tdb_exp_first_use);
- if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
- timeout_add_sec(&tdb->tdb_sfirst_tmo,
- tdb->tdb_soft_first_use);
- }
- (*(tdb->tdb_xform->xf_input))(m, tdb, hlen, off);
- splx(s);
- return (1);
- } else {
- splx(s);
- skiplookup:
- /* XXX do an input policy lookup */
- return (0);
- }
- } else { /* Outgoing from the bridge. */
- tdb = ipsp_spd_lookup(m, af, hlen, &error,
- IPSP_DIRECTION_OUT, NULL, NULL, 0);
- if (tdb != NULL) {
- /*
- * We don't need to do loop detection, the
- * bridge will do that for us.
- */
- #if NPF > 0
- if ((encif = enc_getif(tdb->tdb_rdomain,
- tdb->tdb_tap)) == NULL ||
- pf_test(af, dir, encif, &m) != PF_PASS) {
- m_freem(m);
- return (1);
- }
- if (m == NULL)
- return (1);
- else if (af == AF_INET)
- in_proto_cksum_out(m, encif);
- #ifdef INET6
- else if (af == AF_INET6)
- in6_proto_cksum_out(m, encif);
- #endif /* INET6 */
- #endif /* NPF */
- ip = mtod(m, struct ip *);
- if ((af == AF_INET) &&
- ip_mtudisc && (ip->ip_off & htons(IP_DF)) &&
- tdb->tdb_mtu && ntohs(ip->ip_len) > tdb->tdb_mtu &&
- tdb->tdb_mtutimeout > time_second)
- bridge_send_icmp_err(sc, ifp, eh, m,
- hassnap, llc, tdb->tdb_mtu,
- ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG);
- else
- error = ipsp_process_packet(m, tdb, af, 0);
- return (1);
- } else
- return (0);
- }
- return (0);
- }
- #endif /* IPSEC */
- /*
- * Filter IP packets by peeking into the ethernet frame. This violates
- * the ISO model, but allows us to act as a IP filter at the data link
- * layer. As a result, most of this code will look familiar to those
- * who've read net/if_ethersubr.c and netinet/ip_input.c
- */
- struct mbuf *
- bridge_ip(struct bridge_softc *sc, int dir, struct ifnet *ifp,
- struct ether_header *eh, struct mbuf *m)
- {
- struct llc llc;
- int hassnap = 0;
- struct ip *ip;
- int hlen;
- u_int16_t etype;
- #if NVLAN > 0
- if (m->m_flags & M_VLANTAG)
- return (m);
- #endif
- etype = ntohs(eh->ether_type);
- if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6) {
- if (etype > ETHERMTU ||
- m->m_pkthdr.len < (LLC_SNAPFRAMELEN +
- ETHER_HDR_LEN))
- return (m);
- m_copydata(m, ETHER_HDR_LEN,
- LLC_SNAPFRAMELEN, (caddr_t)&llc);
- if (llc.llc_dsap != LLC_SNAP_LSAP ||
- llc.llc_ssap != LLC_SNAP_LSAP ||
- llc.llc_control != LLC_UI ||
- llc.llc_snap.org_code[0] ||
- llc.llc_snap.org_code[1] ||
- llc.llc_snap.org_code[2])
- return (m);
- etype = ntohs(llc.llc_snap.ether_type);
- if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6)
- return (m);
- hassnap = 1;
- }
- m_adj(m, ETHER_HDR_LEN);
- if (hassnap)
- m_adj(m, LLC_SNAPFRAMELEN);
- switch (etype) {
- case ETHERTYPE_IP:
- if (m->m_pkthdr.len < sizeof(struct ip))
- goto dropit;
- /* Copy minimal header, and drop invalids */
- if (m->m_len < sizeof(struct ip) &&
- (m = m_pullup(m, sizeof(struct ip))) == NULL) {
- ipstat.ips_toosmall++;
- return (NULL);
- }
- ip = mtod(m, struct ip *);
- if (ip->ip_v != IPVERSION) {
- ipstat.ips_badvers++;
- goto dropit;
- }
- hlen = ip->ip_hl << 2; /* get whole header length */
- if (hlen < sizeof(struct ip)) {
- ipstat.ips_badhlen++;
- goto dropit;
- }
- if (hlen > m->m_len) {
- if ((m = m_pullup(m, hlen)) == NULL) {
- ipstat.ips_badhlen++;
- return (NULL);
- }
- ip = mtod(m, struct ip *);
- }
- if ((m->m_pkthdr.csum_flags & M_IPV4_CSUM_IN_OK) == 0) {
- if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_IN_BAD) {
- ipstat.ips_badsum++;
- goto dropit;
- }
- ipstat.ips_inswcsum++;
- if (in_cksum(m, hlen) != 0) {
- ipstat.ips_badsum++;
- goto dropit;
- }
- }
- if (ntohs(ip->ip_len) < hlen)
- goto dropit;
- if (m->m_pkthdr.len < ntohs(ip->ip_len))
- goto dropit;
- if (m->m_pkthdr.len > ntohs(ip->ip_len)) {
- if (m->m_len == m->m_pkthdr.len) {
- m->m_len = ntohs(ip->ip_len);
- m->m_pkthdr.len = ntohs(ip->ip_len);
- } else
- m_adj(m, ntohs(ip->ip_len) - m->m_pkthdr.len);
- }
- #ifdef IPSEC
- if ((sc->sc_if.if_flags & IFF_LINK2) == IFF_LINK2 &&
- bridge_ipsec(sc, ifp, eh, hassnap, &llc,
- dir, AF_INET, hlen, m))
- return (NULL);
- #endif /* IPSEC */
- #if NPF > 0
- /* Finally, we get to filter the packet! */
- if (pf_test(AF_INET, dir, ifp, &m) != PF_PASS)
- goto dropit;
- if (m == NULL)
- goto dropit;
- #endif /* NPF > 0 */
- /* Rebuild the IP header */
- if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
- return (NULL);
- if (m->m_len < sizeof(struct ip))
- goto dropit;
- in_proto_cksum_out(m, ifp);
- ip = mtod(m, struct ip *);
- ip->ip_sum = 0;
- if (0 && (ifp->if_capabilities & IFCAP_CSUM_IPv4))
- m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
- else {
- ipstat.ips_outswcsum++;
- ip->ip_sum = in_cksum(m, hlen);
- }
- break;
- #ifdef INET6
- case ETHERTYPE_IPV6: {
- struct ip6_hdr *ip6;
- if (m->m_len < sizeof(struct ip6_hdr)) {
- if ((m = m_pullup(m, sizeof(struct ip6_hdr)))
- == NULL) {
- ip6stat.ip6s_toosmall++;
- return (NULL);
- }
- }
- ip6 = mtod(m, struct ip6_hdr *);
- if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
- struct ifnet *ifp;
- ip6stat.ip6s_badvers++;
- ifp = if_get(m->m_pkthdr.ph_ifidx);
- if (ifp != NULL)
- in6_ifstat_inc(ifp, ifs6_in_hdrerr);
- goto dropit;
- }
- #ifdef IPSEC
- hlen = sizeof(struct ip6_hdr);
- if ((sc->sc_if.if_flags & IFF_LINK2) == IFF_LINK2 &&
- bridge_ipsec(sc, ifp, eh, hassnap, &llc,
- dir, AF_INET6, hlen, m))
- return (NULL);
- #endif /* IPSEC */
- #if NPF > 0
- if (pf_test(AF_INET6, dir, ifp, &m) != PF_PASS)
- goto dropit;
- if (m == NULL)
- return (NULL);
- #endif /* NPF > 0 */
- in6_proto_cksum_out(m, ifp);
- break;
- }
- #endif /* INET6 */
- default:
- goto dropit;
- break;
- }
- /* Reattach SNAP header */
- if (hassnap) {
- M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
- if (m == NULL)
- goto dropit;
- bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
- }
- /* Reattach ethernet header */
- M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
- if (m == NULL)
- goto dropit;
- bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
- return (m);
- dropit:
- m_freem(m);
- return (NULL);
- }
- void
- bridge_fragment(struct bridge_softc *sc, struct ifnet *ifp,
- struct ether_header *eh, struct mbuf *m)
- {
- struct llc llc;
- struct mbuf *m0;
- int error = 0;
- int hassnap = 0;
- u_int16_t etype;
- struct ip *ip;
- etype = ntohs(eh->ether_type);
- #if NVLAN > 0
- if ((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN ||
- etype == ETHERTYPE_QINQ) {
- int len = m->m_pkthdr.len;
- if (m->m_flags & M_VLANTAG)
- len += ETHER_VLAN_ENCAP_LEN;
- if ((ifp->if_capabilities & IFCAP_VLAN_MTU) &&
- (len - sizeof(struct ether_vlan_header) <= ifp->if_mtu)) {
- bridge_ifenqueue(sc, ifp, m);
- return;
- }
- goto dropit;
- }
- #endif
- if (etype != ETHERTYPE_IP) {
- if (etype > ETHERMTU ||
- m->m_pkthdr.len < (LLC_SNAPFRAMELEN +
- ETHER_HDR_LEN))
- goto dropit;
- m_copydata(m, ETHER_HDR_LEN,
- LLC_SNAPFRAMELEN, (caddr_t)&llc);
- if (llc.llc_dsap != LLC_SNAP_LSAP ||
- llc.llc_ssap != LLC_SNAP_LSAP ||
- llc.llc_control != LLC_UI ||
- llc.llc_snap.org_code[0] ||
- llc.llc_snap.org_code[1] ||
- llc.llc_snap.org_code[2] ||
- llc.llc_snap.ether_type != htons(ETHERTYPE_IP))
- goto dropit;
- hassnap = 1;
- }
- m_adj(m, ETHER_HDR_LEN);
- if (hassnap)
- m_adj(m, LLC_SNAPFRAMELEN);
- if (m->m_len < sizeof(struct ip) &&
- (m = m_pullup(m, sizeof(struct ip))) == NULL)
- goto dropit;
- ip = mtod(m, struct ip *);
- /* Respect IP_DF, return a ICMP_UNREACH_NEEDFRAG. */
- if (ip->ip_off & htons(IP_DF)) {
- bridge_send_icmp_err(sc, ifp, eh, m, hassnap, &llc,
- ifp->if_mtu, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG);
- return;
- }
- error = ip_fragment(m, ifp, ifp->if_mtu);
- if (error) {
- m = NULL;
- goto dropit;
- }
- for (; m; m = m0) {
- m0 = m->m_nextpkt;
- m->m_nextpkt = NULL;
- if (error == 0) {
- if (hassnap) {
- M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
- if (m == NULL) {
- error = ENOBUFS;
- continue;
- }
- bcopy(&llc, mtod(m, caddr_t),
- LLC_SNAPFRAMELEN);
- }
- M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
- if (m == NULL) {
- error = ENOBUFS;
- continue;
- }
- bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
- error = bridge_ifenqueue(sc, ifp, m);
- if (error) {
- continue;
- }
- } else
- m_freem(m);
- }
- if (error == 0)
- ipstat.ips_fragmented++;
- return;
- dropit:
- m_freem(m);
- }
- int
- bridge_ifenqueue(struct bridge_softc *sc, struct ifnet *ifp, struct mbuf *m)
- {
- int error, len;
- /* Loop prevention. */
- m->m_flags |= M_PROTO1;
- #if NGIF > 0
- /* Packet needs etherip encapsulation. */
- if (ifp->if_type == IFT_GIF) {
- /* Count packets input into the gif from outside */
- ifp->if_ipackets++;
- ifp->if_ibytes += m->m_pkthdr.len;
- error = gif_encap(ifp, &m, AF_LINK);
- if (error)
- return (error);
- }
- #endif /* NGIF */
- len = m->m_pkthdr.len;
- error = if_enqueue(ifp, m);
- if (error) {
- sc->sc_if.if_oerrors++;
- return (error);
- }
- sc->sc_if.if_opackets++;
- sc->sc_if.if_obytes += len;
- return (0);
- }
- void
- bridge_send_icmp_err(struct bridge_softc *sc, struct ifnet *ifp,
- struct ether_header *eh, struct mbuf *n, int hassnap, struct llc *llc,
- int mtu, int type, int code)
- {
- struct ip *ip;
- struct icmp *icp;
- struct in_addr t;
- struct mbuf *m, *n2;
- int hlen;
- u_int8_t ether_tmp[ETHER_ADDR_LEN];
- n2 = m_copym(n, 0, M_COPYALL, M_DONTWAIT);
- if (!n2) {
- m_freem(n);
- return;
- }
- m = icmp_do_error(n, type, code, 0, mtu);
- if (m == NULL) {
- m_freem(n2);
- return;
- }
- n = n2;
- ip = mtod(m, struct ip *);
- hlen = ip->ip_hl << 2;
- t = ip->ip_dst;
- ip->ip_dst = ip->ip_src;
- ip->ip_src = t;
- m->m_data += hlen;
- m->m_len -= hlen;
- icp = mtod(m, struct icmp *);
- icp->icmp_cksum = 0;
- icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen);
- m->m_data -= hlen;
- m->m_len += hlen;
- ip->ip_v = IPVERSION;
- ip->ip_off &= htons(IP_DF);
- ip->ip_id = htons(ip_randomid());
- ip->ip_ttl = MAXTTL;
- ip->ip_sum = 0;
- ip->ip_sum = in_cksum(m, hlen);
- /* Swap ethernet addresses */
- bcopy(&eh->ether_dhost, ðer_tmp, sizeof(ether_tmp));
- bcopy(&eh->ether_shost, &eh->ether_dhost, sizeof(ether_tmp));
- bcopy(ðer_tmp, &eh->ether_shost, sizeof(ether_tmp));
- /* Reattach SNAP header */
- if (hassnap) {
- M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
- if (m == NULL)
- goto dropit;
- bcopy(llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
- }
- /* Reattach ethernet header */
- M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
- if (m == NULL)
- goto dropit;
- bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
- bridge_output(ifp, m, NULL, NULL);
- m_freem(n);
- return;
- dropit:
- m_freem(n);
- }
- struct sockaddr *
- bridge_tunnel(struct mbuf *m)
- {
- struct m_tag *mtag;
- if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL)
- return (NULL);
- return ((struct sockaddr *)(mtag + 1));
- }
- struct sockaddr *
- bridge_tunneltag(struct mbuf *m, int af)
- {
- struct m_tag *mtag;
- size_t len;
- struct sockaddr *sa;
- if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) != NULL) {
- sa = (struct sockaddr *)(mtag + 1);
- if (sa->sa_family != af) {
- m_tag_delete(m, mtag);
- mtag = NULL;
- }
- }
- if (mtag == NULL) {
- if (af == AF_INET)
- len = sizeof(struct sockaddr_in);
- else if (af == AF_INET6)
- len = sizeof(struct sockaddr_in6);
- else
- return (NULL);
- mtag = m_tag_get(PACKET_TAG_TUNNEL, len, M_NOWAIT);
- if (mtag == NULL)
- return (NULL);
- bzero(mtag + 1, len);
- sa = (struct sockaddr *)(mtag + 1);
- sa->sa_family = af;
- sa->sa_len = len;
- m_tag_prepend(m, mtag);
- }
- return ((struct sockaddr *)(mtag + 1));
- }
- void
- bridge_tunneluntag(struct mbuf *m)
- {
- struct m_tag *mtag;
- if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) != NULL)
- m_tag_delete(m, mtag);
- }
- void
- bridge_copyaddr(struct sockaddr *src, struct sockaddr *dst)
- {
- if (src != NULL && src->sa_family != AF_UNSPEC)
- memcpy(dst, src, src->sa_len);
- else
- dst->sa_family = AF_UNSPEC;
- }
- /*
- * Specialized deep copy to ensure that the payload after the Ethernet
- * header is nicely aligned.
- */
- struct mbuf *
- bridge_m_dup(struct mbuf *m)
- {
- struct mbuf *m1, *m2, *mx;
- m1 = m_copym2(m, 0, ETHER_HDR_LEN, M_DONTWAIT);
- if (m1 == NULL) {
- return (NULL);
- }
- m2 = m_copym2(m, ETHER_HDR_LEN, M_COPYALL, M_DONTWAIT);
- if (m2 == NULL) {
- m_freem(m1);
- return (NULL);
- }
- for (mx = m1; mx->m_next != NULL; mx = mx->m_next)
- /*EMPTY*/;
- mx->m_next = m2;
- if (m1->m_flags & M_PKTHDR) {
- int len = 0;
- for (mx = m1; mx != NULL; mx = mx->m_next)
- len += mx->m_len;
- m1->m_pkthdr.len = len;
- }
- return (m1);
- }
|