From fd5de0d00564decd3ce12fd1bf6b01d6c22bf96c Mon Sep 17 00:00:00 2001
From: Mark Pizzolato <mark@infocomm.com>
Date: Mon, 31 Oct 2011 11:51:19 -0700
Subject: [PATCH] Added support for VDE (Virtual Distributed Ethernet) network
 packet transport

Fixed filtering for non-pcap network packet transports (i.e. tun/tap, and vde) to properly filter the desired packets.
---
 0readme_ethernet.txt |   31 +-
 makefile             |   13 +-
 sim_ether.c          | 2319 ++++++++++++++++++++++--------------------
 sim_ether.h          |   14 +-
 4 files changed, 1282 insertions(+), 1095 deletions(-)

diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt
index 3e6f8998..eb1c66f0 100644
--- a/0readme_ethernet.txt
+++ b/0readme_ethernet.txt
@@ -133,13 +133,37 @@ OSX (Snow Leopard)
     Invoke the package installer tuntap_20090913.pkg
     Click through the various prompts accepting things and eventually installing the package.
     
-    # Run simulator and:
+    # Build and Run simulator and:
        sim> attach xq tap:tap0
        sim> ! ifconfig tap0 192.168.6.1 netmask 255.255.255.0
 
-    Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1 and things work.
-    As far as I can tell you must run as root for this to work.
+    Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1 
+    and things work.
+    You must run as root for this to work.
     
+-------------------------------------------------------------------------------
+An alternative to direct pcap and tun/tap networking on *nix environments is 
+VDE (Virtual Distributed Ethernet).
+
+Note 1: Using vde based networking is likely more flexible, but it isn't 
+        nearly as efficient.  Host OS overhead will always be higher when 
+        vde networking is used as compared to native pcap and/or tun/tap 
+        networking.
+Note 2: Root access will likely be needed to configure or start the vde 
+        environment prior to starting a simulator which may use it.
+Note 3: Simulators running using VDE networking can run without root 
+        privilege.
+
+Linux (Ubuntu 10.04):
+    apt-get install libvdeplug-dev
+    apt-get install vde2
+
+    vde_switch -s /tmp/switch1 -tap tap0 -m 666
+    ifconfig tap0 192.168.6.1 netmask 255.255.255.0 up
+    
+    # Build and Run simulator and:
+       sim> attach xq vde:/tmp/switch1  #simulator uses IP address 192.168.6.2
+
 -------------------------------------------------------------------------------
 
 Windows notes:
@@ -354,6 +378,7 @@ Dave
                                Change Log
 ===============================================================================
   
+  30-Oct-11  MP   Added support for vde (Virtual Distributed Ethernet) networking
   29-Oct-11  MP   Added support for integrated Tap networking interfaces on OSX
   17-Aug-11  RMS  Fix from Sergey Oboguev relating to XU and XQ Auto Config and 
                   vector assignments
diff --git a/makefile b/makefile
index 4004965d..c4be5123 100644
--- a/makefile
+++ b/makefile
@@ -13,6 +13,7 @@
 #
 ifeq ($(WIN32),)
   #*nix Environments (&& cygwin)
+  GCC = gcc
   ifeq (SunOS,$(shell uname))
     TEST = /bin/test
   else
@@ -62,13 +63,18 @@ ifeq ($(WIN32),)
     NETWORK_CCDEFS = -DUSE_NETWORK
     NETWORK_LDFLAGS = -lpcap
   endif
+  ifeq (vde,$(shell if $(TEST) -e /usr/include/libvdeplug.h -a \( -e /usr/lib/libvdeplug.$(LIBEXT) -o -e /usr/lib64/libvdeplug.$(LIBEXT) \); then echo vde; fi))
+    # Provide support for vde networking
+    NETWORK_CCDEFS += -DUSE_VDE_NETWORK
+    NETWORK_LDFLAGS += -lvdeplug
+  endif
   ifeq (tuntap,$(shell if $(TEST) -e /usr/include/linux/if_tun.h; then echo tuntap; fi))
     # Provide support for Tap networking on Linux
-    NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK
+    NETWORK_CCDEFS += -DUSE_TAP_NETWORK
   endif
   ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext; then echo bsdtuntap; fi))
     # Provide support for Tap networking
-    NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
+    NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
   endif
   ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi))
     MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi
@@ -79,6 +85,7 @@ ifeq ($(WIN32),)
   endif
 else
   #Win32 Environments (via MinGW32)
+  GCC = gcc
   GCC_Path := $(dir $(shell where gcc.exe))
   ifeq ($(NOASYNCH),)
     ifeq (pthreads,$(shell if exist ..\pthreads\Pre-built.2\include\pthread.h echo pthreads))
@@ -119,7 +126,7 @@ else
 endif
 
 
-CC = gcc -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(NETWORK_TAP_CCDEFS) $(OS_CCDEFS) $(ROMS_OPT)
+CC = $(GCC) -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(OS_CCDEFS) $(ROMS_OPT)
 LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) 
 
 #
diff --git a/sim_ether.c b/sim_ether.c
index 04692446..3ca7eefa 100644
--- a/sim_ether.c
+++ b/sim_ether.c
@@ -138,6 +138,15 @@
                       at open time.  This functionality is only useful/needed 
                       on *nix platforms since native sharing of Windows NIC 
                       devices works with no external magic.
+  USE_VDE_NETWORK   - Specifies that support for vde networking should be 
+                      included.  This can be leveraged, along with OS bridging
+                      capabilities to share a single LAN interface.  It also
+                      can allow a simulator to have useful networking 
+                      functionality when running without root access.  This 
+                      allows device names of the form vde:/tmp/switch to be 
+                      specified at open time.  This functionality is only 
+                      available on *nix platforms since the vde api isn't 
+                      available on Windows.
 
   NEED_PCAP_SENDPACKET
                     - Specifies that you are using an older version of libpcap
@@ -151,6 +160,11 @@
 
   Modification history:
 
+  30-Oct-11  MP   Added support for vde (Virtual Distributed Ethernet) networking
+  29-Oct-11  MP   Added support for integrated Tap networking interfaces on OSX
+  12-Aug-11  MP   Cleaned up payload length determination
+                  Fixed race condition detecting reflections when threaded 
+                  reading and writing is enabled
   18-Apr-11  MP   Fixed race condition with self loopback packets in 
                   multithreaded environments
   09-Jan-11  MP   Fixed missing crc data when USE_READER_THREAD is defined and 
@@ -793,6 +807,10 @@ void eth_show_dev (FILE* st, ETH_DEV* dev)
 #endif
 #endif /* USE_TAP_NETWORK */
 
+#ifdef USE_VDE_NETWORK
+#include <libvdeplug.h>
+#endif /* USE_VDE_NETWORK */
+
 /* Allows windows to look up user-defined adapter names */
 #if defined(_WIN32)
 #include <winreg.h>
@@ -1092,40 +1110,42 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname)
   if (!pcap_mac_if_win32(devname, (UCHAR *)&dev->host_nic_phy_hw_addr))
     dev->have_host_nic_phy_addr = 1;
 #elif !defined (__VMS)
-{
-  char command[1024];
-  FILE *f;
+  if (1) {
+    char command[1024];
+    FILE *f;
 
-  memset(command, 0, sizeof(command));
-  snprintf(command, sizeof(command)-1, "ifconfig %s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F] >NIC.hwaddr", devname);
-  system(command);
-  if (f = fopen("NIC.hwaddr", "r")) {
-    if (fgets(command, sizeof(command)-1, f)) {
-      char *p1, *p2;
+    if (0 == strncmp("vde:", devname, 4))
+      return;
+    memset(command, 0, sizeof(command));
+    snprintf(command, sizeof(command)-1, "ifconfig %s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F] >NIC.hwaddr", devname);
+    system(command);
+    if (f = fopen("NIC.hwaddr", "r")) {
+      if (fgets(command, sizeof(command)-1, f)) {
+        char *p1, *p2;
         
-      p1 = strchr(command, ':');
-      while (p1) {
-        p2 = strchr(p1+1, ':');
-        if (p2 == p1+3) {
-          int mac_bytes[6];
-          if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) {
-            dev->host_nic_phy_hw_addr[0] = mac_bytes[0];
-            dev->host_nic_phy_hw_addr[1] = mac_bytes[1];
-            dev->host_nic_phy_hw_addr[2] = mac_bytes[2];
-            dev->host_nic_phy_hw_addr[3] = mac_bytes[3];
-            dev->host_nic_phy_hw_addr[4] = mac_bytes[4];
-            dev->host_nic_phy_hw_addr[5] = mac_bytes[5];
-            dev->have_host_nic_phy_addr = 1;
+        p1 = strchr(command, ':');
+        while (p1) {
+          p2 = strchr(p1+1, ':');
+          if (p2 == p1+3) {
+            int mac_bytes[6];
+            if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) {
+              dev->host_nic_phy_hw_addr[0] = mac_bytes[0];
+              dev->host_nic_phy_hw_addr[1] = mac_bytes[1];
+              dev->host_nic_phy_hw_addr[2] = mac_bytes[2];
+              dev->host_nic_phy_hw_addr[3] = mac_bytes[3];
+              dev->host_nic_phy_hw_addr[4] = mac_bytes[4];
+              dev->host_nic_phy_hw_addr[5] = mac_bytes[5];
+              dev->have_host_nic_phy_addr = 1;
+              }
+            break;
+            }
+          p1 = p2;
           }
-          break;
         }
-        p1 = p2;
+      fclose(f);
+      remove("NIC.hwaddr");
       }
     }
-    fclose(f);
-    remove("NIC.hwaddr");
-  }
-}
 #endif
 }
 
@@ -1148,84 +1168,116 @@ int sched_policy;
 struct sched_param sched_priority;
 #if defined (_WIN32)
 HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle);
-#endif
-#if defined (MUST_DO_SELECT)
-struct timeval timeout;
+#else
 int sel_ret;
-int pcap_fd;
+int do_select = 0;
+int select_fd;
 
-if (dev->pcap_mode)
-  pcap_fd = pcap_get_selectable_fd((pcap_t *)dev->handle);
-else
-  pcap_fd = dev->fd_handle;
+switch (dev->eth_api) {
+  case ETH_API_PCAP:
+#if defined (MUST_DO_SELECT)
+    do_select = 1;
+    select_fd = pcap_get_selectable_fd((pcap_t *)dev->handle);
+#endif
+    break;
+  case ETH_API_TAP:
+  case ETH_API_VDE:
+    do_select = 1;
+    select_fd = dev->fd_handle;
+    break;
+  }
 #endif
 
-  sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
+sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
 
-  /* Boost Priority for this I/O thread vs the CPU instruction execution 
-     thread which in general won't be readily yielding the processor when 
-     this thread needs to run */
-  pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
-  ++sched_priority.sched_priority;
-  pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
+/* Boost Priority for this I/O thread vs the CPU instruction execution 
+   thread which in general won't be readily yielding the processor when 
+   this thread needs to run */
+pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
+++sched_priority.sched_priority;
+pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
 
-  while ((dev->pcap_mode && dev->handle) || dev->fd_handle) {
-#if defined (MUST_DO_SELECT)
-    fd_set setl;
+while (dev->handle) {
+#if defined (_WIN32)
+  if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) {
+#else
+  fd_set setl;
+  struct timeval timeout;
+
+  if (do_select) {
     FD_ZERO(&setl);
-    FD_SET(pcap_fd, &setl);
+    FD_SET(select_fd, &setl);
     timeout.tv_sec = 0;
     timeout.tv_usec = 250*1000;
-    sel_ret = select(1+pcap_fd, &setl, NULL, NULL, &timeout);
-    if (sel_ret < 0 && errno != EINTR) break;
-    if (sel_ret > 0) {
-#else /* !MUST_DO_SELECT */
-#if defined (_WIN32)
-    if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) {
-#else
-    if (1)  {
-#endif
-#endif /* MUST_DO_SELECT */
-      if ((dev->pcap_mode) && (!dev->handle))
-        break;
-      if ((!dev->pcap_mode) && (!dev->fd_handle))
-        break;
-      /* dispatch read request queue available packets */
-      if (dev->pcap_mode)
+    sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
+    }
+  else
+    sel_ret = 1;
+  if (sel_ret < 0 && errno != EINTR) break;
+  if (sel_ret > 0) {
+#endif /* _WIN32 */
+    if (!dev->handle)
+      break;
+    /* dispatch read request queue available packets */
+    switch (dev->eth_api) {
+      case ETH_API_PCAP:
         status = pcap_dispatch ((pcap_t*)dev->handle, -1, &_eth_callback, (u_char*)dev);
+        break;
 #ifdef USE_TAP_NETWORK
-      else {
-        struct pcap_pkthdr header;
-        int len;
-        u_char buf[ETH_MAX_JUMBO_FRAME];
+      case ETH_API_TAP:
+        if (1) {
+          struct pcap_pkthdr header;
+          int len;
+          u_char buf[ETH_MAX_JUMBO_FRAME];
 
-        memset(&header, 0, sizeof(header));
-        len = read(dev->fd_handle, buf, sizeof(buf));
-        if (len > 0) {
-          status = 1;
-          header.caplen = header.len = len;
-          _eth_callback((u_char *)dev, &header, buf);
-        } else {
-          status = 0;
-        }
-      }
-#endif /* USE_TAP_NETWORK */
-
-      if ((status > 0) && (dev->asynch_io)) {
-        int wakeup_needed;
-        pthread_mutex_lock (&dev->lock);
-        wakeup_needed = (dev->read_queue.count != 0);
-        pthread_mutex_unlock (&dev->lock);
-        if (wakeup_needed) {
-          sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n");
-          sim_activate_abs (dev->dptr->units, dev->asynch_io_latency);
+          memset(&header, 0, sizeof(header));
+          len = read(dev->fd_handle, buf, sizeof(buf));
+          if (len > 0) {
+            status = 1;
+            header.caplen = header.len = len;
+            _eth_callback((u_char *)dev, &header, buf);
+            }
+          else
+            status = 0;
           }
+        break;
+#endif /* USE_TAP_NETWORK */
+#ifdef USE_VDE_NETWORK
+      case ETH_API_VDE:
+        if (1) {
+          struct pcap_pkthdr header;
+          int len;
+          u_char buf[ETH_MAX_JUMBO_FRAME];
+
+          memset(&header, 0, sizeof(header));
+          len = vde_recv((VDECONN *)dev->handle, buf, sizeof(buf), 0);
+          if (len > 0) {
+            status = 1;
+            header.caplen = header.len = len;
+            _eth_callback((u_char *)dev, &header, buf);
+            }
+          else
+            status = 0;
+          }
+        break;
+#endif /* USE_VDE_NETWORK */
+      }
+    if ((status > 0) && (dev->asynch_io)) {
+      int wakeup_needed;
+
+      pthread_mutex_lock (&dev->lock);
+      wakeup_needed = (dev->read_queue.count != 0);
+      pthread_mutex_unlock (&dev->lock);
+      if (wakeup_needed) {
+        sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n");
+        sim_activate_abs (dev->dptr->units, dev->asynch_io_latency);
         }
       }
+    }
   }
 
-  sim_debug(dev->dbit, dev->dptr, "Reader Thread Exiting\n");
-  return NULL;
+sim_debug(dev->dbit, dev->dptr, "Reader Thread Exiting\n");
+return NULL;
 }
 
 static void *
@@ -1236,225 +1288,257 @@ struct write_request *request;
 int sched_policy;
 struct sched_param sched_priority;
 
-  /* Boost Priority for this I/O thread vs the CPU instruction execution 
-     thread which in general won't be readily yielding the processor when 
-     this thread needs to run */
-  pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
-  ++sched_priority.sched_priority;
-  pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
+/* Boost Priority for this I/O thread vs the CPU instruction execution 
+   thread which in general won't be readily yielding the processor when 
+   this thread needs to run */
+pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
+++sched_priority.sched_priority;
+pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
 
-  sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n");
+sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n");
 
-  pthread_mutex_lock (&dev->writer_lock);
-  while ((dev->pcap_mode && dev->handle) || dev->fd_handle) {
-    pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
-    while (request = dev->write_requests) {
-      /* Pull buffer off request list */
-      dev->write_requests = request->next;
-      pthread_mutex_unlock (&dev->writer_lock);
-      
-      dev->write_status = _eth_write(dev, &request->packet, NULL);
-      
-      pthread_mutex_lock (&dev->writer_lock);
-      /* Put buffer on free buffer list */
-      request->next = dev->write_buffers;
-      dev->write_buffers = request;
+pthread_mutex_lock (&dev->writer_lock);
+while (dev->handle) {
+  pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
+  while (request = dev->write_requests) {
+    /* Pull buffer off request list */
+    dev->write_requests = request->next;
+    pthread_mutex_unlock (&dev->writer_lock);
+
+    dev->write_status = _eth_write(dev, &request->packet, NULL);
+
+    pthread_mutex_lock (&dev->writer_lock);
+    /* Put buffer on free buffer list */
+    request->next = dev->write_buffers;
+    dev->write_buffers = request;
     }
   }
-  pthread_mutex_unlock (&dev->writer_lock);
+pthread_mutex_unlock (&dev->writer_lock);
 
-  sim_debug(dev->dbit, dev->dptr, "Writer Thread Exiting\n");
-  return NULL;
+sim_debug(dev->dbit, dev->dptr, "Writer Thread Exiting\n");
+return NULL;
 }
 #endif
 
 t_stat eth_set_async (ETH_DEV *dev, int latency)
 {
 #if !defined(USE_READER_THREAD) || !defined(SIM_ASYNCH_IO)
-  char *msg = "Eth: can't operate asynchronously, must poll\r\n";
-  printf ("%s", msg);
-  if (sim_log) fprintf (sim_log, "%s", msg);
-  return SCPE_NOFNC;
+char *msg = "Eth: can't operate asynchronously, must poll\r\n";
+printf ("%s", msg);
+if (sim_log) fprintf (sim_log, "%s", msg);
+return SCPE_NOFNC;
 #else
-  int wakeup_needed;
+int wakeup_needed;
 
-  dev->asynch_io = 1;
-  dev->asynch_io_latency = latency;
-  pthread_mutex_lock (&dev->lock);
-  wakeup_needed = (dev->read_queue.count != 0);
-  pthread_mutex_unlock (&dev->lock);
-  if (wakeup_needed) {
-    sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n");
-    sim_activate_abs (dev->dptr->units, dev->asynch_io_latency);
+dev->asynch_io = 1;
+dev->asynch_io_latency = latency;
+pthread_mutex_lock (&dev->lock);
+wakeup_needed = (dev->read_queue.count != 0);
+pthread_mutex_unlock (&dev->lock);
+if (wakeup_needed) {
+  sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n");
+  sim_activate_abs (dev->dptr->units, dev->asynch_io_latency);
   }
 #endif
-  return SCPE_OK;
+return SCPE_OK;
 }
 
 t_stat eth_clr_async (ETH_DEV *dev)
 {
 #if !defined(USE_READER_THREAD) || !defined(SIM_ASYNCH_IO)
-  return SCPE_NOFNC;
+return SCPE_NOFNC;
 #else
-  /* make sure device exists */
-  if (!dev) return SCPE_UNATT;
+/* make sure device exists */
+if (!dev) return SCPE_UNATT;
 
-  dev->asynch_io = 0;
-  return SCPE_OK;
+dev->asynch_io = 0;
+return SCPE_OK;
 #endif
 }
 
 t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
 {
-  int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ;
-  char errbuf[PCAP_ERRBUF_SIZE];
-  char temp[1024];
-  char* savname = name;
-  int   num;
-  char* msg;
+int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ;
+char errbuf[PCAP_ERRBUF_SIZE];
+char temp[1024];
+char* savname = name;
+int   num;
+char* msg;
 
-  if (bufsz < ETH_MAX_JUMBO_FRAME)
-      bufsz = ETH_MAX_JUMBO_FRAME;  /* Enable handling of jumbo frames */
+if (bufsz < ETH_MAX_JUMBO_FRAME)
+  bufsz = ETH_MAX_JUMBO_FRAME;    /* Enable handling of jumbo frames */
 
-  /* initialize device */
-  eth_zero(dev);
+/* initialize device */
+eth_zero(dev);
 
-  /* translate name of type "ethX" to real device name */
-  if ((strlen(name) == 4)
-      && (tolower(name[0]) == 'e')
-      && (tolower(name[1]) == 't')
-      && (tolower(name[2]) == 'h')
-      && isdigit(name[3])
-     ) {
-    num = atoi(&name[3]);
-    savname = eth_getname(num, temp);
+/* translate name of type "ethX" to real device name */
+if ((strlen(name) == 4)
+    && (tolower(name[0]) == 'e')
+    && (tolower(name[1]) == 't')
+    && (tolower(name[2]) == 'h')
+    && isdigit(name[3])
+   ) {
+  num = atoi(&name[3]);
+  savname = eth_getname(num, temp);
+  if (savname == 0) /* didn't translate */
+    return SCPE_OPENERR;
+  }
+else {
+  /* are they trying to use device description? */
+  savname = eth_getname_bydesc(name, temp);
+  if (savname == 0) { /* didn't translate */
+    /* probably is not ethX and has no description */
+    savname = eth_getname_byname(name, temp);
     if (savname == 0) /* didn't translate */
-      return SCPE_OPENERR;
-  } else {
-    /* are they trying to use device description? */
-    savname = eth_getname_bydesc(name, temp);
-    if (savname == 0) { /* didn't translate */
-      /* probably is not ethX and has no description */
-      savname = eth_getname_byname(name, temp);
-      if (savname == 0) /* didn't translate */
-        savname = name;
+      savname = name;
     }
   }
 
-  /* attempt to connect device */
-  memset(errbuf, 0, sizeof(errbuf));
-  if (strncmp("tap:", savname, 4)) {
+/* attempt to connect device */
+memset(errbuf, 0, sizeof(errbuf));
+if (0 == strncmp("tap:", savname, 4)) {
+  int  tun = -1;    /* TUN/TAP Socket */
+  int  on = 1;
+  char dev_name[64] = "";
+
+#if defined(USE_TAP_NETWORK)
+  if (!strcmp(savname, "tap:tapN")) {
+    msg = "Eth: Must specify actual tap device name (i.e. tap:tap0)\r\n";
+    printf (msg, errbuf);
+    if (sim_log) fprintf (sim_log, msg, errbuf);
+    return SCPE_OPENERR;
+    }
+#endif
+#if defined(__linux) && defined(USE_TAP_NETWORK)
+  if ((tun = open("/dev/net/tun", O_RDWR)) >= 0) {
+    struct ifreq ifr; /* Interface Requests */
+
+    memset(&ifr, 0, sizeof(ifr));
+    /* Set up interface flags */
+    strcpy(ifr.ifr_name, savname+4);
+    ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+
+    /* Send interface requests to TUN/TAP driver. */
+    if (ioctl(tun, TUNSETIFF, &ifr) >= 0) {
+      if (ioctl(tun, FIONBIO, &on)) {
+        strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
+        close(tun);
+        }
+      else {
+        dev->fd_handle = tun;
+        strcpy(savname, ifr.ifr_name);
+        }
+      }
+    else
+      strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
+    }
+  else
+    strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
+#elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK)
+  snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4);
+  dev_name[sizeof(dev_name)-1] = '\0';
+
+  if ((tun = open(dev_name, O_RDWR)) >= 0) {
+    if (ioctl(tun, FIONBIO, &on)) {
+      strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
+      close(tun);
+      }
+    else {
+      dev->fd_handle = tun;
+      strcpy(savname, savname+4);
+      }
+#if defined (__APPLE__)
+    if (1) {
+      struct ifreq ifr;
+      int s;
+
+      memset (&ifr, 0, sizeof(ifr));
+      ifr.ifr_addr.sa_family = AF_INET;
+      strncpy(ifr.ifr_name, savname+4, sizeof(ifr.ifr_name));
+      if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
+        if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) {
+          ifr.ifr_flags |= IFF_UP;
+          ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr);
+          }
+        close(s);
+        }
+      }
+#endif
+    }
+  else
+    strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
+#else
+  strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1);
+#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
+  if (0 == errbuf[0]) {
+    dev->eth_api = ETH_API_TAP;
+    dev->handle = (void *)1;  /* Flag used to indicated open */
+    }
+  }
+else
+  if (0 == strncmp("vde:", savname, 4)) {
+#if defined(USE_VDE_NETWORK)
+    struct vde_open_args voa;
+
+    memset(&voa, 0, sizeof(voa));
+    if (!strcmp(savname, "vde:vdedevice")) {
+      msg = "Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\r\n";
+      printf (msg, errbuf);
+      if (sim_log) fprintf (sim_log, msg, errbuf);
+      return SCPE_OPENERR;
+      }
+    if (!(dev->handle = (void*) vde_open(savname+4, "simh", &voa)))
+      strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
+    else {
+      dev->eth_api = ETH_API_VDE;
+      dev->fd_handle = vde_datafd((VDECONN*)dev->handle);
+      }
+#else
+    strncpy(errbuf, "No support for vde: network devices", sizeof(errbuf)-1);
+#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
+    }
+  else {
     dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
     if (!dev->handle) { /* can't open device */
       msg = "Eth: pcap_open_live error - %s\r\n";
       printf (msg, errbuf);
       if (sim_log) fprintf (sim_log, msg, errbuf);
       return SCPE_OPENERR;
-    }
-    dev->pcap_mode = 1;
-  } else {
-    int  tun = -1;    /* TUN/TAP Socket */
-    int  on = 1;
-    char dev_name[64] = "";
-
-#if defined(USE_TAP_NETWORK)
-    if (!strcmp(savname, "tap:tapN")) {
-      msg = "Eth: Must specify actual tap device name (i.e. tap:tap0)\r\n";
-      printf (msg, errbuf);
-      if (sim_log) fprintf (sim_log, msg, errbuf);
-      return SCPE_OPENERR;
-    }
-#endif
-#if defined(__linux) && defined(USE_TAP_NETWORK)
-    if ((tun = open("/dev/net/tun", O_RDWR)) >= 0) {
-      struct ifreq ifr; /* Interface Requests */
-
-      memset(&ifr, 0, sizeof(ifr));
-      /* Set up interface flags */
-      strcpy(ifr.ifr_name, savname+4);
-      ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
-
-      // Send interface requests to TUN/TAP driver.
-      if (ioctl(tun, TUNSETIFF, &ifr) >= 0) {
-        if (ioctl(tun, FIONBIO, &on)) {
-          strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
-          close(tun);
-        } else {
-          dev->fd_handle = tun;
-          strcpy(savname, ifr.ifr_name);
-        }
-      } else
-        strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
-    } else
-      strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
-#elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK)
-    snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4);
-    dev_name[sizeof(dev_name)-1] = '\0';
-
-    if ((tun = open(dev_name, O_RDWR)) >= 0) {
-      if (ioctl(tun, FIONBIO, &on)) {
-        strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
-        close(tun);
-      } else {
-        dev->fd_handle = tun;
-        strcpy(savname, savname+4);
       }
-#if defined (__APPLE__)
-      if (1) {
-        struct ifreq ifr;
-        int s;
-
-        memset (&ifr, 0, sizeof(ifr));
-        ifr.ifr_addr.sa_family = AF_INET;
-        strncpy(ifr.ifr_name, savname+4, sizeof(ifr.ifr_name));
-        if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
-          if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) {
-            ifr.ifr_flags |= IFF_UP;
-            ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr);
-          }
-          close(s);
-        }
-      }
-#endif
-    } else {
-      strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
+    dev->eth_api = ETH_API_PCAP;
     }
-#else
-    strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1);
-#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
+if (errbuf[0]) {
+  msg = "Eth: open error - %s\r\n";
+  printf (msg, errbuf);
+  if (sim_log) fprintf (sim_log, msg, errbuf);
+  return SCPE_OPENERR;
   }
-  if (errbuf[0]) {
-    msg = "Eth: open error - %s\r\n";
-    printf (msg, errbuf);
-    if (sim_log) fprintf (sim_log, msg, errbuf);
-    return SCPE_OPENERR;
-  }
-  msg = "Eth: opened OS device %s\r\n";
-  printf (msg, savname);
-  if (sim_log) fprintf (sim_log, msg, savname);
+msg = "Eth: opened OS device %s\r\n";
+printf (msg, savname);
+if (sim_log) fprintf (sim_log, msg, savname);
 
-  /* get the NIC's hardware MAC address */
-  eth_get_nic_hw_addr(dev, savname);
+/* get the NIC's hardware MAC address */
+eth_get_nic_hw_addr(dev, savname);
 
-  /* save name of device */
-  dev->name = malloc(strlen(savname)+1);
-  strcpy(dev->name, savname);
+/* save name of device */
+dev->name = malloc(strlen(savname)+1);
+strcpy(dev->name, savname);
 
-  /* save debugging information */
-  dev->dptr = dptr;
-  dev->dbit = dbit;
+/* save debugging information */
+dev->dptr = dptr;
+dev->dbit = dbit;
 
 #if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
-  /* Tell the kernel that the header is fully-formed when it gets it.
-     This is required in order to fake the src address. */
-  if (dev->pcap_mode) {
-    int one = 1;
-    ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one);
+/* Tell the kernel that the header is fully-formed when it gets it.
+   This is required in order to fake the src address. */
+if (dev->eth_api == ETH_API_PCAP) {
+  int one = 1;
+  ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one);
   }
 #endif /* xBSD */
 
 #if defined (USE_READER_THREAD)
-  {
+if (1) {
   pthread_attr_t attr;
 
 #if defined(_WIN32)
@@ -1473,318 +1557,344 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
   }
 #else /* !defined (USE_READER_THREAD */
 #ifdef USE_SETNONBLOCK
-  /* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
-  if (dev->pcap_mode && (pcap_setnonblock (dev->handle, 1, errbuf) == -1)) {
-    msg = "Eth: Failed to set non-blocking: %s\r\n";
-    printf (msg, errbuf);
-    if (sim_log) fprintf (sim_log, msg, errbuf);
+/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
+if ((dev->eth_api == ETH_API_PCAP) && (pcap_setnonblock (dev->handle, 1, errbuf) == -1)) {
+  msg = "Eth: Failed to set non-blocking: %s\r\n";
+  printf (msg, errbuf);
+  if (sim_log) fprintf (sim_log, msg, errbuf);
   }
 #endif
 #endif /* !defined (USE_READER_THREAD */
 #if defined (__APPLE__)
-  if (dev->pcap_mode) {
-    /* Deliver packets immediately, needed for OS X 10.6.2 and later
-     * (Snow-Leopard).
-     * See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
-     * the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110
-     */
-    int v = 1;
-    ioctl(pcap_fileno(dev->handle), BIOCIMMEDIATE, &v);
+if (dev->eth_api == ETH_API_PCAP) {
+  /* Deliver packets immediately, needed for OS X 10.6.2 and later
+   * (Snow-Leopard).
+   * See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
+   * the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110
+   */
+  int v = 1;
+  ioctl(pcap_fileno(dev->handle), BIOCIMMEDIATE, &v);
   }
 #endif
-  return SCPE_OK;
+return SCPE_OK;
 }
 
 t_stat eth_close(ETH_DEV* dev)
 {
-  char* msg = "Eth: closed %s\r\n";
-  pcap_t *pcap;
-  int pcap_fd = dev->fd_handle;
+char* msg = "Eth: closed %s\r\n";
+pcap_t *pcap;
+int pcap_fd = dev->fd_handle;
 
-  /* make sure device exists */
-  if (!dev) return SCPE_UNATT;
+/* make sure device exists */
+if (!dev) return SCPE_UNATT;
 
-  /* close the device */
-  pcap = (pcap_t *)dev->handle;
-  dev->handle = NULL;
-  dev->fd_handle = 0;
-  dev->have_host_nic_phy_addr = 0;
+/* close the device */
+pcap = (pcap_t *)dev->handle;
+dev->handle = NULL;
+dev->fd_handle = 0;
+dev->have_host_nic_phy_addr = 0;
 
 #if defined (USE_READER_THREAD)
-  pthread_join (dev->reader_thread, NULL);
-  pthread_mutex_destroy (&dev->lock);
-  pthread_cond_signal (&dev->writer_cond);
-  pthread_join (dev->writer_thread, NULL);
-  pthread_mutex_destroy (&dev->self_lock);
-  pthread_mutex_destroy (&dev->writer_lock);
-  pthread_cond_destroy (&dev->writer_cond);
-  if (1) {
-    struct write_request *buffer;
-
-    while (buffer = dev->write_buffers) {
-      dev->write_buffers = buffer->next;
-      free(buffer);
+pthread_join (dev->reader_thread, NULL);
+pthread_mutex_destroy (&dev->lock);
+pthread_cond_signal (&dev->writer_cond);
+pthread_join (dev->writer_thread, NULL);
+pthread_mutex_destroy (&dev->self_lock);
+pthread_mutex_destroy (&dev->writer_lock);
+pthread_cond_destroy (&dev->writer_cond);
+if (1) {
+  struct write_request *buffer;
+   while (buffer = dev->write_buffers) {
+    dev->write_buffers = buffer->next;
+    free(buffer);
     }
-    while (buffer = dev->write_requests) {
-      dev->write_requests = buffer->next;
-      free(buffer);
+  while (buffer = dev->write_requests) {
+    dev->write_requests = buffer->next;
+    free(buffer);
     }
   }
-  ethq_destroy (&dev->read_queue);         /* release FIFO queue */
+ethq_destroy (&dev->read_queue);         /* release FIFO queue */
 #endif
 
-  if (dev->pcap_mode)
+switch (dev->eth_api) {
+  case ETH_API_PCAP:
     pcap_close(pcap);
+    break;
 #ifdef USE_TAP_NETWORK
-  else
+  case ETH_API_TAP:
     close(pcap_fd);
+    break;
 #endif
-  printf (msg, dev->name);
-  if (sim_log) fprintf (sim_log, msg, dev->name);
+#ifdef USE_VDE_NETWORK
+  case ETH_API_VDE:
+    vde_close((VDECONN*)pcap);
+    break;
+#endif
+  }
+printf (msg, dev->name);
+if (sim_log) fprintf (sim_log, msg, dev->name);
 
-  /* clean up the mess */
-  free(dev->name);
-  eth_zero(dev);
+/* clean up the mess */
+free(dev->name);
+eth_zero(dev);
 
-  return SCPE_OK;
+return SCPE_OK;
 }
 
 t_stat eth_check_address_conflict (ETH_DEV* dev, 
                                    ETH_MAC* const mac)
 {
-  ETH_PACK send, recv;
-  t_stat status;
-  int responses = 0;
-  char mac_string[32];
+ETH_PACK send, recv;
+t_stat status;
+int responses = 0;
+char mac_string[32];
 
-  eth_mac_fmt(mac, mac_string);
-  sim_debug(dev->dbit, dev->dptr, "Determining Address Conflict for MAC address: %s\n", mac_string);
+eth_mac_fmt(mac, mac_string);
+sim_debug(dev->dbit, dev->dptr, "Determining Address Conflict for MAC address: %s\n", mac_string);
 
-  /* build a loopback forward request packet */
-  memset (&send, 0, sizeof(ETH_PACK));
-  send.len = ETH_MIN_PACKET;                              /* minimum packet size */
-  memcpy(&send.msg[0], mac, sizeof(ETH_MAC));             /* target address */
-  memcpy(&send.msg[6], mac, sizeof(ETH_MAC));             /* source address */
-  send.msg[12] = 0x90;                                    /* loopback packet type */
-  send.msg[14] = 0;                                       /* Offset */
-  send.msg[16] = 2;                                       /* Forward */
-  memcpy(&send.msg[18], mac, sizeof(ETH_MAC));            /* Forward Destination */
-  send.msg[24] = 1;                                       /* Reply */
+/* build a loopback forward request packet */
+memset (&send, 0, sizeof(ETH_PACK));
+send.len = ETH_MIN_PACKET;                              /* minimum packet size */
+memcpy(&send.msg[0], mac, sizeof(ETH_MAC));             /* target address */
+memcpy(&send.msg[6], mac, sizeof(ETH_MAC));             /* source address */
+send.msg[12] = 0x90;                                    /* loopback packet type */
+send.msg[14] = 0;                                       /* Offset */
+send.msg[16] = 2;                                       /* Forward */
+memcpy(&send.msg[18], mac, sizeof(ETH_MAC));            /* Forward Destination */
+send.msg[24] = 1;                                       /* Reply */
 
-  eth_filter(dev, 1, (ETH_MAC *)mac, 0, 0);
+eth_filter(dev, 1, (ETH_MAC *)mac, 0, 0);
 
-  /* send the packet */
-  status = _eth_write (dev, &send, NULL);
-  if (status != SCPE_OK) {
-    char *msg;
-    msg = "Eth: Error Transmitting packet: %s\r\n"
-          "You may need to run as root, or install a libpcap version\r\n"
-          "which is at least 0.9 from www.tcpdump.org\r\n";
-    printf(msg, strerror(errno));
-    if (sim_log) fprintf (sim_log, msg, strerror(errno));
-    return status;
+/* send the packet */
+status = _eth_write (dev, &send, NULL);
+if (status != SCPE_OK) {
+  char *msg;
+  msg = "Eth: Error Transmitting packet: %s\r\n"
+        "You may need to run as root, or install a libpcap version\r\n"
+        "which is at least 0.9 from www.tcpdump.org\r\n";
+  printf(msg, strerror(errno));
+  if (sim_log) fprintf (sim_log, msg, strerror(errno));
+  return status;
   }
 
-  sim_os_ms_sleep (300);   /* time for a conflicting host to respond */
+sim_os_ms_sleep (300);   /* time for a conflicting host to respond */
 
-  /* empty the read queue and count the responses */
-  do {
-    memset (&recv, 0, sizeof(ETH_PACK));
-    status = eth_read (dev, &recv, NULL);
-    if (memcmp(send.msg, recv.msg, 14)== 0)
-      responses++;
+/* empty the read queue and count the responses */
+do {
+  memset (&recv, 0, sizeof(ETH_PACK));
+  status = eth_read (dev, &recv, NULL);
+  if (memcmp(send.msg, recv.msg, 14)== 0)
+    responses++;
   } while (recv.len > 0);
 
-  sim_debug(dev->dbit, dev->dptr, "Address Conflict = %d\n", responses);
-  return responses;
+sim_debug(dev->dbit, dev->dptr, "Address Conflict = %d\n", responses);
+return responses;
 }
 
 t_stat eth_reflect(ETH_DEV* dev)
 {
-  /* Test with an address no NIC should have. */
-  /* We do this to avoid reflections from the wire, */
-  /* in the event that a simulated NIC has a MAC address conflict. */
-  ETH_MAC mac = {0xfe,0xff,0xff,0xff,0xff,0xfe};
+/* Test with an address no NIC should have. */
+/* We do this to avoid reflections from the wire, */
+/* in the event that a simulated NIC has a MAC address conflict. */
+ETH_MAC mac = {0xfe,0xff,0xff,0xff,0xff,0xfe};
 
-  sim_debug(dev->dbit, dev->dptr, "Determining Reflections...\n");
+sim_debug(dev->dbit, dev->dptr, "Determining Reflections...\n");
 
-  dev->reflections = 0;
-  dev->reflections = eth_check_address_conflict (dev, &mac);
+dev->reflections = 0;
+dev->reflections = eth_check_address_conflict (dev, &mac);
 
-  sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections);
-  return dev->reflections;
+sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections);
+return dev->reflections;
 }
 
 static
 t_stat _eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
 {
-  int status = 1;   /* default to failure */
+int status = 1;   /* default to failure */
 
-  /* make sure device exists */
-  if (!dev) return SCPE_UNATT;
+/* make sure device exists */
+if (!dev) return SCPE_UNATT;
 
-  /* make sure packet exists */
-  if (!packet) return SCPE_ARG;
+/* make sure packet exists */
+if (!packet) return SCPE_ARG;
 
-  /* make sure packet is acceptable length */
-  if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
-    int loopback_self_frame = LOOPBACK_SELF_FRAME(dev->physical_addr, packet->msg);
+/* make sure packet is acceptable length */
+if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
+  int loopback_self_frame = LOOPBACK_SELF_FRAME(dev->physical_addr, packet->msg);
 
-    eth_packet_trace (dev, packet->msg, packet->len, "writing");
+  eth_packet_trace (dev, packet->msg, packet->len, "writing");
 
-    /* record sending of loopback packet (done before actual send to avoid race conditions with receiver) */
-    if (loopback_self_frame) {
+  /* record sending of loopback packet (done before actual send to avoid race conditions with receiver) */
+  if (loopback_self_frame) {
 #ifdef USE_READER_THREAD
-        pthread_mutex_lock (&dev->self_lock);
+    pthread_mutex_lock (&dev->self_lock);
 #endif
-        dev->loopback_self_sent += dev->reflections;
-        dev->loopback_self_sent_total++;
+    dev->loopback_self_sent += dev->reflections;
+    dev->loopback_self_sent_total++;
 #ifdef USE_READER_THREAD
-        pthread_mutex_unlock (&dev->self_lock);
+    pthread_mutex_unlock (&dev->self_lock);
 #endif
     }
 
     /* dispatch write request (synchronous; no need to save write info to dev) */
-    if (dev->pcap_mode)
+  switch (dev->eth_api) {
+    case ETH_API_PCAP:
       status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len);
+      break;
 #ifdef USE_TAP_NETWORK
-    else
+    case ETH_API_TAP:
       status = ((packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1);
+      break;
 #endif
-
-    /* On error, correct loopback bookkeeping */
-    if ((status != 0) && loopback_self_frame) {
-#ifdef USE_READER_THREAD
-        pthread_mutex_lock (&dev->self_lock);
+#ifdef USE_VDE_NETWORK
+    case ETH_API_VDE:
+      status = vde_send((VDECONN*)dev->handle, (void *)packet->msg, packet->len, 0);
+      if ((status == packet->len) || (status == 0))
+        status = 0;
+      else
+        if ((status == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
+          status = 0;
+        else
+          status = 1;
+      break;
 #endif
-        dev->loopback_self_sent -= dev->reflections;
-        dev->loopback_self_sent_total--;
+    }
+  /* On error, correct loopback bookkeeping */
+  if ((status != 0) && loopback_self_frame) {
 #ifdef USE_READER_THREAD
-        pthread_mutex_unlock (&dev->self_lock);
+    pthread_mutex_lock (&dev->self_lock);
+#endif
+    dev->loopback_self_sent -= dev->reflections;
+    dev->loopback_self_sent_total--;
+#ifdef USE_READER_THREAD
+    pthread_mutex_unlock (&dev->self_lock);
 #endif
     }
 
   } /* if packet->len */
 
-  /* call optional write callback function */
-  if (routine)
-    (routine)(status);
+/* call optional write callback function */
+if (routine)
+  (routine)(status);
 
-  return ((status == 0) ? SCPE_OK : SCPE_IOERR);
+return ((status == 0) ? SCPE_OK : SCPE_IOERR);
 }
 
 t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
 {
 #ifdef USE_READER_THREAD
-  struct write_request *request;
-  int write_queue_size = 1;
+struct write_request *request;
+int write_queue_size = 1;
 
-  /* make sure device exists */
-  if (!dev) return SCPE_UNATT;
+/* make sure device exists */
+if (!dev) return SCPE_UNATT;
 
-  /* Get a buffer */
-  pthread_mutex_lock (&dev->writer_lock);
-  if (request = dev->write_buffers)
-    dev->write_buffers = request->next;
-  pthread_mutex_unlock (&dev->writer_lock);
-  if (!request)
-    request = malloc(sizeof(*request));
+/* Get a buffer */
+pthread_mutex_lock (&dev->writer_lock);
+if (request = dev->write_buffers)
+  dev->write_buffers = request->next;
+pthread_mutex_unlock (&dev->writer_lock);
+if (!request)
+  request = malloc(sizeof(*request));
 
-  /* Copy buffer contents */
-  request->packet.len = packet->len;
-  request->packet.used = packet->used;
-  request->packet.status = packet->status;
-  request->packet.crc_len = packet->crc_len;
-  memcpy(request->packet.msg, packet->msg, packet->len);
+/* Copy buffer contents */
+request->packet.len = packet->len;
+request->packet.used = packet->used;
+request->packet.status = packet->status;
+request->packet.crc_len = packet->crc_len;
+memcpy(request->packet.msg, packet->msg, packet->len);
 
-  /* Insert buffer at the end of the write list (to make sure that */
-  /* packets make it to the wire in the order they were presented here) */
-  pthread_mutex_lock (&dev->writer_lock);
-  request->next = NULL;
-  if (dev->write_requests) {
-    struct write_request *last_request = dev->write_requests;
+/* Insert buffer at the end of the write list (to make sure that */
+/* packets make it to the wire in the order they were presented here) */
+pthread_mutex_lock (&dev->writer_lock);
+request->next = NULL;
+if (dev->write_requests) {
+  struct write_request *last_request = dev->write_requests;
 
+  ++write_queue_size;
+  while (last_request->next) {
+    last_request = last_request->next;
     ++write_queue_size;
-    while (last_request->next) {
-      last_request = last_request->next;
-      ++write_queue_size;
     }
-    last_request->next = request;
-  } else
+  last_request->next = request;
+  }
+else
     dev->write_requests = request;
-  if (write_queue_size > dev->write_queue_peak)
-    dev->write_queue_peak = write_queue_size;
-  pthread_mutex_unlock (&dev->writer_lock);
+if (write_queue_size > dev->write_queue_peak)
+  dev->write_queue_peak = write_queue_size;
+pthread_mutex_unlock (&dev->writer_lock);
 
-  /* Awaken writer thread to perform actual write */
-  pthread_cond_signal (&dev->writer_cond);
+/* Awaken writer thread to perform actual write */
+pthread_cond_signal (&dev->writer_cond);
 
-  /* Return with a status from some prior write */
-  if (routine)
-      (routine)(dev->write_status);
-  return dev->write_status;
+/* Return with a status from some prior write */
+if (routine)
+  (routine)(dev->write_status);
+return dev->write_status;
 #else
-  return _eth_write(dev, packet, routine);
+return _eth_write(dev, packet, routine);
 #endif
 }
 
 static int
 _eth_hash_lookup(ETH_MULTIHASH hash, const u_char* data)
 {
-  int key = 0x3f & (eth_crc32(0, data, 6) >> 26);
+int key = 0x3f & (eth_crc32(0, data, 6) >> 26);
 
-  key ^= 0x3f;
-  return (hash[key>>3] & (1 << (key&0x7)));
+key ^= 0x3f;
+return (hash[key>>3] & (1 << (key&0x7)));
 }
 
 static int
 _eth_hash_validate(ETH_MAC *MultiCastList, int count, ETH_MULTIHASH hash)
 {
-  ETH_MULTIHASH lhash;
-  int i;
+ETH_MULTIHASH lhash;
+int i;
 
-  memset(lhash, 0, sizeof(lhash));
-  for (i=0; i<count; ++i) {
-    int key = 0x3f & (eth_crc32(0, MultiCastList[i], 6) >> 26);
+memset(lhash, 0, sizeof(lhash));
+for (i=0; i<count; ++i) {
+  int key = 0x3f & (eth_crc32(0, MultiCastList[i], 6) >> 26);
 
-    key ^= 0x3F;
-    printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X Key: %X, Byte: %X, Val: %X\n", 
-        MultiCastList[i][0], MultiCastList[i][1], MultiCastList[i][2], MultiCastList[i][3], MultiCastList[i][4], MultiCastList[i][5], 
-        key, key>>3, (1 << (key&0x7)));
-    lhash[key>>3] |= (1 << (key&0x7));
+  key ^= 0x3F;
+  printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X Key: %X, Byte: %X, Val: %X\n", 
+      MultiCastList[i][0], MultiCastList[i][1], MultiCastList[i][2], MultiCastList[i][3], MultiCastList[i][4], MultiCastList[i][5], 
+      key, key>>3, (1 << (key&0x7)));
+  lhash[key>>3] |= (1 << (key&0x7));
   }
-  if (memcmp(hash, lhash, sizeof(lhash))) {
-    printf("Inconsistent Computed Hash:\n");
-    printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", 
-            hash[0], hash[1], hash[2], hash[3], 
-            hash[4], hash[5], hash[6], hash[7]);
-    printf("Was:       %02X %02X %02X %02X %02X %02X %02X %02X\n", 
-            lhash[0], lhash[1], lhash[2], lhash[3], 
-            lhash[4], lhash[5], lhash[6], lhash[7]);
+if (memcmp(hash, lhash, sizeof(lhash))) {
+  printf("Inconsistent Computed Hash:\n");
+  printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", 
+         hash[0], hash[1], hash[2], hash[3], 
+         hash[4], hash[5], hash[6], hash[7]);
+  printf("Was:       %02X %02X %02X %02X %02X %02X %02X %02X\n", 
+         lhash[0], lhash[1], lhash[2], lhash[3], 
+         lhash[4], lhash[5], lhash[6], lhash[7]);
   }
-    printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", 
-            hash[0], hash[1], hash[2], hash[3], 
-            hash[4], hash[5], hash[6], hash[7]);
-    printf("Was:       %02X %02X %02X %02X %02X %02X %02X %02X\n", 
-            lhash[0], lhash[1], lhash[2], lhash[3], 
-            lhash[4], lhash[5], lhash[6], lhash[7]);
-  return 0;
+else {
+  printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", 
+         hash[0], hash[1], hash[2], hash[3], 
+         hash[4], hash[5], hash[6], hash[7]);
+  printf("Was:       %02X %02X %02X %02X %02X %02X %02X %02X\n", 
+         lhash[0], lhash[1], lhash[2], lhash[3], 
+         lhash[4], lhash[5], lhash[6], lhash[7]);
+  }
+return 0;
 }
 
 static void
 _eth_test_multicast_hash()
 {
-  ETH_MAC tMacs[] = {
-                     {0xAB, 0x00, 0x04, 0x01, 0xAC, 0x10},
-                     {0xAB, 0x00, 0x00, 0x04, 0x00, 0x00},
-                     {0x09, 0x00, 0x2B, 0x00, 0x00, 0x0F},
-                     {0x09, 0x00, 0x2B, 0x02, 0x01, 0x04},
-                     {0x09, 0x00, 0x2B, 0x02, 0x01, 0x07},
-                     {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
-                     {0x01, 0x00, 0x5E, 0x00, 0x00, 0x01}};
-  ETH_MULTIHASH thash = {0x01, 0x40, 0x00, 0x00, 0x48, 0x88, 0x40, 0x00};
+ETH_MAC tMacs[] = {
+                   {0xAB, 0x00, 0x04, 0x01, 0xAC, 0x10},
+                   {0xAB, 0x00, 0x00, 0x04, 0x00, 0x00},
+                   {0x09, 0x00, 0x2B, 0x00, 0x00, 0x0F},
+                   {0x09, 0x00, 0x2B, 0x02, 0x01, 0x04},
+                   {0x09, 0x00, 0x2B, 0x02, 0x01, 0x07},
+                   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+                   {0x01, 0x00, 0x5E, 0x00, 0x00, 0x01}};
+ETH_MULTIHASH thash = {0x01, 0x40, 0x00, 0x00, 0x48, 0x88, 0x40, 0x00};
 
-  _eth_hash_validate(tMacs, sizeof(tMacs)/sizeof(tMacs[0]), thash);
+_eth_hash_validate(tMacs, sizeof(tMacs)/sizeof(tMacs[0]), thash);
 }
 
 /* The IP header */
@@ -1807,7 +1917,7 @@ struct IPHeader {
   uint16 checksum;        /* IP checksum */
   uint32 source_ip;       /* Source Address */
   uint32 dest_ip;         /* Destination Address */
-};
+  };
 
 /* ICMP header */
 struct ICMPHeader {
@@ -1815,14 +1925,14 @@ struct ICMPHeader {
   uint8 code;          /* Type sub code */
   uint16 checksum;     /* ICMP Checksum */
   uint32 otherstuff[1];/* optional data */
-};
+  };
 
 struct UDPHeader {
   uint16 source_port;
   uint16 dest_port;
   uint16 length;      /* The length of the entire UDP datagram, including both header and Data fields. */
   uint16 checksum;
-};
+  };
 
 struct TCPHeader {
   uint16 source_port;
@@ -1844,7 +1954,7 @@ struct TCPHeader {
   uint16 checksum;
   uint16 urgent;
   uint16 otherstuff[1];  /* The rest of the packet */
-};
+  };
 
 #ifndef IPPROTO_TCP
 #define IPPROTO_TCP             6               /* tcp */
@@ -1859,484 +1969,516 @@ struct TCPHeader {
 static uint16 
 ip_checksum(uint16 *buffer, int size) 
 {
-  unsigned long cksum = 0;
+unsigned long cksum = 0;
     
-  /* Sum all the words together, adding the final byte if size is odd  */
-  while (size > 1) {
-    cksum += *buffer++;
-    size -= sizeof(*buffer);
-  }
-  if (size) {
-    uint8 endbytes[2];
+/* Sum all the words together, adding the final byte if size is odd  */
+while (size > 1) {
+  cksum += *buffer++;
+  size -= sizeof(*buffer);
+}
+if (size) {
+  uint8 endbytes[2];
 
-    endbytes[0] = *((uint8 *)buffer);
-    endbytes[1] = 0;
-    cksum += *((uint16 *)endbytes);
+  endbytes[0] = *((uint8 *)buffer);
+  endbytes[1] = 0;
+  cksum += *((uint16 *)endbytes);
   }
 
-  /* Do a little shuffling  */
-  cksum = (cksum >> 16) + (cksum & 0xffff);
-  cksum += (cksum >> 16);
+/* Do a little shuffling  */
+cksum = (cksum >> 16) + (cksum & 0xffff);
+cksum += (cksum >> 16);
     
-  /* Return the bitwise complement of the resulting mishmash  */
-  return (uint16)(~cksum);
+/* Return the bitwise complement of the resulting mishmash  */
+return (uint16)(~cksum);
 }
 
 static uint16 
 pseudo_checksum(uint16 len, uint16 proto, uint16 *src_addr, uint16 *dest_addr, uint8 *buff)
 {
-  uint32 sum;
+uint32 sum;
 
-  /* Sum the data first */
-  sum = 0xffff&(~ip_checksum((uint16 *)buff, len));
+/* Sum the data first */
+sum = 0xffff&(~ip_checksum((uint16 *)buff, len));
 
-  /* add the pseudo header which contains the IP source and destinationn addresses */
-  sum += src_addr[0];
-  sum += src_addr[1];
-  sum += dest_addr[0];
-  sum += dest_addr[1];
-  /* and the protocol number and the length of the UDP packet */
-  sum = sum + htons(proto) + htons(len);
+/* add the pseudo header which contains the IP source and destinationn addresses */
+sum += src_addr[0];
+sum += src_addr[1];
+sum += dest_addr[0];
+sum += dest_addr[1];
+/* and the protocol number and the length of the UDP packet */
+sum = sum + htons(proto) + htons(len);
 
-  /* Do a little shuffling  */
-  sum = (sum >> 16) + (sum & 0xffff);
-  sum += (sum >> 16);
+/* Do a little shuffling  */
+sum = (sum >> 16) + (sum & 0xffff);
+sum += (sum >> 16);
     
-  /* Return the bitwise complement of the resulting mishmash  */
-  return (uint16)(~sum);
+/* Return the bitwise complement of the resulting mishmash  */
+return (uint16)(~sum);
 }
 
 static void
 _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
 {
-  unsigned short* proto = (unsigned short*) &msg[12];
-  struct IPHeader *IP;
-  struct TCPHeader *TCP = NULL;
-  struct UDPHeader *UDP;
-  struct ICMPHeader *ICMP;
-  uint16 orig_checksum;
-  uint16 payload_len;
-  uint16 mtu_payload;
-  uint16 ip_flags;
-  uint16 frag_offset;
-  struct pcap_pkthdr header;
-  uint16 orig_tcp_flags;
+unsigned short* proto = (unsigned short*) &msg[12];
+struct IPHeader *IP;
+struct TCPHeader *TCP = NULL;
+struct UDPHeader *UDP;
+struct ICMPHeader *ICMP;
+uint16 orig_checksum;
+uint16 payload_len;
+uint16 mtu_payload;
+uint16 ip_flags;
+uint16 frag_offset;
+struct pcap_pkthdr header;
+uint16 orig_tcp_flags;
 
-  /* Only interested in IP frames */
-  if (ntohs(*proto) != 0x0800) {
-    ++dev->jumbo_dropped; /* Non IP Frames are dropped */
-    return;
+/* Only interested in IP frames */
+if (ntohs(*proto) != 0x0800) {
+  ++dev->jumbo_dropped; /* Non IP Frames are dropped */
+  return;
   }
-  IP = (struct IPHeader *)&msg[14];
-  if (IP_VERSION(IP) != 4) {
-    ++dev->jumbo_dropped; /* Non IPv4 jumbo frames are dropped */
-    return;
+IP = (struct IPHeader *)&msg[14];
+if (IP_VERSION(IP) != 4) {
+  ++dev->jumbo_dropped; /* Non IPv4 jumbo frames are dropped */
+  return;
   }
-  if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len)) {
-    ++dev->jumbo_dropped; /* Bogus header length frames are dropped */
-    return;
+if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len)) {
+  ++dev->jumbo_dropped; /* Bogus header length frames are dropped */
+  return;
   }
-  if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP)) {
-    ++dev->jumbo_dropped; /* Previously fragmented, but currently jumbo sized frames are dropped */
-    return;
+if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP)) {
+  ++dev->jumbo_dropped; /* Previously fragmented, but currently jumbo sized frames are dropped */
+  return;
   }
-  switch (IP->proto) {
-   case IPPROTO_UDP:
-      UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP));
-      if (ntohs(UDP->length) > (len-IP_HLEN(IP))) {
-        ++dev->jumbo_dropped; /* Bogus UDP packet length (packet contained length exceeds packet size) frames are dropped */
-        return;
-      }
-      if (UDP->checksum == 0)
-        break; /* UDP Checksums are disabled */
-      orig_checksum = UDP->checksum;
-      UDP->checksum = 0;
-      UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP);
-      if (orig_checksum != UDP->checksum)
-        eth_packet_trace (dev, msg, len, "reading jumbo UDP header Checksum Fixed");
-      break;
-   case IPPROTO_ICMP:
-      ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP));
-      orig_checksum = ICMP->checksum;
-      ICMP->checksum = 0;
-      ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP));
-      if (orig_checksum != ICMP->checksum)
-        eth_packet_trace (dev, msg, len, "reading jumbo ICMP header Checksum Fixed");
-      break;
-   case IPPROTO_TCP:
-      TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
-      if ((TCP_DATA_OFFSET(TCP) > (len-IP_HLEN(IP))) || (TCP_DATA_OFFSET(TCP) < 20)) {
-        ++dev->jumbo_dropped; /* Bogus TCP packet header length (packet contained length exceeds packet size) frames are dropped */
-        return;
-      }
-      /* We don't do anything with the TCP checksum since we're going to resegment the TCP data below */
-      break;
-   default:
-      ++dev->jumbo_dropped; /* We onlt handle UDP, ICMP and TCP jumbo frames others are dropped */
+switch (IP->proto) {
+  case IPPROTO_UDP:
+    UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP));
+    if (ntohs(UDP->length) > (len-IP_HLEN(IP))) {
+      ++dev->jumbo_dropped; /* Bogus UDP packet length (packet contained length exceeds packet size) frames are dropped */
       return;
+      }
+    if (UDP->checksum == 0)
+      break; /* UDP Checksums are disabled */
+    orig_checksum = UDP->checksum;
+    UDP->checksum = 0;
+    UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP);
+    if (orig_checksum != UDP->checksum)
+      eth_packet_trace (dev, msg, len, "reading jumbo UDP header Checksum Fixed");
+    break;
+  case IPPROTO_ICMP:
+    ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP));
+    orig_checksum = ICMP->checksum;
+    ICMP->checksum = 0;
+    ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP));
+    if (orig_checksum != ICMP->checksum)
+      eth_packet_trace (dev, msg, len, "reading jumbo ICMP header Checksum Fixed");
+    break;
+  case IPPROTO_TCP:
+    TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
+    if ((TCP_DATA_OFFSET(TCP) > (len-IP_HLEN(IP))) || (TCP_DATA_OFFSET(TCP) < 20)) {
+      ++dev->jumbo_dropped; /* Bogus TCP packet header length (packet contained length exceeds packet size) frames are dropped */
+      return;
+      }
+    /* We don't do anything with the TCP checksum since we're going to resegment the TCP data below */
+    break;
+  default:
+    ++dev->jumbo_dropped; /* We onlt handle UDP, ICMP and TCP jumbo frames others are dropped */
+    return;
   }
-  /* Reasonable Checksums are now in the jumbo packet, but we've got to actually */
-  /* deliver ONLY standard sized ethernet frames.  Our job here is to now act as */
-  /* a router might have to and fragment these IPv4 frames as they are delivered */
-  /* into the virtual NIC. We do this by walking down the packet and dispatching */
-  /* a chunk at a time recomputing an appropriate header for each chunk. For */
-  /* datagram oriented protocols (UDP and ICMP) this is done by simple packet */
-  /* fragmentation.  For TCP this is done by breaking large packets into separate */
-  /* TCP packets. */
-  memset(&header, 0, sizeof(header));
-  switch (IP->proto) {
-   case IPPROTO_UDP:
-   case IPPROTO_ICMP:
-      ++dev->jumbo_fragmented;
-      /* When we're performing LSO (Large Send Offload), we're given a 
-         'template' header which may not include a value being populated 
-         in the IP header length (which is only 16 bits).
-         We process as payload everything which isn't known header data. */
-      payload_len = len - (14 + IP_HLEN(IP));
-      mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP));
-      frag_offset = 0;
-      while (payload_len > 0) {
-        ip_flags = frag_offset;
-        if (payload_len > mtu_payload) {
-          ip_flags |= IP_MF_FLAG;
-          IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP));
-        } else {
-          IP->total_len = htons(payload_len + IP_HLEN(IP));
+/* Reasonable Checksums are now in the jumbo packet, but we've got to actually */
+/* deliver ONLY standard sized ethernet frames.  Our job here is to now act as */
+/* a router might have to and fragment these IPv4 frames as they are delivered */
+/* into the virtual NIC. We do this by walking down the packet and dispatching */
+/* a chunk at a time recomputing an appropriate header for each chunk. For */
+/* datagram oriented protocols (UDP and ICMP) this is done by simple packet */
+/* fragmentation.  For TCP this is done by breaking large packets into separate */
+/* TCP packets. */
+memset(&header, 0, sizeof(header));
+switch (IP->proto) {
+  case IPPROTO_UDP:
+  case IPPROTO_ICMP:
+    ++dev->jumbo_fragmented;
+    /* When we're performing LSO (Large Send Offload), we're given a 
+       'template' header which may not include a value being populated 
+       in the IP header length (which is only 16 bits).
+       We process as payload everything which isn't known header data. */
+    payload_len = len - (14 + IP_HLEN(IP));
+    mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP));
+    frag_offset = 0;
+    while (payload_len > 0) {
+      ip_flags = frag_offset;
+      if (payload_len > mtu_payload) {
+        ip_flags |= IP_MF_FLAG;
+        IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP));
         }
-        IP->flags = htons(ip_flags);
-        IP->checksum = 0;
-        IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
-        header.caplen = header.len = 14 + ntohs(IP->total_len);
-        eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment");
+      else {
+        IP->total_len = htons(payload_len + IP_HLEN(IP));
+        }
+      IP->flags = htons(ip_flags);
+      IP->checksum = 0;
+      IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
+      header.caplen = header.len = 14 + ntohs(IP->total_len);
+      eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment");
 #if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
-          { /* Debugging is easier if we read packets directly with pcap
-               (i.e. we can use Wireshark to verify packet contents)
-               we don't want to do this all the time for 2 reasons:
-                 1) sending through pcap involves kernel transitions and
-                 2) if the current system reflects sent packets, the 
-                    recieving side will receive and process 2 copies of 
-                    any packets sent this way. */
-          ETH_PACK pkt;
+      if (1) {
+        /* Debugging is easier if we read packets directly with pcap
+           (i.e. we can use Wireshark to verify packet contents)
+           we don't want to do this all the time for 2 reasons:
+             1) sending through pcap involves kernel transitions and
+             2) if the current system reflects sent packets, the 
+                recieving side will receive and process 2 copies of 
+                any packets sent this way. */
+        ETH_PACK pkt;
 
-          memset(&pkt, 0, sizeof(pkt));
-          memcpy(pkt.msg, ((u_char *)IP)-14, header.len);
-          pkt.len = header.len;
-          _eth_write(dev, &pkt, NULL);
-          }
+        memset(&pkt, 0, sizeof(pkt));
+        memcpy(pkt.msg, ((u_char *)IP)-14, header.len);
+        pkt.len = header.len;
+        _eth_write(dev, &pkt, NULL);
+        }
 #else
-        _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14);
+      _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14);
 #endif
-        payload_len -= (ntohs(IP->total_len) - IP_HLEN(IP));
-        frag_offset += (ntohs(IP->total_len) - IP_HLEN(IP))>>3;
-        if (payload_len > 0) {
-          /* Move the MAC and IP headers down to just prior to the next payload segment */
-          memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP));
-          IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - IP_HLEN(IP));
+      payload_len -= (ntohs(IP->total_len) - IP_HLEN(IP));
+      frag_offset += (ntohs(IP->total_len) - IP_HLEN(IP))>>3;
+      if (payload_len > 0) {
+        /* Move the MAC and IP headers down to just prior to the next payload segment */
+        memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP));
+        IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - IP_HLEN(IP));
         }
       }
-      break;
-   case IPPROTO_TCP:
-      ++dev->jumbo_fragmented;
-      eth_packet_trace_ex (dev, ((u_char *)IP)-14, len, "Fragmenting Jumbo TCP segment", 1, dev->dbit);
-      TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
-      orig_tcp_flags = ntohs(TCP->data_offset_and_flags);
-      /* When we're performing LSO (Large Send Offload), we're given a 
-         'template' header which may not include a value being populated 
-         in the IP header length (which is only 16 bits).
-         We process as payload everything which isn't known header data. */
-      payload_len = len - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
-      mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
-      while (payload_len > 0) {
-        if (payload_len > mtu_payload) {
-          TCP->data_offset_and_flags = htons(orig_tcp_flags&~(TCP_PSH_FLAG|TCP_FIN_FLAG|TCP_RST_FLAG));
-          IP->total_len = htons(mtu_payload + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
-        } else {
-          TCP->data_offset_and_flags = htons(orig_tcp_flags);
-          IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
+    break;
+  case IPPROTO_TCP:
+    ++dev->jumbo_fragmented;
+    eth_packet_trace_ex (dev, ((u_char *)IP)-14, len, "Fragmenting Jumbo TCP segment", 1, dev->dbit);
+    TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
+    orig_tcp_flags = ntohs(TCP->data_offset_and_flags);
+    /* When we're performing LSO (Large Send Offload), we're given a 
+       'template' header which may not include a value being populated 
+       in the IP header length (which is only 16 bits).
+       We process as payload everything which isn't known header data. */
+    payload_len = len - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
+    mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
+    while (payload_len > 0) {
+      if (payload_len > mtu_payload) {
+        TCP->data_offset_and_flags = htons(orig_tcp_flags&~(TCP_PSH_FLAG|TCP_FIN_FLAG|TCP_RST_FLAG));
+        IP->total_len = htons(mtu_payload + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
         }
-        IP->checksum = 0;
-        IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
-        TCP->checksum = 0;
-        TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP);
-        header.caplen = header.len = 14 + ntohs(IP->total_len);
-        eth_packet_trace_ex (dev, ((u_char *)IP)-14, header.len, "reading TCP segment", 1, dev->dbit);
+      else {
+        TCP->data_offset_and_flags = htons(orig_tcp_flags);
+        IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
+        }
+      IP->checksum = 0;
+      IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
+      TCP->checksum = 0;
+      TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP);
+      header.caplen = header.len = 14 + ntohs(IP->total_len);
+      eth_packet_trace_ex (dev, ((u_char *)IP)-14, header.len, "reading TCP segment", 1, dev->dbit);
 #if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
-          { /* Debugging is easier if we read packets directly with pcap
-               (i.e. we can use Wireshark to verify packet contents)
-               we don't want to do this all the time for 2 reasons:
-                 1) sending through pcap involves kernel transitions and
-                 2) if the current system reflects sent packets, the 
-                    recieving side will receive and process 2 copies of 
-                    any packets sent this way. */
-          ETH_PACK pkt;
+      if (1) {
+        /* Debugging is easier if we read packets directly with pcap
+           (i.e. we can use Wireshark to verify packet contents)
+           we don't want to do this all the time for 2 reasons:
+             1) sending through pcap involves kernel transitions and
+             2) if the current system reflects sent packets, the 
+                recieving side will receive and process 2 copies of 
+                any packets sent this way. */
+        ETH_PACK pkt;
 
-          memset(&pkt, 0, sizeof(pkt));
-          memcpy(pkt.msg, ((u_char *)IP)-14, header.len);
-          pkt.len = header.len;
-          _eth_write(dev, &pkt, NULL);
-          }
+        memset(&pkt, 0, sizeof(pkt));
+        memcpy(pkt.msg, ((u_char *)IP)-14, header.len);
+        pkt.len = header.len;
+        _eth_write(dev, &pkt, NULL);
+        }
 #else
-        _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14);
+      _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14);
 #endif
-        payload_len -= (ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)));
-        if (payload_len > 0) {
-          /* Move the MAC, IP and TCP headers down to just prior to the next payload segment */
-          memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
-          IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)));
-          TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
-          TCP->sequence_number = htonl(mtu_payload + ntohl(TCP->sequence_number));
+      payload_len -= (ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)));
+      if (payload_len > 0) {
+        /* Move the MAC, IP and TCP headers down to just prior to the next payload segment */
+        memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
+        IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)));
+        TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
+        TCP->sequence_number = htonl(mtu_payload + ntohl(TCP->sequence_number));
         }
       }
-      break;
+    break;
   }
 }
 
 static void
 _eth_fix_ip_xsum_offload(ETH_DEV* dev, u_char* msg, int len)
 {
-  unsigned short* proto = (unsigned short*) &msg[12];
-  struct IPHeader *IP;
-  struct TCPHeader *TCP;
-  struct UDPHeader *UDP;
-  struct ICMPHeader *ICMP;
-  uint16 orig_checksum;
+unsigned short* proto = (unsigned short*) &msg[12];
+struct IPHeader *IP;
+struct TCPHeader *TCP;
+struct UDPHeader *UDP;
+struct ICMPHeader *ICMP;
+uint16 orig_checksum;
 
-  /* Only need to process locally originated packets */
-  if ((!dev->have_host_nic_phy_addr) || (memcmp(msg+6, dev->host_nic_phy_hw_addr, 6)))
-    return;
-  /* Only interested in IP frames */
-  if (ntohs(*proto) != 0x0800)
-    return;
-  IP = (struct IPHeader *)&msg[14];
-  if (IP_VERSION(IP) != 4)
-    return; /* Only interested in IPv4 frames */
-  if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len))
-    return; /* Bogus header length */
-  orig_checksum = IP->checksum;
-  IP->checksum = 0;
-  IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
-  if (orig_checksum != IP->checksum)
-    eth_packet_trace (dev, msg, len, "reading IP header Checksum Fixed");
-  if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP))
-    return; /* Insufficient data to compute payload checksum */
-  switch (IP->proto) {
-   case IPPROTO_UDP:
-      UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP));
-      if (ntohs(UDP->length) > (len-IP_HLEN(IP)))
-        return; /* packet contained length exceeds packet size */
-      if (UDP->checksum == 0)
-        return; /* UDP Checksums are disabled */
-      orig_checksum = UDP->checksum;
-      UDP->checksum = 0;
-      UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP);
-      if (orig_checksum != UDP->checksum)
-        eth_packet_trace (dev, msg, len, "reading UDP header Checksum Fixed");
-      break;
-   case IPPROTO_TCP:
-      TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
-      orig_checksum = TCP->checksum;
-      TCP->checksum = 0;
-      TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP);
-      if (orig_checksum != TCP->checksum)
-        eth_packet_trace (dev, msg, len, "reading TCP header Checksum Fixed");
-      break;
-   case IPPROTO_ICMP:
-      ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP));
-      orig_checksum = ICMP->checksum;
-      ICMP->checksum = 0;
-      ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP));
-      if (orig_checksum != ICMP->checksum)
-        eth_packet_trace (dev, msg, len, "reading ICMP header Checksum Fixed");
-      break;
+/* Only need to process locally originated packets */
+if ((!dev->have_host_nic_phy_addr) || (memcmp(msg+6, dev->host_nic_phy_hw_addr, 6)))
+  return;
+/* Only interested in IP frames */
+if (ntohs(*proto) != 0x0800)
+  return;
+IP = (struct IPHeader *)&msg[14];
+if (IP_VERSION(IP) != 4)
+  return; /* Only interested in IPv4 frames */
+if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len))
+  return; /* Bogus header length */
+orig_checksum = IP->checksum;
+IP->checksum = 0;
+IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
+if (orig_checksum != IP->checksum)
+  eth_packet_trace (dev, msg, len, "reading IP header Checksum Fixed");
+if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP))
+  return; /* Insufficient data to compute payload checksum */
+switch (IP->proto) {
+  case IPPROTO_UDP:
+    UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP));
+    if (ntohs(UDP->length) > (len-IP_HLEN(IP)))
+      return; /* packet contained length exceeds packet size */
+    if (UDP->checksum == 0)
+      return; /* UDP Checksums are disabled */
+    orig_checksum = UDP->checksum;
+    UDP->checksum = 0;
+    UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP);
+    if (orig_checksum != UDP->checksum)
+      eth_packet_trace (dev, msg, len, "reading UDP header Checksum Fixed");
+    break;
+  case IPPROTO_TCP:
+    TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
+    orig_checksum = TCP->checksum;
+    TCP->checksum = 0;
+    TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP);
+    if (orig_checksum != TCP->checksum)
+      eth_packet_trace (dev, msg, len, "reading TCP header Checksum Fixed");
+    break;
+  case IPPROTO_ICMP:
+    ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP));
+    orig_checksum = ICMP->checksum;
+    ICMP->checksum = 0;
+    ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP));
+    if (orig_checksum != ICMP->checksum)
+      eth_packet_trace (dev, msg, len, "reading ICMP header Checksum Fixed");
+    break;
   }
 }
 
 static void
 _eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data)
 {
-  ETH_DEV*  dev = (ETH_DEV*) info;
+ETH_DEV*  dev = (ETH_DEV*) info;
+int to_me;
+int from_me = 0;
+int i;
+int bpf_used;
+
+switch (dev->eth_api) {
+  case ETH_API_PCAP:
 #ifdef USE_BPF
-  int to_me = 1;
-
-  /* AUTODIN II hash mode? */
-  if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast))
-    to_me = _eth_hash_lookup(dev->hash, data);
-#else /* !USE_BPF */
-  int to_me = 0;
-  int from_me = 0;
-  int i;
-
-  eth_packet_trace (dev, data, header->len, "received");
-f
-  for (i = 0; i < dev->addr_count; i++) {
-    if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1;
-    if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1;
-  }
-
-  /* all multicast mode? */
-  if (dev->all_multicast && (data[0] & 0x01)) to_me = 1;
-
-  /* promiscuous mode? */
-  if (dev->promiscuous) to_me = 1;
-
-  /* AUTODIN II hash mode? */
-  if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01))
-    to_me = _eth_hash_lookup(dev->hash, data);
+    bpf_used = 1;
+    to_me = 1;
+    /* AUTODIN II hash mode? */
+    if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast))
+      to_me = _eth_hash_lookup(dev->hash, data);
+    break;
 #endif /* USE_BPF */
+  case ETH_API_TAP:
+  case ETH_API_VDE:
+    bpf_used = 0;
+    to_me = 0;
+    eth_packet_trace (dev, data, header->len, "received");
 
-  /* detect reception of loopback packet to our physical address */
-  if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) {
+    for (i = 0; i < dev->addr_count; i++) {
+      if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1;
+      if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1;
+    }
+
+    /* all multicast mode? */
+    if (dev->all_multicast && (data[0] & 0x01)) to_me = 1;
+
+    /* promiscuous mode? */
+    if (dev->promiscuous) to_me = 1;
+
+    /* AUTODIN II hash mode? */
+    if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01))
+      to_me = _eth_hash_lookup(dev->hash, data);
+    break;
+  }
+
+/* detect reception of loopback packet to our physical address */
+if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) {
 #ifdef USE_READER_THREAD
-    pthread_mutex_lock (&dev->self_lock);
+  pthread_mutex_lock (&dev->self_lock);
 #endif
-    dev->loopback_self_rcvd_total++;
-        /* lower reflection count - if already zero, pass it on */
-    if (dev->loopback_self_sent > 0) {
-      eth_packet_trace (dev, data, header->len, "ignored");
-      dev->loopback_self_sent--;
-      to_me = 0;
-    } 
-#ifndef USE_BPF
-    else
+  dev->loopback_self_rcvd_total++;
+  /* lower reflection count - if already zero, pass it on */
+  if (dev->loopback_self_sent > 0) {
+    eth_packet_trace (dev, data, header->len, "ignored");
+    dev->loopback_self_sent--;
+    to_me = 0;
+    }
+  else
+    if (!bpf_used)
       from_me = 0;
-#endif
 #ifdef USE_READER_THREAD
-    pthread_mutex_unlock (&dev->self_lock);
+  pthread_mutex_unlock (&dev->self_lock);
 #endif
   }
 
-#ifdef USE_BPF
-  if (to_me) {
-#else /* !USE_BPF */
-  if (to_me && !from_me) {
-#endif
-    if (header->len > ETH_MIN_JUMBO_FRAME) {
-      if (header->len <= header->caplen) /* Whole Frame captured? */
-        _eth_fix_ip_jumbo_offload(dev, data, header->len);
-      else
-        ++dev->jumbo_truncated;
-      return;
+if (bpf_used ? to_me : (to_me && !from_me)) {
+  if (header->len > ETH_MIN_JUMBO_FRAME) {
+    if (header->len <= header->caplen) /* Whole Frame captured? */
+      _eth_fix_ip_jumbo_offload(dev, data, header->len);
+    else
+      ++dev->jumbo_truncated;
+    return;
     }
 #if defined (USE_READER_THREAD)
-    if (1) {
-      int crc_len = 0;
-      uint8 crc_data[4];
-      uint32 len = header->len;
-      u_char* moved_data = NULL;
+  if (1) {
+    int crc_len = 0;
+    uint8 crc_data[4];
+    uint32 len = header->len;
+    u_char* moved_data = NULL;
 
-      if (header->len < ETH_MIN_PACKET) {   /* Pad runt packets before CRC append */
-        moved_data = malloc(ETH_MIN_PACKET);
-        memcpy(moved_data, data, len);
-        memset(moved_data + len, 0, ETH_MIN_PACKET-len);
-        len = ETH_MIN_PACKET;
-        data = moved_data;
+    if (header->len < ETH_MIN_PACKET) {   /* Pad runt packets before CRC append */
+      moved_data = malloc(ETH_MIN_PACKET);
+      memcpy(moved_data, data, len);
+      memset(moved_data + len, 0, ETH_MIN_PACKET-len);
+      len = ETH_MIN_PACKET;
+      data = moved_data;
       }
 
-      /* If necessary, fix IP header checksums for packets originated locally */
-      /* but were presumed to be traversing a NIC which was going to handle that task */
-      /* This must be done before any needed CRC calculation */
-      _eth_fix_ip_xsum_offload(dev, (u_char*)data, len);
-    
-      if (dev->need_crc)
-        crc_len = eth_get_packet_crc32_data(data, len, crc_data);
-
-      eth_packet_trace (dev, data, len, "rcvqd");
-
-      pthread_mutex_lock (&dev->lock);
-      ethq_insert_data(&dev->read_queue, 2, data, 0, len, crc_len, crc_data, 0);
-      pthread_mutex_unlock (&dev->lock);
-      free(moved_data);
-    }
-#else
-    /* set data in passed read packet */
-    dev->read_packet->len = header->len;
-    memcpy(dev->read_packet->msg, data, header->len);
-    /* Handle runt case and pad with zeros.  */
-    /* The real NIC won't hand us runts from the wire, BUT we may be getting */
-    /* some packets looped back before they actually traverse the wire */
-    /* (by an internal bridge device for instance) */
-    if (header->len < ETH_MIN_PACKET) {
-      memset(&dev->read_packet->msg[header->len], 0, ETH_MIN_PACKET-header->len);
-      dev->read_packet->len = ETH_MIN_PACKET;
-    }
-    /* If necessary, fix IP header checksums for packets originated by the local host */
+    /* If necessary, fix IP header checksums for packets originated locally */
     /* but were presumed to be traversing a NIC which was going to handle that task */
     /* This must be done before any needed CRC calculation */
-    _eth_fix_ip_xsum_offload(dev, dev->read_packet->msg, dev->read_packet->len);
+    _eth_fix_ip_xsum_offload(dev, (u_char*)data, len);
+    
     if (dev->need_crc)
-      dev->read_packet->crc_len = eth_add_packet_crc32(dev->read_packet->msg, dev->read_packet->len);
-    else
-      dev->read_packet->crc_len = 0;
+      crc_len = eth_get_packet_crc32_data(data, len, crc_data);
 
-    eth_packet_trace (dev, dev->read_packet->msg, dev->read_packet->len, "reading");
+    eth_packet_trace (dev, data, len, "rcvqd");
 
-    /* call optional read callback function */
-    if (dev->read_callback)
-      (dev->read_callback)(0);
+    pthread_mutex_lock (&dev->lock);
+    ethq_insert_data(&dev->read_queue, 2, data, 0, len, crc_len, crc_data, 0);
+    pthread_mutex_unlock (&dev->lock);
+    free(moved_data);
+    }
+#else /* !USE_READER_THREAD */
+  /* set data in passed read packet */
+  dev->read_packet->len = header->len;
+  memcpy(dev->read_packet->msg, data, header->len);
+  /* Handle runt case and pad with zeros.  */
+  /* The real NIC won't hand us runts from the wire, BUT we may be getting */
+  /* some packets looped back before they actually traverse the wire */
+  /* (by an internal bridge device for instance) */
+  if (header->len < ETH_MIN_PACKET) {
+    memset(&dev->read_packet->msg[header->len], 0, ETH_MIN_PACKET-header->len);
+    dev->read_packet->len = ETH_MIN_PACKET;
+    }
+  /* If necessary, fix IP header checksums for packets originated by the local host */
+  /* but were presumed to be traversing a NIC which was going to handle that task */
+  /* This must be done before any needed CRC calculation */
+  _eth_fix_ip_xsum_offload(dev, dev->read_packet->msg, dev->read_packet->len);
+  if (dev->need_crc)
+    dev->read_packet->crc_len = eth_add_packet_crc32(dev->read_packet->msg, dev->read_packet->len);
+  else
+    dev->read_packet->crc_len = 0;
+
+  eth_packet_trace (dev, dev->read_packet->msg, dev->read_packet->len, "reading");
+
+  /* call optional read callback function */
+  if (dev->read_callback)
+    (dev->read_callback)(0);
 #endif
   }
 }
 
 int eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
 {
-  int status;
+int status;
 
-  /* make sure device exists */
+/* make sure device exists */
 
-  if (!dev) return 0;
+if (!dev) return 0;
 
-  /* make sure packet exists */
-  if (!packet) return 0;
+/* make sure packet exists */
+if (!packet) return 0;
 
-  packet->len = 0;
+packet->len = 0;
 #if !defined (USE_READER_THREAD)
-  /* set read packet */
-  dev->read_packet = packet;
+/* set read packet */
+dev->read_packet = packet;
 
-  /* set optional callback routine */
-  dev->read_callback = routine;
+/* set optional callback routine */
+dev->read_callback = routine;
 
-  /* dispatch read request to either receive a filtered packet or timeout */
-  do {
-    if (dev->pcap_mode)
+/* dispatch read request to either receive a filtered packet or timeout */
+do {
+  switch (dev->eth_api) {
+    case ETH_API_PCAP:
       status = pcap_dispatch((pcap_t*)dev->handle, 1, &_eth_callback, (u_char*)dev);
+      break;
 #ifdef USE_TAP_NETWORK
-    else {
-      struct pcap_pkthdr header;
-      int len;
-      u_char buf[ETH_MAX_JUMBO_FRAME];
+    case ETH_API_TAP:
+      if (1) {
+        struct pcap_pkthdr header;
+        int len;
+        u_char buf[ETH_MAX_JUMBO_FRAME];
 
-      memset(&header, 0, sizeof(header));
-      len = read(dev->fd_handle, buf, sizeof(buf));
-      if (len > 0) {
-        status = 1;
-        header.caplen = header.len = len;
-        _eth_callback((u_char *)dev, &header, buf);
-      } else {
-        status = 0;
-      }
-    }
+        memset(&header, 0, sizeof(header));
+        len = read(dev->fd_handle, buf, sizeof(buf));
+        if (len > 0) {
+          status = 1;
+          header.caplen = header.len = len;
+          _eth_callback((u_char *)dev, &header, buf);
+          }
+        else
+          status = 0;
+        }
+      break;
 #endif /* USE_TAP_NETWORK */
+#ifdef USE_VDE_NETWORK
+    case ETH_API_VDE:
+      if (1) {
+        struct pcap_pkthdr header;
+        int len;
+        u_char buf[ETH_MAX_JUMBO_FRAME];
+
+        memset(&header, 0, sizeof(header));
+        len = vde_recv((VDECONN*)dev->handle, buf, sizeof(buf), 0);
+        if (len > 0) {
+          status = 1;
+          header.caplen = header.len = len;
+          _eth_callback((u_char *)dev, &header, buf);
+          }
+        else
+          status = 0;
+        }
+      break;
+#endif /* USE_VDE_NETWORK */
+    }
   } while ((status) && (0 == packet->len));
 
 #else /* USE_READER_THREAD */
 
-    status = 0;
-    pthread_mutex_lock (&dev->lock);
-    if (dev->read_queue.count > 0) {
-      ETH_ITEM* item = &dev->read_queue.item[dev->read_queue.head];
-      packet->len = item->packet.len;
-      packet->crc_len = item->packet.crc_len;
-      memcpy(packet->msg, item->packet.msg, ((packet->len > packet->crc_len) ? packet->len : packet->crc_len));
-      status = 1;
-      ethq_remove(&dev->read_queue);
-    }
-    pthread_mutex_unlock (&dev->lock);  
-    if ((status) && (routine))
-      routine(0);
+  status = 0;
+  pthread_mutex_lock (&dev->lock);
+  if (dev->read_queue.count > 0) {
+    ETH_ITEM* item = &dev->read_queue.item[dev->read_queue.head];
+    packet->len = item->packet.len;
+    packet->crc_len = item->packet.crc_len;
+    memcpy(packet->msg, item->packet.msg, ((packet->len > packet->crc_len) ? packet->len : packet->crc_len));
+    status = 1;
+    ethq_remove(&dev->read_queue);
+  }
+  pthread_mutex_unlock (&dev->lock);  
+  if ((status) && (routine))
+    routine(0);
 #endif
 
-  return status;
+return status;
 }
 
 t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
@@ -2351,181 +2493,182 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
                        ETH_BOOL all_multicast, ETH_BOOL promiscuous, 
                        ETH_MULTIHASH* const hash)
 {
-  int i;
-  bpf_u_int32  bpf_subnet, bpf_netmask;
-  char buf[114+66*ETH_FILTER_MAX];
-  char errbuf[PCAP_ERRBUF_SIZE];
-  char mac[20];
-  char* buf2;
-  t_stat status;
+int i;
+bpf_u_int32  bpf_subnet, bpf_netmask;
+char buf[114+66*ETH_FILTER_MAX];
+char errbuf[PCAP_ERRBUF_SIZE];
+char mac[20];
+char* buf2;
+t_stat status;
 #ifdef USE_BPF
-  struct bpf_program bpf;
-  char* msg;
+struct bpf_program bpf;
+char* msg;
 #endif
 
-  /* make sure device exists */
-  if (!dev) return SCPE_UNATT;
+/* make sure device exists */
+if (!dev) return SCPE_UNATT;
 
-  /* filter count OK? */
-  if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX))
-    return SCPE_ARG;
-  else
-    if (!addresses) return SCPE_ARG;
+/* filter count OK? */
+if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX))
+  return SCPE_ARG;
+else
+  if (!addresses) return SCPE_ARG;
 
-  /* test reflections.  This is done early in this routine since eth_reflect */
-  /* calls eth_filter recursively and thus changes the state of the device. */
-  if (dev->reflections == -1)
-    status = eth_reflect(dev);
+/* test reflections.  This is done early in this routine since eth_reflect */
+/* calls eth_filter recursively and thus changes the state of the device. */
+if (dev->reflections == -1)
+  status = eth_reflect(dev);
 
-  /* set new filter addresses */
-  for (i = 0; i < addr_count; i++)
-    memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC));
-  dev->addr_count = addr_count;
+/* set new filter addresses */
+for (i = 0; i < addr_count; i++)
+  memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC));
+dev->addr_count = addr_count;
 
-  /* store other flags */
-  dev->all_multicast = all_multicast;
-  dev->promiscuous   = promiscuous;
+/* store other flags */
+dev->all_multicast = all_multicast;
+dev->promiscuous   = promiscuous;
 
-  /* store multicast hash data */
-  dev->hash_filter = (hash != NULL);
-  if (hash) {
-    memcpy(dev->hash, hash, sizeof(*hash));
-    sim_debug(dev->dbit, dev->dptr, "Multicast Hash: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
-                                    dev->hash[0], dev->hash[1], dev->hash[2], dev->hash[3], 
-                                    dev->hash[4], dev->hash[5], dev->hash[6], dev->hash[7]);
+/* store multicast hash data */
+dev->hash_filter = (hash != NULL);
+if (hash) {
+  memcpy(dev->hash, hash, sizeof(*hash));
+  sim_debug(dev->dbit, dev->dptr, "Multicast Hash: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
+                                  dev->hash[0], dev->hash[1], dev->hash[2], dev->hash[3], 
+                                  dev->hash[4], dev->hash[5], dev->hash[6], dev->hash[7]);
   }
 
-  /* print out filter information if debugging */
-  if (dev->dptr->dctrl & dev->dbit) {
-    sim_debug(dev->dbit, dev->dptr, "Filter Set\n");
-    for (i = 0; i < addr_count; i++) {
-      char mac[20];
-      eth_mac_fmt(&dev->filter_address[i], mac);
-      sim_debug(dev->dbit, dev->dptr, "  Addr[%d]: %s\n", i, mac);
+/* print out filter information if debugging */
+if (dev->dptr->dctrl & dev->dbit) {
+  sim_debug(dev->dbit, dev->dptr, "Filter Set\n");
+  for (i = 0; i < addr_count; i++) {
+    char mac[20];
+    eth_mac_fmt(&dev->filter_address[i], mac);
+    sim_debug(dev->dbit, dev->dptr, "  Addr[%d]: %s\n", i, mac);
     }
-    if (dev->all_multicast)
-      sim_debug(dev->dbit, dev->dptr, "All Multicast\n");
-    if (dev->promiscuous)
-      sim_debug(dev->dbit, dev->dptr, "Promiscuous\n");
+  if (dev->all_multicast)
+    sim_debug(dev->dbit, dev->dptr, "All Multicast\n");
+  if (dev->promiscuous)
+    sim_debug(dev->dbit, dev->dptr, "Promiscuous\n");
   }
 
-  /* setup BPF filters and other fields to minimize packet delivery */
-  strcpy(buf, "");
+/* setup BPF filters and other fields to minimize packet delivery */
+strcpy(buf, "");
 
-  /* construct destination filters - since the real ethernet interface was set
-     into promiscuous mode by eth_open(), we need to filter out the packets that
-     our simulated interface doesn't want. */
-  if (!dev->promiscuous) {
-    for (i = 0; i < addr_count; i++) {
-      eth_mac_fmt(&dev->filter_address[i], mac);
-      if (!strstr(buf, mac))    /* eliminate duplicates */
-        sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "((", mac);
+/* construct destination filters - since the real ethernet interface was set
+   into promiscuous mode by eth_open(), we need to filter out the packets that
+   our simulated interface doesn't want. */
+if (!dev->promiscuous) {
+  for (i = 0; i < addr_count; i++) {
+    eth_mac_fmt(&dev->filter_address[i], mac);
+    if (!strstr(buf, mac))    /* eliminate duplicates */
+      sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "((", mac);
     }
-    if (dev->all_multicast || dev->hash_filter)
-      sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : "((");
-    if (strlen(buf) > 0)
-      sprintf(&buf[strlen(buf)], ")");
-  }
-
-  /* construct source filters - this prevents packets from being reflected back 
-     by systems where WinPcap and libpcap cause packet reflections. Note that
-     some systems do not reflect packets at all. This *assumes* that the 
-     simulated NIC will not send out packets with multicast source fields. */
-  if ((addr_count > 0) && (dev->reflections > 0)) {
-    if (strlen(buf) > 0)
-      sprintf(&buf[strlen(buf)], " and ");
-    sprintf (&buf[strlen(buf)], "not (");
-    buf2 = &buf[strlen(buf)];
-    for (i = 0; i < addr_count; i++) {
-      if (dev->filter_address[i][0] & 0x01) continue; /* skip multicast addresses */
-      eth_mac_fmt(&dev->filter_address[i], mac);
-      if (!strstr(buf2, mac))   /* eliminate duplicates */
-        sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac);
-    }
-    sprintf (&buf[strlen(buf)], ")");
-  }
+  if (dev->all_multicast || dev->hash_filter)
+    sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : "((");
   if (strlen(buf) > 0)
     sprintf(&buf[strlen(buf)], ")");
-  /* When changing the Physical Address on a LAN interface, VMS sends out a 
-     loopback packet with the source and destination addresses set to the same 
-     value as the Physical Address which is being setup.  This packet is
-     designed to find and help diagnose MAC address conflicts (which also 
-     include DECnet address conflicts). Normally, this packet would not be 
-     seen by the sender, only by the other machine that has the same Physical 
-     Address (or possibly DECnet address). If the ethernet subsystem is 
-     reflecting packets, the network startup will fail to start if it sees the 
-     reflected packet, since it thinks another system is using this Physical 
-     Address (or DECnet address). We have to let these packets through, so 
-     that if another machine has the same Physical Address (or DECnet address)
-     that we can detect it. Both eth_write() and _eth_callback() help by 
-     checking the reflection count - eth_write() adds the reflection count to
-     dev->loopback_self_sent, and _eth_callback() check the value - if the
-     dev->loopback_self_sent count is zero, then the packet has come from 
-     another machine with the same address, and needs to be passed on to the 
-     simulated machine. */
-  memset(dev->physical_addr, 0, sizeof(ETH_MAC));
-  dev->loopback_self_sent = 0;
-  /* check for physical address in filters */
-  if ((addr_count) && (dev->reflections > 0)) {
-    for (i = 0; i < addr_count; i++) {
-      if (dev->filter_address[i][0]&1)
-        continue;  /* skip all multicast addresses */
-      eth_mac_fmt(&dev->filter_address[i], mac);
-      if (strcmp(mac, "00:00:00:00:00:00") != 0) {
-        memcpy(dev->physical_addr, &dev->filter_address[i], sizeof(ETH_MAC));
-        /* let packets through where dst and src are the same as our physical address */
-        sprintf (&buf[strlen(buf)], " or ((ether dst %s) and (ether src %s))", mac, mac);
-        break;
+  }
+
+/* construct source filters - this prevents packets from being reflected back 
+   by systems where WinPcap and libpcap cause packet reflections. Note that
+   some systems do not reflect packets at all. This *assumes* that the 
+   simulated NIC will not send out packets with multicast source fields. */
+if ((addr_count > 0) && (dev->reflections > 0)) {
+  if (strlen(buf) > 0)
+    sprintf(&buf[strlen(buf)], " and ");
+  sprintf (&buf[strlen(buf)], "not (");
+  buf2 = &buf[strlen(buf)];
+  for (i = 0; i < addr_count; i++) {
+    if (dev->filter_address[i][0] & 0x01) continue; /* skip multicast addresses */
+    eth_mac_fmt(&dev->filter_address[i], mac);
+    if (!strstr(buf2, mac))   /* eliminate duplicates */
+      sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac);
+    }
+  sprintf (&buf[strlen(buf)], ")");
+  }
+if (strlen(buf) > 0)
+  sprintf(&buf[strlen(buf)], ")");
+/* When changing the Physical Address on a LAN interface, VMS sends out a 
+   loopback packet with the source and destination addresses set to the same 
+   value as the Physical Address which is being setup.  This packet is
+   designed to find and help diagnose MAC address conflicts (which also 
+   include DECnet address conflicts). Normally, this packet would not be 
+   seen by the sender, only by the other machine that has the same Physical 
+   Address (or possibly DECnet address). If the ethernet subsystem is 
+   reflecting packets, the network startup will fail to start if it sees the 
+   reflected packet, since it thinks another system is using this Physical 
+   Address (or DECnet address). We have to let these packets through, so 
+   that if another machine has the same Physical Address (or DECnet address)
+   that we can detect it. Both eth_write() and _eth_callback() help by 
+   checking the reflection count - eth_write() adds the reflection count to
+   dev->loopback_self_sent, and _eth_callback() check the value - if the
+   dev->loopback_self_sent count is zero, then the packet has come from 
+   another machine with the same address, and needs to be passed on to the 
+   simulated machine. */
+memset(dev->physical_addr, 0, sizeof(ETH_MAC));
+dev->loopback_self_sent = 0;
+/* check for physical address in filters */
+if ((addr_count) && (dev->reflections > 0)) {
+  for (i = 0; i < addr_count; i++) {
+    if (dev->filter_address[i][0]&1)
+      continue;  /* skip all multicast addresses */
+    eth_mac_fmt(&dev->filter_address[i], mac);
+    if (strcmp(mac, "00:00:00:00:00:00") != 0) {
+      memcpy(dev->physical_addr, &dev->filter_address[i], sizeof(ETH_MAC));
+      /* let packets through where dst and src are the same as our physical address */
+      sprintf (&buf[strlen(buf)], " or ((ether dst %s) and (ether src %s))", mac, mac);
+      break;
       }
     }
   }
-  if ((0 == strlen(buf)) && (!dev->promiscuous)) /* Empty filter means match nothing */
-      strcpy(buf, "ether host fe:ff:ff:ff:ff:ff"); /* this should be a good match nothing filter */
-  sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf);
+if ((0 == strlen(buf)) && (!dev->promiscuous)) /* Empty filter means match nothing */
+  strcpy(buf, "ether host fe:ff:ff:ff:ff:ff"); /* this should be a good match nothing filter */
+sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf);
 
-  /* get netmask, which is required for compiling */
-  if (dev->pcap_mode && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0)) {
-      bpf_netmask = 0;
-  }
+/* get netmask, which is required for compiling */
+if ((dev->eth_api == ETH_API_PCAP) && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0))
+  bpf_netmask = 0;
 
 #ifdef USE_BPF
-  if (dev->pcap_mode) {
-    /* compile filter string */
-    if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) {
+if (dev->eth_api == ETH_API_PCAP) {
+  /* compile filter string */
+  if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) {
+    sprintf(errbuf, "%s", pcap_geterr(dev->handle));
+    msg = "Eth: pcap_compile error: %s\r\n";
+    printf(msg, errbuf);
+    if (sim_log) fprintf (sim_log, msg, errbuf);
+    sim_debug(dev->dbit, dev->dptr, "Eth: pcap_compile error: %s\n", errbuf);
+    /* show erroneous BPF string */
+    msg = "Eth: BPF string is: |%s|\r\n";
+    printf (msg, buf);
+    if (sim_log) fprintf (sim_log, msg, buf);
+    }
+  else {
+    /* apply compiled filter string */
+    if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) {
       sprintf(errbuf, "%s", pcap_geterr(dev->handle));
-      msg = "Eth: pcap_compile error: %s\r\n";
+      msg = "Eth: pcap_setfilter error: %s\r\n";
       printf(msg, errbuf);
       if (sim_log) fprintf (sim_log, msg, errbuf);
-      sim_debug(dev->dbit, dev->dptr, "Eth: pcap_compile error: %s\n", errbuf);
-      /* show erroneous BPF string */
-      msg = "Eth: BPF string is: |%s|\r\n";
-      printf (msg, buf);
-      if (sim_log) fprintf (sim_log, msg, buf);
-    } else {
-      /* apply compiled filter string */
-      if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) {
-        sprintf(errbuf, "%s", pcap_geterr(dev->handle));
-        msg = "Eth: pcap_setfilter error: %s\r\n";
-        printf(msg, errbuf);
-        if (sim_log) fprintf (sim_log, msg, errbuf);
-        sim_debug(dev->dbit, dev->dptr, "Eth: pcap_setfilter error: %s\n", errbuf);
-      } else {
+      sim_debug(dev->dbit, dev->dptr, "Eth: pcap_setfilter error: %s\n", errbuf);
+      }
+    else {
 #ifdef USE_SETNONBLOCK
-        /* set file non-blocking */
-        status = pcap_setnonblock (dev->handle, 1, errbuf);
+      /* set file non-blocking */
+      status = pcap_setnonblock (dev->handle, 1, errbuf);
 #endif /* USE_SETNONBLOCK */
       }
-      pcap_freecode(&bpf);
+    pcap_freecode(&bpf);
     }
 #ifdef USE_READER_THREAD
-    pthread_mutex_lock (&dev->lock);
-    ethq_clear (&dev->read_queue); /* Empty FIFO Queue when filter list changes */
-    pthread_mutex_unlock (&dev->lock);
+  pthread_mutex_lock (&dev->lock);
+  ethq_clear (&dev->read_queue); /* Empty FIFO Queue when filter list changes */
+  pthread_mutex_unlock (&dev->lock);
 #endif
   }
 #endif /* USE_BPF */
 
-  return SCPE_OK;
+return SCPE_OK;
 }
 
 /*
@@ -2549,149 +2692,157 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
 */
 int eth_host_devices(int used, int max, ETH_LIST* list)
 {
-  pcap_t* conn;
-  int i, j, datalink;
-  char errbuf[PCAP_ERRBUF_SIZE];
+pcap_t* conn;
+int i, j, datalink;
+char errbuf[PCAP_ERRBUF_SIZE];
 
-  for (i=0; i<used; ++i) {
-    /* Cull any non-ethernet interface types */
-    conn = pcap_open_live(list[i].name, ETH_MAX_PACKET, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
-    if (NULL != conn) datalink = pcap_datalink(conn), pcap_close(conn);
-    if ((NULL == conn) || (datalink != DLT_EN10MB)) {
-      for (j=i; j<used-1; ++j)
-        list[j] = list[j+1];
-      --used;
-      --i;
+for (i=0; i<used; ++i) {
+  /* Cull any non-ethernet interface types */
+  conn = pcap_open_live(list[i].name, ETH_MAX_PACKET, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
+  if (NULL != conn) datalink = pcap_datalink(conn), pcap_close(conn);
+  if ((NULL == conn) || (datalink != DLT_EN10MB)) {
+    for (j=i; j<used-1; ++j)
+      list[j] = list[j+1];
+    --used;
+    --i;
     }
   } /* for */
 
 #if defined(_WIN32)
-  /* replace device description with user-defined adapter name (if defined) */
-  for (i=0; i<used; i++) {
-    char regkey[2048];
-    char regval[2048];
-    LONG status;
-    DWORD reglen, regtype;
-    HKEY reghnd;
+/* replace device description with user-defined adapter name (if defined) */
+for (i=0; i<used; i++) {
+  char regkey[2048];
+  char regval[2048];
+  LONG status;
+  DWORD reglen, regtype;
+  HKEY reghnd;
 
-    /* These registry keys don't seem to exist for all devices, so we simply ignore errors. */
-    /* Windows XP x64 registry uses wide characters by default,
-       so we force use of narrow characters by using the 'A'(ANSI) version of RegOpenKeyEx.
-       This could cause some problems later, if this code is internationalized. Ideally,
-       the pcap lookup will return wide characters, and we should use them to build a wide
-       registry key, rather than hardcoding the string as we do here. */
-    if(list[i].name[strlen( "\\Device\\NPF_" )] == '{') {
-      sprintf( regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
-               "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%hs\\Connection", list[i].name+
-               strlen( "\\Device\\NPF_" ) );
-      if((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, &reghnd)) != ERROR_SUCCESS) {
-        continue;
-      }
-      reglen = sizeof(regval);
+  /* These registry keys don't seem to exist for all devices, so we simply ignore errors. */
+  /* Windows XP x64 registry uses wide characters by default,
+     so we force use of narrow characters by using the 'A'(ANSI) version of RegOpenKeyEx.
+     This could cause some problems later, if this code is internationalized. Ideally,
+     the pcap lookup will return wide characters, and we should use them to build a wide
+     registry key, rather than hardcoding the string as we do here. */
+  if (list[i].name[strlen( "\\Device\\NPF_" )] == '{') {
+    sprintf( regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
+             "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%hs\\Connection", list[i].name+
+             strlen( "\\Device\\NPF_" ) );
+    if ((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, &reghnd)) != ERROR_SUCCESS)
+      continue;
+    reglen = sizeof(regval);
 
-      /* look for user-defined adapter name, bail if not found */  
-      /* same comment about Windows XP x64 (above) using RegQueryValueEx */
-      if((status = RegQueryValueExA (reghnd, "Name", NULL, &regtype, regval, &reglen)) != ERROR_SUCCESS) {
-        RegCloseKey (reghnd);
-        continue;
+    /* look for user-defined adapter name, bail if not found */  
+    /* same comment about Windows XP x64 (above) using RegQueryValueEx */
+    if ((status = RegQueryValueExA (reghnd, "Name", NULL, &regtype, regval, &reglen)) != ERROR_SUCCESS) {
+      RegCloseKey (reghnd);
+      continue;
       }
-      /* make sure value is the right type, bail if not acceptable */
-      if((regtype != REG_SZ) || (reglen > sizeof(regval))) {
-        RegCloseKey (reghnd);
-        continue;
+    /* make sure value is the right type, bail if not acceptable */
+    if ((regtype != REG_SZ) || (reglen > sizeof(regval))) {
+      RegCloseKey (reghnd);
+      continue;
       }
-      /* registry value seems OK, finish up and replace description */
-      RegCloseKey (reghnd );
-      sprintf (list[i].desc, "%s", regval);
+    /* registry value seems OK, finish up and replace description */
+    RegCloseKey (reghnd );
+    sprintf (list[i].desc, "%s", regval);
     }
   } /* for */
 #endif
 
 #ifdef USE_TAP_NETWORK
-  if (used < max) {
-    list[used].num = used;
+if (used < max) {
+  list[used].num = used;
 #if defined(__OpenBSD__)
-    sprintf(list[used].name, "%s", "tap:tunN");
+  sprintf(list[used].name, "%s", "tap:tunN");
 #else
-    sprintf(list[used].name, "%s", "tap:tapN");
+  sprintf(list[used].name, "%s", "tap:tapN");
 #endif
-    sprintf(list[used].desc, "%s", "Integrated Tun/Tap support");
-    ++used;
+  sprintf(list[used].desc, "%s", "Integrated Tun/Tap support");
+  ++used;
+  }
+#endif
+#ifdef USE_VDE_NETWORK
+if (used < max) {
+  list[used].num = used;
+  sprintf(list[used].name, "%s", "vde:device");
+  sprintf(list[used].desc, "%s", "Integrated VDE support");
+  ++used;
   }
 #endif
 
-  return used;
+return used;
 }
 
 int eth_devices(int max, ETH_LIST* list)
 {
-  int i = 0;
+int i = 0;
 #ifndef DONT_USE_PCAP_FINDALLDEVS
-  pcap_if_t* alldevs;
-  pcap_if_t* dev;
-  char errbuf[PCAP_ERRBUF_SIZE];
+pcap_if_t* alldevs;
+pcap_if_t* dev;
+char errbuf[PCAP_ERRBUF_SIZE];
 
-  /* retrieve the device list */
-  if (pcap_findalldevs(&alldevs, errbuf) == -1) {
-    char* msg = "Eth: error in pcap_findalldevs: %s\r\n";
-    printf (msg, errbuf);
-    if (sim_log) fprintf (sim_log, msg, errbuf);
-  } else {
-    /* copy device list into the passed structure */
-    for (i=0, dev=alldevs; dev; dev=dev->next) {
-      if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue;
-      list[i].num = i;
-      sprintf(list[i].name, "%s", dev->name);
-      if (dev->description)
-        sprintf(list[i].desc, "%s", dev->description);
-      else
-        sprintf(list[i].desc, "%s", "No description available");
-      if (i++ >= max) break;
+/* retrieve the device list */
+if (pcap_findalldevs(&alldevs, errbuf) == -1) {
+  char* msg = "Eth: error in pcap_findalldevs: %s\r\n";
+  printf (msg, errbuf);
+  if (sim_log) fprintf (sim_log, msg, errbuf);
+  }
+else {
+  /* copy device list into the passed structure */
+  for (i=0, dev=alldevs; dev; dev=dev->next) {
+    if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue;
+    list[i].num = i;
+    sprintf(list[i].name, "%s", dev->name);
+    if (dev->description)
+      sprintf(list[i].desc, "%s", dev->description);
+    else
+      sprintf(list[i].desc, "%s", "No description available");
+    if (i++ >= max) break;
     }
 
-    /* free device list */
-    pcap_freealldevs(alldevs);
+  /* free device list */
+  pcap_freealldevs(alldevs);
   }
 #endif
 
-  /* Add any host specific devices and/or validate those already found */
-  i = eth_host_devices(i, max, list);
+/* Add any host specific devices and/or validate those already found */
+i = eth_host_devices(i, max, list);
 
-  /* return device count */
-  return i;
+/* return device count */
+return i;
 }
 
 void eth_show_dev (FILE *st, ETH_DEV* dev)
 {
-  fprintf(st, "Ethernet Device:\n");
-  if (!dev) {
-    fprintf(st, "-- Not Attached\n");
-    return;
+fprintf(st, "Ethernet Device:\n");
+if (!dev) {
+  fprintf(st, "-- Not Attached\n");
+  return;
   }
-  fprintf(st, "  Name:                  %s\n", dev->name);
-  fprintf(st, "  Reflections:           %d\n", dev->reflections);
-  fprintf(st, "  Self Loopbacks Sent:   %d\n", dev->loopback_self_sent_total);
-  fprintf(st, "  Self Loopbacks Rcvd:   %d\n", dev->loopback_self_rcvd_total);
-  if (dev->have_host_nic_phy_addr) {
-    char hw_mac[20];
+fprintf(st, "  Name:                  %s\n", dev->name);
+fprintf(st, "  Reflections:           %d\n", dev->reflections);
+fprintf(st, "  Self Loopbacks Sent:   %d\n", dev->loopback_self_sent_total);
+fprintf(st, "  Self Loopbacks Rcvd:   %d\n", dev->loopback_self_rcvd_total);
+if (dev->have_host_nic_phy_addr) {
+  char hw_mac[20];
 
-    eth_mac_fmt(&dev->host_nic_phy_hw_addr, hw_mac);
-    fprintf(st, "  Host NIC Address:      %s\n", hw_mac);
+  eth_mac_fmt(&dev->host_nic_phy_hw_addr, hw_mac);
+  fprintf(st, "  Host NIC Address:      %s\n", hw_mac);
   }
-  if (dev->jumbo_dropped)
-    fprintf(st, "  Jumbo Dropped:         %d\n", dev->jumbo_dropped);
-  if (dev->jumbo_fragmented)
-    fprintf(st, "  Jumbo Fragmented:      %d\n", dev->jumbo_fragmented);
-  if (dev->jumbo_truncated)
-    fprintf(st, "  Jumbo Truncated:       %d\n", dev->jumbo_truncated);
+if (dev->jumbo_dropped)
+  fprintf(st, "  Jumbo Dropped:         %d\n", dev->jumbo_dropped);
+if (dev->jumbo_fragmented)
+  fprintf(st, "  Jumbo Fragmented:      %d\n", dev->jumbo_fragmented);
+if (dev->jumbo_truncated)
+  fprintf(st, "  Jumbo Truncated:       %d\n", dev->jumbo_truncated);
 #if defined(USE_READER_THREAD)
-  fprintf(st, "  Asynch Interrupts:       %s\n", dev->asynch_io?"Enabled":"Disabled");
-  if (dev->asynch_io)
-    fprintf(st, "  Interrupt Latency:       %d uSec\n", dev->asynch_io_latency);
-  fprintf(st, "  Read Queue: Count:       %d\n", dev->read_queue.count);
-  fprintf(st, "  Read Queue: High:        %d\n", dev->read_queue.high);
-  fprintf(st, "  Read Queue: Loss:        %d\n", dev->read_queue.loss);
-  fprintf(st, "  Peak Write Queue Size:   %d\n", dev->write_queue_peak);
+fprintf(st, "  Asynch Interrupts:       %s\n", dev->asynch_io?"Enabled":"Disabled");
+if (dev->asynch_io)
+  fprintf(st, "  Interrupt Latency:       %d uSec\n", dev->asynch_io_latency);
+fprintf(st, "  Read Queue: Count:       %d\n", dev->read_queue.count);
+fprintf(st, "  Read Queue: High:        %d\n", dev->read_queue.high);
+fprintf(st, "  Read Queue: Loss:        %d\n", dev->read_queue.loss);
+fprintf(st, "  Peak Write Queue Size:   %d\n", dev->write_queue_peak);
 #endif
 }
 #endif /* USE_NETWORK */
diff --git a/sim_ether.h b/sim_ether.h
index de155548..1478c40c 100644
--- a/sim_ether.h
+++ b/sim_ether.h
@@ -28,6 +28,7 @@
 
   Modification history:
 
+  30-Oct-11  MP   Added support for vde (Virtual Distributed Ethernet) networking
   18-Apr-11  MP   Fixed race condition with self loopback packets in 
                   multithreaded environments
   09-Dec-10  MP   Added support to determine if network address conflicts exist
@@ -89,13 +90,13 @@
 #if defined (USE_READER_THREAD)
 #if defined (USE_SETNONBLOCK)
 #undef USE_SETNONBLOCK
-#endif
+#endif /* USE_SETNONBLOCK */
 #undef PCAP_READ_TIMEOUT
 #define PCAP_READ_TIMEOUT 15
-#if !defined (xBSD) && !defined(_WIN32) && !defined(VMS)
-#define MUST_DO_SELECT
-#endif
+#if (!defined (xBSD) && !defined(_WIN32) && !defined(VMS)) || defined (USE_TAP_NETWORK) || defined (USE_VDE_NETWORK)
+#define MUST_DO_SELECT 1
 #endif
+#endif /* USE_READER_THREAD */
 
 /*
   USE_BPF is defined to let this code leverage the libpcap/OS kernel provided 
@@ -175,7 +176,10 @@ struct eth_device {
   char*         name;                                   /* name of ethernet device */
   void*         handle;                                 /* handle of implementation-specific device */
   int           fd_handle;                              /* fd to kernel device (where needed) */
-  int           pcap_mode;                              /* Flag indicating if pcap API are being used to move packets */
+  int           eth_api;                                /* Designator for which API is being used to move packets */
+#define ETH_API_PCAP 0                                  /* Pcap API in use */
+#define ETH_API_TAP  1                                  /* tun/tap API in use */
+#define ETH_API_VDE  2                                  /* VDE API in use */
   ETH_PCALLBACK read_callback;                          /* read callback function */
   ETH_PCALLBACK write_callback;                         /* write callback function */
   ETH_PACK*     read_packet;                            /* read packet */