Module Name: src Committed By: jmcneill Date: Mon Dec 26 12:39:20 UTC 2011
Modified Files: src/sys/arch/usermode/conf: GENERIC.common files.usermode src/sys/arch/usermode/dev: mainbus.c src/sys/arch/usermode/include: mainbus.h thunk.h src/sys/arch/usermode/usermode: machdep.c thunk.c Added Files: src/sys/arch/usermode/dev: if_veth.c Log Message: first cut at networking support for usermode, doesn't fully work yet but enough to get an address with dhcp and answer arps To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/usermode/conf/GENERIC.common cvs rdiff -u -r1.12 -r1.13 src/sys/arch/usermode/conf/files.usermode cvs rdiff -u -r0 -r1.1 src/sys/arch/usermode/dev/if_veth.c cvs rdiff -u -r1.5 -r1.6 src/sys/arch/usermode/dev/mainbus.c cvs rdiff -u -r1.4 -r1.5 src/sys/arch/usermode/include/mainbus.h cvs rdiff -u -r1.44 -r1.45 src/sys/arch/usermode/include/thunk.h cvs rdiff -u -r1.42 -r1.43 src/sys/arch/usermode/usermode/machdep.c cvs rdiff -u -r1.51 -r1.52 src/sys/arch/usermode/usermode/thunk.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/usermode/conf/GENERIC.common diff -u src/sys/arch/usermode/conf/GENERIC.common:1.1 src/sys/arch/usermode/conf/GENERIC.common:1.2 --- src/sys/arch/usermode/conf/GENERIC.common:1.1 Tue Dec 20 21:01:39 2011 +++ src/sys/arch/usermode/conf/GENERIC.common Mon Dec 26 12:39:19 2011 @@ -1,9 +1,9 @@ -# $NetBSD: GENERIC.common,v 1.1 2011/12/20 21:01:39 jmcneill Exp $ +# $NetBSD: GENERIC.common,v 1.2 2011/12/26 12:39:19 jmcneill Exp $ include "arch/usermode/conf/std.usermode" options INCLUDE_CONFIG_FILE -#ident "GENERIC-$Revision: 1.1 $" +#ident "GENERIC-$Revision: 1.2 $" maxusers 32 makeoptions DEBUG="-O1 -g3" @@ -49,6 +49,7 @@ cpu0 at mainbus? clock0 at mainbus? ttycons0 at mainbus? ld0 at mainbus? +veth0 at mainbus? #options SDL #genfb0 at thunkbus? @@ -56,6 +57,7 @@ ld0 at mainbus? pseudo-device loop pseudo-device pty +pseudo-device bpfilter # Pull in optional local configuration cinclude "arch/usermode/conf/GENERIC.local" Index: src/sys/arch/usermode/conf/files.usermode diff -u src/sys/arch/usermode/conf/files.usermode:1.12 src/sys/arch/usermode/conf/files.usermode:1.13 --- src/sys/arch/usermode/conf/files.usermode:1.12 Tue Dec 20 21:01:39 2011 +++ src/sys/arch/usermode/conf/files.usermode Mon Dec 26 12:39:19 2011 @@ -1,4 +1,4 @@ -# $NetBSD: files.usermode,v 1.12 2011/12/20 21:01:39 jmcneill Exp $ +# $NetBSD: files.usermode,v 1.13 2011/12/26 12:39:19 jmcneill Exp $ maxpartitions 8 maxusers 8 16 64 @@ -27,6 +27,10 @@ device ttycons { } : tty attach ttycons at thunkbus file arch/usermode/dev/ttycons.c ttycons +device veth { } : arp, ether, ifnet +attach veth at thunkbus +file arch/usermode/dev/if_veth.c veth + attach ld at thunkbus with ld_thunkbus file arch/usermode/dev/ld_thunkbus.c ld_thunkbus Index: src/sys/arch/usermode/dev/mainbus.c diff -u src/sys/arch/usermode/dev/mainbus.c:1.5 src/sys/arch/usermode/dev/mainbus.c:1.6 --- src/sys/arch/usermode/dev/mainbus.c:1.5 Thu Aug 25 11:06:29 2011 +++ src/sys/arch/usermode/dev/mainbus.c Mon Dec 26 12:39:19 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: mainbus.c,v 1.5 2011/08/25 11:06:29 jmcneill Exp $ */ +/* $NetBSD: mainbus.c,v 1.6 2011/12/26 12:39:19 jmcneill Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ #endif #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.5 2011/08/25 11:06:29 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.6 2011/12/26 12:39:19 jmcneill Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -55,6 +55,8 @@ CFATTACH_DECL_NEW(mainbus, sizeof(mainbu mainbus_match, mainbus_attach, NULL, NULL); extern char *usermode_root_image_path; +extern char *usermode_tap_device; +extern char *usermode_tap_eaddr; static int mainbus_match(device_t parent, cfdata_t match, void *opaque) @@ -88,6 +90,13 @@ mainbus_attach(device_t parent, device_t taa.taa_type = THUNKBUS_TYPE_TTYCONS; config_found_ia(self, "thunkbus", &taa, mainbus_print); + if (usermode_tap_device) { + taa.taa_type = THUNKBUS_TYPE_VETH; + taa.u.veth.device = usermode_tap_device; + taa.u.veth.eaddr = usermode_tap_eaddr; + config_found_ia(self, "thunkbus", &taa, mainbus_print); + } + if (usermode_root_image_path) { taa.taa_type = THUNKBUS_TYPE_DISKIMAGE; taa.u.diskimage.path = usermode_root_image_path; Index: src/sys/arch/usermode/include/mainbus.h diff -u src/sys/arch/usermode/include/mainbus.h:1.4 src/sys/arch/usermode/include/mainbus.h:1.5 --- src/sys/arch/usermode/include/mainbus.h:1.4 Thu Aug 25 11:06:29 2011 +++ src/sys/arch/usermode/include/mainbus.h Mon Dec 26 12:39:19 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: mainbus.h,v 1.4 2011/08/25 11:06:29 jmcneill Exp $ */ +/* $NetBSD: mainbus.h,v 1.5 2011/12/26 12:39:19 jmcneill Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -36,11 +36,16 @@ struct thunkbus_attach_args { #define THUNKBUS_TYPE_TTYCONS 2 #define THUNKBUS_TYPE_DISKIMAGE 3 #define THUNKBUS_TYPE_GENFB 4 +#define THUNKBUS_TYPE_VETH 5 union { struct { const char *path; } diskimage; + struct { + const char *device; + const char *eaddr; + } veth; } u; }; Index: src/sys/arch/usermode/include/thunk.h diff -u src/sys/arch/usermode/include/thunk.h:1.44 src/sys/arch/usermode/include/thunk.h:1.45 --- src/sys/arch/usermode/include/thunk.h:1.44 Tue Dec 20 22:48:59 2011 +++ src/sys/arch/usermode/include/thunk.h Mon Dec 26 12:39:19 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: thunk.h,v 1.44 2011/12/20 22:48:59 jmcneill Exp $ */ +/* $NetBSD: thunk.h,v 1.45 2011/12/26 12:39:19 jmcneill Exp $ */ /*- * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> @@ -108,6 +108,7 @@ int thunk_open(const char *, int, mode_t int thunk_fstat_getsize(int, ssize_t *, ssize_t *); ssize_t thunk_pread(int, void *, size_t, off_t); ssize_t thunk_pwrite(int, const void *, size_t, off_t); +ssize_t thunk_read(int, void *, size_t); ssize_t thunk_write(int, const void *, size_t); int thunk_fsync(int); int thunk_mkstemp(char *); @@ -145,6 +146,12 @@ int thunk_getcpuinfo(char *, int *); int thunk_getmachine(char *, size_t, char *, size_t); +int thunk_setown(int); + +int thunk_open_tap(const char *); +int thunk_pollin_tap(int, int); +int thunk_pollout_tap(int, int); + int thunk_sdl_init(unsigned int, unsigned int, unsigned short); void * thunk_sdl_getfb(size_t); int thunk_sdl_getchar(void); Index: src/sys/arch/usermode/usermode/machdep.c diff -u src/sys/arch/usermode/usermode/machdep.c:1.42 src/sys/arch/usermode/usermode/machdep.c:1.43 --- src/sys/arch/usermode/usermode/machdep.c:1.42 Sat Dec 24 12:26:58 2011 +++ src/sys/arch/usermode/usermode/machdep.c Mon Dec 26 12:39:20 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.42 2011/12/24 12:26:58 reinoud Exp $ */ +/* $NetBSD: machdep.c,v 1.43 2011/12/26 12:39:20 jmcneill Exp $ */ /*- * Copyright (c) 2011 Reinoud Zandijk <rein...@netbsd.org> @@ -38,7 +38,7 @@ #include "opt_sdl.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.42 2011/12/24 12:26:58 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.43 2011/12/26 12:39:20 jmcneill Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -64,6 +64,9 @@ char module_machine_usermode[_SYS_NMLN] static char **saved_argv; char *usermode_root_image_path = NULL; +static char usermode_tap_devicebuf[PATH_MAX] = ""; +char *usermode_tap_device = NULL; +char *usermode_tap_eaddr = NULL; void main(int argc, char *argv[]); void usermode_reboot(void); @@ -95,7 +98,27 @@ main(int argc, char *argv[]) for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { - usermode_root_image_path = argv[i]; + if (strncmp(argv[i], "tap=", strlen("tap=")) == 0) { + char *tap = argv[i] + strlen("tap="); + char *mac = strchr(tap, ','); + if (mac == NULL) { + printf("bad tap= format\n"); + return; + } + *mac++ = '\0'; + if (*tap != '/') + snprintf(usermode_tap_devicebuf, + sizeof(usermode_tap_devicebuf), + "/dev/%s", tap); + else + snprintf(usermode_tap_devicebuf, + sizeof(usermode_tap_devicebuf), + "%s", tap); + usermode_tap_device = usermode_tap_devicebuf; + usermode_tap_eaddr = mac; + } else { + usermode_root_image_path = argv[i]; + } continue; } for (j = 1; argv[i][j] != '\0'; j++) { Index: src/sys/arch/usermode/usermode/thunk.c diff -u src/sys/arch/usermode/usermode/thunk.c:1.51 src/sys/arch/usermode/usermode/thunk.c:1.52 --- src/sys/arch/usermode/usermode/thunk.c:1.51 Tue Dec 20 22:48:59 2011 +++ src/sys/arch/usermode/usermode/thunk.c Mon Dec 26 12:39:20 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: thunk.c,v 1.51 2011/12/20 22:48:59 jmcneill Exp $ */ +/* $NetBSD: thunk.c,v 1.52 2011/12/26 12:39:20 jmcneill Exp $ */ /*- * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> @@ -28,7 +28,7 @@ #include <sys/cdefs.h> #ifdef __NetBSD__ -__RCSID("$NetBSD: thunk.c,v 1.51 2011/12/20 22:48:59 jmcneill Exp $"); +__RCSID("$NetBSD: thunk.c,v 1.52 2011/12/26 12:39:20 jmcneill Exp $"); #endif #include <sys/types.h> @@ -36,12 +36,19 @@ __RCSID("$NetBSD: thunk.c,v 1.51 2011/12 #include <sys/reboot.h> #include <sys/poll.h> #include <sys/sysctl.h> +#include <sys/socket.h> #include <machine/vmparam.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_ether.h> +#include <net/if_tap.h> + #include <aio.h> #include <assert.h> #include <errno.h> #include <fcntl.h> +#include <ifaddrs.h> #include <sched.h> #include <stdarg.h> #include <stdint.h> @@ -455,6 +462,12 @@ thunk_pwrite(int d, const void *buf, siz } ssize_t +thunk_read(int d, void *buf, size_t nbytes) +{ + return read(d, buf, nbytes); +} + +ssize_t thunk_write(int d, const void *buf, size_t nbytes) { return write(d, buf, nbytes); @@ -688,3 +701,62 @@ thunk_getmachine(char *machine, size_t m return 0; } + +int +thunk_setown(int fd) +{ + return fcntl(fd, F_SETOWN, getpid()); +} + +int +thunk_open_tap(const char *device) +{ + int fd, error, enable; + + /* open tap device */ + fd = open(device, O_RDWR|O_NONBLOCK); + if (fd == -1) + return -1; + + /* set async mode */ + enable = 1; + error = ioctl(fd, FIOASYNC, &enable); + if (error) + return -1; + + return fd; +} + +int +thunk_pollin_tap(int fd, int timeout) +{ +#if 0 + struct pollfd fds[1]; + + fds[0].fd = fd; + fds[0].events = POLLIN|POLLRDNORM; + fds[0].revents = 0; + + return poll(fds, __arraycount(fds), timeout); +#else + int error, len; + + error = ioctl(fd, FIONREAD, &len); + if (error) + return 0; + + return len; +#endif +} + +int +thunk_pollout_tap(int fd, int timeout) +{ + struct pollfd fds[1]; + + fds[0].fd = fd; + fds[0].events = POLLOUT|POLLWRNORM; + fds[0].revents = 0; + + return poll(fds, __arraycount(fds), timeout); +} Added files: Index: src/sys/arch/usermode/dev/if_veth.c diff -u /dev/null src/sys/arch/usermode/dev/if_veth.c:1.1 --- /dev/null Mon Dec 26 12:39:20 2011 +++ src/sys/arch/usermode/dev/if_veth.c Mon Dec 26 12:39:19 2011 @@ -0,0 +1,348 @@ +/* $NetBSD: if_veth.c,v 1.1 2011/12/26 12:39:19 jmcneill Exp $ */ + +/*- + * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> + * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: if_veth.c,v 1.1 2011/12/26 12:39:19 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/device.h> + +#include <net/if.h> +#include <net/if_ether.h> +#include <net/if_media.h> + +#include <net/bpf.h> + +#include <machine/mainbus.h> +#include <machine/thunk.h> + +static int veth_match(device_t, cfdata_t, void *); +static void veth_attach(device_t, device_t, void *); + +static int veth_init(struct ifnet *); +static void veth_start(struct ifnet *); +static void veth_stop(struct ifnet *, int); +static void veth_watchdog(struct ifnet *); +static int veth_ioctl(struct ifnet *, u_long, void *); + +static int veth_rx(void *); +static void veth_softrx(void *); +static void veth_softtx(void *); + +static int veth_ifmedia_change(struct ifnet *); +static void veth_ifmedia_status(struct ifnet *, struct ifmediareq *); + +#ifdef VETH_DEBUG +#define vethprintf printf +#else +static inline void vethprintf(const char *fmt, ...) { } +#endif + +struct veth_softc { + device_t sc_dev; + struct ethercom sc_ec; + struct ifmedia sc_ifmedia; + int sc_tapfd; + uint8_t sc_eaddr[ETHER_ADDR_LEN]; + uint8_t sc_rx_buf[4096 + 65536]; + void *sc_rx_ih; + void *sc_rx_intr; + void *sc_tx_intr; +}; + +CFATTACH_DECL_NEW(veth, sizeof(struct veth_softc), + veth_match, veth_attach, NULL, NULL); + +static int +veth_match(device_t parent, cfdata_t match, void *opaque) +{ + struct thunkbus_attach_args *taa = opaque; + + if (taa->taa_type != THUNKBUS_TYPE_VETH) + return 0; + + return 1; +} + +static void +veth_attach(device_t parent, device_t self, void *opaque) +{ + struct veth_softc *sc = device_private(self); + struct thunkbus_attach_args *taa = opaque; + struct ifnet *ifp = &sc->sc_ec.ec_if; + + sc->sc_dev = self; + sc->sc_tapfd = thunk_open_tap(taa->u.veth.device); + if (sc->sc_tapfd == -1) { + aprint_error(": couldn't open %s: %d\n", + taa->u.veth.device, thunk_geterrno()); + return; + } + if (ether_aton_r(sc->sc_eaddr, sizeof(sc->sc_eaddr), + taa->u.veth.eaddr) != 0) { + aprint_error(": couldn't parse hw address '%s'\n", + taa->u.veth.eaddr); + return; + } + + aprint_naive("\n"); + aprint_normal(": Virtual Ethernet (device = %s)\n", taa->u.veth.device); + + aprint_normal_dev(self, "Ethernet address %s\n", + ether_sprintf(sc->sc_eaddr)); + + strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = veth_ioctl; + ifp->if_watchdog = veth_watchdog; + ifp->if_start = veth_start; + ifp->if_init = veth_init; + ifp->if_stop = veth_stop; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + IFQ_SET_READY(&ifq->if_snd); + + if_attach(ifp); + ether_ifattach(ifp, sc->sc_eaddr); + + ifmedia_init(&sc->sc_ifmedia, 0, + veth_ifmedia_change, + veth_ifmedia_status); + ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); + ifmedia_set(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX); + + sc->sc_rx_intr = softint_establish(SOFTINT_NET, veth_softrx, sc); + if (sc->sc_rx_intr == NULL) + panic("couldn't establish veth rx softint"); + sc->sc_tx_intr = softint_establish(SOFTINT_NET, veth_softtx, sc); + if (sc->sc_tx_intr == NULL) + panic("couldn't establish veth tx softint"); + + thunk_setown(sc->sc_tapfd); + + sc->sc_rx_ih = sigio_intr_establish(veth_rx, sc); + if (sc->sc_rx_ih == NULL) + panic("couldn't establish veth rx interrupt"); +} + +static int +veth_init(struct ifnet *ifp) +{ + vethprintf("%s: %s flags=%x\n", __func__, ifp->if_xname, ifp->if_flags); + + veth_stop(ifp, 0); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + return 0; +} + +static int +veth_rx(void *priv) +{ + struct veth_softc *sc = priv; + + softint_schedule(sc->sc_rx_intr); + + return 0; +} + +static void +veth_softrx(void *priv) +{ + struct veth_softc *sc = priv; + struct ifnet *ifp = &sc->sc_ec.ec_if; + struct mbuf *m; + ssize_t len; + int s, avail; + + for (;;) { + avail = thunk_pollin_tap(sc->sc_tapfd, 0); + if (avail == 0) + break; + + len = thunk_read(sc->sc_tapfd, sc->sc_rx_buf, + min(avail, sizeof(sc->sc_rx_buf))); + vethprintf("%s: read returned %d\n", __func__, len); + if (len == -1) + panic("read() from tap failed"); + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + vethprintf("MGETHDR failed (input error)\n"); + ++ifp->if_ierrors; + continue; + } + if (len > MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + ++ifp->if_ierrors; + vethprintf("M_EXT not set (input error)\n"); + continue; + } + } + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = len; + memcpy(mtod(m, void *), sc->sc_rx_buf, len); + ++ifp->if_ipackets; + + bpf_mtap(ifp, m); + + s = splnet(); + ifp->if_input(ifp, m); + splx(s); + } +} + +static void +veth_softtx(void *priv) +{ + struct veth_softc *sc = priv; + struct ifnet *ifp = &sc->sc_ec.ec_if; + int s; + + if (ifp->if_flags & IFF_OACTIVE) { + if (thunk_pollout_tap(sc->sc_tapfd, 0) == 1) + ifp->if_flags &= ~IFF_OACTIVE; + } + + s = splnet(); + veth_start(ifp); + splx(s); +} + +static void +veth_start(struct ifnet *ifp) +{ + struct veth_softc *sc = ifp->if_softc; + struct mbuf *m0; + ssize_t len; + + vethprintf("%s: %s flags=%x\n", __func__, ifp->if_xname, ifp->if_flags); + + if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) + return; + + for (;;) { + IFQ_POLL(&ifp->if_snd, m0); + if (m0 == NULL) + break; + + if (thunk_pollout_tap(sc->sc_tapfd, 0) != 1) { + printf("queue full\n"); + ifp->if_flags |= IFF_OACTIVE; + break; + } + + IFQ_DEQUEUE(&ifp->if_snd, m0); + bpf_mtap(ifp, m0); + + vethprintf("write %d bytes...\n", m0->m_pkthdr.len); + len = thunk_write(sc->sc_tapfd, mtod(m0, void *), + m0->m_pkthdr.len); + vethprintf("write returned %d\n", len); + if (len > 0) + ++ifp->if_opackets; + else + ++ifp->if_oerrors; + m_freem(m0); + } +} + +static void +veth_stop(struct ifnet *ifp, int disable) +{ + vethprintf("%s: %s flags=%x\n", __func__, ifp->if_xname, ifp->if_flags); + ifp->if_timer = 0; + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); +} + +static void +veth_watchdog(struct ifnet *ifp) +{ + vethprintf("%s: %s flags=%x\n", __func__, ifp->if_xname, ifp->if_flags); + ++ifp->if_oerrors; + veth_init(ifp); +} + +static int +veth_ioctl(struct ifnet *ifp, u_long cmd, void *data) +{ + struct veth_softc *sc = ifp->if_softc; + struct ifreq *ifr; + int s, error; + + vethprintf("%s: %s flags=%x\n", __func__, ifp->if_xname, ifp->if_flags); + + s = splnet(); + + switch (cmd) { + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + ifr = data; + error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { + if (ifp->if_flags & IFF_RUNNING) { + veth_init(ifp); + } + error = 0; + } + break; + default: + error = ether_ioctl(ifp, cmd, data); + break; + } + + splx(s); + return error; +} + +static int +veth_ifmedia_change(struct ifnet *ifp) +{ + vethprintf("%s: %s flags=%x\n", __func__, ifp->if_xname, ifp->if_flags); + return 0; +} + +static void +veth_ifmedia_status(struct ifnet *ifp, struct ifmediareq *req) +{ + vethprintf("%s: %s flags=%x\n", __func__, ifp->if_xname, ifp->if_flags); + req->ifm_status |= IFM_ACTIVE | IFM_AVALID; + req->ifm_active = IFM_100_TX | IFM_FDX | IFM_ETHER; +}