diff --git a/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/autoip.c b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/autoip.c
new file mode 100644
index 0000000..92bb459
--- /dev/null
+++ b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/autoip.c
@@ -0,0 +1,536 @@
+/**
+ * @file
+ * AutoIP Automatic LinkLocal IP Configuration
+ *
+ */
+
+/*
+ *
+ * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Dominik Spies <kontakt@dspies.de>
+ *
+ * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
+ * with RFC 3927.
+ *
+ *
+ * Please coordinate changes and requests with Dominik Spies
+ * <kontakt@dspies.de>
+ */
+
+/*******************************************************************************
+ * USAGE:
+ * 
+ * define LWIP_AUTOIP 1  in your lwipopts.h
+ * 
+ * If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
+ * - First, call autoip_init().
+ * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
+ *   that should be defined in autoip.h.
+ *   I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
+ *   Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
+ *
+ * Without DHCP:
+ * - Call autoip_start() after netif_add().
+ * 
+ * With DHCP:
+ * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
+ * - Configure your DHCP Client.
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/mem.h"
+#include "lwip/udp.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/autoip.h"
+#include "netif/etharp.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* 169.254.0.0 */
+#define AUTOIP_NET         0xA9FE0000
+/* 169.254.1.0 */
+#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
+/* 169.254.254.255 */
+#define AUTOIP_RANGE_END   (AUTOIP_NET | 0xFEFF)
+
+
+/** Pseudo random macro based on netif informations.
+ * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
+#ifndef LWIP_AUTOIP_RAND
+#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
+                                   ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
+                                   ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
+                                   ((u32_t)((netif->hwaddr[4]) & 0xff))) + \
+                                   (netif->autoip?netif->autoip->tried_llipaddr:0))
+#endif /* LWIP_AUTOIP_RAND */
+
+/**
+ * Macro that generates the initial IP address to be tried by AUTOIP.
+ * If you want to override this, define it to something else in lwipopts.h.
+ */
+#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
+#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
+  htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
+                 ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
+#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
+
+/* static functions */
+static void autoip_handle_arp_conflict(struct netif *netif);
+
+/* creates a pseudo random LL IP-Address for a network interface */
+static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
+
+/* sends an ARP probe */
+static err_t autoip_arp_probe(struct netif *netif);
+
+/* sends an ARP announce */
+static err_t autoip_arp_announce(struct netif *netif);
+
+/* configure interface for use with current LL IP-Address */
+static err_t autoip_bind(struct netif *netif);
+
+/* start sending probes for llipaddr */
+static void autoip_start_probing(struct netif *netif);
+
+/**
+ * Initialize this module
+ */
+void
+autoip_init(void)
+{
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
+}
+
+/** Set a statically allocated struct autoip to work with.
+ * Using this prevents autoip_start to allocate it using mem_malloc.
+ *
+ * @param netif the netif for which to set the struct autoip
+ * @param dhcp (uninitialised) dhcp struct allocated by the application
+ */
+void
+autoip_set_struct(struct netif *netif, struct autoip *autoip)
+{
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+  LWIP_ASSERT("autoip != NULL", autoip != NULL);
+  LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
+
+  /* clear data structure */
+  memset(autoip, 0, sizeof(struct autoip));
+  /* autoip->state = AUTOIP_STATE_OFF; */
+  netif->autoip = autoip;
+}
+
+/** Restart AutoIP client and check the next address (conflict detected)
+ *
+ * @param netif The netif under AutoIP control
+ */
+static void
+autoip_restart(struct netif *netif)
+{
+  netif->autoip->tried_llipaddr++;
+  autoip_start(netif);
+}
+
+/**
+ * Handle a IP address conflict after an ARP conflict detection
+ */
+static void
+autoip_handle_arp_conflict(struct netif *netif)
+{
+  /* Somehow detect if we are defending or retreating */
+  unsigned char defend = 1; /* tbd */
+
+  if(defend) {
+    if(netif->autoip->lastconflict > 0) {
+      /* retreat, there was a conflicting ARP in the last
+       * DEFEND_INTERVAL seconds
+       */
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+        ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
+
+      /* TODO: close all TCP sessions */
+      autoip_restart(netif);
+    } else {
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+        ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
+      autoip_arp_announce(netif);
+      netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+    }
+  } else {
+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+      ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
+    /* TODO: close all TCP sessions */
+    autoip_restart(netif);
+  }
+}
+
+/**
+ * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
+ *
+ * @param netif network interface on which create the IP-Address
+ * @param ipaddr ip address to initialize
+ */
+static void
+autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
+{
+  /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
+   * compliant to RFC 3927 Section 2.1
+   * We have 254 * 256 possibilities */
+
+  u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
+  addr += netif->autoip->tried_llipaddr;
+  addr = AUTOIP_NET | (addr & 0xffff);
+  /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ 
+
+  if (addr < AUTOIP_RANGE_START) {
+    addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
+  }
+  if (addr > AUTOIP_RANGE_END) {
+    addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
+  }
+  LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
+    (addr <= AUTOIP_RANGE_END));
+  ip4_addr_set_u32(ipaddr, htonl(addr));
+  
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+    ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
+    ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
+}
+
+/**
+ * Sends an ARP probe from a network interface
+ *
+ * @param netif network interface used to send the probe
+ */
+static err_t
+autoip_arp_probe(struct netif *netif)
+{
+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
+    (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,
+    &netif->autoip->llipaddr, ARP_REQUEST);
+}
+
+/**
+ * Sends an ARP announce from a network interface
+ *
+ * @param netif network interface used to send the announce
+ */
+static err_t
+autoip_arp_announce(struct netif *netif)
+{
+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
+    (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,
+    &netif->autoip->llipaddr, ARP_REQUEST);
+}
+
+/**
+ * Configure interface for use with current LL IP-Address
+ *
+ * @param netif network interface to configure with current LL IP-Address
+ */
+static err_t
+autoip_bind(struct netif *netif)
+{
+  struct autoip *autoip = netif->autoip;
+  ip_addr_t sn_mask, gw_addr;
+
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+    ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
+    ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
+    ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
+
+  IP4_ADDR(&sn_mask, 255, 255, 0, 0);
+  IP4_ADDR(&gw_addr, 0, 0, 0, 0);
+
+  netif_set_ipaddr(netif, &autoip->llipaddr);
+  netif_set_netmask(netif, &sn_mask);
+  netif_set_gw(netif, &gw_addr);  
+
+  /* bring the interface up */
+  netif_set_up(netif);
+
+  return ERR_OK;
+}
+
+/**
+ * Start AutoIP client
+ *
+ * @param netif network interface on which start the AutoIP client
+ */
+err_t
+autoip_start(struct netif *netif)
+{
+  struct autoip *autoip = netif->autoip;
+  err_t result = ERR_OK;
+
+  if(netif_is_up(netif)) {
+    netif_set_down(netif);
+  }
+
+  /* Set IP-Address, Netmask and Gateway to 0 to make sure that
+   * ARP Packets are formed correctly
+   */
+  ip_addr_set_zero(&netif->ip_addr);
+  ip_addr_set_zero(&netif->netmask);
+  ip_addr_set_zero(&netif->gw);
+
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+    ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
+    netif->name[1], (u16_t)netif->num));
+  if(autoip == NULL) {
+    /* no AutoIP client attached yet? */
+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+      ("autoip_start(): starting new AUTOIP client\n"));
+    autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
+    if(autoip == NULL) {
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+        ("autoip_start(): could not allocate autoip\n"));
+      return ERR_MEM;
+    }
+    memset(autoip, 0, sizeof(struct autoip));
+    /* store this AutoIP client in the netif */
+    netif->autoip = autoip;
+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
+  } else {
+    autoip->state = AUTOIP_STATE_OFF;
+    autoip->ttw = 0;
+    autoip->sent_num = 0;
+    ip_addr_set_zero(&autoip->llipaddr);
+    autoip->lastconflict = 0;
+  }
+
+  autoip_create_addr(netif, &(autoip->llipaddr));
+  autoip_start_probing(netif);
+
+  return result;
+}
+
+static void
+autoip_start_probing(struct netif *netif)
+{
+  struct autoip *autoip = netif->autoip;
+
+  autoip->state = AUTOIP_STATE_PROBING;
+  autoip->sent_num = 0;
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+     ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+      ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+
+  /* time to wait to first probe, this is randomly
+   * choosen out of 0 to PROBE_WAIT seconds.
+   * compliant to RFC 3927 Section 2.2.1
+   */
+  autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
+
+  /*
+   * if we tried more then MAX_CONFLICTS we must limit our rate for
+   * accquiring and probing address
+   * compliant to RFC 3927 Section 2.2.1
+   */
+  if(autoip->tried_llipaddr > MAX_CONFLICTS) {
+    autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+  }
+}
+
+/**
+ * Handle a possible change in the network configuration.
+ *
+ * If there is an AutoIP address configured, take the interface down
+ * and begin probing with the same address.
+ */
+void
+autoip_network_changed(struct netif *netif)
+{
+  if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
+    netif_set_down(netif);
+    autoip_start_probing(netif);
+  }
+}
+
+/**
+ * Stop AutoIP client
+ *
+ * @param netif network interface on which stop the AutoIP client
+ */
+err_t
+autoip_stop(struct netif *netif)
+{
+  netif->autoip->state = AUTOIP_STATE_OFF;
+  netif_set_down(netif);
+  return ERR_OK;
+}
+
+/**
+ * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
+ */
+void
+autoip_tmr()
+{
+  struct netif *netif = netif_list;
+  /* loop through netif's */
+  while (netif != NULL) {
+    /* only act on AutoIP configured interfaces */
+    if (netif->autoip != NULL) {
+      if(netif->autoip->lastconflict > 0) {
+        netif->autoip->lastconflict--;
+      }
+
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+        ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
+        (u16_t)(netif->autoip->state), netif->autoip->ttw));
+
+      switch(netif->autoip->state) {
+        case AUTOIP_STATE_PROBING:
+          if(netif->autoip->ttw > 0) {
+            netif->autoip->ttw--;
+          } else {
+            if(netif->autoip->sent_num >= PROBE_NUM) {
+              netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
+              netif->autoip->sent_num = 0;
+              netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+                 ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+                  ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+                  ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+            } else {
+              autoip_arp_probe(netif);
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+                ("autoip_tmr() PROBING Sent Probe\n"));
+              netif->autoip->sent_num++;
+              /* calculate time to wait to next probe */
+              netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
+                ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
+                PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
+            }
+          }
+          break;
+
+        case AUTOIP_STATE_ANNOUNCING:
+          if(netif->autoip->ttw > 0) {
+            netif->autoip->ttw--;
+          } else {
+            if(netif->autoip->sent_num == 0) {
+             /* We are here the first time, so we waited ANNOUNCE_WAIT seconds
+              * Now we can bind to an IP address and use it.
+              *
+              * autoip_bind calls netif_set_up. This triggers a gratuitous ARP
+              * which counts as an announcement.
+              */
+              autoip_bind(netif);
+            } else {
+              autoip_arp_announce(netif);
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+                ("autoip_tmr() ANNOUNCING Sent Announce\n"));
+            }
+            netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+            netif->autoip->sent_num++;
+
+            if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
+                netif->autoip->state = AUTOIP_STATE_BOUND;
+                netif->autoip->sent_num = 0;
+                netif->autoip->ttw = 0;
+                 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+                    ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+                     ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+                     ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+            }
+          }
+          break;
+      }
+    }
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+}
+
+/**
+ * Handles every incoming ARP Packet, called by etharp_arp_input.
+ *
+ * @param netif network interface to use for autoip processing
+ * @param hdr Incoming ARP packet
+ */
+void
+autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
+{
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
+  if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
+   /* when ip.src == llipaddr && hw.src != netif->hwaddr
+    *
+    * when probing  ip.dst == llipaddr && hw.src != netif->hwaddr
+    * we have a conflict and must solve it
+    */
+    ip_addr_t sipaddr, dipaddr;
+    struct eth_addr netifaddr;
+    ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
+
+    /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
+     * structure packing (not using structure copy which breaks strict-aliasing rules).
+     */
+    IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
+    IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
+      
+    if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
+        ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
+         (netif->autoip->sent_num == 0))) {
+     /* RFC 3927 Section 2.2.1:
+      * from beginning to after ANNOUNCE_WAIT
+      * seconds we have a conflict if
+      * ip.src == llipaddr OR
+      * ip.dst == llipaddr && hw.src != own hwaddr
+      */
+      if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
+          (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
+           !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
+        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
+          ("autoip_arp_reply(): Probe Conflict detected\n"));
+        autoip_restart(netif);
+      }
+    } else {
+     /* RFC 3927 Section 2.5:
+      * in any state we have a conflict if
+      * ip.src == llipaddr && hw.src != own hwaddr
+      */
+      if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
+          !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
+        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
+          ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
+        autoip_handle_arp_conflict(netif);
+      }
+    }
+  }
+}
+
+#endif /* LWIP_AUTOIP */
diff --git a/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/icmp.c b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/icmp.c
new file mode 100644
index 0000000..32902a5
--- /dev/null
+++ b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/icmp.c
@@ -0,0 +1,335 @@
+/**
+ * @file
+ * ICMP - Internet Control Message Protocol
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/* Some ICMP messages should be passed to the transport protocols. This
+   is not implemented. */
+
+#include "lwip/opt.h"
+
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/icmp.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/ip.h"
+#include "lwip/def.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+
+#include <string.h>
+
+/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
+ * used to modify and send a response packet (and to 1 if this is not the case,
+ * e.g. when link header is stripped of when receiving) */
+#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+
+/* The amount of data from the original packet to return in a dest-unreachable */
+#define ICMP_DEST_UNREACH_DATASIZE 8
+
+static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
+
+/**
+ * Processes ICMP input packets, called from ip_input().
+ *
+ * Currently only processes icmp echo requests and sends
+ * out the echo response.
+ *
+ * @param p the icmp echo request packet, p->payload pointing to the ip header
+ * @param inp the netif on which this packet was received
+ */
+void
+icmp_input(struct pbuf *p, struct netif *inp)
+{
+  u8_t type;
+#ifdef LWIP_DEBUG
+  u8_t code;
+#endif /* LWIP_DEBUG */
+  struct icmp_echo_hdr *iecho;
+  struct ip_hdr *iphdr;
+  s16_t hlen;
+
+  ICMP_STATS_INC(icmp.recv);
+  snmp_inc_icmpinmsgs();
+
+
+  iphdr = (struct ip_hdr *)p->payload;
+  hlen = IPH_HL(iphdr) * 4;
+  if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
+    goto lenerr;
+  }
+
+  type = *((u8_t *)p->payload);
+#ifdef LWIP_DEBUG
+  code = *(((u8_t *)p->payload)+1);
+#endif /* LWIP_DEBUG */
+  switch (type) {
+  case ICMP_ER:
+    /* This is OK, echo reply might have been parsed by a raw PCB
+       (as obviously, an echo request has been sent, too). */
+    break; 
+  case ICMP_ECHO:
+#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
+    {
+      int accepted = 1;
+#if !LWIP_MULTICAST_PING
+      /* multicast destination address? */
+      if (ip_addr_ismulticast(&current_iphdr_dest)) {
+        accepted = 0;
+      }
+#endif /* LWIP_MULTICAST_PING */
+#if !LWIP_BROADCAST_PING
+      /* broadcast destination address? */
+      if (ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
+        accepted = 0;
+      }
+#endif /* LWIP_BROADCAST_PING */
+      /* broadcast or multicast destination address not acceptd? */
+      if (!accepted) {
+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
+        ICMP_STATS_INC(icmp.err);
+        pbuf_free(p);
+        return;
+      }
+    }
+#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
+    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
+      goto lenerr;
+    }
+    if (inet_chksum_pbuf(p) != 0) {
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
+      pbuf_free(p);
+      ICMP_STATS_INC(icmp.chkerr);
+      snmp_inc_icmpinerrors();
+      return;
+    }
+#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+    if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
+      /* p is not big enough to contain link headers
+       * allocate a new one and copy p into it
+       */
+      struct pbuf *r;
+      /* switch p->payload to ip header */
+      if (pbuf_header(p, hlen)) {
+        LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
+        goto memerr;
+      }
+      /* allocate new packet buffer with space for link headers */
+      r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
+      if (r == NULL) {
+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
+        goto memerr;
+      }
+      LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
+                  (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
+      /* copy the whole packet including ip header */
+      if (pbuf_copy(r, p) != ERR_OK) {
+        LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
+        goto memerr;
+      }
+      iphdr = (struct ip_hdr *)r->payload;
+      /* switch r->payload back to icmp header */
+      if (pbuf_header(r, -hlen)) {
+        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
+        goto memerr;
+      }
+      /* free the original p */
+      pbuf_free(p);
+      /* we now have an identical copy of p that has room for link headers */
+      p = r;
+    } else {
+      /* restore p->payload to point to icmp header */
+      if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
+        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
+        goto memerr;
+      }
+    }
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+    /* At this point, all checks are OK. */
+    /* We generate an answer by switching the dest and src ip addresses,
+     * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
+    iecho = (struct icmp_echo_hdr *)p->payload;
+    ip_addr_copy(iphdr->src, *ip_current_dest_addr());
+    ip_addr_copy(iphdr->dest, *ip_current_src_addr());
+    ICMPH_TYPE_SET(iecho, ICMP_ER);
+    /* adjust the checksum */
+    if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
+      iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
+    } else {
+      iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
+    }
+
+    /* Set the correct TTL and recalculate the header checksum. */
+    IPH_TTL_SET(iphdr, ICMP_TTL);
+    IPH_CHKSUM_SET(iphdr, 0);
+#if CHECKSUM_GEN_IP
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
+#endif /* CHECKSUM_GEN_IP */
+
+    ICMP_STATS_INC(icmp.xmit);
+    /* increase number of messages attempted to send */
+    snmp_inc_icmpoutmsgs();
+    /* increase number of echo replies attempted to send */
+    snmp_inc_icmpoutechoreps();
+
+    if(pbuf_header(p, hlen)) {
+      LWIP_ASSERT("Can't move over header in packet", 0);
+    } else {
+      err_t ret;
+      /* send an ICMP packet, src addr is the dest addr of the curren packet */
+      ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
+                   ICMP_TTL, 0, IP_PROTO_ICMP, inp);
+      if (ret != ERR_OK) {
+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
+      }
+    }
+    break;
+  default:
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", 
+                (s16_t)type, (s16_t)code));
+    ICMP_STATS_INC(icmp.proterr);
+    ICMP_STATS_INC(icmp.drop);
+  }
+  pbuf_free(p);
+  return;
+lenerr:
+  pbuf_free(p);
+  ICMP_STATS_INC(icmp.lenerr);
+  snmp_inc_icmpinerrors();
+  return;
+#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+memerr:
+  pbuf_free(p);
+  ICMP_STATS_INC(icmp.err);
+  snmp_inc_icmpinerrors();
+  return;
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+}
+
+/**
+ * Send an icmp 'destination unreachable' packet, called from ip_input() if
+ * the transport layer protocol is unknown and from udp_input() if the local
+ * port is not bound.
+ *
+ * @param p the input packet for which the 'unreachable' should be sent,
+ *          p->payload pointing to the IP header
+ * @param t type of the 'unreachable' packet
+ */
+void
+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
+{
+  icmp_send_response(p, ICMP_DUR, t);
+}
+
+#if IP_FORWARD || IP_REASSEMBLY
+/**
+ * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
+ *
+ * @param p the input packet for which the 'time exceeded' should be sent,
+ *          p->payload pointing to the IP header
+ * @param t type of the 'time exceeded' packet
+ */
+void
+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
+{
+  icmp_send_response(p, ICMP_TE, t);
+}
+
+#endif /* IP_FORWARD || IP_REASSEMBLY */
+
+/**
+ * Send an icmp packet in response to an incoming packet.
+ *
+ * @param p the input packet for which the 'unreachable' should be sent,
+ *          p->payload pointing to the IP header
+ * @param type Type of the ICMP header
+ * @param code Code of the ICMP header
+ */
+static void
+icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
+{
+  struct pbuf *q;
+  struct ip_hdr *iphdr;
+  /* we can use the echo header here */
+  struct icmp_echo_hdr *icmphdr;
+  ip_addr_t iphdr_src;
+
+  /* ICMP header + IP header + 8 bytes of data */
+  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
+                 PBUF_RAM);
+  if (q == NULL) {
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
+    return;
+  }
+  LWIP_ASSERT("check that first pbuf can hold icmp message",
+             (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
+
+  iphdr = (struct ip_hdr *)p->payload;
+  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
+  LWIP_DEBUGF(ICMP_DEBUG, (" to "));
+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
+  LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
+
+  icmphdr = (struct icmp_echo_hdr *)q->payload;
+  icmphdr->type = type;
+  icmphdr->code = code;
+  icmphdr->id = 0;
+  icmphdr->seqno = 0;
+
+  /* copy fields from original packet */
+  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
+          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
+
+  /* calculate checksum */
+  icmphdr->chksum = 0;
+  icmphdr->chksum = inet_chksum(icmphdr, q->len);
+  ICMP_STATS_INC(icmp.xmit);
+  /* increase number of messages attempted to send */
+  snmp_inc_icmpoutmsgs();
+  /* increase number of destination unreachable messages attempted to send */
+  snmp_inc_icmpouttimeexcds();
+  ip_addr_copy(iphdr_src, iphdr->src);
+  ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
+  pbuf_free(q);
+}
+
+#endif /* LWIP_ICMP */
diff --git a/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/igmp.c b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/igmp.c
new file mode 100644
index 0000000..4e4405e
--- /dev/null
+++ b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/igmp.c
@@ -0,0 +1,817 @@
+/**
+ * @file
+ * IGMP - Internet Group Management Protocol
+ *
+ */
+
+/*
+ * Copyright (c) 2002 CITEL Technologies Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in the 
+ *    documentation and/or other materials provided with the distribution. 
+ * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE. 
+ *
+ * This file is a contribution to the lwIP TCP/IP stack.
+ * The Swedish Institute of Computer Science and Adam Dunkels
+ * are specifically granted permission to redistribute this
+ * source code.
+*/
+
+/*-------------------------------------------------------------
+Note 1)
+Although the rfc requires V1 AND V2 capability
+we will only support v2 since now V1 is very old (August 1989)
+V1 can be added if required
+
+a debug print and statistic have been implemented to
+show this up.
+-------------------------------------------------------------
+-------------------------------------------------------------
+Note 2)
+A query for a specific group address (as opposed to ALLHOSTS)
+has now been implemented as I am unsure if it is required
+
+a debug print and statistic have been implemented to
+show this up.
+-------------------------------------------------------------
+-------------------------------------------------------------
+Note 3)
+The router alert rfc 2113 is implemented in outgoing packets
+but not checked rigorously incoming
+-------------------------------------------------------------
+Steve Reynolds
+------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------------
+ * RFC 988  - Host extensions for IP multicasting                         - V0
+ * RFC 1054 - Host extensions for IP multicasting                         -
+ * RFC 1112 - Host extensions for IP multicasting                         - V1
+ * RFC 2236 - Internet Group Management Protocol, Version 2               - V2  <- this code is based on this RFC (it's the "de facto" standard)
+ * RFC 3376 - Internet Group Management Protocol, Version 3               - V3
+ * RFC 4604 - Using Internet Group Management Protocol Version 3...       - V3+
+ * RFC 2113 - IP Router Alert Option                                      - 
+ *----------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------------
+ * Includes
+ *----------------------------------------------------------------------------*/
+
+#include "lwip/opt.h"
+
+#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/igmp.h"
+#include "lwip/debug.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/ip.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+#include "lwip/stats.h"
+
+#include "string.h"
+
+/* 
+ * IGMP constants
+ */
+#define IGMP_TTL                       1
+#define IGMP_MINLEN                    8
+#define ROUTER_ALERT                   0x9404U
+#define ROUTER_ALERTLEN                4
+
+/*
+ * IGMP message types, including version number.
+ */
+#define IGMP_MEMB_QUERY                0x11 /* Membership query         */
+#define IGMP_V1_MEMB_REPORT            0x12 /* Ver. 1 membership report */
+#define IGMP_V2_MEMB_REPORT            0x16 /* Ver. 2 membership report */
+#define IGMP_LEAVE_GROUP               0x17 /* Leave-group message      */
+
+/* Group  membership states */
+#define IGMP_GROUP_NON_MEMBER          0
+#define IGMP_GROUP_DELAYING_MEMBER     1
+#define IGMP_GROUP_IDLE_MEMBER         2
+
+/**
+ * IGMP packet format.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct igmp_msg {
+ PACK_STRUCT_FIELD(u8_t           igmp_msgtype);
+ PACK_STRUCT_FIELD(u8_t           igmp_maxresp);
+ PACK_STRUCT_FIELD(u16_t          igmp_checksum);
+ PACK_STRUCT_FIELD(ip_addr_p_t    igmp_group_address);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+
+static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
+static err_t  igmp_remove_group(struct igmp_group *group);
+static void   igmp_timeout( struct igmp_group *group);
+static void   igmp_start_timer(struct igmp_group *group, u8_t max_time);
+static void   igmp_stop_timer(struct igmp_group *group);
+static void   igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
+static err_t  igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
+static void   igmp_send(struct igmp_group *group, u8_t type);
+
+
+static struct igmp_group* igmp_group_list;
+static ip_addr_t     allsystems;
+static ip_addr_t     allrouters;
+
+
+/**
+ * Initialize the IGMP module
+ */
+void
+igmp_init(void)
+{
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
+
+  IP4_ADDR(&allsystems, 224, 0, 0, 1);
+  IP4_ADDR(&allrouters, 224, 0, 0, 2);
+}
+
+#ifdef LWIP_DEBUG
+/**
+ * Dump global IGMP groups list
+ */
+void
+igmp_dump_group_list()
+{ 
+  struct igmp_group *group = igmp_group_list;
+
+  while (group != NULL) {
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
+    ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
+    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
+    group = group->next;
+  }
+  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+}
+#else
+#define igmp_dump_group_list()
+#endif /* LWIP_DEBUG */
+
+/**
+ * Start IGMP processing on interface
+ *
+ * @param netif network interface on which start IGMP processing
+ */
+err_t
+igmp_start(struct netif *netif)
+{
+  struct igmp_group* group;
+
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
+
+  group = igmp_lookup_group(netif, &allsystems);
+
+  if (group != NULL) {
+    group->group_state = IGMP_GROUP_IDLE_MEMBER;
+    group->use++;
+
+    /* Allow the igmp messages at the MAC level */
+    if (netif->igmp_mac_filter != NULL) {
+      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
+      ip_addr_debug_print(IGMP_DEBUG, &allsystems);
+      LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+      netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
+    }
+
+    return ERR_OK;
+  }
+
+  return ERR_MEM;
+}
+
+/**
+ * Stop IGMP processing on interface
+ *
+ * @param netif network interface on which stop IGMP processing
+ */
+err_t
+igmp_stop(struct netif *netif)
+{
+  struct igmp_group *group = igmp_group_list;
+  struct igmp_group *prev  = NULL;
+  struct igmp_group *next;
+
+  /* look for groups joined on this interface further down the list */
+  while (group != NULL) {
+    next = group->next;
+    /* is it a group joined on this interface? */
+    if (group->netif == netif) {
+      /* is it the first group of the list? */
+      if (group == igmp_group_list) {
+        igmp_group_list = next;
+      }
+      /* is there a "previous" group defined? */
+      if (prev != NULL) {
+        prev->next = next;
+      }
+      /* disable the group at the MAC level */
+      if (netif->igmp_mac_filter != NULL) {
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
+        ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
+        LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+        netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
+      }
+      /* free group */
+      memp_free(MEMP_IGMP_GROUP, group);
+    } else {
+      /* change the "previous" */
+      prev = group;
+    }
+    /* move to "next" */
+    group = next;
+  }
+  return ERR_OK;
+}
+
+/**
+ * Report IGMP memberships for this interface
+ *
+ * @param netif network interface on which report IGMP memberships
+ */
+void
+igmp_report_groups(struct netif *netif)
+{
+  struct igmp_group *group = igmp_group_list;
+
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
+
+  while (group != NULL) {
+    if (group->netif == netif) {
+      igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
+    }
+    group = group->next;
+  }
+}
+
+/**
+ * Search for a group in the global igmp_group_list
+ *
+ * @param ifp the network interface for which to look
+ * @param addr the group ip address to search for
+ * @return a struct igmp_group* if the group has been found,
+ *         NULL if the group wasn't found.
+ */
+struct igmp_group *
+igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
+{
+  struct igmp_group *group = igmp_group_list;
+
+  while (group != NULL) {
+    if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
+      return group;
+    }
+    group = group->next;
+  }
+
+  /* to be clearer, we return NULL here instead of
+   * 'group' (which is also NULL at this point).
+   */
+  return NULL;
+}
+
+/**
+ * Search for a specific igmp group and create a new one if not found-
+ *
+ * @param ifp the network interface for which to look
+ * @param addr the group ip address to search
+ * @return a struct igmp_group*,
+ *         NULL on memory error.
+ */
+struct igmp_group *
+igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
+{
+  struct igmp_group *group = igmp_group_list;
+  
+  /* Search if the group already exists */
+  group = igmp_lookfor_group(ifp, addr);
+  if (group != NULL) {
+    /* Group already exists. */
+    return group;
+  }
+
+  /* Group doesn't exist yet, create a new one */
+  group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
+  if (group != NULL) {
+    group->netif              = ifp;
+    ip_addr_set(&(group->group_address), addr);
+    group->timer              = 0; /* Not running */
+    group->group_state        = IGMP_GROUP_NON_MEMBER;
+    group->last_reporter_flag = 0;
+    group->use                = 0;
+    group->next               = igmp_group_list;
+    
+    igmp_group_list = group;
+  }
+
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
+  ip_addr_debug_print(IGMP_DEBUG, addr);
+  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
+
+  return group;
+}
+
+/**
+ * Remove a group in the global igmp_group_list
+ *
+ * @param group the group to remove from the global igmp_group_list
+ * @return ERR_OK if group was removed from the list, an err_t otherwise
+ */
+static err_t
+igmp_remove_group(struct igmp_group *group)
+{
+  err_t err = ERR_OK;
+
+  /* Is it the first group? */
+  if (igmp_group_list == group) {
+    igmp_group_list = group->next;
+  } else {
+    /* look for group further down the list */
+    struct igmp_group *tmpGroup;
+    for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
+      if (tmpGroup->next == group) {
+        tmpGroup->next = group->next;
+        break;
+      }
+    }
+    /* Group not found in the global igmp_group_list */
+    if (tmpGroup == NULL)
+      err = ERR_ARG;
+  }
+  /* free group */
+  memp_free(MEMP_IGMP_GROUP, group);
+
+  return err;
+}
+
+/**
+ * Called from ip_input() if a new IGMP packet is received.
+ *
+ * @param p received igmp packet, p->payload pointing to the ip header
+ * @param inp network interface on which the packet was received
+ * @param dest destination ip address of the igmp packet
+ */
+void
+igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
+{
+  struct ip_hdr *    iphdr;
+  struct igmp_msg*   igmp;
+  struct igmp_group* group;
+  struct igmp_group* groupref;
+
+  IGMP_STATS_INC(igmp.recv);
+
+  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */    
+  iphdr = (struct ip_hdr *)p->payload;
+  if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
+    pbuf_free(p);
+    IGMP_STATS_INC(igmp.lenerr);
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
+    return;
+  }
+
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
+  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
+  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
+  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
+  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
+
+  /* Now calculate and check the checksum */
+  igmp = (struct igmp_msg *)p->payload;
+  if (inet_chksum(igmp, p->len)) {
+    pbuf_free(p);
+    IGMP_STATS_INC(igmp.chkerr);
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
+    return;
+  }
+
+  /* Packet is ok so find an existing group */
+  group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
+  
+  /* If group can be found or create... */
+  if (!group) {
+    pbuf_free(p);
+    IGMP_STATS_INC(igmp.drop);
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
+    return;
+  }
+
+  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
+  switch (igmp->igmp_msgtype) {
+   case IGMP_MEMB_QUERY: {
+     /* IGMP_MEMB_QUERY to the "all systems" address ? */
+     if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
+       /* THIS IS THE GENERAL QUERY */
+       LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
+
+       if (igmp->igmp_maxresp == 0) {
+         IGMP_STATS_INC(igmp.rx_v1);
+         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
+         igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
+       } else {
+         IGMP_STATS_INC(igmp.rx_general);
+       }
+
+       groupref = igmp_group_list;
+       while (groupref) {
+         /* Do not send messages on the all systems group address! */
+         if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
+           igmp_delaying_member(groupref, igmp->igmp_maxresp);
+         }
+         groupref = groupref->next;
+       }
+     } else {
+       /* IGMP_MEMB_QUERY to a specific group ? */
+       if (!ip_addr_isany(&igmp->igmp_group_address)) {
+         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
+         ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
+         if (ip_addr_cmp(dest, &allsystems)) {
+           ip_addr_t groupaddr;
+           LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
+           /* we first need to re-look for the group since we used dest last time */
+           ip_addr_copy(groupaddr, igmp->igmp_group_address);
+           group = igmp_lookfor_group(inp, &groupaddr);
+         } else {
+           LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
+         }
+
+         if (group != NULL) {
+           IGMP_STATS_INC(igmp.rx_group);
+           igmp_delaying_member(group, igmp->igmp_maxresp);
+         } else {
+           IGMP_STATS_INC(igmp.drop);
+         }
+       } else {
+         IGMP_STATS_INC(igmp.proterr);
+       }
+     }
+     break;
+   }
+   case IGMP_V2_MEMB_REPORT: {
+     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
+     IGMP_STATS_INC(igmp.rx_report);
+     if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
+       /* This is on a specific group we have already looked up */
+       group->timer = 0; /* stopped */
+       group->group_state = IGMP_GROUP_IDLE_MEMBER;
+       group->last_reporter_flag = 0;
+     }
+     break;
+   }
+   default: {
+     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
+       igmp->igmp_msgtype, group->group_state, &group, group->netif));
+     IGMP_STATS_INC(igmp.proterr);
+     break;
+   }
+  }
+
+  pbuf_free(p);
+  return;
+}
+
+/**
+ * Join a group on one network interface.
+ *
+ * @param ifaddr ip address of the network interface which should join a new group
+ * @param groupaddr the ip address of the group which to join
+ * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
+ */
+err_t
+igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
+{
+  err_t              err = ERR_VAL; /* no matching interface */
+  struct igmp_group *group;
+  struct netif      *netif;
+
+  /* make sure it is multicast address */
+  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
+  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
+
+  /* loop through netif's */
+  netif = netif_list;
+  while (netif != NULL) {
+    /* Should we join this interface ? */
+    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
+      /* find group or create a new one if not found */
+      group = igmp_lookup_group(netif, groupaddr);
+
+      if (group != NULL) {
+        /* This should create a new group, check the state to make sure */
+        if (group->group_state != IGMP_GROUP_NON_MEMBER) {
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
+        } else {
+          /* OK - it was new group */
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
+          ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+
+          /* If first use of the group, allow the group at the MAC level */
+          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
+            ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
+          }
+
+          IGMP_STATS_INC(igmp.tx_join);
+          igmp_send(group, IGMP_V2_MEMB_REPORT);
+
+          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
+
+          /* Need to work out where this timer comes from */
+          group->group_state = IGMP_GROUP_DELAYING_MEMBER;
+        }
+        /* Increment group use */
+        group->use++;
+        /* Join on this interface */
+        err = ERR_OK;
+      } else {
+        /* Return an error even if some network interfaces are joined */
+        /** @todo undo any other netif already joined */
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
+        return ERR_MEM;
+      }
+    }
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+
+  return err;
+}
+
+/**
+ * Leave a group on one network interface.
+ *
+ * @param ifaddr ip address of the network interface which should leave a group
+ * @param groupaddr the ip address of the group which to leave
+ * @return ERR_OK if group was left on the netif(s), an err_t otherwise
+ */
+err_t
+igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
+{
+  err_t              err = ERR_VAL; /* no matching interface */
+  struct igmp_group *group;
+  struct netif      *netif;
+
+  /* make sure it is multicast address */
+  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
+  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
+
+  /* loop through netif's */
+  netif = netif_list;
+  while (netif != NULL) {
+    /* Should we leave this interface ? */
+    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
+      /* find group */
+      group = igmp_lookfor_group(netif, groupaddr);
+
+      if (group != NULL) {
+        /* Only send a leave if the flag is set according to the state diagram */
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
+        ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+        LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+
+        /* If there is no other use of the group */
+        if (group->use <= 1) {
+          /* If we are the last reporter for this group */
+          if (group->last_reporter_flag) {
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
+            IGMP_STATS_INC(igmp.tx_leave);
+            igmp_send(group, IGMP_LEAVE_GROUP);
+          }
+          
+          /* Disable the group at the MAC level */
+          if (netif->igmp_mac_filter != NULL) {
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
+            ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
+          }
+          
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
+          ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));          
+          
+          /* Free the group */
+          igmp_remove_group(group);
+        } else {
+          /* Decrement group use */
+          group->use--;
+        }
+        /* Leave on this interface */
+        err = ERR_OK;
+      } else {
+        /* It's not a fatal error on "leavegroup" */
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
+      }
+    }
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+
+  return err;
+}
+
+/**
+ * The igmp timer function (both for NO_SYS=1 and =0)
+ * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
+ */
+void
+igmp_tmr(void)
+{
+  struct igmp_group *group = igmp_group_list;
+
+  while (group != NULL) {
+    if (group->timer > 0) {
+      group->timer--;
+      if (group->timer == 0) {
+        igmp_timeout(group);
+      }
+    }
+    group = group->next;
+  }
+}
+
+/**
+ * Called if a timeout for one group is reached.
+ * Sends a report for this group.
+ *
+ * @param group an igmp_group for which a timeout is reached
+ */
+static void
+igmp_timeout(struct igmp_group *group)
+{
+  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
+  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
+    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
+    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
+
+    IGMP_STATS_INC(igmp.tx_report);
+    igmp_send(group, IGMP_V2_MEMB_REPORT);
+  }
+}
+
+/**
+ * Start a timer for an igmp group
+ *
+ * @param group the igmp_group for which to start a timer
+ * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
+ *        every call to igmp_tmr())
+ */
+static void
+igmp_start_timer(struct igmp_group *group, u8_t max_time)
+{
+  /* ensure the input value is > 0 */
+  if (max_time == 0) {
+    max_time = 1;
+  }
+  /* ensure the random value is > 0 */
+  group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
+}
+
+/**
+ * Stop a timer for an igmp_group
+ *
+ * @param group the igmp_group for which to stop the timer
+ */
+static void
+igmp_stop_timer(struct igmp_group *group)
+{
+  group->timer = 0;
+}
+
+/**
+ * Delaying membership report for a group if necessary
+ *
+ * @param group the igmp_group for which "delaying" membership report
+ * @param maxresp query delay
+ */
+static void
+igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
+{
+  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
+     ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
+      ((group->timer == 0) || (maxresp < group->timer)))) {
+    igmp_start_timer(group, maxresp);
+    group->group_state = IGMP_GROUP_DELAYING_MEMBER;
+  }
+}
+
+
+/**
+ * Sends an IP packet on a network interface. This function constructs the IP header
+ * and calculates the IP header checksum. If the source IP address is NULL,
+ * the IP address of the outgoing network interface is filled in as source address.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers
+ *         returns errors returned by netif->output
+ */
+static err_t
+igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
+{
+  /* This is the "router alert" option */
+  u16_t ra[2];
+  ra[0] = PP_HTONS(ROUTER_ALERT);
+  ra[1] = 0x0000; /* Router shall examine packet */
+  IGMP_STATS_INC(igmp.xmit);
+  return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
+}
+
+/**
+ * Send an igmp packet to a specific group.
+ *
+ * @param group the group to which to send the packet
+ * @param type the type of igmp packet to send
+ */
+static void
+igmp_send(struct igmp_group *group, u8_t type)
+{
+  struct pbuf*     p    = NULL;
+  struct igmp_msg* igmp = NULL;
+  ip_addr_t   src  = *IP_ADDR_ANY;
+  ip_addr_t*  dest = NULL;
+
+  /* IP header + "router alert" option + IGMP header */
+  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
+  
+  if (p) {
+    igmp = (struct igmp_msg *)p->payload;
+    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
+               (p->len >= sizeof(struct igmp_msg)));
+    ip_addr_copy(src, group->netif->ip_addr);
+     
+    if (type == IGMP_V2_MEMB_REPORT) {
+      dest = &(group->group_address);
+      ip_addr_copy(igmp->igmp_group_address, group->group_address);
+      group->last_reporter_flag = 1; /* Remember we were the last to report */
+    } else {
+      if (type == IGMP_LEAVE_GROUP) {
+        dest = &allrouters;
+        ip_addr_copy(igmp->igmp_group_address, group->group_address);
+      }
+    }
+
+    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
+      igmp->igmp_msgtype  = type;
+      igmp->igmp_maxresp  = 0;
+      igmp->igmp_checksum = 0;
+      igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
+
+      igmp_ip_output_if(p, &src, dest, group->netif);
+    }
+
+    pbuf_free(p);
+  } else {
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
+    IGMP_STATS_INC(igmp.memerr);
+  }
+}
+
+#endif /* LWIP_IGMP */
diff --git a/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/inet.c b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/inet.c
new file mode 100644
index 0000000..e283a57
--- /dev/null
+++ b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/inet.c
@@ -0,0 +1,42 @@
+/**
+ * @file
+ * Functions common to all TCP/IPv4 modules, such as the byte order functions.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/inet.h"
+
diff --git a/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/inet_chksum.c b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/inet_chksum.c
new file mode 100644
index 0000000..960252f
--- /dev/null
+++ b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/inet_chksum.c
@@ -0,0 +1,450 @@
+/**
+ * @file
+ * Incluse internet checksum functions.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/inet_chksum.h"
+#include "lwip/def.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/* These are some reference implementations of the checksum algorithm, with the
+ * aim of being simple, correct and fully portable. Checksumming is the
+ * first thing you would want to optimize for your platform. If you create
+ * your own version, link it in and in your cc.h put:
+ * 
+ * #define LWIP_CHKSUM <your_checksum_routine> 
+ *
+ * Or you can select from the implementations below by defining
+ * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
+ */
+
+#ifndef LWIP_CHKSUM
+# define LWIP_CHKSUM lwip_standard_chksum
+# ifndef LWIP_CHKSUM_ALGORITHM
+#  define LWIP_CHKSUM_ALGORITHM 2
+# endif
+#endif
+/* If none set: */
+#ifndef LWIP_CHKSUM_ALGORITHM
+# define LWIP_CHKSUM_ALGORITHM 0
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
+/**
+ * lwip checksum
+ *
+ * @param dataptr points to start of data to be summed at any boundary
+ * @param len length of data to be summed
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ *
+ * @note accumulator size limits summable length to 64k
+ * @note host endianess is irrelevant (p3 RFC1071)
+ */
+static u16_t
+lwip_standard_chksum(void *dataptr, u16_t len)
+{
+  u32_t acc;
+  u16_t src;
+  u8_t *octetptr;
+
+  acc = 0;
+  /* dataptr may be at odd or even addresses */
+  octetptr = (u8_t*)dataptr;
+  while (len > 1) {
+    /* declare first octet as most significant
+       thus assume network order, ignoring host order */
+    src = (*octetptr) << 8;
+    octetptr++;
+    /* declare second octet as least significant */
+    src |= (*octetptr);
+    octetptr++;
+    acc += src;
+    len -= 2;
+  }
+  if (len > 0) {
+    /* accumulate remaining octet */
+    src = (*octetptr) << 8;
+    acc += src;
+  }
+  /* add deferred carry bits */
+  acc = (acc >> 16) + (acc & 0x0000ffffUL);
+  if ((acc & 0xffff0000UL) != 0) {
+    acc = (acc >> 16) + (acc & 0x0000ffffUL);
+  }
+  /* This maybe a little confusing: reorder sum using htons()
+     instead of ntohs() since it has a little less call overhead.
+     The caller must invert bits for Internet sum ! */
+  return htons((u16_t)acc);
+}
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
+/*
+ * Curt McDowell
+ * Broadcom Corp.
+ * csm@broadcom.com
+ *
+ * IP checksum two bytes at a time with support for
+ * unaligned buffer.
+ * Works for len up to and including 0x20000.
+ * by Curt McDowell, Broadcom Corp. 12/08/2005
+ *
+ * @param dataptr points to start of data to be summed at any boundary
+ * @param len length of data to be summed
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ */
+
+static u16_t
+lwip_standard_chksum(void *dataptr, int len)
+{
+  u8_t *pb = (u8_t *)dataptr;
+  u16_t *ps, t = 0;
+  u32_t sum = 0;
+  int odd = ((mem_ptr_t)pb & 1);
+
+  /* Get aligned to u16_t */
+  if (odd && len > 0) {
+    ((u8_t *)&t)[1] = *pb++;
+    len--;
+  }
+
+  /* Add the bulk of the data */
+  ps = (u16_t *)(void *)pb;
+  while (len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  /* Consume left-over byte, if any */
+  if (len > 0) {
+    ((u8_t *)&t)[0] = *(u8_t *)ps;
+  }
+
+  /* Add end bytes */
+  sum += t;
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  sum = FOLD_U32T(sum);
+  sum = FOLD_U32T(sum);
+
+  /* Swap if alignment was odd */
+  if (odd) {
+    sum = SWAP_BYTES_IN_WORD(sum);
+  }
+
+  return (u16_t)sum;
+}
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
+/**
+ * An optimized checksum routine. Basically, it uses loop-unrolling on
+ * the checksum loop, treating the head and tail bytes specially, whereas
+ * the inner loop acts on 8 bytes at a time. 
+ *
+ * @arg start of buffer to be checksummed. May be an odd byte address.
+ * @len number of bytes in the buffer to be checksummed.
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ * 
+ * by Curt McDowell, Broadcom Corp. December 8th, 2005
+ */
+
+static u16_t
+lwip_standard_chksum(void *dataptr, int len)
+{
+  u8_t *pb = (u8_t *)dataptr;
+  u16_t *ps, t = 0;
+  u32_t *pl;
+  u32_t sum = 0, tmp;
+  /* starts at odd byte address? */
+  int odd = ((mem_ptr_t)pb & 1);
+
+  if (odd && len > 0) {
+    ((u8_t *)&t)[1] = *pb++;
+    len--;
+  }
+
+  ps = (u16_t *)pb;
+
+  if (((mem_ptr_t)ps & 3) && len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  pl = (u32_t *)ps;
+
+  while (len > 7)  {
+    tmp = sum + *pl++;          /* ping */
+    if (tmp < sum) {
+      tmp++;                    /* add back carry */
+    }
+
+    sum = tmp + *pl++;          /* pong */
+    if (sum < tmp) {
+      sum++;                    /* add back carry */
+    }
+
+    len -= 8;
+  }
+
+  /* make room in upper bits */
+  sum = FOLD_U32T(sum);
+
+  ps = (u16_t *)pl;
+
+  /* 16-bit aligned word remaining? */
+  while (len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  /* dangling tail byte remaining? */
+  if (len > 0) {                /* include odd byte */
+    ((u8_t *)&t)[0] = *(u8_t *)ps;
+  }
+
+  sum += t;                     /* add end bytes */
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  sum = FOLD_U32T(sum);
+  sum = FOLD_U32T(sum);
+
+  if (odd) {
+    sum = SWAP_BYTES_IN_WORD(sum);
+  }
+
+  return (u16_t)sum;
+}
+#endif
+
+/* inet_chksum_pseudo:
+ *
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
+ * IP addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ip address (used for checksum of pseudo header)
+ * @param dst destination ip address (used for checksum of pseudo header)
+ * @param proto ip protocol (used for checksum of pseudo header)
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pseudo(struct pbuf *p,
+       ip_addr_t *src, ip_addr_t *dest,
+       u8_t proto, u16_t proto_len)
+{
+  u32_t acc;
+  u32_t addr;
+  struct pbuf *q;
+  u8_t swapped;
+
+  acc = 0;
+  swapped = 0;
+  /* iterate through all pbuf in chain */
+  for(q = p; q != NULL; q = q->next) {
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
+      (void *)q, (void *)q->next));
+    acc += LWIP_CHKSUM(q->payload, q->len);
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
+    /* just executing this next line is probably faster that the if statement needed
+       to check whether we really need to execute it, and does no harm */
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+  addr = ip4_addr_get_u32(src);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  addr = ip4_addr_get_u32(dest);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  acc += (u32_t)htons((u16_t)proto);
+  acc += (u32_t)htons(proto_len);
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* inet_chksum_pseudo:
+ *
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
+ * IP addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ip address (used for checksum of pseudo header)
+ * @param dst destination ip address (used for checksum of pseudo header)
+ * @param proto ip protocol (used for checksum of pseudo header)
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pseudo_partial(struct pbuf *p,
+       ip_addr_t *src, ip_addr_t *dest,
+       u8_t proto, u16_t proto_len, u16_t chksum_len)
+{
+  u32_t acc;
+  u32_t addr;
+  struct pbuf *q;
+  u8_t swapped;
+  u16_t chklen;
+
+  acc = 0;
+  swapped = 0;
+  /* iterate through all pbuf in chain */
+  for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
+      (void *)q, (void *)q->next));
+    chklen = q->len;
+    if (chklen > chksum_len) {
+      chklen = chksum_len;
+    }
+    acc += LWIP_CHKSUM(q->payload, chklen);
+    chksum_len -= chklen;
+    LWIP_ASSERT("delete me", chksum_len < 0x7fff);
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
+    /* fold the upper bit down */
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+  addr = ip4_addr_get_u32(src);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  addr = ip4_addr_get_u32(dest);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  acc += (u32_t)htons((u16_t)proto);
+  acc += (u32_t)htons(proto_len);
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* inet_chksum:
+ *
+ * Calculates the Internet checksum over a portion of memory. Used primarily for IP
+ * and ICMP.
+ *
+ * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
+ * @param len length of the buffer to calculate the checksum
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+
+u16_t
+inet_chksum(void *dataptr, u16_t len)
+{
+  return ~LWIP_CHKSUM(dataptr, len);
+}
+
+/**
+ * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
+ * inet_chksum only pbufs are used).
+ *
+ * @param p pbuf chain over that the checksum should be calculated
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pbuf(struct pbuf *p)
+{
+  u32_t acc;
+  struct pbuf *q;
+  u8_t swapped;
+
+  acc = 0;
+  swapped = 0;
+  for(q = p; q != NULL; q = q->next) {
+    acc += LWIP_CHKSUM(q->payload, q->len);
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
+ * like MEMCPY but generates a checksum at the same time. Since this is a
+ * performance-sensitive function, you might want to create your own version
+ * in assembly targeted at your hardware by defining it in lwipopts.h:
+ *   #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
+ */
+
+#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
+/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
+ * For architectures with big caches, data might still be in cache when
+ * generating the checksum after copying.
+ */
+u16_t
+lwip_chksum_copy(void *dst, const void *src, u16_t len)
+{
+  MEMCPY(dst, src, len);
+  return LWIP_CHKSUM(dst, len);
+}
+#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */
diff --git a/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip.c b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip.c
new file mode 100644
index 0000000..6f24871
--- /dev/null
+++ b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip.c
@@ -0,0 +1,857 @@
+/**
+ * @file
+ * This is the IPv4 layer implementation for incoming and outgoing IP traffic.
+ * 
+ * @see ip_frag.c
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/ip_frag.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp.h"
+#include "lwip/igmp.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/snmp.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+#include "lwip/stats.h"
+#include "arch/perf.h"
+
+#include <string.h>
+
+/** Set this to 0 in the rare case of wanting to call an extra function to
+ * generate the IP checksum (in contrast to calculating it on-the-fly). */
+#ifndef LWIP_INLINE_IP_CHKSUM
+#define LWIP_INLINE_IP_CHKSUM   1
+#endif
+#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
+#define CHECKSUM_GEN_IP_INLINE  1
+#else
+#define CHECKSUM_GEN_IP_INLINE  0
+#endif
+
+#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
+#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
+
+/** Some defines for DHCP to let link-layer-addressed packets through while the
+ * netif is down.
+ * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
+ * to return 1 if the port is accepted and 0 if the port is not accepted.
+ */
+#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
+/* accept DHCP client port and custom port */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
+         || (LWIP_IP_ACCEPT_UDP_PORT(port)))
+#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+/* accept custom port only */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
+#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+/* accept DHCP client port only */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
+#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+
+#else /* LWIP_DHCP */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
+#endif /* LWIP_DHCP */
+
+/**
+ * The interface that provided the packet for the current callback
+ * invocation.
+ */
+struct netif *current_netif;
+
+/**
+ * Header of the input packet currently being processed.
+ */
+const struct ip_hdr *current_header;
+/** Source IP address of current_header */
+ip_addr_t current_iphdr_src;
+/** Destination IP address of current_header */
+ip_addr_t current_iphdr_dest;
+
+/** The IP header ID of the next outgoing IP packet */
+static u16_t ip_id;
+
+/**
+ * Finds the appropriate network interface for a given IP address. It
+ * searches the list of network interfaces linearly. A match is found
+ * if the masked IP address of the network interface equals the masked
+ * IP address given to the function.
+ *
+ * @param dest the destination IP address for which to find the route
+ * @return the netif on which to send to reach dest
+ */
+struct netif *
+ip_route(ip_addr_t *dest)
+{
+  struct netif *netif;
+
+  /* iterate through netifs */
+  for(netif = netif_list; netif != NULL; netif = netif->next) {
+    /* network mask matches? */
+    if (netif_is_up(netif)) {
+      if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
+        /* return netif on which to forward IP packet */
+        return netif;
+      }
+    }
+  }
+  if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    snmp_inc_ipoutnoroutes();
+    return NULL;
+  }
+  /* no matching netif found, use default netif */
+  return netif_default;
+}
+
+#if IP_FORWARD
+/**
+ * Forwards an IP packet. It finds an appropriate route for the
+ * packet, decrements the TTL value of the packet, adjusts the
+ * checksum and outputs the packet on the appropriate interface.
+ *
+ * @param p the packet to forward (p->payload points to IP header)
+ * @param iphdr the IP header of the input packet
+ * @param inp the netif on which this packet was received
+ */
+static void
+ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
+{
+  struct netif *netif;
+
+  PERF_START;
+
+  /* RFC3927 2.7: do not forward link-local addresses */
+  if (ip_addr_islinklocal(&current_iphdr_dest)) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+      ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+    goto return_noroute;
+  }
+
+  /* Find network interface where to forward this IP packet to. */
+  netif = ip_route(&current_iphdr_dest);
+  if (netif == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
+      ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+      ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+    goto return_noroute;
+  }
+  /* Do not forward packets onto the same network interface on which
+   * they arrived. */
+  if (netif == inp) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
+    goto return_noroute;
+  }
+
+  /* decrement TTL */
+  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
+  /* send ICMP if TTL == 0 */
+  if (IPH_TTL(iphdr) == 0) {
+    snmp_inc_ipinhdrerrors();
+#if LWIP_ICMP
+    /* Don't send ICMP messages in response to ICMP messages */
+    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
+      icmp_time_exceeded(p, ICMP_TE_TTL);
+    }
+#endif /* LWIP_ICMP */
+    return;
+  }
+
+  /* Incrementally update the IP checksum. */
+  if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
+  } else {
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
+  }
+
+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+    ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+
+  IP_STATS_INC(ip.fw);
+  IP_STATS_INC(ip.xmit);
+  snmp_inc_ipforwdatagrams();
+
+  PERF_STOP("ip_forward");
+  /* transmit pbuf on chosen interface */
+  netif->output(netif, p, &current_iphdr_dest);
+  return;
+return_noroute:
+  snmp_inc_ipoutnoroutes();
+}
+#endif /* IP_FORWARD */
+
+/**
+ * This function is called by the network interface device driver when
+ * an IP packet is received. The function does the basic checks of the
+ * IP header such as packet size being at least larger than the header
+ * size etc. If the packet was not destined for us, the packet is
+ * forwarded (using ip_forward). The IP checksum is always checked.
+ *
+ * Finally, the packet is sent to the upper layer protocol input function.
+ * 
+ * @param p the received IP packet (p->payload points to IP header)
+ * @param inp the netif on which this packet was received
+ * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
+ *         processed, but currently always returns ERR_OK)
+ */
+err_t
+ip_input(struct pbuf *p, struct netif *inp)
+{
+  struct ip_hdr *iphdr;
+  struct netif *netif;
+  u16_t iphdr_hlen;
+  u16_t iphdr_len;
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  int check_ip_src=1;
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+
+  IP_STATS_INC(ip.recv);
+  snmp_inc_ipinreceives();
+
+  /* identify the IP header */
+  iphdr = (struct ip_hdr *)p->payload;
+  if (IPH_V(iphdr) != 4) {
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
+    ip_debug_print(p);
+    pbuf_free(p);
+    IP_STATS_INC(ip.err);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipinhdrerrors();
+    return ERR_OK;
+  }
+
+  /* obtain IP header length in number of 32-bit words */
+  iphdr_hlen = IPH_HL(iphdr);
+  /* calculate IP header length in bytes */
+  iphdr_hlen *= 4;
+  /* obtain ip length in bytes */
+  iphdr_len = ntohs(IPH_LEN(iphdr));
+
+  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
+  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
+    if (iphdr_hlen > p->len) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
+        iphdr_hlen, p->len));
+    }
+    if (iphdr_len > p->tot_len) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
+        iphdr_len, p->tot_len));
+    }
+    /* free (drop) packet pbufs */
+    pbuf_free(p);
+    IP_STATS_INC(ip.lenerr);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipindiscards();
+    return ERR_OK;
+  }
+
+  /* verify checksum */
+#if CHECKSUM_CHECK_IP
+  if (inet_chksum(iphdr, iphdr_hlen) != 0) {
+
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+      ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
+    ip_debug_print(p);
+    pbuf_free(p);
+    IP_STATS_INC(ip.chkerr);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipinhdrerrors();
+    return ERR_OK;
+  }
+#endif
+
+  /* Trim pbuf. This should have been done at the netif layer,
+   * but we'll do it anyway just to be sure that its done. */
+  pbuf_realloc(p, iphdr_len);
+
+  /* copy IP addresses to aligned ip_addr_t */
+  ip_addr_copy(current_iphdr_dest, iphdr->dest);
+  ip_addr_copy(current_iphdr_src, iphdr->src);
+
+  /* match packet against an interface, i.e. is this packet for us? */
+#if LWIP_IGMP
+  if (ip_addr_ismulticast(&current_iphdr_dest)) {
+    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &current_iphdr_dest))) {
+      netif = inp;
+    } else {
+      netif = NULL;
+    }
+  } else
+#endif /* LWIP_IGMP */
+  {
+    /* start trying with inp. if that's not acceptable, start walking the
+       list of configured netifs.
+       'first' is used as a boolean to mark whether we started walking the list */
+    int first = 1;
+    netif = inp;
+    do {
+      LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
+          ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
+          ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
+          ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
+          ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
+
+      /* interface is up and configured? */
+      if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
+        /* unicast to this interface address? */
+        if (ip_addr_cmp(&current_iphdr_dest, &(netif->ip_addr)) ||
+            /* or broadcast on this interface network address? */
+            ip_addr_isbroadcast(&current_iphdr_dest, netif)) {
+          LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
+              netif->name[0], netif->name[1]));
+          /* break out of for loop */
+          break;
+        }
+#if LWIP_AUTOIP
+        /* connections to link-local addresses must persist after changing
+           the netif's address (RFC3927 ch. 1.9) */
+        if ((netif->autoip != NULL) &&
+            ip_addr_cmp(&current_iphdr_dest, &(netif->autoip->llipaddr))) {
+          LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
+              netif->name[0], netif->name[1]));
+          /* break out of for loop */
+          break;
+        }
+#endif /* LWIP_AUTOIP */
+      }
+      if (first) {
+        first = 0;
+        netif = netif_list;
+      } else {
+        netif = netif->next;
+      }
+      if (netif == inp) {
+        netif = netif->next;
+      }
+    } while(netif != NULL);
+  }
+
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
+   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
+   * According to RFC 1542 section 3.1.1, referred by RFC 2131).
+   *
+   * If you want to accept private broadcast communication while a netif is down,
+   * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
+   *
+   * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
+   */
+  if (netif == NULL) {
+    /* remote port is DHCP server? */
+    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
+      struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
+        ntohs(udphdr->dest)));
+      if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
+        netif = inp;
+        check_ip_src = 0;
+      }
+    }
+  }
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+
+  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
+  if (check_ip_src && !ip_addr_isany(&current_iphdr_src))
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+  {  if ((ip_addr_isbroadcast(&current_iphdr_src, inp)) ||
+         (ip_addr_ismulticast(&current_iphdr_src))) {
+      /* packet source is not valid */
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
+      /* free (drop) packet pbufs */
+      pbuf_free(p);
+      IP_STATS_INC(ip.drop);
+      snmp_inc_ipinaddrerrors();
+      snmp_inc_ipindiscards();
+      return ERR_OK;
+    }
+  }
+
+  /* packet not for us? */
+  if (netif == NULL) {
+    /* packet not for us, route or discard */
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
+#if IP_FORWARD
+    /* non-broadcast packet? */
+    if (!ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
+      /* try to forward IP packet on (other) interfaces */
+      ip_forward(p, iphdr, inp);
+    } else
+#endif /* IP_FORWARD */
+    {
+      snmp_inc_ipinaddrerrors();
+      snmp_inc_ipindiscards();
+    }
+    pbuf_free(p);
+    return ERR_OK;
+  }
+  /* packet consists of multiple fragments? */
+  if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
+#if IP_REASSEMBLY /* packet fragment reassembly code present? */
+    LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
+      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
+    /* reassemble the packet*/
+    p = ip_reass(p);
+    /* packet not fully reassembled yet? */
+    if (p == NULL) {
+      return ERR_OK;
+    }
+    iphdr = (struct ip_hdr *)p->payload;
+#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
+    pbuf_free(p);
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
+      ntohs(IPH_OFFSET(iphdr))));
+    IP_STATS_INC(ip.opterr);
+    IP_STATS_INC(ip.drop);
+    /* unsupported protocol feature */
+    snmp_inc_ipinunknownprotos();
+    return ERR_OK;
+#endif /* IP_REASSEMBLY */
+  }
+
+#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
+
+#if LWIP_IGMP
+  /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
+  if((iphdr_hlen > IP_HLEN) &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
+#else
+  if (iphdr_hlen > IP_HLEN) {
+#endif /* LWIP_IGMP */
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
+    pbuf_free(p);
+    IP_STATS_INC(ip.opterr);
+    IP_STATS_INC(ip.drop);
+    /* unsupported protocol feature */
+    snmp_inc_ipinunknownprotos();
+    return ERR_OK;
+  }
+#endif /* IP_OPTIONS_ALLOWED == 0 */
+
+  /* send to upper layers */
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
+  ip_debug_print(p);
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
+
+  current_netif = inp;
+  current_header = iphdr;
+
+#if LWIP_RAW
+  /* raw input did not eat the packet? */
+  if (raw_input(p, inp) == 0)
+#endif /* LWIP_RAW */
+  {
+
+    switch (IPH_PROTO(iphdr)) {
+#if LWIP_UDP
+    case IP_PROTO_UDP:
+#if LWIP_UDPLITE
+    case IP_PROTO_UDPLITE:
+#endif /* LWIP_UDPLITE */
+      snmp_inc_ipindelivers();
+      udp_input(p, inp);
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+    case IP_PROTO_TCP:
+      snmp_inc_ipindelivers();
+      tcp_input(p, inp);
+      break;
+#endif /* LWIP_TCP */
+#if LWIP_ICMP
+    case IP_PROTO_ICMP:
+      snmp_inc_ipindelivers();
+      icmp_input(p, inp);
+      break;
+#endif /* LWIP_ICMP */
+#if LWIP_IGMP
+    case IP_PROTO_IGMP:
+      igmp_input(p, inp, &current_iphdr_dest);
+      break;
+#endif /* LWIP_IGMP */
+    default:
+#if LWIP_ICMP
+      /* send ICMP destination protocol unreachable unless is was a broadcast */
+      if (!ip_addr_isbroadcast(&current_iphdr_dest, inp) &&
+          !ip_addr_ismulticast(&current_iphdr_dest)) {
+        p->payload = iphdr;
+        icmp_dest_unreach(p, ICMP_DUR_PROTO);
+      }
+#endif /* LWIP_ICMP */
+      pbuf_free(p);
+
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
+
+      IP_STATS_INC(ip.proterr);
+      IP_STATS_INC(ip.drop);
+      snmp_inc_ipinunknownprotos();
+    }
+  }
+
+  current_netif = NULL;
+  current_header = NULL;
+  ip_addr_set_any(&current_iphdr_src);
+  ip_addr_set_any(&current_iphdr_dest);
+
+  return ERR_OK;
+}
+
+/**
+ * Sends an IP packet on a network interface. This function constructs
+ * the IP header and calculates the IP header checksum. If the source
+ * IP address is NULL, the IP address of the outgoing network
+ * interface is filled in as source address.
+ * If the destination IP address is IP_HDRINCL, p is assumed to already
+ * include an IP header and p->payload points to it instead of the data.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers
+ *         returns errors returned by netif->output
+ *
+ * @note ip_id: RFC791 "some host may be able to simply use
+ *  unique identifiers independent of destination"
+ */
+err_t
+ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+             u8_t ttl, u8_t tos,
+             u8_t proto, struct netif *netif)
+{
+#if IP_OPTIONS_SEND
+  return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
+}
+
+/**
+ * Same as ip_output_if() but with the possibility to include IP options:
+ *
+ * @ param ip_options pointer to the IP options, copied into the IP header
+ * @ param optlen length of ip_options
+ */
+err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
+       u16_t optlen)
+{
+#endif /* IP_OPTIONS_SEND */
+  struct ip_hdr *iphdr;
+  ip_addr_t dest_addr;
+#if CHECKSUM_GEN_IP_INLINE
+  u32_t chk_sum = 0;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  snmp_inc_ipoutrequests();
+
+  /* Should the IP header be generated or is it already included in p? */
+  if (dest != IP_HDRINCL) {
+    u16_t ip_hlen = IP_HLEN;
+#if IP_OPTIONS_SEND
+    u16_t optlen_aligned = 0;
+    if (optlen != 0) {
+#if CHECKSUM_GEN_IP_INLINE
+      int i;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+      /* round up to a multiple of 4 */
+      optlen_aligned = ((optlen + 3) & ~3);
+      ip_hlen += optlen_aligned;
+      /* First write in the IP options */
+      if (pbuf_header(p, optlen_aligned)) {
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
+        IP_STATS_INC(ip.err);
+        snmp_inc_ipoutdiscards();
+        return ERR_BUF;
+      }
+      MEMCPY(p->payload, ip_options, optlen);
+      if (optlen < optlen_aligned) {
+        /* zero the remaining bytes */
+        memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
+      }
+#if CHECKSUM_GEN_IP_INLINE
+      for (i = 0; i < optlen_aligned/2; i++) {
+        chk_sum += ((u16_t*)p->payload)[i];
+      }
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    }
+#endif /* IP_OPTIONS_SEND */
+    /* generate IP header */
+    if (pbuf_header(p, IP_HLEN)) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
+
+      IP_STATS_INC(ip.err);
+      snmp_inc_ipoutdiscards();
+      return ERR_BUF;
+    }
+
+    iphdr = (struct ip_hdr *)p->payload;
+    LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
+               (p->len >= sizeof(struct ip_hdr)));
+
+    IPH_TTL_SET(iphdr, ttl);
+    IPH_PROTO_SET(iphdr, proto);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += LWIP_MAKE_U16(proto, ttl);
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+    /* dest cannot be NULL here */
+    ip_addr_copy(iphdr->dest, *dest);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
+    chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+    IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += iphdr->_v_hl_tos;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    IPH_LEN_SET(iphdr, htons(p->tot_len));
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += iphdr->_len;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    IPH_OFFSET_SET(iphdr, 0);
+    IPH_ID_SET(iphdr, htons(ip_id));
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += iphdr->_id;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    ++ip_id;
+
+    if (ip_addr_isany(src)) {
+      ip_addr_copy(iphdr->src, netif->ip_addr);
+    } else {
+      /* src cannot be NULL here */
+      ip_addr_copy(iphdr->src, *src);
+    }
+
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
+    chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
+    chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
+    chk_sum = (chk_sum >> 16) + chk_sum;
+    chk_sum = ~chk_sum;
+    iphdr->_chksum = chk_sum; /* network order */
+#else /* CHECKSUM_GEN_IP_INLINE */
+    IPH_CHKSUM_SET(iphdr, 0);
+#if CHECKSUM_GEN_IP
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
+#endif
+#endif /* CHECKSUM_GEN_IP_INLINE */
+  } else {
+    /* IP header already included in p */
+    iphdr = (struct ip_hdr *)p->payload;
+    ip_addr_copy(dest_addr, iphdr->dest);
+    dest = &dest_addr;
+  }
+
+  IP_STATS_INC(ip.xmit);
+
+  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
+  ip_debug_print(p);
+
+#if ENABLE_LOOPBACK
+  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);
+  }
+#if LWIP_IGMP
+  if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
+    netif_loop_output(netif, p, dest);
+  }
+#endif /* LWIP_IGMP */
+#endif /* ENABLE_LOOPBACK */
+#if IP_FRAG
+  /* don't fragment if interface has mtu set to 0 [loopif] */
+  if (netif->mtu && (p->tot_len > netif->mtu)) {
+    return ip_frag(p, netif, dest);
+  }
+#endif /* IP_FRAG */
+
+  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
+  return netif->output(netif, p, dest);
+}
+
+/**
+ * Simple interface to ip_output_if. It finds the outgoing network
+ * interface and calls upon ip_output_if to do the actual work.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ *
+ * @return ERR_RTE if no route is found
+ *         see ip_output_if() for more return values
+ */
+err_t
+ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+          u8_t ttl, u8_t tos, u8_t proto)
+{
+  struct netif *netif;
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  if ((netif = ip_route(dest)) == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    return ERR_RTE;
+  }
+
+  return ip_output_if(p, src, dest, ttl, tos, proto, netif);
+}
+
+#if LWIP_NETIF_HWADDRHINT
+/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
+ *  before calling ip_output_if.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param addr_hint address hint pointer set to netif->addr_hint before
+ *        calling ip_output_if()
+ *
+ * @return ERR_RTE if no route is found
+ *         see ip_output_if() for more return values
+ */
+err_t
+ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
+{
+  struct netif *netif;
+  err_t err;
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  if ((netif = ip_route(dest)) == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    return ERR_RTE;
+  }
+
+  netif->addr_hint = addr_hint;
+  err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
+  netif->addr_hint = NULL;
+
+  return err;
+}
+#endif /* LWIP_NETIF_HWADDRHINT*/
+
+#if IP_DEBUG
+/* Print an IP header by using LWIP_DEBUGF
+ * @param p an IP packet, p->payload pointing to the IP header
+ */
+void
+ip_debug_print(struct pbuf *p)
+{
+  struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
+  u8_t *payload;
+
+  payload = (u8_t *)iphdr + IP_HLEN;
+
+  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",
+                    IPH_V(iphdr),
+                    IPH_HL(iphdr),
+                    IPH_TOS(iphdr),
+                    ntohs(IPH_LEN(iphdr))));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",
+                    ntohs(IPH_ID(iphdr)),
+                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",
+                    IPH_TTL(iphdr),
+                    IPH_PROTO(iphdr),
+                    ntohs(IPH_CHKSUM(iphdr))));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",
+                    ip4_addr1_16(&iphdr->src),
+                    ip4_addr2_16(&iphdr->src),
+                    ip4_addr3_16(&iphdr->src),
+                    ip4_addr4_16(&iphdr->src)));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",
+                    ip4_addr1_16(&iphdr->dest),
+                    ip4_addr2_16(&iphdr->dest),
+                    ip4_addr3_16(&iphdr->dest),
+                    ip4_addr4_16(&iphdr->dest)));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+}
+#endif /* IP_DEBUG */
diff --git a/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip_addr.c b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip_addr.c
new file mode 100644
index 0000000..8f633ff
--- /dev/null
+++ b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip_addr.c
@@ -0,0 +1,312 @@
+/**
+ * @file
+ * This is the IPv4 address tools implementation.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+
+/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
+const ip_addr_t ip_addr_any = { IPADDR_ANY };
+const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST };
+
+/**
+ * Determine if an address is a broadcast address on a network interface 
+ * 
+ * @param addr address to be checked
+ * @param netif the network interface against which the address is checked
+ * @return returns non-zero if the address is a broadcast address
+ */
+u8_t
+ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
+{
+  ip_addr_t ipaddr;
+  ip4_addr_set_u32(&ipaddr, addr);
+
+  /* all ones (broadcast) or all zeroes (old skool broadcast) */
+  if ((~addr == IPADDR_ANY) ||
+      (addr == IPADDR_ANY)) {
+    return 1;
+  /* no broadcast support on this network interface? */
+  } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
+    /* the given address cannot be a broadcast address
+     * nor can we check against any broadcast addresses */
+    return 0;
+  /* address matches network interface address exactly? => no broadcast */
+  } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
+    return 0;
+  /*  on the same (sub) network... */
+  } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
+         /* ...and host identifier bits are all ones? =>... */
+          && ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
+           (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
+    /* => network broadcast address */
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/** Checks if a netmask is valid (starting with ones, then only zeros)
+ *
+ * @param netmask the IPv4 netmask to check (in network byte order!)
+ * @return 1 if the netmask is valid, 0 if it is not
+ */
+u8_t
+ip4_addr_netmask_valid(u32_t netmask)
+{
+  u32_t mask;
+  u32_t nm_hostorder = lwip_htonl(netmask);
+
+  /* first, check for the first zero */
+  for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
+    if ((nm_hostorder & mask) == 0) {
+      break;
+    }
+  }
+  /* then check that there is no one */
+  for (; mask != 0; mask >>= 1) {
+    if ((nm_hostorder & mask) != 0) {
+      /* there is a one after the first zero -> invalid */
+      return 0;
+    }
+  }
+  /* no one after the first zero -> valid */
+  return 1;
+}
+
+/* Here for now until needed in other places in lwIP */
+#ifndef isprint
+#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)
+#define isprint(c)           in_range(c, 0x20, 0x7f)
+#define isdigit(c)           in_range(c, '0', '9')
+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
+#define islower(c)           in_range(c, 'a', 'z')
+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+#endif
+
+/**
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ *
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
+ * @return ip address in network order
+ */
+u32_t
+ipaddr_addr(const char *cp)
+{
+  ip_addr_t val;
+
+  if (ipaddr_aton(cp, &val)) {
+    return ip4_addr_get_u32(&val);
+  }
+  return (IPADDR_NONE);
+}
+
+/**
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ *
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
+ * @param addr pointer to which to save the ip address in network order
+ * @return 1 if cp could be converted to addr, 0 on failure
+ */
+int
+ipaddr_aton(const char *cp, ip_addr_t *addr)
+{
+  u32_t val;
+  u8_t base;
+  char c;
+  u32_t parts[4];
+  u32_t *pp = parts;
+
+  c = *cp;
+  for (;;) {
+    /*
+     * Collect number up to ``.''.
+     * Values are specified as for C:
+     * 0x=hex, 0=octal, 1-9=decimal.
+     */
+    if (!isdigit(c))
+      return (0);
+    val = 0;
+    base = 10;
+    if (c == '0') {
+      c = *++cp;
+      if (c == 'x' || c == 'X') {
+        base = 16;
+        c = *++cp;
+      } else
+        base = 8;
+    }
+    for (;;) {
+      if (isdigit(c)) {
+        val = (val * base) + (int)(c - '0');
+        c = *++cp;
+      } else if (base == 16 && isxdigit(c)) {
+        val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
+        c = *++cp;
+      } else
+        break;
+    }
+    if (c == '.') {
+      /*
+       * Internet format:
+       *  a.b.c.d
+       *  a.b.c   (with c treated as 16 bits)
+       *  a.b (with b treated as 24 bits)
+       */
+      if (pp >= parts + 3) {
+        return (0);
+      }
+      *pp++ = val;
+      c = *++cp;
+    } else
+      break;
+  }
+  /*
+   * Check for trailing characters.
+   */
+  if (c != '\0' && !isspace(c)) {
+    return (0);
+  }
+  /*
+   * Concoct the address according to
+   * the number of parts specified.
+   */
+  switch (pp - parts + 1) {
+
+  case 0:
+    return (0);       /* initial nondigit */
+
+  case 1:             /* a -- 32 bits */
+    break;
+
+  case 2:             /* a.b -- 8.24 bits */
+    if (val > 0xffffffUL) {
+      return (0);
+    }
+    val |= parts[0] << 24;
+    break;
+
+  case 3:             /* a.b.c -- 8.8.16 bits */
+    if (val > 0xffff) {
+      return (0);
+    }
+    val |= (parts[0] << 24) | (parts[1] << 16);
+    break;
+
+  case 4:             /* a.b.c.d -- 8.8.8.8 bits */
+    if (val > 0xff) {
+      return (0);
+    }
+    val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+    break;
+  default:
+    LWIP_ASSERT("unhandled", 0);
+    break;
+  }
+  if (addr) {
+    ip4_addr_set_u32(addr, htonl(val));
+  }
+  return (1);
+}
+
+/**
+ * Convert numeric IP address into decimal dotted ASCII representation.
+ * returns ptr to static buffer; not reentrant!
+ *
+ * @param addr ip address in network order to convert
+ * @return pointer to a global static (!) buffer that holds the ASCII
+ *         represenation of addr
+ */
+char *
+ipaddr_ntoa(const ip_addr_t *addr)
+{
+  static char str[16];
+  return ipaddr_ntoa_r(addr, str, 16);
+}
+
+/**
+ * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
+ *
+ * @param addr ip address in network order to convert
+ * @param buf target buffer where the string is stored
+ * @param buflen length of buf
+ * @return either pointer to buf which now holds the ASCII
+ *         representation of addr or NULL if buf was too small
+ */
+char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
+{
+  u32_t s_addr;
+  char inv[3];
+  char *rp;
+  u8_t *ap;
+  u8_t rem;
+  u8_t n;
+  u8_t i;
+  int len = 0;
+
+  s_addr = ip4_addr_get_u32(addr);
+
+  rp = buf;
+  ap = (u8_t *)&s_addr;
+  for(n = 0; n < 4; n++) {
+    i = 0;
+    do {
+      rem = *ap % (u8_t)10;
+      *ap /= (u8_t)10;
+      inv[i++] = '0' + rem;
+    } while(*ap);
+    while(i--) {
+      if (len++ >= buflen) {
+        return NULL;
+      }
+      *rp++ = inv[i];
+    }
+    if (len++ >= buflen) {
+      return NULL;
+    }
+    *rp++ = '.';
+    ap++;
+  }
+  *--rp = 0;
+  return buf;
+}
diff --git a/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip_frag.c b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip_frag.c
new file mode 100644
index 0000000..8d18434
--- /dev/null
+++ b/20120401V7.1.1-RC1/Demo/Common/ethernet/lwip-1.4.0/src/core/ipv4/ip_frag.c
@@ -0,0 +1,863 @@
+/**
+ * @file
+ * This is the IPv4 packet segmentation and reassembly implementation.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Jani Monoses <jani@iv.ro> 
+ *         Simon Goldschmidt
+ * original reassembly code by Adam Dunkels <adam@sics.se>
+ * 
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip_frag.h"
+#include "lwip/def.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/snmp.h"
+#include "lwip/stats.h"
+#include "lwip/icmp.h"
+
+#include <string.h>
+
+#if IP_REASSEMBLY
+/**
+ * The IP reassembly code currently has the following limitations:
+ * - IP header options are not supported
+ * - fragments must not overlap (e.g. due to different routes),
+ *   currently, overlapping or duplicate fragments are thrown away
+ *   if IP_REASS_CHECK_OVERLAP=1 (the default)!
+ *
+ * @todo: work with IP header options
+ */
+
+/** Setting this to 0, you can turn off checking the fragments for overlapping
+ * regions. The code gets a little smaller. Only use this if you know that
+ * overlapping won't occur on your network! */
+#ifndef IP_REASS_CHECK_OVERLAP
+#define IP_REASS_CHECK_OVERLAP 1
+#endif /* IP_REASS_CHECK_OVERLAP */
+
+/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
+ * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
+ * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
+ * is set to 1, so one datagram can be reassembled at a time, only. */
+#ifndef IP_REASS_FREE_OLDEST
+#define IP_REASS_FREE_OLDEST 1
+#endif /* IP_REASS_FREE_OLDEST */
+
+#define IP_REASS_FLAG_LASTFRAG 0x01
+
+/** This is a helper struct which holds the starting
+ * offset and the ending offset of this fragment to
+ * easily chain the fragments.
+ * It has the same packing requirements as the IP header, since it replaces
+ * the IP header in memory in incoming fragments (after copying it) to keep
+ * track of the various fragments. (-> If the IP header doesn't need packing,
+ * this struct doesn't need packing, too.)
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_reass_helper {
+  PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
+  PACK_STRUCT_FIELD(u16_t start);
+  PACK_STRUCT_FIELD(u16_t end);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB)  \
+  (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
+   ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
+   IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
+
+/* global variables */
+static struct ip_reassdata *reassdatagrams;
+static u16_t ip_reass_pbufcount;
+
+/* function prototypes */
+static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
+static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
+
+/**
+ * Reassembly timer base function
+ * for both NO_SYS == 0 and 1 (!).
+ *
+ * Should be called every 1000 msec (defined by IP_TMR_INTERVAL).
+ */
+void
+ip_reass_tmr(void)
+{
+  struct ip_reassdata *r, *prev = NULL;
+
+  r = reassdatagrams;
+  while (r != NULL) {
+    /* Decrement the timer. Once it reaches 0,
+     * clean up the incomplete fragment assembly */
+    if (r->timer > 0) {
+      r->timer--;
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
+      prev = r;
+      r = r->next;
+    } else {
+      /* reassembly timed out */
+      struct ip_reassdata *tmp;
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
+      tmp = r;
+      /* get the next pointer before freeing */
+      r = r->next;
+      /* free the helper struct and all enqueued pbufs */
+      ip_reass_free_complete_datagram(tmp, prev);
+     }
+   }
+}
+
+/**
+ * Free a datagram (struct ip_reassdata) and all its pbufs.
+ * Updates the total count of enqueued pbufs (ip_reass_pbufcount),
+ * SNMP counters and sends an ICMP time exceeded packet.
+ *
+ * @param ipr datagram to free
+ * @param prev the previous datagram in the linked list
+ * @return the number of pbufs freed
+ */
+static int
+ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
+{
+  u16_t pbufs_freed = 0;
+  u8_t clen;
+  struct pbuf *p;
+  struct ip_reass_helper *iprh;
+
+  LWIP_ASSERT("prev != ipr", prev != ipr);
+  if (prev != NULL) {
+    LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
+  }
+
+  snmp_inc_ipreasmfails();
+#if LWIP_ICMP
+  iprh = (struct ip_reass_helper *)ipr->p->payload;
+  if (iprh->start == 0) {
+    /* The first fragment was received, send ICMP time exceeded. */
+    /* First, de-queue the first pbuf from r->p. */
+    p = ipr->p;
+    ipr->p = iprh->next_pbuf;
+    /* Then, copy the original header into it. */
+    SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
+    icmp_time_exceeded(p, ICMP_TE_FRAG);
+    clen = pbuf_clen(p);
+    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
+    pbufs_freed += clen;
+    pbuf_free(p);
+  }
+#endif /* LWIP_ICMP */
+
+  /* First, free all received pbufs.  The individual pbufs need to be released 
+     separately as they have not yet been chained */
+  p = ipr->p;
+  while (p != NULL) {
+    struct pbuf *pcur;
+    iprh = (struct ip_reass_helper *)p->payload;
+    pcur = p;
+    /* get the next pointer before freeing */
+    p = iprh->next_pbuf;
+    clen = pbuf_clen(pcur);
+    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
+    pbufs_freed += clen;
+    pbuf_free(pcur);
+  }
+  /* Then, unchain the struct ip_reassdata from the list and free it. */
+  ip_reass_dequeue_datagram(ipr, prev);
+  LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
+  ip_reass_pbufcount -= pbufs_freed;
+
+  return pbufs_freed;
+}
+
+#if IP_REASS_FREE_OLDEST
+/**
+ * Free the oldest datagram to make room for enqueueing new fragments.
+ * The datagram 'fraghdr' belongs to is not freed!
+ *
+ * @param fraghdr IP header of the current fragment
+ * @param pbufs_needed number of pbufs needed to enqueue
+ *        (used for freeing other datagrams if not enough space)
+ * @return the number of pbufs freed
+ */
+static int
+ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
+{
+  /* @todo Can't we simply remove the last datagram in the
+   *       linked list behind reassdatagrams?
+   */
+  struct ip_reassdata *r, *oldest, *prev;
+  int pbufs_freed = 0, pbufs_freed_current;
+  int other_datagrams;
+
+  /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
+   * but don't free the datagram that 'fraghdr' belongs to! */
+  do {
+    oldest = NULL;
+    prev = NULL;
+    other_datagrams = 0;
+    r = reassdatagrams;
+    while (r != NULL) {
+      if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
+        /* Not the same datagram as fraghdr */
+        other_datagrams++;
+        if (oldest == NULL) {
+          oldest = r;
+        } else if (r->timer <= oldest->timer) {
+          /* older than the previous oldest */
+          oldest = r;
+        }
+      }
+      if (r->next != NULL) {
+        prev = r;
+      }
+      r = r->next;
+    }
+    if (oldest != NULL) {
+      pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
+      pbufs_freed += pbufs_freed_current;
+    }
+  } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
+  return pbufs_freed;
+}
+#endif /* IP_REASS_FREE_OLDEST */
+
+/**
+ * Enqueues a new fragment into the fragment queue
+ * @param fraghdr points to the new fragments IP hdr
+ * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
+ * @return A pointer to the queue location into which the fragment was enqueued
+ */
+static struct ip_reassdata*
+ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
+{
+  struct ip_reassdata* ipr;
+  /* No matching previous fragment found, allocate a new reassdata struct */
+  ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
+  if (ipr == NULL) {
+#if IP_REASS_FREE_OLDEST
+    if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
+      ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
+    }
+    if (ipr == NULL)
+#endif /* IP_REASS_FREE_OLDEST */
+    {
+      IPFRAG_STATS_INC(ip_frag.memerr);
+      LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
+      return NULL;
+    }
+  }
+  memset(ipr, 0, sizeof(struct ip_reassdata));
+  ipr->timer = IP_REASS_MAXAGE;
+
+  /* enqueue the new structure to the front of the list */
+  ipr->next = reassdatagrams;
+  reassdatagrams = ipr;
+  /* copy the ip header for later tests and input */
+  /* @todo: no ip options supported? */
+  SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
+  return ipr;
+}
+
+/**
+ * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.
+ * @param ipr points to the queue entry to dequeue
+ */
+static void
+ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
+{
+  
+  /* dequeue the reass struct  */
+  if (reassdatagrams == ipr) {
+    /* it was the first in the list */
+    reassdatagrams = ipr->next;
+  } else {
+    /* it wasn't the first, so it must have a valid 'prev' */
+    LWIP_ASSERT("sanity check linked list", prev != NULL);
+    prev->next = ipr->next;
+  }
+
+  /* now we can free the ip_reass struct */
+  memp_free(MEMP_REASSDATA, ipr);
+}
+
+/**
+ * Chain a new pbuf into the pbuf list that composes the datagram.  The pbuf list
+ * will grow over time as  new pbufs are rx.
+ * Also checks that the datagram passes basic continuity checks (if the last
+ * fragment was received at least once).
+ * @param root_p points to the 'root' pbuf for the current datagram being assembled.
+ * @param new_p points to the pbuf for the current fragment
+ * @return 0 if invalid, >0 otherwise
+ */
+static int
+ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
+{
+  struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
+  struct pbuf *q;
+  u16_t offset,len;
+  struct ip_hdr *fraghdr;
+  int valid = 1;
+
+  /* Extract length and fragment offset from current fragment */
+  fraghdr = (struct ip_hdr*)new_p->payload; 
+  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
+  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
+
+  /* overwrite the fragment's ip header from the pbuf with our helper struct,
+   * and setup the embedded helper structure. */
+  /* make sure the struct ip_reass_helper fits into the IP header */
+  LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
+              sizeof(struct ip_reass_helper) <= IP_HLEN);
+  iprh = (struct ip_reass_helper*)new_p->payload;
+  iprh->next_pbuf = NULL;
+  iprh->start = offset;
+  iprh->end = offset + len;
+
+  /* Iterate through until we either get to the end of the list (append),
+   * or we find on with a larger offset (insert). */
+  for (q = ipr->p; q != NULL;) {
+    iprh_tmp = (struct ip_reass_helper*)q->payload;
+    if (iprh->start < iprh_tmp->start) {
+      /* the new pbuf should be inserted before this */
+      iprh->next_pbuf = q;
+      if (iprh_prev != NULL) {
+        /* not the fragment with the lowest offset */
+#if IP_REASS_CHECK_OVERLAP
+        if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
+          /* fragment overlaps with previous or following, throw away */
+          goto freepbuf;
+        }
+#endif /* IP_REASS_CHECK_OVERLAP */
+        iprh_prev->next_pbuf = new_p;
+      } else {
+        /* fragment with the lowest offset */
+        ipr->p = new_p;
+      }
+      break;
+    } else if(iprh->start == iprh_tmp->start) {
+      /* received the same datagram twice: no need to keep the datagram */
+      goto freepbuf;
+#if IP_REASS_CHECK_OVERLAP
+    } else if(iprh->start < iprh_tmp->end) {
+      /* overlap: no need to keep the new datagram */
+      goto freepbuf;
+#endif /* IP_REASS_CHECK_OVERLAP */
+    } else {
+      /* Check if the fragments received so far have no wholes. */
+      if (iprh_prev != NULL) {
+        if (iprh_prev->end != iprh_tmp->start) {
+          /* There is a fragment missing between the current
+           * and the previous fragment */
+          valid = 0;
+        }
+      }
+    }
+    q = iprh_tmp->next_pbuf;
+    iprh_prev = iprh_tmp;
+  }
+
+  /* If q is NULL, then we made it to the end of the list. Determine what to do now */
+  if (q == NULL) {
+    if (iprh_prev != NULL) {
+      /* this is (for now), the fragment with the highest offset:
+       * chain it to the last fragment */
+#if IP_REASS_CHECK_OVERLAP
+      LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
+#endif /* IP_REASS_CHECK_OVERLAP */
+      iprh_prev->next_pbuf = new_p;
+      if (iprh_prev->end != iprh->start) {
+        valid = 0;
+      }
+    } else {
+#if IP_REASS_CHECK_OVERLAP
+      LWIP_ASSERT("no previous fragment, this must be the first fragment!",
+        ipr->p == NULL);
+#endif /* IP_REASS_CHECK_OVERLAP */
+      /* this is the first fragment we ever received for this ip datagram */
+      ipr->p = new_p;
+    }
+  }
+
+  /* At this point, the validation part begins: */
+  /* If we already received the last fragment */
+  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
+    /* and had no wholes so far */
+    if (valid) {
+      /* then check if the rest of the fragments is here */
+      /* Check if the queue starts with the first datagram */
+      if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
+        valid = 0;
+      } else {
+        /* and check that there are no wholes after this datagram */
+        iprh_prev = iprh;
+        q = iprh->next_pbuf;
+        while (q != NULL) {
+          iprh = (struct ip_reass_helper*)q->payload;
+          if (iprh_prev->end != iprh->start) {
+            valid = 0;
+            break;
+          }
+          iprh_prev = iprh;
+          q = iprh->next_pbuf;
+        }
+        /* if still valid, all fragments are received
+         * (because to the MF==0 already arrived */
+        if (valid) {
+          LWIP_ASSERT("sanity check", ipr->p != NULL);
+          LWIP_ASSERT("sanity check",
+            ((struct ip_reass_helper*)ipr->p->payload) != iprh);
+          LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
+            iprh->next_pbuf == NULL);
+          LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
+            iprh->end == ipr->datagram_len);
+        }
+      }
+    }
+    /* If valid is 0 here, there are some fragments missing in the middle
+     * (since MF == 0 has already arrived). Such datagrams simply time out if
+     * no more fragments are received... */
+    return valid;
+  }
+  /* If we come here, not all fragments were received, yet! */
+  return 0; /* not yet valid! */
+#if IP_REASS_CHECK_OVERLAP
+freepbuf:
+  ip_reass_pbufcount -= pbuf_clen(new_p);
+  pbuf_free(new_p);
+  return 0;
+#endif /* IP_REASS_CHECK_OVERLAP */
+}
+
+/**
+ * Reassembles incoming IP fragments into an IP datagram.
+ *
+ * @param p points to a pbuf chain of the fragment
+ * @return NULL if reassembly is incomplete, ? otherwise
+ */
+struct pbuf *
+ip_reass(struct pbuf *p)
+{
+  struct pbuf *r;
+  struct ip_hdr *fraghdr;
+  struct ip_reassdata *ipr;
+  struct ip_reass_helper *iprh;
+  u16_t offset, len;
+  u8_t clen;
+  struct ip_reassdata *ipr_prev = NULL;
+
+  IPFRAG_STATS_INC(ip_frag.recv);
+  snmp_inc_ipreasmreqds();
+
+  fraghdr = (struct ip_hdr*)p->payload;
+
+  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
+    LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
+    IPFRAG_STATS_INC(ip_frag.err);
+    goto nullreturn;
+  }
+
+  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
+  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
+
+  /* Check if we are allowed to enqueue more datagrams. */
+  clen = pbuf_clen(p);
+  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
+#if IP_REASS_FREE_OLDEST
+    if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
+        ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
+#endif /* IP_REASS_FREE_OLDEST */
+    {
+      /* No datagram could be freed and still too many pbufs enqueued */
+      LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
+        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
+      IPFRAG_STATS_INC(ip_frag.memerr);
+      /* @todo: send ICMP time exceeded here? */
+      /* drop this pbuf */
+      goto nullreturn;
+    }
+  }
+
+  /* Look for the datagram the fragment belongs to in the current datagram queue,
+   * remembering the previous in the queue for later dequeueing. */
+  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
+    /* Check if the incoming fragment matches the one currently present
+       in the reassembly buffer. If so, we proceed with copying the
+       fragment into the buffer. */
+    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
+        ntohs(IPH_ID(fraghdr))));
+      IPFRAG_STATS_INC(ip_frag.cachehit);
+      break;
+    }
+    ipr_prev = ipr;
+  }
+
+  if (ipr == NULL) {
+  /* Enqueue a new datagram into the datagram queue */
+    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
+    /* Bail if unable to enqueue */
+    if(ipr == NULL) {
+      goto nullreturn;
+    }
+  } else {
+    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && 
+      ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
+      /* ipr->iphdr is not the header from the first fragment, but fraghdr is
+       * -> copy fraghdr into ipr->iphdr since we want to have the header
+       * of the first fragment (for ICMP time exceeded and later, for copying
+       * all options, if supported)*/
+      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
+    }
+  }
+  /* Track the current number of pbufs current 'in-flight', in order to limit 
+  the number of fragments that may be enqueued at any one time */
+  ip_reass_pbufcount += clen;
+
+  /* At this point, we have either created a new entry or pointing 
+   * to an existing one */
+
+  /* check for 'no more fragments', and update queue entry*/
+  if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
+    ipr->flags |= IP_REASS_FLAG_LASTFRAG;
+    ipr->datagram_len = offset + len;
+    LWIP_DEBUGF(IP_REASS_DEBUG,
+     ("ip_reass: last fragment seen, total len %"S16_F"\n",
+      ipr->datagram_len));
+  }
+  /* find the right place to insert this pbuf */
+  /* @todo: trim pbufs if fragments are overlapping */
+  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
+    /* the totally last fragment (flag more fragments = 0) was received at least
+     * once AND all fragments are received */
+    ipr->datagram_len += IP_HLEN;
+
+    /* save the second pbuf before copying the header over the pointer */
+    r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
+
+    /* copy the original ip header back to the first pbuf */
+    fraghdr = (struct ip_hdr*)(ipr->p->payload);
+    SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
+    IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
+    IPH_OFFSET_SET(fraghdr, 0);
+    IPH_CHKSUM_SET(fraghdr, 0);
+    /* @todo: do we need to set calculate the correct checksum? */
+    IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
+
+    p = ipr->p;
+
+    /* chain together the pbufs contained within the reass_data list. */
+    while(r != NULL) {
+      iprh = (struct ip_reass_helper*)r->payload;
+
+      /* hide the ip header for every succeding fragment */
+      pbuf_header(r, -IP_HLEN);
+      pbuf_cat(p, r);
+      r = iprh->next_pbuf;
+    }
+    /* release the sources allocate for the fragment queue entry */
+    ip_reass_dequeue_datagram(ipr, ipr_prev);
+
+    /* and adjust the number of pbufs currently queued for reassembly. */
+    ip_reass_pbufcount -= pbuf_clen(p);
+
+    /* Return the pbuf chain */
+    return p;
+  }
+  /* the datagram is not (yet?) reassembled completely */
+  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
+  return NULL;
+
+nullreturn:
+  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
+  IPFRAG_STATS_INC(ip_frag.drop);
+  pbuf_free(p);
+  return NULL;
+}
+#endif /* IP_REASSEMBLY */
+
+#if IP_FRAG
+#if IP_FRAG_USES_STATIC_BUF
+static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
+#else /* IP_FRAG_USES_STATIC_BUF */
+
+#if !LWIP_NETIF_TX_SINGLE_PBUF
+/** Allocate a new struct pbuf_custom_ref */
+static struct pbuf_custom_ref*
+ip_frag_alloc_pbuf_custom_ref(void)
+{
+  return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
+}
+
+/** Free a struct pbuf_custom_ref */
+static void
+ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
+{
+  LWIP_ASSERT("p != NULL", p != NULL);
+  memp_free(MEMP_FRAG_PBUF, p);
+}
+
+/** Free-callback function to free a 'struct pbuf_custom_ref', called by
+ * pbuf_free. */
+static void
+ipfrag_free_pbuf_custom(struct pbuf *p)
+{
+  struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
+  LWIP_ASSERT("pcr != NULL", pcr != NULL);
+  LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
+  if (pcr->original != NULL) {
+    pbuf_free(pcr->original);
+  }
+  ip_frag_free_pbuf_custom_ref(pcr);
+}
+#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+/**
+ * Fragment an IP datagram if too large for the netif.
+ *
+ * Chop the datagram in MTU sized chunks and send them in order
+ * by using a fixed size static memory buffer (PBUF_REF) or
+ * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
+ *
+ * @param p ip packet to send
+ * @param netif the netif on which to send
+ * @param dest destination ip address to which to send
+ *
+ * @return ERR_OK if sent successfully, err_t otherwise
+ */
+err_t 
+ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
+{
+  struct pbuf *rambuf;
+#if IP_FRAG_USES_STATIC_BUF
+  struct pbuf *header;
+#else
+#if !LWIP_NETIF_TX_SINGLE_PBUF
+  struct pbuf *newpbuf;
+#endif
+  struct ip_hdr *original_iphdr;
+#endif
+  struct ip_hdr *iphdr;
+  u16_t nfb;
+  u16_t left, cop;
+  u16_t mtu = netif->mtu;
+  u16_t ofo, omf;
+  u16_t last;
+  u16_t poff = IP_HLEN;
+  u16_t tmp;
+#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
+  u16_t newpbuflen = 0;
+  u16_t left_to_copy;
+#endif
+
+  /* Get a RAM based MTU sized pbuf */
+#if IP_FRAG_USES_STATIC_BUF
+  /* When using a static buffer, we use a PBUF_REF, which we will
+   * use to reference the packet (without link header).
+   * Layer and length is irrelevant.
+   */
+  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
+  if (rambuf == NULL) {
+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
+    return ERR_MEM;
+  }
+  rambuf->tot_len = rambuf->len = mtu;
+  rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
+
+  /* Copy the IP header in it */
+  iphdr = (struct ip_hdr *)rambuf->payload;
+  SMEMCPY(iphdr, p->payload, IP_HLEN);
+#else /* IP_FRAG_USES_STATIC_BUF */
+  original_iphdr = (struct ip_hdr *)p->payload;
+  iphdr = original_iphdr;
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+  /* Save original offset */
+  tmp = ntohs(IPH_OFFSET(iphdr));
+  ofo = tmp & IP_OFFMASK;
+  omf = tmp & IP_MF;
+
+  left = p->tot_len - IP_HLEN;
+
+  nfb = (mtu - IP_HLEN) / 8;
+
+  while (left) {
+    last = (left <= mtu - IP_HLEN);
+
+    /* Set new offset and MF flag */
+    tmp = omf | (IP_OFFMASK & (ofo));
+    if (!last) {
+      tmp = tmp | IP_MF;
+    }
+
+    /* Fill this fragment */
+    cop = last ? left : nfb * 8;
+
+#if IP_FRAG_USES_STATIC_BUF
+    poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
+#else /* IP_FRAG_USES_STATIC_BUF */
+#if LWIP_NETIF_TX_SINGLE_PBUF
+    rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
+    if (rambuf == NULL) {
+      return ERR_MEM;
+    }
+    LWIP_ASSERT("this needs a pbuf in one piece!",
+      (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
+    poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
+    /* make room for the IP header */
+    if(pbuf_header(rambuf, IP_HLEN)) {
+      pbuf_free(rambuf);
+      return ERR_MEM;
+    }
+    /* fill in the IP header */
+    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
+    iphdr = rambuf->payload;
+#else /* LWIP_NETIF_TX_SINGLE_PBUF */
+    /* When not using a static buffer, create a chain of pbufs.
+     * The first will be a PBUF_RAM holding the link and IP header.
+     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
+     * but limited to the size of an mtu.
+     */
+    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
+    if (rambuf == NULL) {
+      return ERR_MEM;
+    }
+    LWIP_ASSERT("this needs a pbuf in one piece!",
+                (p->len >= (IP_HLEN)));
+    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
+    iphdr = (struct ip_hdr *)rambuf->payload;
+
+    /* Can just adjust p directly for needed offset. */
+    p->payload = (u8_t *)p->payload + poff;
+    p->len -= poff;
+
+    left_to_copy = cop;
+    while (left_to_copy) {
+      struct pbuf_custom_ref *pcr;
+      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
+      /* Is this pbuf already empty? */
+      if (!newpbuflen) {
+        p = p->next;
+        continue;
+      }
+      pcr = ip_frag_alloc_pbuf_custom_ref();
+      if (pcr == NULL) {
+        pbuf_free(rambuf);
+        return ERR_MEM;
+      }
+      /* Mirror this pbuf, although we might not need all of it. */
+      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
+      if (newpbuf == NULL) {
+        ip_frag_free_pbuf_custom_ref(pcr);
+        pbuf_free(rambuf);
+        return ERR_MEM;
+      }
+      pbuf_ref(p);
+      pcr->original = p;
+      pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
+
+      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
+       * so that it is removed when pbuf_dechain is later called on rambuf.
+       */
+      pbuf_cat(rambuf, newpbuf);
+      left_to_copy -= newpbuflen;
+      if (left_to_copy) {
+        p = p->next;
+      }
+    }
+    poff = newpbuflen;
+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+    /* Correct header */
+    IPH_OFFSET_SET(iphdr, htons(tmp));
+    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
+    IPH_CHKSUM_SET(iphdr, 0);
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
+
+#if IP_FRAG_USES_STATIC_BUF
+    if (last) {
+      pbuf_realloc(rambuf, left + IP_HLEN);
+    }
+
+    /* This part is ugly: we alloc a RAM based pbuf for 
+     * the link level header for each chunk and then 
+     * free it.A PBUF_ROM style pbuf for which pbuf_header
+     * worked would make things simpler.
+     */
+    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
+    if (header != NULL) {
+      pbuf_chain(header, rambuf);
+      netif->output(netif, header, dest);
+      IPFRAG_STATS_INC(ip_frag.xmit);
+      snmp_inc_ipfragcreates();
+      pbuf_free(header);
+    } else {
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
+      pbuf_free(rambuf);
+      return ERR_MEM;
+    }
+#else /* IP_FRAG_USES_STATIC_BUF */
+    /* No need for separate header pbuf - we allowed room for it in rambuf
+     * when allocated.
+     */
+    netif->output(netif, rambuf, dest);
+    IPFRAG_STATS_INC(ip_frag.xmit);
+
+    /* Unfortunately we can't reuse rambuf - the hardware may still be
+     * using the buffer. Instead we free it (and the ensuing chain) and
+     * recreate it next time round the loop. If we're lucky the hardware
+     * will have already sent the packet, the free will really free, and
+     * there will be zero memory penalty.
+     */
+    
+    pbuf_free(rambuf);
+#endif /* IP_FRAG_USES_STATIC_BUF */
+    left -= cop;
+    ofo += nfb;
+  }
+#if IP_FRAG_USES_STATIC_BUF
+  pbuf_free(rambuf);
+#endif /* IP_FRAG_USES_STATIC_BUF */
+  snmp_inc_ipfragoks();
+  return ERR_OK;
+}
+#endif /* IP_FRAG */