diff options
author | Jason Wright <jason@cvs.openbsd.org> | 1999-03-12 02:40:44 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 1999-03-12 02:40:44 +0000 |
commit | b252f8d0f6dc726b14efb8b561a77780f984c6dc (patch) | |
tree | 2800e17e1e6a2064442fe3981e07fc1e8f837a7c | |
parent | a0d27280f9724b0746cd7de1a81934f2932f6be4 (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.4 | 32 | ||||
-rw-r--r-- | sys/net/if_bridge.c | 309 | ||||
-rw-r--r-- | sys/net/if_bridge.h | 12 | ||||
-rw-r--r-- | sys/sys/sockio.h | 4 | ||||
-rw-r--r-- | usr.sbin/brconfig/brconfig.8 | 30 | ||||
-rw-r--r-- | usr.sbin/brconfig/brconfig.c | 151 |
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"); } |