Index: src/core/ipv4/ip.c
===================================================================
--- src/core/ipv4/ip.c	(revision 423)
+++ src/core/ipv4/ip.c	(working copy)
@@ -531,9 +531,19 @@
   LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
   ip_debug_print(p);
 
-  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
-
-  return netif->output(netif, p, dest);
+#if (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) && !LWIP_NETIF_LOOPBACK_MULTITHREADING
+  if (ip_addr_cmp(dest, &netif->ip_addr)) {
+    /* Packet to self, enqueue it for loopback */
+    LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
+
+    return netif_loop_output(netif, p, dest);
+  } else
+#endif /* (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) && !LWIP_NETIF_LOOPBACK_MULTITHREADING */
+  {
+    LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
+
+    return netif->output(netif, p, dest);
+  }
 }
 
 /**
Index: src/core/netif.c
===================================================================
--- src/core/netif.c	(revision 422)
+++ src/core/netif.c	(working copy)
@@ -36,7 +36,12 @@
  *
  */
 
-#include "lwip/opt.h"
+#include "lwip/opt.h"
+
+#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
+#if LWIP_NETIF_LOOPBACK_MULTITHREADING!=LWIP_LOOPIF_MULTITHREADING
+#error LWIP_NETIF_LOOPBACK_MULTITHREADING must be set equal to LWIP_LOOPIF_MULTITHREADING
+#endif
 
 #include "lwip/def.h"
 #include "lwip/ip_addr.h"
@@ -45,6 +50,9 @@
 #include "lwip/snmp.h"
 #include "lwip/igmp.h"
 #include "netif/etharp.h"
+#if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING
+#include "lwip/sys.h"
+#endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */
 
 #if LWIP_NETIF_STATUS_CALLBACK
 #define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }
@@ -57,7 +65,7 @@
 #else
 #define NETIF_LINK_CALLBACK(n) { /* NOP */ }
 #endif /* LWIP_NETIF_LINK_CALLBACK */ 
-
+
 struct netif *netif_list;
 struct netif *netif_default;
 
@@ -105,7 +113,11 @@
 #endif /* LWIP_NETIF_LINK_CALLBACK */
 #if LWIP_IGMP
   netif->igmp_mac_filter = NULL;
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP */
+#if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING
+  netif->loop_first = NULL;
+  netif->loop_last = NULL;
+#endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */
 
   /* remember netif specific state information data */
   netif->state = state;
@@ -497,3 +509,133 @@
         netif->link_callback = link_callback;
 }
 #endif /* LWIP_NETIF_LINK_CALLBACK */
+
+#if ENABLE_LOOPBACK
+/**
+ * Send an IP packet to be received on the same netif (loopif-like).
+ * The pbuf is simply copied and handed back to netif->input.
+ * In multithreaded mode, this is done directly since netif->input must put
+ * the packet on a queue.
+ * In callback mode, the packet is put on an internal queue and is fed to
+ * netif->input by netif_poll().
+ *
+ * @param netif the lwip network interface structure
+ * @param p the (IP) packet to 'send'
+ * @param ipaddr the ip address to send the packet to (not used)
+ * @return ERR_OK if the packet has been sent
+ *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated
+ */
+err_t
+netif_loop_output(struct netif *netif, struct pbuf *p,
+       struct ip_addr *ipaddr)
+{
+#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
+  SYS_ARCH_DECL_PROTECT(lev);
+  struct pbuf *last;
+#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
+  struct pbuf *r;
+  err_t err;
+
+  LWIP_UNUSED_ARG(ipaddr);
+
+  /* Allocate a new pbuf */
+  r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
+  if (r == NULL) {
+    return ERR_MEM;
+  }
+
+  /* Copy the whole pbuf queue p into the single pbuf r */
+  if ((err = pbuf_copy(r, p)) != ERR_OK) {
+    pbuf_free(r);
+    r = NULL;
+    return err;
+  }
+
+#if LWIP_NETIF_LOOPBACK_MULTITHREADING
+  /* Multithreading environment, netif->input() is supposed to put the packet
+     into a mailbox, so we can safely call it here without risking to re-enter
+     functions that are not reentrant (TCP!!!) */
+  if(netif->input(r, netif) != ERR_OK) {
+    pbuf_free(r);
+    r = NULL;
+  }
+#else /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
+  /* Raw API without threads: put the packet on a linked list which gets emptied
+     through calling netif_poll(). */
+
+  /* let last point to the last pbuf in chain r */
+  for (last = r; last->next != NULL; last = last->next);
+  SYS_ARCH_PROTECT(lev);
+  if(netif->loop_first != NULL) {
+    LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
+    netif->loop_last->next = r;
+    netif->loop_last = last;
+  } else {
+    netif->loop_first = r;
+    netif->loop_last = last;
+  }
+  SYS_ARCH_UNPROTECT(lev);
+#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
+
+  return ERR_OK;    
+}
+
+#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
+/**
+ * Call netif_poll() in the main loop of your application. This is to prevent
+ * reentering non-reentrant functions like tcp_input(). Packets passed to
+ * netif_loop_output() are put on a list that is passed to netif->input() by
+ * netif_poll().
+ */
+void
+netif_poll(void)
+{
+  SYS_ARCH_DECL_PROTECT(lev);
+  struct pbuf *in, *in_end;
+  struct netif *netif = netif_list;
+
+  /* loop through netifs */
+  while (netif != NULL) {
+    do {
+      /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
+      SYS_ARCH_PROTECT(lev);
+      in = netif->loop_first;
+      if(in) {
+        in_end = in;
+        while(in_end->len != in_end->tot_len) {
+          LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
+          in_end = in_end->next;
+        }
+        /* 'in_end' now points to the last pbuf from 'in' */
+        if(in_end == netif->loop_last) {
+          /* this was the last pbuf in the list */
+          netif->loop_first = netif->loop_last = NULL;
+        } else {
+          /* pop the pbuf off the list */
+          netif->loop_first = in_end->next;
+          LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
+        }
+      }
+      SYS_ARCH_UNPROTECT(lev);
+
+      if(in != NULL) {
+        if(in_end->next != NULL) {
+          /* De-queue the pbuf from its successors on the 'loop_' list. */
+          in_end->next = NULL;
+        }
+        if(netif->input(in, netif) != ERR_OK) {
+          pbuf_free(in);
+        }
+        /* Don't reference the packet any more! */
+        in = NULL;
+        in_end = NULL;
+      }
+    /* go on while there is a packet on the list */
+    } while(netif->loop_first != NULL);
+
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+}
+#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
+#endif /* ENABLE_LOOPBACK */
Index: src/include/lwip/netif.h
===================================================================
--- src/include/lwip/netif.h	(revision 422)
+++ src/include/lwip/netif.h	(working copy)
@@ -32,8 +32,10 @@
 #ifndef __LWIP_NETIF_H__
 #define __LWIP_NETIF_H__
 
-#include "lwip/opt.h"
+#include "lwip/opt.h"
 
+#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
+
 #include "lwip/err.h"
 
 #include "lwip/ip_addr.h"
@@ -165,6 +167,11 @@
 #if LWIP_NETIF_HWADDRHINT
   u8_t *addr_hint;
 #endif /* LWIP_NETIF_HWADDRHINT */
+#if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING
+  /* List of packets to be queued for ourselves. */
+  struct pbuf *loop_first;
+  struct pbuf *loop_last;
+#endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */
 };
 
 #if LWIP_SNMP
@@ -242,4 +249,11 @@
 }
 #endif
 
+#if ENABLE_LOOPBACK
+err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip);
+#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
+void netif_poll(void);
+#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
+#endif /* ENABLE_LOOPBACK */
+
 #endif /* __LWIP_NETIF_H__ */
Index: src/include/lwip/opt.h
===================================================================
--- src/include/lwip/opt.h	(revision 423)
+++ src/include/lwip/opt.h	(working copy)
@@ -409,7 +409,7 @@
  */
 #ifndef IP_DEFAULT_TTL
 #define IP_DEFAULT_TTL                  255
-#endif
+#endif
 
 /*
    ----------------------------------
@@ -814,7 +814,32 @@
 #ifndef LWIP_NETIF_HWADDRHINT
 #define LWIP_NETIF_HWADDRHINT           0
 #endif
+
+/**
+ * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP
+ * address equal to the netif IP address, looping them back up the stack.
+ */
+#ifndef LWIP_NETIF_LOOPBACK
+#define LWIP_NETIF_LOOPBACK             0
+#endif
 
+/**
+ * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in
+ * the system, as netifs must change how they behave depending on this setting
+ * for the LWIP_NETIF_LOOPBACK option to work.
+ * Setting this is needed to avoid reentering non-reentrant functions like
+ * tcp_input().
+ *    LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a
+ *       multithreaded environment like tcpip.c. In this case, netif->input()
+ *       is called directly.
+ *    LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.
+ *       The packets are put on a list and netif_poll() must be called in
+ *       the main application loop.
+ */
+#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING
+#define LWIP_NETIF_LOOPBACK_MULTITHREADING    (!NO_SYS)
+#endif
+
 /*
    ------------------------------------
    ---------- LOOPIF options ----------
@@ -840,7 +865,7 @@
  *       the main application loop.
  */
 #ifndef LWIP_LOOPIF_MULTITHREADING
-#define LWIP_LOOPIF_MULTITHREADING      1
+#define LWIP_LOOPIF_MULTITHREADING      (!NO_SYS)
 #endif
 
 /*
Index: src/include/netif/loopif.h
===================================================================
--- src/include/netif/loopif.h	(revision 422)
+++ src/include/netif/loopif.h	(working copy)
@@ -40,7 +40,7 @@
 #endif
 
 #if !LWIP_LOOPIF_MULTITHREADING
-void loopif_poll(struct netif *netif);
+#define loopif_poll(netif) netif_poll()
 #endif
 
 err_t loopif_init(struct netif *netif);
Index: src/netif/loopif.c
===================================================================
--- src/netif/loopif.c	(revision 422)
+++ src/netif/loopif.c	(working copy)
@@ -40,150 +40,9 @@
 #if LWIP_HAVE_LOOPIF
 
 #include "netif/loopif.h"
-#include "lwip/pbuf.h"
 #include "lwip/snmp.h"
 
-#include <string.h>
-
-#if !LWIP_LOOPIF_MULTITHREADING
-
-#include "lwip/sys.h"
-#include "lwip/mem.h"
-
-/* helper struct for the linked list of pbufs */
-struct loopif_private {
-  struct pbuf *first;
-  struct pbuf *last;
-};
-
 /**
- * Call loopif_poll() in the main loop of your application. This is to prevent
- * reentering non-reentrant functions like tcp_input(). Packets passed to
- * loopif_output() are put on a list that is passed to netif->input() by
- * loopif_poll().
- *
- * @param netif the lwip network interface structure for this loopif
- */
-void
-loopif_poll(struct netif *netif)
-{
-  SYS_ARCH_DECL_PROTECT(lev);
-  struct pbuf *in, *in_end;
-  struct loopif_private *priv = (struct loopif_private*)netif->state;
-
-  LWIP_ERROR("priv != NULL", (priv != NULL), return;);
-
-  do {
-    /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
-    SYS_ARCH_PROTECT(lev);
-    in = priv->first;
-    if(in) {
-      in_end = in;
-      while(in_end->len != in_end->tot_len) {
-        LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
-        in_end = in_end->next;
-      }
-      /* 'in_end' now points to the last pbuf from 'in' */
-      if(in_end == priv->last) {
-        /* this was the last pbuf in the list */
-        priv->first = priv->last = NULL;
-      } else {
-        /* pop the pbuf off the list */
-        priv->first = in_end->next;
-        LWIP_ASSERT("should not be null since first != last!", priv->first != NULL);
-      }
-    }
-    SYS_ARCH_UNPROTECT(lev);
-  
-    if(in != NULL) {
-      if(in_end->next != NULL) {
-        /* De-queue the pbuf from its successors on the 'priv' list. */
-        in_end->next = NULL;
-      }
-      if(netif->input(in, netif) != ERR_OK) {
-        pbuf_free(in);
-      }
-      /* Don't reference the packet any more! */
-      in = NULL;
-      in_end = NULL;
-    }
-  /* go on while there is a packet on the list */
-  } while(priv->first != NULL);
-}
-#endif /* LWIP_LOOPIF_MULTITHREADING */
-
-/**
- * Send an IP packet over the loopback interface.
- * The pbuf is simply copied and handed back to netif->input.
- * In multithreaded mode, this is done directly since netif->input must put
- * the packet on a queue.
- * In callback mode, the packet is put on an internal queue and is fed to
- * netif->input by loopif_poll().
- *
- * @param netif the lwip network interface structure for this loopif
- * @param p the (IP) packet to 'send'
- * @param ipaddr the ip address to send the packet to (not used for loopif)
- * @return ERR_OK if the packet has been sent
- *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated
- */
-static err_t
-loopif_output(struct netif *netif, struct pbuf *p,
-       struct ip_addr *ipaddr)
-{
-#if !LWIP_LOOPIF_MULTITHREADING
-  SYS_ARCH_DECL_PROTECT(lev);
-  struct loopif_private *priv;
-  struct pbuf *last;
-#endif /* LWIP_LOOPIF_MULTITHREADING */
-  struct pbuf *r;
-  err_t err;
-
-  LWIP_UNUSED_ARG(ipaddr);
-
-  /* Allocate a new pbuf */
-  r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
-  if (r == NULL) {
-    return ERR_MEM;
-  }
-
-  /* Copy the whole pbuf queue p into the single pbuf r */
-  if ((err = pbuf_copy(r, p)) != ERR_OK) {
-    pbuf_free(r);
-    r = NULL;
-    return err;
-  }
-
-#if LWIP_LOOPIF_MULTITHREADING
-  /* Multithreading environment, netif->input() is supposed to put the packet
-     into a mailbox, so we can safely call it here without risking to re-enter
-     functions that are not reentrant (TCP!!!) */
-  if(netif->input(r, netif) != ERR_OK) {
-    pbuf_free(r);
-    r = NULL;
-  }
-#else /* LWIP_LOOPIF_MULTITHREADING */
-  /* Raw API without threads: put the packet on a linked list which gets emptied
-     through calling loopif_poll(). */
-  priv = (struct loopif_private*)netif->state;
-
-  /* let last point to the last pbuf in chain r */
-  for (last = r; last->next != NULL; last = last->next);
-  SYS_ARCH_PROTECT(lev);
-  if(priv->first != NULL) {
-    LWIP_ASSERT("if first != NULL, last must also be != NULL", priv->last != NULL);
-    priv->last->next = r;
-    priv->last = last;
-  } else {
-    priv->first = r;
-    priv->last = last;
-  }
-  SYS_ARCH_UNPROTECT(lev);
-#endif /* LWIP_LOOPIF_MULTITHREADING */
-
-  return ERR_OK;    
-}
-
-/**
  * Initialize a lwip network interface structure for a loopback interface
  *
  * @param netif the lwip network interface structure for this loopif
@@ -193,16 +52,6 @@
 err_t
 loopif_init(struct netif *netif)
 {
-#if !LWIP_LOOPIF_MULTITHREADING
-  struct loopif_private *priv;
-
-  priv = (struct loopif_private*)mem_malloc(sizeof(struct loopif_private));
-  if(priv == NULL) 
-    return ERR_MEM;
-  priv->first = priv->last = NULL;
-  netif->state = priv;
-#endif /* LWIP_LOOPIF_MULTITHREADING */
-
   /* initialize the snmp variables and counters inside the struct netif
    * ifSpeed: no assumption can be made!
    */
@@ -210,7 +59,7 @@
 
   netif->name[0] = 'l';
   netif->name[1] = 'o';
-  netif->output = loopif_output;
+  netif->output = netif_loop_output;
   return ERR_OK;
 }
 
