WIP - cleaner MTU change
diff --git a/src/drivers/net/netvsc.c b/src/drivers/net/netvsc.c
index 5be52fb..f753868 100644
--- a/src/drivers/net/netvsc.c
+++ b/src/drivers/net/netvsc.c
@@ -852,16 +852,9 @@
 	struct net_device *netdev = rndis->netdev;
 	int rc;
 
-	/* A closed device holds no NetVSC (or RNDIS) state, so there
-	 * is nothing to reset.
-	 */
-	if ( ! netdev_is_open ( netdev ) )
-		return 0;
-
-	/* Close and reopen device to reset any stale state */
-	netdev_close ( netdev );
-	if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
-		DBGC ( netvsc, "NETVSC %s could not reopen: %s\n",
+	/* Reset network device */
+	if ( ( rc = netdev_reset ( netdev ) ) != 0 ) {
+		DBGC ( netvsc, "NETVSC %s could not reset: %s\n",
 		       netvsc->name, strerror ( rc ) );
 		return rc;
 	}
diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h
index af932c2..0c6fe9c 100644
--- a/src/include/ipxe/netdevice.h
+++ b/src/include/ipxe/netdevice.h
@@ -723,6 +723,7 @@
 extern int register_netdev ( struct net_device *netdev );
 extern int netdev_open ( struct net_device *netdev );
 extern void netdev_close ( struct net_device *netdev );
+extern int netdev_reset ( struct net_device *netdev );
 extern void unregister_netdev ( struct net_device *netdev );
 extern void netdev_irq ( struct net_device *netdev, int enable );
 extern struct net_device * find_netdev ( const char *name );
diff --git a/src/net/netdev_settings.c b/src/net/netdev_settings.c
index fb98663..2c08a6a 100644
--- a/src/net/netdev_settings.c
+++ b/src/net/netdev_settings.c
@@ -453,11 +453,10 @@
 			       netdev->name, mtu );
 		}
 
-		/* Close and reopen network device if MTU has increased */
+		/* Reset network device if MTU has increased */
 		if ( netdev_is_open ( netdev ) && ( mtu > old_mtu ) ) {
-			netdev_close ( netdev );
-			if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
-				DBGC ( netdev, "NETDEV %s could not reopen: "
+			if ( ( rc = netdev_reset ( netdev ) ) != 0 ) {
+				DBGC ( netdev, "NETDEV %s could not reset: "
 				       "%s\n", netdev->name, strerror ( rc ) );
 				return rc;
 			}
diff --git a/src/net/netdevice.c b/src/net/netdevice.c
index 07961bf..db33794 100644
--- a/src/net/netdevice.c
+++ b/src/net/netdevice.c
@@ -613,6 +613,23 @@
 }
 
 /**
+ * Flush device's transmit and receive queues
+ *
+ * @v netdev		Network device
+ */
+static void netdev_flush ( struct net_device *netdev ) {
+
+	/* Sanity check */
+	assert ( ! ( netdev->state & NETDEV_OPEN ) );
+
+	/* Flush TX queue */
+	netdev_tx_flush ( netdev );
+
+	/* Flush RX queue */
+	netdev_rx_flush ( netdev );
+}
+
+/**
  * Finish network device configuration
  *
  * @v config		Network device configuration
@@ -657,8 +674,7 @@
 		container_of ( refcnt, struct net_device, refcnt );
 
 	stop_timer ( &netdev->link_block );
-	netdev_tx_flush ( netdev );
-	netdev_rx_flush ( netdev );
+	netdev_flush ( netdev );
 	clear_settings ( netdev_settings ( netdev ) );
 	free ( netdev );
 }
@@ -880,8 +896,47 @@
 	netdev->op->close ( netdev );
 
 	/* Flush TX and RX queues */
-	netdev_tx_flush ( netdev );
-	netdev_rx_flush ( netdev );
+	netdev_flush ( netdev );
+}
+
+/**
+ * Reset transmit and receive queues
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+int netdev_reset ( struct net_device *netdev ) {
+	int rc;
+
+	/* Do nothing unless device is open */
+	if ( ! ( netdev->state & NETDEV_OPEN ) )
+		return 0;
+
+	DBGC ( netdev, "NETDEV %s resetting\n", netdev->name );
+
+	/* Mark as closed */
+	netdev->state &= ~NETDEV_OPEN;
+
+	/* Close the device */
+	netdev->op->close ( netdev );
+
+	/* Flush TX and RX queues */
+	netdev_flush ( netdev );
+
+	/* Mark as opened */
+	netdev->state |= NETDEV_OPEN;
+
+	/* Reopen device */
+	if ( ( rc = netdev->op->open ( netdev ) ) != 0 )
+		goto err;
+
+	return 0;
+
+ err:
+	netdev->state &= ~NETDEV_OPEN;
+	list_del ( &netdev->open_list );
+	netdev_notify ( netdev );
+	return rc;
 }
 
 /**