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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
+ * 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;
+}