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;
+}

Reply via email to