LCOV - code coverage report
Current view: top level - net - bridgectl.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 392 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: bridgectl.c,v 1.8 2018/02/05 05:06:51 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 "pf.h"
      35             : 
      36             : #include <sys/param.h>
      37             : #include <sys/systm.h>
      38             : #include <sys/mbuf.h>
      39             : #include <sys/socket.h>
      40             : #include <sys/ioctl.h>
      41             : #include <sys/timeout.h>
      42             : #include <sys/kernel.h>
      43             : 
      44             : #include <crypto/siphash.h>
      45             : 
      46             : #include <net/if.h>
      47             : 
      48             : #include <netinet/in.h>
      49             : #include <netinet/if_ether.h>
      50             : 
      51             : #include <net/if_bridge.h>
      52             : 
      53             : 
      54             : int     bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
      55             : int     bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
      56             : u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
      57             : 
      58             : int     bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
      59             : int     bridge_addrule(struct bridge_iflist *, struct ifbrlreq *, int out);
      60             : 
      61             : int
      62           0 : bridgectl_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
      63             : {
      64           0 :         struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
      65           0 :         struct ifbreq *req = (struct ifbreq *)data;
      66           0 :         struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
      67           0 :         struct ifbareq *bareq = (struct ifbareq *)data;
      68           0 :         struct ifbrparam *bparam = (struct ifbrparam *)data;
      69             :         struct bridge_iflist *p;
      70             :         struct ifnet *ifs;
      71             :         int error = 0;
      72             : 
      73           0 :         switch (cmd) {
      74             :         case SIOCBRDGRTS:
      75           0 :                 error = bridge_rtfind(sc, (struct ifbaconf *)data);
      76           0 :                 break;
      77             :         case SIOCBRDGFLUSH:
      78           0 :                 bridge_rtflush(sc, req->ifbr_ifsflags);
      79           0 :                 break;
      80             :         case SIOCBRDGSADDR:
      81           0 :                 ifs = ifunit(bareq->ifba_ifsname);
      82           0 :                 if (ifs == NULL) {                      /* no such interface */
      83             :                         error = ENOENT;
      84           0 :                         break;
      85             :                 }
      86           0 :                 p = (struct bridge_iflist *)ifs->if_bridgeport;
      87           0 :                 if (p == NULL || p->bridge_sc != sc) {
      88             :                         error = ESRCH;
      89           0 :                         break;
      90             :                 }
      91             : 
      92           0 :                 ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
      93           0 :                     bareq->ifba_flags, NULL);
      94           0 :                 if (ifs == NULL)
      95           0 :                         error = ENOMEM;
      96             :                 break;
      97             :         case SIOCBRDGDADDR:
      98           0 :                 error = bridge_rtdaddr(sc, &bareq->ifba_dst);
      99           0 :                 break;
     100             :         case SIOCBRDGGCACHE:
     101           0 :                 bparam->ifbrp_csize = sc->sc_brtmax;
     102           0 :                 break;
     103             :         case SIOCBRDGSCACHE:
     104           0 :                 sc->sc_brtmax = bparam->ifbrp_csize;
     105           0 :                 break;
     106             :         case SIOCBRDGSTO:
     107           0 :                 if (bparam->ifbrp_ctime < 0 ||
     108           0 :                     bparam->ifbrp_ctime > INT_MAX / hz) {
     109             :                         error = EINVAL;
     110           0 :                         break;
     111             :                 }
     112           0 :                 sc->sc_brttimeout = bparam->ifbrp_ctime;
     113           0 :                 if (bparam->ifbrp_ctime != 0)
     114           0 :                         timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
     115             :                 else
     116           0 :                         timeout_del(&sc->sc_brtimeout);
     117             :                 break;
     118             :         case SIOCBRDGGTO:
     119           0 :                 bparam->ifbrp_ctime = sc->sc_brttimeout;
     120           0 :                 break;
     121             :         case SIOCBRDGARL:
     122           0 :                 ifs = ifunit(brlreq->ifbr_ifsname);
     123           0 :                 if (ifs == NULL) {
     124             :                         error = ENOENT;
     125           0 :                         break;
     126             :                 }
     127           0 :                 p = (struct bridge_iflist *)ifs->if_bridgeport;
     128           0 :                 if (p == NULL || p->bridge_sc != sc) {
     129             :                         error = ESRCH;
     130           0 :                         break;
     131             :                 }
     132           0 :                 if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
     133           0 :                     brlreq->ifbr_action != BRL_ACTION_PASS) ||
     134           0 :                     (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
     135             :                         error = EINVAL;
     136           0 :                         break;
     137             :                 }
     138           0 :                 if (brlreq->ifbr_flags & BRL_FLAG_IN) {
     139           0 :                         error = bridge_addrule(p, brlreq, 0);
     140           0 :                         if (error)
     141             :                                 break;
     142             :                 }
     143           0 :                 if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
     144           0 :                         error = bridge_addrule(p, brlreq, 1);
     145           0 :                         if (error)
     146             :                                 break;
     147             :                 }
     148             :                 break;
     149             :         case SIOCBRDGFRL:
     150           0 :                 ifs = ifunit(brlreq->ifbr_ifsname);
     151           0 :                 if (ifs == NULL) {
     152             :                         error = ENOENT;
     153           0 :                         break;
     154             :                 }
     155           0 :                 p = (struct bridge_iflist *)ifs->if_bridgeport;
     156           0 :                 if (p == NULL || p->bridge_sc != sc) {
     157             :                         error = ESRCH;
     158           0 :                         break;
     159             :                 }
     160           0 :                 bridge_flushrule(p);
     161           0 :                 break;
     162             :         case SIOCBRDGGRL:
     163           0 :                 error = bridge_brlconf(sc, (struct ifbrlconf *)data);
     164           0 :                 break;
     165             :         default:
     166             :                 break;
     167             :         }
     168             : 
     169           0 :         return (error);
     170             : }
     171             : 
     172             : struct ifnet *
     173           0 : bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
     174             :     struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
     175             : {
     176             :         struct bridge_rtnode *p, *q;
     177             :         struct bridge_tunneltag *brtag = NULL;
     178             :         u_int32_t h;
     179             :         int dir;
     180             : 
     181           0 :         if (m != NULL) {
     182             :                 /* Check if the mbuf was tagged with a tunnel endpoint addr */
     183           0 :                 brtag = bridge_tunnel(m);
     184           0 :         }
     185             : 
     186           0 :         h = bridge_hash(sc, ea);
     187           0 :         p = LIST_FIRST(&sc->sc_rts[h]);
     188           0 :         if (p == NULL) {
     189           0 :                 if (sc->sc_brtcnt >= sc->sc_brtmax)
     190             :                         goto done;
     191           0 :                 p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
     192           0 :                 if (p == NULL)
     193             :                         goto done;
     194             : 
     195           0 :                 bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
     196           0 :                 p->brt_if = ifp;
     197           0 :                 p->brt_age = 1;
     198           0 :                 bridge_copytag(brtag, &p->brt_tunnel);
     199             : 
     200           0 :                 if (setflags)
     201           0 :                         p->brt_flags = flags;
     202             :                 else
     203           0 :                         p->brt_flags = IFBAF_DYNAMIC;
     204             : 
     205           0 :                 LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
     206           0 :                 sc->sc_brtcnt++;
     207           0 :                 goto want;
     208             :         }
     209             : 
     210           0 :         do {
     211             :                 q = p;
     212           0 :                 p = LIST_NEXT(p, brt_next);
     213             : 
     214           0 :                 dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
     215           0 :                 if (dir == 0) {
     216           0 :                         if (setflags) {
     217           0 :                                 q->brt_if = ifp;
     218           0 :                                 q->brt_flags = flags;
     219           0 :                         } else if (!(q->brt_flags & IFBAF_STATIC))
     220           0 :                                 q->brt_if = ifp;
     221             : 
     222           0 :                         if (q->brt_if == ifp)
     223           0 :                                 q->brt_age = 1;
     224           0 :                         ifp = q->brt_if;
     225           0 :                         bridge_copytag(brtag, &q->brt_tunnel);
     226             : 
     227           0 :                         goto want;
     228             :                 }
     229             : 
     230           0 :                 if (dir > 0) {
     231           0 :                         if (sc->sc_brtcnt >= sc->sc_brtmax)
     232             :                                 goto done;
     233           0 :                         p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
     234           0 :                         if (p == NULL)
     235             :                                 goto done;
     236             : 
     237           0 :                         bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
     238           0 :                         p->brt_if = ifp;
     239           0 :                         p->brt_age = 1;
     240           0 :                         bridge_copytag(brtag, &p->brt_tunnel);
     241             : 
     242           0 :                         if (setflags)
     243           0 :                                 p->brt_flags = flags;
     244             :                         else
     245           0 :                                 p->brt_flags = IFBAF_DYNAMIC;
     246             : 
     247           0 :                         LIST_INSERT_BEFORE(q, p, brt_next);
     248           0 :                         sc->sc_brtcnt++;
     249           0 :                         goto want;
     250             :                 }
     251             : 
     252           0 :                 if (p == NULL) {
     253           0 :                         if (sc->sc_brtcnt >= sc->sc_brtmax)
     254             :                                 goto done;
     255           0 :                         p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
     256           0 :                         if (p == NULL)
     257             :                                 goto done;
     258             : 
     259           0 :                         bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
     260           0 :                         p->brt_if = ifp;
     261           0 :                         p->brt_age = 1;
     262           0 :                         bridge_copytag(brtag, &p->brt_tunnel);
     263             : 
     264           0 :                         if (setflags)
     265           0 :                                 p->brt_flags = flags;
     266             :                         else
     267           0 :                                 p->brt_flags = IFBAF_DYNAMIC;
     268           0 :                         LIST_INSERT_AFTER(q, p, brt_next);
     269           0 :                         sc->sc_brtcnt++;
     270           0 :                         goto want;
     271             :                 }
     272           0 :         } while (p != NULL);
     273             : 
     274             : done:
     275           0 :         ifp = NULL;
     276             : want:
     277           0 :         return (ifp);
     278             : }
     279             : 
     280             : struct bridge_rtnode *
     281           0 : bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
     282             : {
     283             :         struct bridge_rtnode *p;
     284             :         u_int32_t h;
     285             :         int dir;
     286             : 
     287           0 :         h = bridge_hash(sc, ea);
     288           0 :         LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
     289           0 :                 dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
     290           0 :                 if (dir == 0)
     291           0 :                         return (p);
     292           0 :                 if (dir > 0)
     293             :                         goto fail;
     294             :         }
     295             : fail:
     296           0 :         return (NULL);
     297           0 : }
     298             : 
     299             : u_int32_t
     300           0 : bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
     301             : {
     302           0 :         return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
     303             :             BRIDGE_RTABLE_MASK;
     304             : }
     305             : 
     306             : /*
     307             :  * Perform an aging cycle
     308             :  */
     309             : void
     310           0 : bridge_rtage(void *vsc)
     311             : {
     312           0 :         struct bridge_softc *sc = vsc;
     313             :         struct bridge_rtnode *n, *p;
     314             :         int i;
     315             : 
     316           0 :         KERNEL_ASSERT_LOCKED();
     317             : 
     318           0 :         for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
     319           0 :                 n = LIST_FIRST(&sc->sc_rts[i]);
     320           0 :                 while (n != NULL) {
     321           0 :                         if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
     322           0 :                                 n->brt_age = !n->brt_age;
     323           0 :                                 if (n->brt_age)
     324           0 :                                         n->brt_age = 0;
     325           0 :                                 n = LIST_NEXT(n, brt_next);
     326           0 :                         } else if (n->brt_age) {
     327           0 :                                 n->brt_age = 0;
     328           0 :                                 n = LIST_NEXT(n, brt_next);
     329           0 :                         } else {
     330           0 :                                 p = LIST_NEXT(n, brt_next);
     331           0 :                                 LIST_REMOVE(n, brt_next);
     332           0 :                                 sc->sc_brtcnt--;
     333           0 :                                 free(n, M_DEVBUF, sizeof *n);
     334             :                                 n = p;
     335             :                         }
     336             :                 }
     337             :         }
     338             : 
     339           0 :         if (sc->sc_brttimeout != 0)
     340           0 :                 timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
     341           0 : }
     342             : 
     343             : void
     344           0 : bridge_rtagenode(struct ifnet *ifp, int age)
     345             : {
     346             :         struct bridge_softc *sc;
     347             :         struct bridge_rtnode *n;
     348             :         int i;
     349             : 
     350           0 :         sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
     351           0 :         if (sc == NULL)
     352           0 :                 return;
     353             : 
     354             :         /*
     355             :          * If the age is zero then flush, otherwise set all the expiry times to
     356             :          * age for the interface
     357             :          */
     358           0 :         if (age == 0)
     359           0 :                 bridge_rtdelete(sc, ifp, 1);
     360             :         else {
     361           0 :                 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
     362           0 :                         LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
     363             :                                 /* Cap the expiry time to 'age' */
     364           0 :                                 if (n->brt_if == ifp &&
     365           0 :                                     n->brt_age > time_uptime + age &&
     366           0 :                                     (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
     367           0 :                                         n->brt_age = time_uptime + age;
     368             :                         }
     369             :                 }
     370             :         }
     371           0 : }
     372             : 
     373             : /*
     374             :  * Remove all dynamic addresses from the cache
     375             :  */
     376             : void
     377           0 : bridge_rtflush(struct bridge_softc *sc, int full)
     378             : {
     379             :         int i;
     380             :         struct bridge_rtnode *p, *n;
     381             : 
     382           0 :         for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
     383           0 :                 n = LIST_FIRST(&sc->sc_rts[i]);
     384           0 :                 while (n != NULL) {
     385           0 :                         if (full ||
     386           0 :                             (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
     387           0 :                                 p = LIST_NEXT(n, brt_next);
     388           0 :                                 LIST_REMOVE(n, brt_next);
     389           0 :                                 sc->sc_brtcnt--;
     390           0 :                                 free(n, M_DEVBUF, sizeof *n);
     391             :                                 n = p;
     392           0 :                         } else
     393           0 :                                 n = LIST_NEXT(n, brt_next);
     394             :                 }
     395             :         }
     396           0 : }
     397             : 
     398             : /*
     399             :  * Remove an address from the cache
     400             :  */
     401             : int
     402           0 : bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
     403             : {
     404             :         int h;
     405             :         struct bridge_rtnode *p;
     406             : 
     407           0 :         h = bridge_hash(sc, ea);
     408           0 :         LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
     409           0 :                 if (memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
     410           0 :                         LIST_REMOVE(p, brt_next);
     411           0 :                         sc->sc_brtcnt--;
     412           0 :                         free(p, M_DEVBUF, sizeof *p);
     413           0 :                         return (0);
     414             :                 }
     415             :         }
     416             : 
     417           0 :         return (ENOENT);
     418           0 : }
     419             : 
     420             : /*
     421             :  * Delete routes to a specific interface member.
     422             :  */
     423             : void
     424           0 : bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
     425             : {
     426             :         int i;
     427             :         struct bridge_rtnode *n, *p;
     428             : 
     429             :         /*
     430             :          * Loop through all of the hash buckets and traverse each
     431             :          * chain looking for routes to this interface.
     432             :          */
     433           0 :         for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
     434           0 :                 n = LIST_FIRST(&sc->sc_rts[i]);
     435           0 :                 while (n != NULL) {
     436           0 :                         if (n->brt_if != ifp) {
     437             :                                 /* Not ours */
     438           0 :                                 n = LIST_NEXT(n, brt_next);
     439           0 :                                 continue;
     440             :                         }
     441           0 :                         if (dynonly &&
     442           0 :                             (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
     443             :                                 /* only deleting dynamics */
     444           0 :                                 n = LIST_NEXT(n, brt_next);
     445           0 :                                 continue;
     446             :                         }
     447           0 :                         p = LIST_NEXT(n, brt_next);
     448           0 :                         LIST_REMOVE(n, brt_next);
     449           0 :                         sc->sc_brtcnt--;
     450           0 :                         free(n, M_DEVBUF, sizeof *n);
     451             :                         n = p;
     452             :                 }
     453             :         }
     454           0 : }
     455             : 
     456             : /*
     457             :  * Gather all of the routes for this interface.
     458             :  */
     459             : int
     460           0 : bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
     461             : {
     462             :         int i, error = 0, onlycnt = 0;
     463             :         u_int32_t cnt = 0;
     464             :         struct bridge_rtnode *n;
     465           0 :         struct ifbareq bareq;
     466             : 
     467           0 :         if (baconf->ifbac_len == 0)
     468           0 :                 onlycnt = 1;
     469             : 
     470           0 :         for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
     471           0 :                 LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
     472           0 :                         if (!onlycnt) {
     473           0 :                                 if (baconf->ifbac_len < sizeof(struct ifbareq))
     474             :                                         goto done;
     475           0 :                                 bcopy(sc->sc_if.if_xname, bareq.ifba_name,
     476             :                                     sizeof(bareq.ifba_name));
     477           0 :                                 bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
     478             :                                     sizeof(bareq.ifba_ifsname));
     479           0 :                                 bcopy(&n->brt_addr, &bareq.ifba_dst,
     480             :                                     sizeof(bareq.ifba_dst));
     481           0 :                                 bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
     482           0 :                                     sstosa(&bareq.ifba_dstsa));
     483           0 :                                 bareq.ifba_age = n->brt_age;
     484           0 :                                 bareq.ifba_flags = n->brt_flags;
     485           0 :                                 error = copyout((caddr_t)&bareq,
     486           0 :                                     (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
     487           0 :                                 if (error)
     488             :                                         goto done;
     489           0 :                                 baconf->ifbac_len -= sizeof(struct ifbareq);
     490           0 :                         }
     491           0 :                         cnt++;
     492             :                 }
     493             :         }
     494             : done:
     495           0 :         baconf->ifbac_len = cnt * sizeof(struct ifbareq);
     496           0 :         return (error);
     497           0 : }
     498             : 
     499             : void
     500           0 : bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
     501             : {
     502             :         struct bridge_softc *sc;
     503             :         struct bridge_iflist *bif;
     504             :         u_int8_t *addr;
     505             : 
     506           0 :         addr = (u_int8_t *)ea;
     507             : 
     508           0 :         bif = (struct bridge_iflist *)ifp->if_bridgeport;
     509           0 :         sc = bif->bridge_sc;
     510             : 
     511             :         /*
     512             :          * Update the bridge interface if it is in
     513             :          * the learning state.
     514             :          */
     515           0 :         if ((bif->bif_flags & IFBIF_LEARNING) &&
     516           0 :             (ETHER_IS_MULTICAST(addr) == 0) &&
     517           0 :             !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
     518           0 :               addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
     519             :                 /* Care must be taken with spanning tree */
     520           0 :                 if ((bif->bif_flags & IFBIF_STP) &&
     521           0 :                     (bif->bif_state == BSTP_IFSTATE_DISCARDING))
     522           0 :                         return;
     523             : 
     524             :                 /* Delete the address from the bridge */
     525           0 :                 bridge_rtdaddr(sc, ea);
     526             : 
     527           0 :                 if (!delete) {
     528             :                         /* Update the bridge table */
     529           0 :                         bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL);
     530           0 :                 }
     531             :         }
     532           0 : }
     533             : 
     534             : /*
     535             :  * bridge filter/matching rules
     536             :  */
     537             : int
     538           0 : bridge_brlconf(struct bridge_softc *sc, struct ifbrlconf *bc)
     539             : {
     540             :         struct ifnet *ifp;
     541             :         struct bridge_iflist *ifl;
     542             :         struct brl_node *n;
     543           0 :         struct ifbrlreq req;
     544             :         int error = 0;
     545             :         u_int32_t i = 0, total = 0;
     546             : 
     547           0 :         ifp = ifunit(bc->ifbrl_ifsname);
     548           0 :         if (ifp == NULL)
     549           0 :                 return (ENOENT);
     550           0 :         ifl = (struct bridge_iflist *)ifp->if_bridgeport;
     551           0 :         if (ifl == NULL || ifl->bridge_sc != sc)
     552           0 :                 return (ESRCH);
     553             : 
     554           0 :         SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
     555           0 :                 total++;
     556             :         }
     557           0 :         SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
     558           0 :                 total++;
     559             :         }
     560             : 
     561           0 :         if (bc->ifbrl_len == 0) {
     562             :                 i = total;
     563           0 :                 goto done;
     564             :         }
     565             : 
     566           0 :         SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
     567           0 :                 bzero(&req, sizeof req);
     568           0 :                 if (bc->ifbrl_len < sizeof(req))
     569             :                         goto done;
     570           0 :                 strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
     571           0 :                 strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
     572           0 :                 req.ifbr_action = n->brl_action;
     573           0 :                 req.ifbr_flags = n->brl_flags;
     574           0 :                 req.ifbr_src = n->brl_src;
     575           0 :                 req.ifbr_dst = n->brl_dst;
     576           0 :                 req.ifbr_arpf = n->brl_arpf;
     577             : #if NPF > 0
     578           0 :                 req.ifbr_tagname[0] = '\0';
     579           0 :                 if (n->brl_tag)
     580           0 :                         pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
     581             : #endif
     582           0 :                 error = copyout((caddr_t)&req,
     583           0 :                     (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
     584           0 :                 if (error)
     585             :                         goto done;
     586           0 :                 i++;
     587           0 :                 bc->ifbrl_len -= sizeof(req);
     588             :         }
     589             : 
     590           0 :         SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
     591           0 :                 bzero(&req, sizeof req);
     592           0 :                 if (bc->ifbrl_len < sizeof(req))
     593             :                         goto done;
     594           0 :                 strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
     595           0 :                 strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
     596           0 :                 req.ifbr_action = n->brl_action;
     597           0 :                 req.ifbr_flags = n->brl_flags;
     598           0 :                 req.ifbr_src = n->brl_src;
     599           0 :                 req.ifbr_dst = n->brl_dst;
     600           0 :                 req.ifbr_arpf = n->brl_arpf;
     601             : #if NPF > 0
     602           0 :                 req.ifbr_tagname[0] = '\0';
     603           0 :                 if (n->brl_tag)
     604           0 :                         pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
     605             : #endif
     606           0 :                 error = copyout((caddr_t)&req,
     607           0 :                     (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
     608           0 :                 if (error)
     609             :                         goto done;
     610           0 :                 i++;
     611           0 :                 bc->ifbrl_len -= sizeof(req);
     612             :         }
     613             : 
     614             : done:
     615           0 :         bc->ifbrl_len = i * sizeof(req);
     616           0 :         return (error);
     617           0 : }
     618             : 
     619             : u_int8_t
     620           0 : bridge_arpfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m)
     621             : {
     622           0 :         struct ether_arp         ea;
     623             : 
     624           0 :         if (!(n->brl_arpf.brla_flags & (BRLA_ARP|BRLA_RARP)))
     625           0 :                 return (1);
     626             : 
     627           0 :         if (ntohs(eh->ether_type) != ETHERTYPE_ARP)
     628           0 :                 return (0);
     629           0 :         if (m->m_pkthdr.len <= ETHER_HDR_LEN + sizeof(ea))
     630           0 :                 return (0);     /* log error? */
     631           0 :         m_copydata(m, ETHER_HDR_LEN, sizeof(ea), (caddr_t)&ea);
     632             : 
     633           0 :         if (ntohs(ea.arp_hrd) != ARPHRD_ETHER ||
     634           0 :             ntohs(ea.arp_pro) != ETHERTYPE_IP ||
     635           0 :             ea.arp_hln != ETHER_ADDR_LEN ||
     636           0 :             ea.arp_pln != sizeof(struct in_addr))
     637           0 :                 return (0);
     638           0 :         if ((n->brl_arpf.brla_flags & BRLA_ARP) &&
     639           0 :             ntohs(ea.arp_op) != ARPOP_REQUEST &&
     640           0 :             ntohs(ea.arp_op) != ARPOP_REPLY)
     641           0 :                 return (0);
     642           0 :         if ((n->brl_arpf.brla_flags & BRLA_RARP) &&
     643           0 :             ntohs(ea.arp_op) != ARPOP_REVREQUEST &&
     644           0 :             ntohs(ea.arp_op) != ARPOP_REVREPLY)
     645           0 :                 return (0);
     646           0 :         if (n->brl_arpf.brla_op && ntohs(ea.arp_op) != n->brl_arpf.brla_op)
     647           0 :                 return (0);
     648           0 :         if (n->brl_arpf.brla_flags & BRLA_SHA &&
     649           0 :             memcmp(ea.arp_sha, &n->brl_arpf.brla_sha, ETHER_ADDR_LEN))
     650           0 :                 return (0);
     651           0 :         if (n->brl_arpf.brla_flags & BRLA_THA &&
     652           0 :             memcmp(ea.arp_tha, &n->brl_arpf.brla_tha, ETHER_ADDR_LEN))
     653           0 :                 return (0);
     654           0 :         if (n->brl_arpf.brla_flags & BRLA_SPA &&
     655           0 :             memcmp(ea.arp_spa, &n->brl_arpf.brla_spa, sizeof(struct in_addr)))
     656           0 :                 return (0);
     657           0 :         if (n->brl_arpf.brla_flags & BRLA_TPA &&
     658           0 :             memcmp(ea.arp_tpa, &n->brl_arpf.brla_tpa, sizeof(struct in_addr)))
     659           0 :                 return (0);
     660             : 
     661           0 :         return (1);
     662           0 : }
     663             : 
     664             : u_int8_t
     665           0 : bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
     666             : {
     667             :         struct brl_node *n;
     668             :         u_int8_t flags;
     669             : 
     670           0 :         SIMPLEQ_FOREACH(n, h, brl_next) {
     671           0 :                 if (!bridge_arpfilter(n, eh, m))
     672             :                         continue;
     673           0 :                 flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
     674           0 :                 if (flags == 0)
     675             :                         goto return_action;
     676           0 :                 if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
     677           0 :                         if (memcmp(eh->ether_shost, &n->brl_src,
     678             :                             ETHER_ADDR_LEN))
     679             :                                 continue;
     680           0 :                         if (memcmp(eh->ether_dhost, &n->brl_dst,
     681             :                             ETHER_ADDR_LEN))
     682             :                                 continue;
     683             :                         goto return_action;
     684             :                 }
     685           0 :                 if (flags == BRL_FLAG_SRCVALID) {
     686           0 :                         if (memcmp(eh->ether_shost, &n->brl_src,
     687             :                             ETHER_ADDR_LEN))
     688             :                                 continue;
     689             :                         goto return_action;
     690             :                 }
     691           0 :                 if (flags == BRL_FLAG_DSTVALID) {
     692           0 :                         if (memcmp(eh->ether_dhost, &n->brl_dst,
     693             :                             ETHER_ADDR_LEN))
     694             :                                 continue;
     695             :                         goto return_action;
     696             :                 }
     697             :         }
     698           0 :         return (BRL_ACTION_PASS);
     699             : 
     700             : return_action:
     701             : #if NPF > 0
     702           0 :         pf_tag_packet(m, n->brl_tag, -1);
     703             : #endif
     704           0 :         return (n->brl_action);
     705           0 : }
     706             : 
     707             : int
     708           0 : bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
     709             : {
     710             :         struct brl_node *n;
     711             : 
     712           0 :         n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT);
     713           0 :         if (n == NULL)
     714           0 :                 return (ENOMEM);
     715           0 :         bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
     716           0 :         bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
     717           0 :         n->brl_action = req->ifbr_action;
     718           0 :         n->brl_flags = req->ifbr_flags;
     719           0 :         n->brl_arpf = req->ifbr_arpf;
     720             : #if NPF > 0
     721           0 :         if (req->ifbr_tagname[0])
     722           0 :                 n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
     723             :         else
     724           0 :                 n->brl_tag = 0;
     725             : #endif
     726           0 :         if (out) {
     727           0 :                 n->brl_flags &= ~BRL_FLAG_IN;
     728           0 :                 n->brl_flags |= BRL_FLAG_OUT;
     729           0 :                 SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
     730           0 :         } else {
     731           0 :                 n->brl_flags &= ~BRL_FLAG_OUT;
     732           0 :                 n->brl_flags |= BRL_FLAG_IN;
     733           0 :                 SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
     734             :         }
     735           0 :         return (0);
     736           0 : }
     737             : 
     738             : void
     739           0 : bridge_flushrule(struct bridge_iflist *bif)
     740             : {
     741             :         struct brl_node *p;
     742             : 
     743           0 :         while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
     744             :                 p = SIMPLEQ_FIRST(&bif->bif_brlin);
     745           0 :                 SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
     746             : #if NPF > 0
     747           0 :                 pf_tag_unref(p->brl_tag);
     748             : #endif
     749           0 :                 free(p, M_DEVBUF, sizeof *p);
     750             :         }
     751           0 :         while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
     752             :                 p = SIMPLEQ_FIRST(&bif->bif_brlout);
     753           0 :                 SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
     754             : #if NPF > 0
     755           0 :                 pf_tag_unref(p->brl_tag);
     756             : #endif
     757           0 :                 free(p, M_DEVBUF, sizeof *p);
     758             :         }
     759           0 : }

Generated by: LCOV version 1.13