summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>1999-03-12 02:40:44 +0000
committerJason Wright <jason@cvs.openbsd.org>1999-03-12 02:40:44 +0000
commitb252f8d0f6dc726b14efb8b561a77780f984c6dc (patch)
tree2800e17e1e6a2064442fe3981e07fc1e8f837a7c
parenta0d27280f9724b0746cd7de1a81934f2932f6be4 (diff)
big overhaul:
o SNAP encapsulated IP filtering o static address cache entries o address deletion from cache o dynamic & full cache flush o filter packets based on each interface, not on the bridge as a whole o KNF nits o allow addition of ~IFF_UP interfaces o man page & user level fixes to match the above
-rw-r--r--share/man/man4/bridge.432
-rw-r--r--sys/net/if_bridge.c309
-rw-r--r--sys/net/if_bridge.h12
-rw-r--r--sys/sys/sockio.h4
-rw-r--r--usr.sbin/brconfig/brconfig.830
-rw-r--r--usr.sbin/brconfig/brconfig.c151
6 files changed, 463 insertions, 75 deletions
diff --git a/share/man/man4/bridge.4 b/share/man/man4/bridge.4
index 2eb36c8290f..b143a1eccbd 100644
--- a/share/man/man4/bridge.4
+++ b/share/man/man4/bridge.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bridge.4,v 1.4 1999/03/05 21:10:58 jason Exp $
+.\" $OpenBSD: bridge.4,v 1.5 1999/03/12 02:40:42 jason Exp $
.\"
.\" Copyright (c) 1999 Jason L. Wright (jason@thought.net)
.\" All rights reserved.
@@ -142,11 +142,17 @@ needs to be in advance.
The argument structure is defined as follows:
.Bd -literal -offset indent
struct ifbareq {
- char ifba_name[IFNAMSIZ]; /* destination ifs */
- u_int32_t ifba_age; /* addr age */
- struct ether_addr ifba_dst; /* dest addr */
+ char ifba_name[IFNAMSIZ]; /* bridge name */
+ char ifba_ifsname[IFNAMSIZ]; /* dest ifs */
+ u_int8_t ifba_age; /* addr age */
+ u_int8_t ifba_flags; /* addr age */
+ struct ether_addr ifba_dst; /* dest addr */
};
+#define IFBAF_TYPEMASK 0x03 /* address type mask */
+#define IFBAF_DYNAMIC 0x00 /* dynamically learned */
+#define IFBAF_STATIC 0x01 /* static address */
+
struct ifbaconf {
char ifbac_name[IFNAMSIZ]; /* bridge name */
u_int32_t ifbac_len; /* buffer size */
@@ -158,6 +164,21 @@ struct ifbaconf {
#define ifbac_req ifbac_ifbacu.ifbacu_req
};
.Ed
+.It Dv SIOCBRDGSADDR
+.Pq Li "struct ifbareq"
+Add an entry, manually, to the address cache for the bridge named in
+.Ar ifba_name .
+The address and its associated interface and flags are set in the
+.Ar ifba_dst ,
+.Ar ifba_ifsname ,
+.Ar ifba_flags
+fields, respectively.
+.It Dv SIOCBRDGDADDR
+.Pq Li "struct ifbareq"
+Delete an entry from the address cache of the bridge named in
+.Ar ifba_name .
+Entries are deleted strictly based on the address field
+.Ar ifba_dst .
.It Dv SIOCBRDGSCACHE
.Pq Li "struct ifbcachereq"
Set the maximum address cache size for the bridge named in
@@ -206,7 +227,8 @@ into the system.
For delete operation, it means that the named interface is not a member
of the bridge.
.It Bq Eq ENOMEM
-Memory could not be allocated for an interface to be added to the bridge.
+Memory could not be allocated for an interface or cache entry
+to be added to the bridge.
.It Bq Eq EEXIST
The named interface is already a member of the bridge.
.It Bq Eq EBUSY
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index a77eee962f0..cc777402272 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.c,v 1.5 1999/03/05 22:09:18 jason Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.6 1999/03/12 02:40:43 jason Exp $ */
/*
* Copyright (c) 1999 Jason L. Wright (jason@thought.net)
@@ -46,6 +46,7 @@
#include <net/if.h>
#include <net/if_types.h>
+#include <net/if_llc.h>
#include <net/route.h>
#ifdef INET
@@ -81,6 +82,13 @@
#define BRIDGE_RTABLE_TIMEOUT 240
#endif
+/*
+ * This really should be defined in if_llc.h but in case it isn't.
+ */
+#ifndef llc_snap
+#define llc_snap llc_un.type_snap
+#endif
+
extern int ifqmaxlen;
/*
@@ -98,7 +106,8 @@ struct bridge_iflist {
struct bridge_rtnode {
LIST_ENTRY(bridge_rtnode) brt_next; /* next in list */
struct ifnet *brt_if; /* destination ifs */
- u_int32_t brt_age; /* age counter */
+ u_int8_t brt_flags; /* address flags */
+ u_int8_t brt_age; /* age counter */
struct ether_addr brt_addr; /* dst addr */
};
@@ -129,8 +138,10 @@ int bridge_rtfind __P((struct bridge_softc *, struct ifbaconf *));
void bridge_rtage __P((void *));
void bridge_rttrim __P((struct bridge_softc *));
void bridge_rtdelete __P((struct bridge_softc *, struct ifnet *));
+int bridge_rtdaddr __P((struct bridge_softc *, struct ether_addr *));
+int bridge_rtflush __P((struct bridge_softc *));
struct ifnet * bridge_rtupdate __P((struct bridge_softc *,
- struct ether_addr *, struct ifnet *ifp));
+ struct ether_addr *, struct ifnet *ifp, int, u_int8_t));
struct ifnet * bridge_rtlookup __P((struct bridge_softc *,
struct ether_addr *));
u_int32_t bridge_hash __P((struct ether_addr *));
@@ -148,7 +159,7 @@ u_int32_t bridge_hash __P((struct ether_addr *));
#define BRIDGE_FILTER_PASS 0
#define BRIDGE_FILTER_DROP 1
int bridge_filter __P((struct bridge_softc *, struct ifnet *,
- struct ether_header *, struct mbuf *));
+ struct ether_header *, struct mbuf **));
#endif
void
@@ -187,10 +198,12 @@ bridge_ioctl(ifp, cmd, data)
struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
struct ifbreq *req = (struct ifbreq *)data;
struct ifbaconf *baconf = (struct ifbaconf *)data;
+ struct ifbareq *bareq = (struct ifbareq *)data;
struct ifbcachereq *bcachereq = (struct ifbcachereq *)data;
struct ifbifconf *bifconf = (struct ifbifconf *)data;
struct ifbcachetoreq *bcacheto = (struct ifbcachetoreq *)data;
- int error = 0, s;
+ struct ifreq ifreq;
+ int error = 0, s;
struct bridge_iflist *p;
s = splimp();
@@ -220,9 +233,43 @@ bridge_ioctl(ifp, cmd, data)
break;
}
- error = ifpromisc(ifs, 1);
- if (error != 0)
- break;
+ if ((ifs->if_flags & IFF_UP) == 0) {
+ /*
+ * Bring interface up long enough to set
+ * promiscuous flag, then shut it down again.
+ */
+ strncpy(ifreq.ifr_name, req->ifbr_ifsname,
+ sizeof(ifreq.ifr_name) - 1);
+ ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
+ 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;
+
+
+ strncpy(ifreq.ifr_name, req->ifbr_ifsname,
+ sizeof(ifreq.ifr_name) - 1);
+ ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
+ 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;
+ }
p = (struct bridge_iflist *) malloc(
sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);
@@ -270,6 +317,46 @@ bridge_ioctl(ifp, cmd, data)
}
error = bridge_rtfind(sc, baconf);
break;
+ case SIOCBRDGFLUSH:
+ if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
+ break;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ error = ENETDOWN;
+ break;
+ }
+ error = bridge_rtflush(sc);
+ break;
+ case SIOCBRDGSADDR:
+ if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
+ break;
+
+ ifs = ifunit(bareq->ifba_ifsname);
+ if (ifs == NULL) { /* no such interface */
+ error = ENOENT;
+ break;
+ }
+
+ if (ifs->if_bridge == NULL ||
+ ifs->if_bridge != (caddr_t)sc) {
+ error = ESRCH;
+ break;
+ }
+
+ ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
+ bareq->ifba_flags);
+ if (ifs == NULL)
+ error = ENOMEM;
+ break;
+ case SIOCBRDGDADDR:
+ if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
+ break;
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ error = ENETDOWN;
+ break;
+ }
+ error = bridge_rtdaddr(sc, &bareq->ifba_dst);
+ break;
case SIOCBRDGGCACHE:
bcachereq->ifbc_size = sc->sc_brtmax;
break;
@@ -598,7 +685,7 @@ bridge_input(ifp, eh, m)
!(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, ifp);
+ bridge_rtupdate(sc, src, ifp, 0, IFBAF_DYNAMIC);
/*
* If packet is unicast, destined for someone on "this"
@@ -644,8 +731,8 @@ bridge_input(ifp, eh, m)
* Pass the packet to the ip filtering code and drop
* here if necessary.
*/
- if (bridge_filter(sc, ifp, eh, m) == BRIDGE_FILTER_DROP) {
- if (m->m_flags & (M_BCAST|M_MCAST)) {
+ if (bridge_filter(sc, ifp, eh, &m) == BRIDGE_FILTER_DROP) {
+ if (m == NULL || m->m_flags & (M_BCAST|M_MCAST)) {
/*
* Broadcasts should be passed down if filtered
* by the bridge, so that they can be filtered
@@ -658,6 +745,10 @@ bridge_input(ifp, eh, m)
splx(s);
return (NULL);
}
+ if (m == NULL) {
+ splx(s);
+ return (NULL);
+ }
#endif
/*
@@ -774,10 +865,12 @@ bridge_broadcast(sc, ifp, eh, m)
}
struct ifnet *
-bridge_rtupdate(sc, ea, ifp)
+bridge_rtupdate(sc, ea, ifp, setflags, flags)
struct bridge_softc *sc;
struct ether_addr *ea;
struct ifnet *ifp;
+ int setflags;
+ u_int8_t flags;
{
struct bridge_rtnode *p, *q;
u_int32_t h;
@@ -796,9 +889,8 @@ bridge_rtupdate(sc, ea, ifp)
splx(s);
return (NULL);
}
- p = (struct bridge_rtnode *)
- malloc(sizeof(struct bridge_rtnode),
- M_DEVBUF, M_NOWAIT);
+ p = (struct bridge_rtnode *)malloc(
+ sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
if (p == NULL) {
splx(s);
return (NULL);
@@ -807,6 +899,12 @@ bridge_rtupdate(sc, ea, ifp)
bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
p->brt_if = ifp;
p->brt_age = 1;
+
+ 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++;
splx(s);
@@ -819,10 +917,15 @@ bridge_rtupdate(sc, ea, ifp)
dir = bcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
if (dir == 0) {
- q->brt_if = ifp;
- q->brt_age = 1;
+ if (setflags) {
+ q->brt_if = ifp;
+ q->brt_flags = flags;
+ }
+
+ if (q->brt_if == ifp)
+ q->brt_age = 1;
splx(s);
- return (ifp);
+ return (q->brt_if);
}
if (dir > 0) {
@@ -830,9 +933,8 @@ bridge_rtupdate(sc, ea, ifp)
splx(s);
return (NULL);
}
- p = (struct bridge_rtnode *)
- malloc(sizeof(struct bridge_rtnode),
- M_DEVBUF, M_NOWAIT);
+ p = (struct bridge_rtnode *)malloc(
+ sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
if (p == NULL) {
splx(s);
return (NULL);
@@ -841,6 +943,12 @@ bridge_rtupdate(sc, ea, ifp)
bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
p->brt_if = ifp;
p->brt_age = 1;
+
+ if (setflags)
+ p->brt_flags = flags;
+ else
+ p->brt_flags = IFBAF_DYNAMIC;
+
LIST_INSERT_BEFORE(q, p, brt_next);
sc->sc_brtcnt++;
splx(s);
@@ -852,9 +960,8 @@ bridge_rtupdate(sc, ea, ifp)
splx(s);
return (NULL);
}
- p = (struct bridge_rtnode *)
- malloc(sizeof(struct bridge_rtnode),
- M_DEVBUF, M_NOWAIT);
+ p = (struct bridge_rtnode *)malloc(
+ sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
if (p == NULL) {
splx(s);
return (NULL);
@@ -863,6 +970,11 @@ bridge_rtupdate(sc, ea, ifp)
bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
p->brt_if = ifp;
p->brt_age = 1;
+
+ if (setflags)
+ p->brt_flags = flags;
+ else
+ p->brt_flags = IFBAF_DYNAMIC;
LIST_INSERT_AFTER(q, p, brt_next);
sc->sc_brtcnt++;
splx(s);
@@ -990,13 +1102,15 @@ bridge_rttrim(sc)
n = LIST_FIRST(&sc->sc_rts[i]);
while (n != NULL) {
p = LIST_NEXT(n, brt_next);
- LIST_REMOVE(n, brt_next);
- sc->sc_brtcnt--;
- free(n, M_DEVBUF);
- n = p;
- if (sc->sc_brtcnt <= sc->sc_brtmax) {
- splx(s);
- return;
+ if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
+ LIST_REMOVE(n, brt_next);
+ sc->sc_brtcnt--;
+ free(n, M_DEVBUF);
+ n = p;
+ if (sc->sc_brtcnt <= sc->sc_brtmax) {
+ splx(s);
+ return;
+ }
}
}
}
@@ -1023,7 +1137,13 @@ bridge_rtage(vsc)
for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
n = LIST_FIRST(&sc->sc_rts[i]);
while (n != NULL) {
- if (n->brt_age) {
+ 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);
}
@@ -1043,6 +1163,73 @@ bridge_rtage(vsc)
}
/*
+ * Remove all dynamic addresses from the cache
+ */
+int
+bridge_rtflush(sc)
+ struct bridge_softc *sc;
+{
+ int s, i;
+ struct bridge_rtnode *p, *n;
+
+ s = splhigh();
+ if (sc->sc_rts == NULL) {
+ splx(s);
+ return (ENETDOWN);
+ }
+
+ 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_DYNAMIC) {
+ p = LIST_NEXT(n, brt_next);
+ LIST_REMOVE(n, brt_next);
+ sc->sc_brtcnt--;
+ free(n, M_DEVBUF);
+ n = p;
+ }
+ else
+ n = LIST_NEXT(n, brt_next);
+ }
+ }
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Remove an address from the cache
+ */
+int
+bridge_rtdaddr(sc, ea)
+ struct bridge_softc *sc;
+ struct ether_addr *ea;
+{
+ int h, s;
+ struct bridge_rtnode *p;
+
+ s = splhigh();
+ if (sc->sc_rts == NULL) {
+ splx(s);
+ return (ENETDOWN);
+ }
+
+ h = bridge_hash(ea);
+ p = LIST_FIRST(&sc->sc_rts[h]);
+ while (p != NULL) {
+ if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
+ LIST_REMOVE(p, brt_next);
+ sc->sc_brtcnt--;
+ free(p, M_DEVBUF);
+ splx(s);
+ return (0);
+ }
+ p = LIST_NEXT(p, brt_next);
+ }
+ splx(s);
+ return (ENOENT);
+}
+/*
* Delete routes to a specific interface member.
*/
void
@@ -1117,11 +1304,14 @@ bridge_rtfind(sc, baconf)
splx(s);
return (0);
}
- bcopy(n->brt_if->if_xname, bareq.ifba_name,
- sizeof(bareq.ifba_name));
+ 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));
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) {
@@ -1148,26 +1338,45 @@ bridge_rtfind(sc, baconf)
* who've read net/if_ethersubr.c and netinet/ip_input.c
*/
int
-bridge_filter(sc, ifp, eh, n)
+bridge_filter(sc, ifp, eh, np)
struct bridge_softc *sc;
struct ifnet *ifp;
struct ether_header *eh;
- struct mbuf *n;
+ struct mbuf **np;
{
- struct mbuf *m, *m0;
+ struct mbuf *m = *np;
+ struct llc *llc;
struct ip *ip;
u_int16_t etype;
- int hlen, r;
+ int hlen, r, off = 0;
if (fr_checkp == NULL)
return (BRIDGE_FILTER_PASS);
- /*
- * XXX TODO: Handle LSAP packets
- */
etype = ntohs(eh->ether_type);
- if (etype != ETHERTYPE_IP)
- return (BRIDGE_FILTER_PASS);
+ if (etype != ETHERTYPE_IP) {
+ if (etype > ETHERMTU) /* Can't be SNAP */
+ return (BRIDGE_FILTER_PASS);
+
+ m = *np;
+ if (m->m_len < 8) {
+ m = m_pullup(m, 8);
+ *np = m;
+ if (m == NULL)
+ return (BRIDGE_FILTER_DROP);
+ }
+ llc = mtod(m, struct llc *);
+ if (llc->llc_control != LLC_UI ||
+ llc->llc_dsap != LLC_SNAP_LSAP ||
+ llc->llc_ssap != LLC_SNAP_LSAP ||
+ llc->llc_snap.org_code[0] != 0 ||
+ llc->llc_snap.org_code[1] != 0 ||
+ llc->llc_snap.org_code[2] != 0 ||
+ ntohs(llc->llc_snap.ether_type) != ETHERTYPE_IP)
+ return (BRIDGE_FILTER_PASS);
+ off = 8;
+ }
+
/*
* We need a full copy because we're going to be destructive
@@ -1175,12 +1384,10 @@ bridge_filter(sc, ifp, eh, n)
* XXX This needs to be turned into a munge -> check ->
* XXX unmunge section, for now, we copy.
*/
- m = m_copym2(n, 0, M_COPYALL, M_NOWAIT);
+ m = m_copym2(m, off, M_COPYALL, M_NOWAIT);
if (m == NULL)
return (BRIDGE_FILTER_DROP);
- m->m_pkthdr.rcvif = &sc->sc_if;
-
/*
* Pull up the IP header
*/
@@ -1238,12 +1445,14 @@ bridge_filter(sc, ifp, eh, n)
}
/*
- * Finally, we get to filter the packet!
+ * Finally, we get to filter the packet! Pass through
+ * once with the bridge as the rcvif, and again with the
+ * real receiving interface as rcvif.
*/
- m0 = m;
- if (fr_checkp && (*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m0))
+ m->m_pkthdr.rcvif = ifp;
+ if (fr_checkp && (*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m))
return (BRIDGE_FILTER_DROP);
- ip = mtod(m = m0, struct ip *);
+
r = BRIDGE_FILTER_PASS;
out:
diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h
index 164e75e10e3..7838fdf2c6f 100644
--- a/sys/net/if_bridge.h
+++ b/sys/net/if_bridge.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.h,v 1.3 1999/03/05 21:10:52 jason Exp $ */
+/* $OpenBSD: if_bridge.h,v 1.4 1999/03/12 02:40:43 jason Exp $ */
/*
* Copyright (c) 1999 Jason L. Wright (jason@thought.net)
@@ -58,11 +58,17 @@ struct ifbifconf {
* Bridge address request
*/
struct ifbareq {
- char ifba_name[IFNAMSIZ]; /* destination ifs */
- u_int32_t ifba_age; /* route age */
+ char ifba_name[IFNAMSIZ]; /* bridge name */
+ char ifba_ifsname[IFNAMSIZ]; /* destination ifs */
+ u_int8_t ifba_age; /* address age */
+ u_int8_t ifba_flags; /* address flags */
struct ether_addr ifba_dst; /* destination addr */
};
+#define IFBAF_TYPEMASK 0x03 /* address type mask */
+#define IFBAF_DYNAMIC 0x00 /* dynamically learned */
+#define IFBAF_STATIC 0x01 /* static address */
+
struct ifbaconf {
char ifbac_name[IFNAMSIZ]; /* bridge ifs name */
u_int32_t ifbac_len; /* buffer size */
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index 3d64bf9cafd..aad00f61001 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sockio.h,v 1.7 1999/03/05 21:10:55 jason Exp $ */
+/* $OpenBSD: sockio.h,v 1.8 1999/03/12 02:40:43 jason Exp $ */
/* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */
/*-
@@ -92,6 +92,8 @@
#define SIOCBRDGSADDR _IOWR('i', 68, struct ifbareq) /* set addr flags */
#define SIOCBRDGSTO _IOWR('i', 69, struct ifbcachetoreq) /* cache timeout */
#define SIOCBRDGGTO _IOWR('i', 70, struct ifbcachetoreq) /* cache timeout */
+#define SIOCBRDGDADDR _IOWR('i', 71, struct ifbareq) /* delete addr */
+#define SIOCBRDGFLUSH _IOWR('i', 72, struct ifbreq) /* flush addr cache */
#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet mtu */
#define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet mtu */
diff --git a/usr.sbin/brconfig/brconfig.8 b/usr.sbin/brconfig/brconfig.8
index 0ea89687926..453d5baa589 100644
--- a/usr.sbin/brconfig/brconfig.8
+++ b/usr.sbin/brconfig/brconfig.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: brconfig.8,v 1.6 1999/03/05 22:09:19 jason Exp $
+.\" $OpenBSD: brconfig.8,v 1.7 1999/03/12 02:40:43 jason Exp $
.\"
.\" Copyright (c) 1999 Jason L. Wright (jason@thought.net)
.\" All rights reserved.
@@ -47,6 +47,10 @@
.Op Ar delete interface-name
.Op Ar maxaddr size
.Op Ar timeout time
+.Op Ar static interface-name address
+.Op Ar deladdr address
+.Op Ar flush
+.Op Ar flushall
.Op Ar link0
.Op Ar link1
.Op Ar -link0
@@ -78,11 +82,6 @@ Display the addresses that have been learned by the bridge.
Add the interface named by
.Ar interface-name
as a member of the bridge.
-The interface must already be ready for packet
-reception, (ie. it must be in the
-.Cm up
-state, see
-.Xr ifconfig 8 )
The interface is put into promiscuous mode so
that it can receive every packet sent on the
network.
@@ -105,6 +104,17 @@ The default is 240 seconds.
If
.Cm time
is set to zero, then entries will not be expired.
+.It Ar static interface-name address
+Add a static entry into the address cache pointing to
+.Cm interface-name .
+Static entries are never aged out of the cache or replaced if the address
+is seen on a different interface.
+.It Ar deladdr address
+Delete an address from the cache.
+.It Ar flush
+Remove all dynamically learned addresses from the cache.
+.It Ar flushall
+Remove all addresses from the cache including static addresses.
.It Ar link0
Setting this flag stops all non-IP multicast packets from
being forwarded by the bridge.
@@ -122,16 +132,16 @@ flag on the bridge interface.
.El
.Sh EXAMPLES
.Bl -tag -width brconfig
-.It Cm brconfig bridge0 add pn0 add mx0 up
-Add the Ethernet interfaces pn0 and mx0 to the bridge bridge0, and
+.It Cm brconfig bridge0 add rl0 add xl0 up
+Add the Ethernet interfaces rl0 and xl0 to the bridge bridge0, and
start the bridge forwarding packets.
.It Cm brconfig bridge0
Retrieve a list of interfaces that are members of bridge0, and the addresses
learned by the bridge.
.It Cm brconfig bridge0 down
Stop bridge0 from forwarding packets.
-.It Cm brconfig bridge0 delete pn0
-Remove the interface pn0 from the bridge bridge0.
+.It Cm brconfig bridge0 delete xl0
+Remove the interface xl0 from the bridge bridge0.
.El
.Sh SEE ALSO
.Xr ifconfig 8 ,
diff --git a/usr.sbin/brconfig/brconfig.c b/usr.sbin/brconfig/brconfig.c
index c7cda0f9dcc..362f931a9ff 100644
--- a/usr.sbin/brconfig/brconfig.c
+++ b/usr.sbin/brconfig/brconfig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: brconfig.c,v 1.5 1999/03/08 13:06:36 jason Exp $ */
+/* $OpenBSD: brconfig.c,v 1.6 1999/03/12 02:40:43 jason Exp $ */
/*
* Copyright (c) 1999 Jason L. Wright (jason@thought.net)
@@ -55,8 +55,12 @@ int bridge_setflag(int, char *, short);
int bridge_clrflag(int, char *, short);
int bridge_list(int, char *, char *);
int bridge_addrs(int, char *, char *);
+int bridge_addaddr(int, char *, char *, char *);
+int bridge_deladdr(int, char *, char *);
int bridge_maxaddr(int, char *, char *);
int bridge_timeout(int, char *, char *);
+int bridge_flush(int, char *);
+int bridge_flushall(int, char *);
int bridge_add(int, char *, char *);
int bridge_delete(int, char *, char *);
int bridge_status(int, char *);
@@ -69,7 +73,7 @@ void printb(char *, unsigned short, char *);
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
-#define IFBABITS "\020\1BLACKHOLE\2STATIC\3DYNAMIC"
+#define IFBABITS "\020\1STATIC"
void
usage() {
@@ -143,6 +147,37 @@ main(argc, argv)
if (error)
return (error);
}
+ else if (strcmp("flush", argv[0]) == 0) {
+ error = bridge_flush(sock, brdg);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("flushall", argv[0]) == 0) {
+ error = bridge_flushall(sock, brdg);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("static", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc < 2) {
+ warnx("static requires 2 arguments");
+ return (EX_USAGE);
+ }
+ error = bridge_addaddr(sock, brdg, argv[0], argv[1]);
+ if (error)
+ return (error);
+ argc--; argv++;
+ }
+ else if (strcmp("deladdr", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("deladdr requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_deladdr(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
else if (strcmp("link0", argv[0]) == 0) {
error = bridge_setflag(sock, brdg, IFF_LINK0);
if (error)
@@ -294,6 +329,58 @@ bridge_clrflag(s, brdg, f)
}
int
+bridge_flushall(s, brdg)
+ int s;
+ char *brdg;
+{
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCGIFFLAGS)");
+ return (EX_IOERR);
+ }
+
+ if ((ifr.ifr_flags & IFF_UP) == 0)
+ return (0);
+
+ strncpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCSIFFLAGS)");
+ return (EX_IOERR);
+ }
+
+ strncpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCSIFFLAGS)");
+ return (EX_IOERR);
+ }
+
+ return (0);
+}
+
+int
+bridge_flush(s, brdg)
+ int s;
+ char *brdg;
+{
+ struct ifbreq req;
+
+ strncpy(req.ifbr_name, brdg, sizeof(req.ifbr_name) - 1);
+ req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
+ if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) {
+ warn("ioctl(SIOCBRDGFLUSH)");
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
bridge_list(s, brdg, delim)
int s;
char *brdg, *delim;
@@ -417,13 +504,67 @@ bridge_maxaddr(s, brdg, arg)
}
int
+bridge_deladdr(s, brdg, addr)
+ int s;
+ char *brdg, *addr;
+{
+ struct ifbareq ifba;
+ struct ether_addr *ea;
+
+ strncpy(ifba.ifba_name, brdg, sizeof(ifba.ifba_name) - 1);
+ ifba.ifba_name[sizeof(ifba.ifba_name) - 1] = '\0';
+ ea = ether_aton(addr);
+ if (ea == NULL) {
+ warnx("Invalid address: %s", addr);
+ return (EX_USAGE);
+ }
+ bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
+
+ if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0) {
+ warn("ioctl(SIOCBRDGDADDR)");
+ return (EX_IOERR);
+ }
+
+ return (0);
+}
+
+int
+bridge_addaddr(s, brdg, ifname, addr)
+ int s;
+ char *brdg, *ifname, *addr;
+{
+ struct ifbareq ifba;
+ struct ether_addr *ea;
+
+ strncpy(ifba.ifba_name, brdg, sizeof(ifba.ifba_name) - 1);
+ ifba.ifba_name[sizeof(ifba.ifba_name) - 1] = '\0';
+ strncpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname) - 1);
+ ifba.ifba_ifsname[sizeof(ifba.ifba_ifsname) - 1] = '\0';
+
+ ea = ether_aton(addr);
+ if (ea == NULL) {
+ warnx("Invalid address: %s", addr);
+ return (EX_USAGE);
+ }
+ bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
+ ifba.ifba_flags = IFBAF_STATIC;
+
+ if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0) {
+ warn("ioctl(SIOCBRDGSADDR)");
+ return (EX_IOERR);
+ }
+
+ return (0);
+}
+
+int
bridge_addrs(s, brdg, delim)
int s;
char *brdg, *delim;
{
struct ifbaconf ifbac;
struct ifbareq *ifba;
- char *inbuf = NULL, buf[sizeof(ifba->ifba_name) + 1];
+ char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1];
int i, len = 8192;
while (1) {
@@ -446,12 +587,10 @@ bridge_addrs(s, brdg, delim)
for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
ifba = ifbac.ifbac_req + i;
bzero(buf, sizeof(buf));
- strncpy(buf, ifba->ifba_name, sizeof(ifba->ifba_name));
+ strncpy(buf, ifba->ifba_ifsname, sizeof(ifba->ifba_ifsname));
printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst),
buf, ifba->ifba_age);
-#if 0
printb("flags", ifba->ifba_flags, IFBABITS);
-#endif
printf("\n");
}