diff options
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_bridge.c | 10 | ||||
-rw-r--r-- | sys/net/if_vether.c | 232 |
2 files changed, 241 insertions, 1 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 1d14ec1c3c9..50fcbbb673b 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.c,v 1.174 2009/01/06 21:23:18 claudio Exp $ */ +/* $OpenBSD: if_bridge.c,v 1.175 2009/11/09 03:16:05 deraadt Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -2766,6 +2766,9 @@ bridge_fragment(struct bridge_softc *sc, struct ifnet *ifp, int bridge_ifenqueue(struct bridge_softc *sc, struct ifnet *ifp, struct mbuf *m) { +#if VETHER > 0 + extern void vetherstart(struct ifnet *); +#endif int error, len; short mflags; @@ -2774,6 +2777,11 @@ bridge_ifenqueue(struct bridge_softc *sc, struct ifnet *ifp, struct mbuf *m) if (ifp->if_type == IFT_GIF) m->m_flags |= M_PROTO1; #endif +#if VETHER > 0 + /* Indicate packets which are outbound */ + if (ifp->if_start == vetherstart) + m->m_flags |= M_PROTO1; +#endif #if NVLAN > 0 /* * If the underlying interface cannot do VLAN tag insertion itself, diff --git a/sys/net/if_vether.c b/sys/net/if_vether.c new file mode 100644 index 00000000000..b681b5f39fd --- /dev/null +++ b/sys/net/if_vether.c @@ -0,0 +1,232 @@ +/* $OpenBSD: if_vether.c,v 1.1 2009/11/09 03:16:05 deraadt Exp $ */ + +/* + * Copyright (c) 2009 Theo de Raadt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "vether.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_var.h> +#endif + +#include <dev/rndvar.h> + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include <net/bpf.h> +#endif + +#ifdef MPLS_DEBUG +#define DPRINTF(x) do { if (vetherdebug) printf x ; } while (0) +#else +#define DPRINTF(x) +#endif + +void vetherattach(int); +int vetherioctl(struct ifnet *, u_long, caddr_t); +void vetherstart(struct ifnet *); +int vether_clone_create(struct if_clone *, int); +int vether_clone_destroy(struct ifnet *); +int vether_media_change(struct ifnet *); +void vether_media_status(struct ifnet *, struct ifmediareq *); + +struct vether_softc { + struct arpcom sc_ac; + struct ifmedia sc_media; + LIST_ENTRY(vether_softc) sc_list; +}; + +LIST_HEAD(, vether_softc) vether_list; +struct if_clone vether_cloner = + IF_CLONE_INITIALIZER("vether", vether_clone_create, vether_clone_destroy); + + +int +vether_media_change(struct ifnet *ifp) +{ + return (0); +} + +void +vether_media_status(struct ifnet *ifp, struct ifmediareq *imr) +{ + imr->ifm_active = IFM_ETHER | IFM_AUTO; + imr->ifm_status = IFM_AVALID | IFM_ACTIVE; +} + +void +vetherattach(int nvether) +{ + LIST_INIT(&vether_list); + if_clone_attach(&vether_cloner); +} + +int +vether_clone_create(struct if_clone *ifc, int unit) +{ + struct ifnet *ifp; + struct vether_softc *sc; + u_int32_t macaddr_rnd; + int s; + + if ((sc = malloc(sizeof(*sc), + M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) + return (ENOMEM); + + /* from if_tun.c: generate fake MAC address: 00 bd xx xx xx unit_no */ + sc->sc_ac.ac_enaddr[0] = 0x00; + sc->sc_ac.ac_enaddr[1] = 0xbd; + /* + * This no longer happens pre-scheduler so let's use the real + * random subsystem instead of random(). + */ + macaddr_rnd = arc4random(); + bcopy(&macaddr_rnd, &sc->sc_ac.ac_enaddr[2], sizeof(u_int32_t)); + sc->sc_ac.ac_enaddr[5] = (u_char)unit + 1; + + ifp = &sc->sc_ac.ac_if; + snprintf(ifp->if_xname, sizeof ifp->if_xname, "vether%d", unit); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_softc = sc; + ifp->if_ioctl = vetherioctl; + ifp->if_start = vetherstart; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + IFQ_SET_READY(&ifp->if_snd); + + ifmedia_init(&sc->sc_media, 0, vether_media_change, + vether_media_status); + ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); + + if_attach(ifp); + ether_ifattach(ifp); + + s = splnet(); + LIST_INSERT_HEAD(&vether_list, sc, sc_list); + splx(s); + return (0); +} + +int +vether_clone_destroy(struct ifnet *ifp) +{ + struct vether_softc *sc = ifp->if_softc; + int s; + + s = splnet(); + LIST_REMOVE(sc, sc_list); + splx(s); + + ether_ifdetach(ifp); + if_detach(ifp); + free(sc, M_DEVBUF); + return (0); +} + +/* + * Start output on the vether interface. + */ +void +vetherstart(struct ifnet *ifp) +{ + struct mbuf *m; + int s, inout; + + for (;;) { + s = splnet(); + IFQ_DEQUEUE(&ifp->if_snd, m); + splx(s); + + if (m == NULL) + return; + + inout = (m->m_flags & M_PROTO1) ? + BPF_DIRECTION_IN : BPF_DIRECTION_OUT; + m->m_flags &= ~M_PROTO1; + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap_ether(ifp->if_bpf, m, inout); +#endif + + if (inout == BPF_DIRECTION_IN) + ether_input_mbuf(ifp, m); + else + m_freem(m); + } +} + +/* ARGSUSED */ +int +vetherioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct vether_softc *sc = (struct vether_softc *)ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *)data; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0, link_state; + + ifr = (struct ifreq *)data; + switch (cmd) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; +#ifdef INET + if (ifa->ifa_addr->sa_family == AF_INET) + arp_ifinit(&sc->sc_ac, ifa); +#endif + /* FALLTHROUGH */ + + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + ifp->if_flags |= IFF_RUNNING; + link_state = LINK_STATE_UP; + } else { + ifp->if_flags &= ~IFF_RUNNING; + link_state = LINK_STATE_DOWN; + } + if (ifp->if_link_state != link_state) { + ifp->if_link_state = link_state; + if_link_state_change(ifp); + } + break; + + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); + break; + + default: + error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); + } + return (error); +} |