---
 Documentation/lguest/lguest.c   |  160 +++++++++-------------------------------
 drivers/lguest/Makefile         |    2 
 drivers/lguest/lg.h             |    5 +
 drivers/lguest/lguest_user.c    |    7 +
 include/linux/lguest_launcher.h |    1 
 5 files changed, 53 insertions(+), 122 deletions(-)

diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -786,70 +786,6 @@ static void console_output(struct virtqu
 	add_used(vq, head, len);
 }
 
-/*
- * The Network
- *
- * Handling output for network is also simple: we get all the output buffers
- * and write them to /dev/net/tun.
- */
-struct net_info {
-	int tunfd;
-};
-
-static void net_output(struct virtqueue *vq)
-{
-	struct net_info *net_info = vq->dev->priv;
-	unsigned int head, out, in;
-	int len;
-	struct iovec iov[vq->vring.num];
-
-	vq->irq = &xmit_irq;
-	vq->irq_suppressed = &xmit_irq_suppressed;
-
-	head = wait_for_vq_desc(vq, iov, &out, &in);
-	if (in)
-		errx(1, "Input buffers in net output queue?");
-	len = writev(net_info->tunfd, iov, out);
-	if (len < 0)
-		errx(1, "Write to tun failed?");
-	add_used(vq, head, len);
-}
-
-/* Will reading from this file descriptor block? */
-static bool will_block(int fd)
-{
-	fd_set fdset;
-	struct timeval zero = { 0, 0 };
-	FD_ZERO(&fdset);
-	FD_SET(fd, &fdset);
-	return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
-}
-
-/* This is where we handle packets coming in from the tun device to our
- * Guest. */
-static void net_input(struct virtqueue *vq)
-{
-	int len;
-	unsigned int head, out, in;
-	struct iovec iov[vq->vring.num];
-	struct net_info *net_info = vq->dev->priv;
-
-	vq->irq = &recv_irq;
-	vq->irq_suppressed = &recv_irq_suppressed;
-
-	head = wait_for_vq_desc(vq, iov, &out, &in);
-	if (out)
-		errx(1, "Output buffers in net input queue?");
-
-	/* Deliver interrupt now, since we're about to sleep. */
-	if (vq->pending_used && will_block(net_info->tunfd))
-		trigger_irq(vq);
-
-	len = readv(net_info->tunfd, iov, in);
-	if (len <= 0)
-		err(1, "Failed to read from tun.");
-	add_used(vq, head, len);
-}
 
 /* This is the helper to create threads. */
 static int do_thread(void *_vq)
@@ -1325,61 +1261,44 @@ static int get_tun_device(char tapif[IFN
 	return netfd;
 }
 
-/*L:195 Our network is a Host<->Guest network.  This can either use bridging or
- * routing, but the principle is the same: it uses the "tun" device to inject
- * packets into the Host as if they came in from a normal network card.  We
- * just shunt packets between the Guest and the tun device. */
-static void setup_tun_net(char *arg)
-{
-	struct device *dev;
-	struct net_info *net_info = malloc(sizeof(*net_info));
-	int ipfd;
-	u32 ip = INADDR_ANY;
-	bool bridging = false;
-	char tapif[IFNAMSIZ], *p;
-	struct virtio_net_config conf;
-
-	net_info->tunfd = get_tun_device(tapif);
-
-	/* First we create a new network device. */
-	dev = new_device("net", VIRTIO_ID_NET);
-	dev->priv = net_info;
-
-	/* Network devices need a receive and a send queue, just like
-	 * console. */
-	add_virtqueue(dev, VIRTQUEUE_NUM, net_input);
-	add_virtqueue(dev, VIRTQUEUE_NUM, net_output);
-
-	/* We need a socket to perform the magic network ioctls to bring up the
-	 * tap interface, connect to the bridge etc.  Any socket will do! */
-	ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
-	if (ipfd < 0)
-		err(1, "opening IP socket");
-
-	/* If the command line was --tunnet=bridge:<name> do bridging. */
-	if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
-		arg += strlen(BRIDGE_PFX);
-		bridging = true;
-	}
-
-	/* A mac address may follow the bridge name or IP address */
-	p = strchr(arg, ':');
-	if (p) {
-		str2mac(p+1, conf.mac);
-		add_feature(dev, VIRTIO_NET_F_MAC);
-		*p = '\0';
-	}
-
-	/* arg is now either an IP address or a bridge name */
-	if (bridging)
-		add_to_bridge(ipfd, tapif, arg);
-	else
-		ip = str2ip(arg);
-
-	/* Set up the tun device. */
-	configure_device(ipfd, tapif, ip);
-
-	/* Expect Guest to handle everything except UFO */
+/*L:195 Our network is a Host<->Guest network.
+  * This one is a dummy in the kernel; it just replies to arps and pings. */
+ static void setup_kernel_net(char *arg)
+ {
+ 	struct net_info {
+ 		unsigned long rcv_pfn;
+ 		unsigned long rcv_irq;
+ 		unsigned long xmit_pfn;
+ 		unsigned long xmit_irq;
+ 		unsigned long num;
+ 		u32 ipaddr;
+ 		unsigned char ethaddr[ETH_ALEN];
+ 	} net_info;
+ 	struct virtio_net_config conf;
+ 
+ 	/* First we create a new network device. */
+ 	dev = new_device("net", VIRTIO_ID_NET);
+ 
+ 	/* Network devices need a receive and a send queue, just like
+ 	 * console. */
+ 	add_virtqueue(dev, VIRTQUEUE_NUM, NULL);
+ 	add_virtqueue(dev, VIRTQUEUE_NUM, NULL);
+ 
+ 	net_info.rcv_pfn = dev->vq->config->pfn;
+ 	net_info.xmit_pfn = dev->vq->next->config->pfn;
+ 
+ 	/* Set IP address. */
+ 	net_info.ipaddr = htonl(str2ip(arg));
+ 
+ 	/* Set ethernet address: no multicast bit, but local assignment set */
+ 	net_info.ethaddr[0] = 0xfe;
+ 	net_info.ethaddr[1] = 104;
+ 	net_info.ethaddr[2] = 97;
+ 	net_info.ethaddr[3] = 99;
+ 	net_info.ethaddr[4] = 107;
+ 	net_info.ethaddr[5] = 0;
+ 
+ 	/* Expect Guest to handle everything except UFO, and indirect. */
 	add_feature(dev, VIRTIO_NET_F_CSUM);
 	add_feature(dev, VIRTIO_NET_F_GUEST_CSUM);
 	add_feature(dev, VIRTIO_NET_F_GUEST_TSO4);
@@ -1388,8 +1307,7 @@ static void setup_tun_net(char *arg)
 	add_feature(dev, VIRTIO_NET_F_HOST_TSO4);
 	add_feature(dev, VIRTIO_NET_F_HOST_TSO6);
 	add_feature(dev, VIRTIO_NET_F_HOST_ECN);
-	/* We handle indirect ring entries */
-	add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
+
 	set_config(dev, sizeof(conf), &conf);
 
 	/* We don't need the socket any more; setup is done. */
diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile
--- a/drivers/lguest/Makefile
+++ b/drivers/lguest/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_LGUEST_GUEST) += lguest_dev
 # Host requires the other files, which can be a module.
 obj-$(CONFIG_LGUEST)	+= lg.o
 lg-y = core.o hypercalls.o page_tables.o interrupts_and_traps.o \
-	segments.o lguest_user.o
+	segments.o lguest_user.o dummynet.o
 
 lg-$(CONFIG_X86_32) += x86/switcher_32.o x86/core.o
 
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -209,6 +209,11 @@ void lguest_device_remove(void);
 void do_hypercalls(struct lg_cpu *cpu);
 void write_timestamp(struct lg_cpu *cpu);
 
+/* dummynet.c: */
+int attach_dummynet(struct lguest *lg, const unsigned long __user *input);
+bool notify_for_dummynet(struct lguest *lg, unsigned long addr);
+void detach_dummynet(struct lguest *lg);
+
 /*L:035
  * Let's step aside for the moment, to study one important routine that's used
  * widely in the Host code.
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -15,6 +15,9 @@ bool send_notify_to_eventfd(struct lg_cp
 {
 	unsigned int i;
 
+	if (notify_for_dummynet(cpu->lg, cpu->pending_notify))
+		return true;
+
 	/* lg->eventfds is RCU-protected */
 	preempt_disable();
 	for (i = 0; i < cpu->lg->num_eventfds; i++) {
@@ -297,6 +300,8 @@ static ssize_t write(struct file *file, 
 		return user_send_irq(cpu, input);
 	case LHREQ_EVENTFD:
 		return attach_eventfd(lg, input);
+	case LHREQ_DUMMYNET:
+		return attach_dummynet(lg, input);
 	default:
 		return -EINVAL;
 	}
@@ -346,6 +351,8 @@ static int close(struct inode *inode, st
 
 	printk("Guest Exits: %lu\n", lg->exits);
 
+	detach_dummynet(lg);
+
 	/* Free the memory allocated to the lguest_struct */
 	kfree(lg);
 	/* Release lock and exit. */
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h
--- a/include/linux/lguest_launcher.h
+++ b/include/linux/lguest_launcher.h
@@ -59,6 +59,7 @@ enum lguest_req
 	LHREQ_IRQ, /* + irq */
 	LHREQ_BREAK, /* No longer used */
 	LHREQ_EVENTFD, /* + address, fd. */
+	LHREQ_DUMMYNET, /* + rcvpfn, rcvirq, xmitpfn, xmitirq, num, ip, ethaddr */
 };
 
 /* The alignment to use between consumer and producer parts of vring.
