Index: src/core/ipv4/ip.c
===================================================================
--- src/core/ipv4/ip.c	(revision 408)
+++ src/core/ipv4/ip.c	(working copy)
@@ -523,9 +523,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 IP_TO_SELF && !IP_TO_SELF_MULTITHREADING
+  if (ip_addr_cmp(dest, &netif->ip_addr)) {
+    /* Packet to self, enqueue it */
+    LWIP_DEBUGF(IP_DEBUG, ("netif_output_to_self()"));
+
+    return netif_output_to_self(netif, p, dest);
+  } else
+#endif /* IP_TO_SELF && !IP_TO_SELF_MULTITHREADING */
+  {
+    LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
+
+    return netif->output(netif, p, dest);
+  }
 }
 
 /**
Index: src/core/netif.c
===================================================================
--- src/core/netif.c	(revision 408)
+++ src/core/netif.c	(working copy)
@@ -45,6 +45,9 @@
 #include "lwip/snmp.h"
 #include "lwip/igmp.h"
 #include "netif/etharp.h"
+#if IP_TO_SELF && !IP_TO_SELF_MULTITHREADING
+#include "lwip/sys.h"
+#endif /* IP_TO_SELF && !IP_TO_SELF_MULTITHREADING */
 
 #if LWIP_NETIF_STATUS_CALLBACK
 #define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }
@@ -57,7 +60,7 @@
 #else
 #define NETIF_LINK_CALLBACK(n) { /* NOP */ }
 #endif /* LWIP_NETIF_LINK_CALLBACK */ 
-
+
 struct netif *netif_list;
 struct netif *netif_default;
 
@@ -105,7 +108,11 @@
 #endif /* LWIP_NETIF_LINK_CALLBACK */
 #if LWIP_IGMP
   netif->igmp_mac_filter = NULL;
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP */
+#if IP_TO_SELF && !IP_TO_SELF_MULTITHREADING
+  netif->self_first = NULL;
+  netif->self_last = NULL;
+#endif /* IP_TO_SELF && !IP_TO_SELF_MULTITHREADING */
 
   /* remember netif specific state information data */
   netif->state = state;
@@ -497,3 +504,133 @@
         netif->link_callback = link_callback;
 }
 #endif /* LWIP_NETIF_LINK_CALLBACK */
+
+#if IP_TO_SELF
+/**
+ * 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_output_to_self(struct netif *netif, struct pbuf *p,
+       struct ip_addr *ipaddr)
+{
+#if !IP_TO_SELF_MULTITHREADING
+  SYS_ARCH_DECL_PROTECT(lev);
+  struct pbuf *last;
+#endif /* IP_TO_SELF_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 IP_TO_SELF_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 /* IP_TO_SELF_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->self_first != NULL) {
+    LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->self_last != NULL);
+    netif->self_last->next = r;
+    netif->self_last = last;
+  } else {
+    netif->self_first = r;
+    netif->self_last = last;
+  }
+  SYS_ARCH_UNPROTECT(lev);
+#endif /* IP_TO_SELF_MULTITHREADING */
+
+  return ERR_OK;    
+}
+
+#if !IP_TO_SELF_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_output_to_self() 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->self_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->self_last) {
+          /* this was the last pbuf in the list */
+          netif->self_first = netif->self_last = NULL;
+        } else {
+          /* pop the pbuf off the list */
+          netif->self_first = in_end->next;
+          LWIP_ASSERT("should not be null since first != last!", netif->self_first != NULL);
+        }
+      }
+      SYS_ARCH_UNPROTECT(lev);
+
+      if(in != NULL) {
+        if(in_end->next != NULL) {
+          /* De-queue the pbuf from its successors on the 'self_' 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->self_first != NULL);
+
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+}
+#endif /* !IP_TO_SELF_MULTITHREADING */
+#endif /* IP_TO_SELF */
Index: src/include/lwip/netif.h
===================================================================
--- src/include/lwip/netif.h	(revision 408)
+++ src/include/lwip/netif.h	(working copy)
@@ -165,6 +165,11 @@
 #if LWIP_NETIF_HWADDRHINT
   u8_t *addr_hint;
 #endif /* LWIP_NETIF_HWADDRHINT */
+#if IP_TO_SELF && !IP_TO_SELF_MULTITHREADING
+  /* List of packets to be queued for ourselves. */
+  struct pbuf *self_first;
+  struct pbuf *self_last;
+#endif /* IP_TO_SELF && !IP_TO_SELF_MULTITHREADING */
 };
 
 #if LWIP_SNMP
@@ -242,4 +247,11 @@
 }
 #endif
 
+#if IP_TO_SELF
+err_t netif_output_to_self(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip);
+#if !IP_TO_SELF_MULTITHREADING
+void netif_poll(void);
+#endif /* !IP_TO_SELF_MULTITHREADING */
+#endif /* IP_TO_SELF */
+
 #endif /* __LWIP_NETIF_H__ */
Index: src/include/lwip/opt.h
===================================================================
--- src/include/lwip/opt.h	(revision 408)
+++ src/include/lwip/opt.h	(working copy)
@@ -409,8 +409,33 @@
  */
 #ifndef IP_DEFAULT_TTL
 #define IP_DEFAULT_TTL                  255
+#endif
+
+/**
+ * IP_TO_SELF==1: Support sending packets with a destination IP address
+ * equal to the netif IP address, looping them back up the stack.
+ */
+#ifndef IP_TO_SELF
+#define IP_TO_SELF                      0
 #endif
 
+/**
+ * LWIP_LOOPIF_MULTITHREADING: Indicates whether threading is enabled in
+ * the system, as netifs must change how they behave depending on this setting
+ * for the IP_TO_SELF option to work.
+ * Setting this is needed to avoid reentering non-reentrant functions like
+ * tcp_input().
+ *    IP_TO_SELF_MULTITHREADING==1: Indicates that the user is using a
+ *       multithreaded environment like tcpip.c. In this case, netif->input()
+ *       is called directly.
+ *    IP_TO_SELF_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 IP_TO_SELF_MULTITHREADING
+#define IP_TO_SELF_MULTITHREADING       (!NO_SYS)
+#endif
+
 /*
    ----------------------------------
    ---------- ICMP options ----------
