mirror of
https://github.com/openbsd/src.git
synced 2025-01-04 23:35:36 -08:00
Split functions in if_bridge.c into if_bridge.c bridgectl.c .
Splitting functions in if_bridge.c into if_bridge.c for the forwarding part and bridgectl.c for the control part. It shouldn't have any functional change. ok reyk@ mpi@ yasuoka@
This commit is contained in:
parent
c90437d4f5
commit
062b28b9b1
@ -1,4 +1,4 @@
|
||||
# $OpenBSD: files,v 1.607 2015/11/06 18:07:57 mpi Exp $
|
||||
# $OpenBSD: files,v 1.608 2015/12/01 18:28:29 goda Exp $
|
||||
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
|
||||
|
||||
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
|
||||
@ -769,6 +769,7 @@ file net/bsd-comp.c ppp_bsdcomp
|
||||
file net/ppp-deflate.c ppp_deflate
|
||||
file net/if_tun.c tun needs-count
|
||||
file net/if_bridge.c bridge needs-count
|
||||
file net/bridgectl.c bridge
|
||||
file net/bridgestp.c bridge
|
||||
file net/if_vlan.c vlan needs-count
|
||||
file net/pipex.c pipex
|
||||
|
737
sys/net/bridgectl.c
Normal file
737
sys/net/bridgectl.c
Normal file
@ -0,0 +1,737 @@
|
||||
/* $OpenBSD: bridgectl.c,v 1.1 2015/12/01 18:28:29 goda 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 "mpw.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/timeout.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/filio.h>
|
||||
|
||||
#include <crypto/siphash.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_llc.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 INET6
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
|
||||
#if NBPFILTER > 0
|
||||
#include <net/bpf.h>
|
||||
#endif
|
||||
|
||||
#include <net/if_bridge.h>
|
||||
|
||||
|
||||
int bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
|
||||
void bridge_rtage(struct bridge_softc *);
|
||||
int bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
|
||||
u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
|
||||
|
||||
int bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
|
||||
int bridge_addrule(struct bridge_iflist *, struct ifbrlreq *, int out);
|
||||
|
||||
int
|
||||
bridgectl_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 ifbrlreq *brlreq = (struct ifbrlreq *)data;
|
||||
struct ifbareq *bareq = (struct ifbareq *)data;
|
||||
struct ifbrparam *bparam = (struct ifbrparam *)data;
|
||||
struct bridge_iflist *p;
|
||||
struct ifnet *ifs;
|
||||
int error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCBRDGRTS:
|
||||
error = bridge_rtfind(sc, (struct ifbaconf *)data);
|
||||
break;
|
||||
case SIOCBRDGFLUSH:
|
||||
bridge_rtflush(sc, req->ifbr_ifsflags);
|
||||
break;
|
||||
case SIOCBRDGSADDR:
|
||||
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:
|
||||
error = bridge_rtdaddr(sc, &bareq->ifba_dst);
|
||||
break;
|
||||
case SIOCBRDGGCACHE:
|
||||
bparam->ifbrp_csize = sc->sc_brtmax;
|
||||
break;
|
||||
case SIOCBRDGSCACHE:
|
||||
sc->sc_brtmax = bparam->ifbrp_csize;
|
||||
break;
|
||||
case SIOCBRDGSTO:
|
||||
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 SIOCBRDGARL:
|
||||
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:
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
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, sizeof *n);
|
||||
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, sizeof *n);
|
||||
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, sizeof *p);
|
||||
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, sizeof *n);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* bridge filter/matching rules
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
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, sizeof *p);
|
||||
}
|
||||
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, sizeof *p);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: if_bridge.c,v 1.271 2015/12/01 14:49:04 goda Exp $ */
|
||||
/* $OpenBSD: if_bridge.c,v 1.272 2015/12/01 18:28:29 goda Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
|
||||
@ -42,7 +42,6 @@
|
||||
#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>
|
||||
@ -127,31 +126,13 @@ 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_ifinput(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 *,
|
||||
@ -160,7 +141,6 @@ int bridge_ipsec(struct bridge_softc *, struct ifnet *,
|
||||
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) \
|
||||
@ -285,9 +265,6 @@ 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;
|
||||
@ -532,64 +509,6 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
}
|
||||
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);
|
||||
@ -597,54 +516,6 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
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)
|
||||
@ -664,11 +535,22 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
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 SIOCBRDGRTS:
|
||||
case SIOCBRDGGCACHE:
|
||||
case SIOCBRDGGPRI:
|
||||
case SIOCBRDGGMA:
|
||||
case SIOCBRDGGHT:
|
||||
case SIOCBRDGGFD:
|
||||
case SIOCBRDGGTO:
|
||||
case SIOCBRDGGRL:
|
||||
break;
|
||||
case SIOCBRDGFLUSH:
|
||||
case SIOCBRDGSADDR:
|
||||
case SIOCBRDGDADDR:
|
||||
case SIOCBRDGSCACHE:
|
||||
case SIOCBRDGSTO:
|
||||
case SIOCBRDGARL:
|
||||
case SIOCBRDGFRL:
|
||||
case SIOCBRDGSPRI:
|
||||
case SIOCBRDGSFD:
|
||||
case SIOCBRDGSMA:
|
||||
@ -684,6 +566,9 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
error = bridgectl_ioctl(ifp, cmd, data);
|
||||
|
||||
if (!error)
|
||||
error = bstp_ioctl(ifp, cmd, data);
|
||||
|
||||
@ -704,41 +589,6 @@ bridge_ifdetach(struct ifnet *ifp)
|
||||
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)
|
||||
{
|
||||
@ -827,86 +677,6 @@ done:
|
||||
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)
|
||||
{
|
||||
@ -1555,345 +1325,6 @@ bridge_span(struct bridge_softc *sc, struct mbuf *m)
|
||||
}
|
||||
}
|
||||
|
||||
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, sizeof *n);
|
||||
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, sizeof *n);
|
||||
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, sizeof *p);
|
||||
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, sizeof *n);
|
||||
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.
|
||||
@ -1946,96 +1377,6 @@ bridge_blocknonip(struct ether_header *eh, struct mbuf *m)
|
||||
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, sizeof *p);
|
||||
}
|
||||
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, sizeof *p);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IPSEC
|
||||
int
|
||||
bridge_ipsec(struct bridge_softc *sc, struct ifnet *ifp,
|
||||
@ -2723,4 +2064,3 @@ bridge_m_dup(struct mbuf *m)
|
||||
|
||||
return (m1);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: if_bridge.h,v 1.47 2015/11/28 15:21:45 yasuoka Exp $ */
|
||||
/* $OpenBSD: if_bridge.h,v 1.48 2015/12/01 18:28:29 goda Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
|
||||
@ -433,6 +433,7 @@ struct bridge_softc {
|
||||
};
|
||||
|
||||
extern const u_int8_t bstp_etheraddr[];
|
||||
struct llc;
|
||||
|
||||
void bridge_ifdetach(struct ifnet *);
|
||||
int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
|
||||
@ -443,6 +444,7 @@ void bridge_rtagenode(struct ifnet *, int);
|
||||
struct sockaddr *bridge_tunnel(struct mbuf *);
|
||||
struct sockaddr *bridge_tunneltag(struct mbuf *, int);
|
||||
void bridge_tunneluntag(struct mbuf *);
|
||||
void bridge_copyaddr(struct sockaddr *, struct sockaddr *);
|
||||
|
||||
struct bstp_state *bstp_create(struct ifnet *);
|
||||
void bstp_destroy(struct bstp_state *);
|
||||
@ -456,5 +458,20 @@ struct mbuf *bstp_input(struct bstp_state *, struct bstp_port *,
|
||||
void bstp_ifstate(void *);
|
||||
u_int8_t bstp_getstate(struct bstp_state *, struct bstp_port *);
|
||||
void bstp_ifsflags(struct bstp_port *, u_int);
|
||||
void bridge_send_icmp_err(struct bridge_softc *, struct ifnet *,
|
||||
struct ether_header *, struct mbuf *, int, struct llc *, int, int, int);
|
||||
|
||||
int bridgectl_ioctl(struct ifnet *, u_long, caddr_t);
|
||||
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 *);
|
||||
void bridge_rtflush(struct bridge_softc *, int);
|
||||
void bridge_timer(void *);
|
||||
|
||||
u_int8_t bridge_filterrule(struct brl_head *, struct ether_header *,
|
||||
struct mbuf *);
|
||||
void bridge_flushrule(struct bridge_iflist *);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _NET_IF_BRIDGE_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user