diff --git a/Demo/Common/ethernet/lwIP/core/dhcp.c b/Demo/Common/ethernet/lwIP/core/dhcp.c
index 2dabd4f..47f65c2 100644
--- a/Demo/Common/ethernet/lwIP/core/dhcp.c
+++ b/Demo/Common/ethernet/lwIP/core/dhcp.c
@@ -1,1464 +1,1464 @@
-/**
- * @file
- *
- * Dynamic Host Configuration Protocol client
- */
-
-/*
- *
- * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>
- * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.
- * 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 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.
- *
- * Author: Leon Woestenberg <leon.woestenberg@gmx.net>
- *
- * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
- * with RFC 2131 and RFC 2132.
- *
- * TODO:
- * - Proper parsing of DHCP messages exploiting file/sname field overloading.
- * - Add JavaDoc style documentation (API, internals).
- * - Support for interfaces other than Ethernet (SLIP, PPP, ...)
- *
- * Please coordinate changes and requests with Leon Woestenberg
- * <leon.woestenberg@gmx.net>
- *
- * Integration with your code:
- *
- * In lwip/dhcp.h
- * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
- * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
- *
- * Then have your application call dhcp_coarse_tmr() and
- * dhcp_fine_tmr() on the defined intervals.
- *
- * dhcp_start(struct netif *netif);
- * starts a DHCP client instance which configures the interface by
- * obtaining an IP address lease and maintaining it.
- *
- * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
- * to remove the DHCP client.
- *
- */
- 
-#include <string.h>
- 
-#include "lwip/stats.h"
-#include "lwip/mem.h"
-#include "lwip/udp.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/inet.h"
-#include "netif/etharp.h"
-
-#include "lwip/sys.h"
-#include "lwip/opt.h"
-#include "lwip/dhcp.h"
-
-#if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */
-
-/** global transaction identifier, must be
- *  unique for each DHCP request. We simply increment, starting
- *  with this value (easy to match with a packet analyzer) */
-static u32_t xid = 0xABCD0000;
-
-/** DHCP client state machine functions */
-static void dhcp_handle_ack(struct netif *netif);
-static void dhcp_handle_nak(struct netif *netif);
-static void dhcp_handle_offer(struct netif *netif);
-
-static err_t dhcp_discover(struct netif *netif);
-static err_t dhcp_select(struct netif *netif);
-static void dhcp_check(struct netif *netif);
-static void dhcp_bind(struct netif *netif);
-static err_t dhcp_decline(struct netif *netif);
-static err_t dhcp_rebind(struct netif *netif);
-static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);
-
-/** receive, unfold, parse and free incoming messages */
-static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
-static err_t dhcp_unfold_reply(struct dhcp *dhcp);
-static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);
-static u8_t dhcp_get_option_byte(u8_t *ptr);
-#if 0
-static u16_t dhcp_get_option_short(u8_t *ptr);
-#endif
-static u32_t dhcp_get_option_long(u8_t *ptr);
-static void dhcp_free_reply(struct dhcp *dhcp);
-
-/** set the DHCP timers */
-static void dhcp_timeout(struct netif *netif);
-static void dhcp_t1_timeout(struct netif *netif);
-static void dhcp_t2_timeout(struct netif *netif);
-
-/** build outgoing messages */
-/** create a DHCP request, fill in common headers */
-static err_t dhcp_create_request(struct netif *netif);
-/** free a DHCP request */
-static void dhcp_delete_request(struct netif *netif);
-/** add a DHCP option (type, then length in bytes) */
-static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
-/** add option values */
-static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
-static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
-static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
-/** always add the DHCP options trailer to end and pad */
-static void dhcp_option_trailer(struct dhcp *dhcp);
-
-/**
- * Back-off the DHCP client (because of a received NAK response).
- *
- * Back-off the DHCP client because of a received NAK. Receiving a
- * NAK means the client asked for something non-sensible, for
- * example when it tries to renew a lease obtained on another network.
- *
- * We back-off and will end up restarting a fresh DHCP negotiation later.
- *
- * @param state pointer to DHCP state structure
- */
-static void dhcp_handle_nak(struct netif *netif) {
-  struct dhcp *dhcp = netif->dhcp;
-  u16_t msecs = 10 * 1000;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", 
-    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
-  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_handle_nak(): set request timeout %"U16_F" msecs\n", msecs));
-  dhcp_set_state(dhcp, DHCP_BACKING_OFF);
-}
-
-/**
- * Checks if the offered IP address is already in use.
- *
- * It does so by sending an ARP request for the offered address and
- * entering CHECKING state. If no ARP reply is received within a small
- * interval, the address is assumed to be free for use by us.
- */
-static void dhcp_check(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  err_t result;
-  u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
-    (s16_t)netif->name[1]));
-  /* create an ARP query for the offered IP address, expecting that no host
-     responds, as the IP address should not be in use. */
-  result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
-  if (result != ERR_OK) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));
-  }
-  dhcp->tries++;
-  msecs = 500;
-  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
-  dhcp_set_state(dhcp, DHCP_CHECKING);
-}
-
-/**
- * Remember the configuration offered by a DHCP server.
- *
- * @param state pointer to DHCP state structure
- */
-static void dhcp_handle_offer(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  /* obtain the server address */
-  u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
-    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
-  if (option_ptr != NULL)
-  {
-    dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));
-    /* remember offered address */
-    ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
-
-    dhcp_select(netif);
-  }
-}
-
-/**
- * Select a DHCP server offer out of all offers.
- *
- * Simply select the first offer received.
- *
- * @param netif the netif under DHCP control
- * @return lwIP specific error (see error.h)
- */
-static err_t dhcp_select(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  err_t result;
-  u32_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
-
-  /* create and initialize the DHCP message header */
-  result = dhcp_create_request(netif);
-  if (result == ERR_OK)
-  {
-    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
-    dhcp_option_byte(dhcp, DHCP_REQUEST);
-
-    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
-    dhcp_option_short(dhcp, 576);
-
-    /* MUST request the offered IP address */
-    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
-    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
-
-    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
-    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
-
-    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
-    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
-    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
-    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
-    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
-
-    dhcp_option_trailer(dhcp);
-    /* shrink the pbuf to the actual content length */
-    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
-    /* TODO: we really should bind to a specific local interface here
-       but we cannot specify an unconfigured netif as it is addressless */
-    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-    /* send broadcast to any DHCP server */
-    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
-    udp_send(dhcp->pcb, dhcp->p_out);
-    /* reconnect to any (or to server here?!) */
-    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
-    dhcp_delete_request(netif);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_select: REQUESTING\n"));
-    dhcp_set_state(dhcp, DHCP_REQUESTING);
-  } else {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
-  }
-  dhcp->tries++;
-  msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;
-  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_select(): set request timeout %"U32_F" msecs\n", msecs));
-  return result;
-}
-
-/**
- * The DHCP timer that checks for lease renewal/rebind timeouts.
- *
- */
-void dhcp_coarse_tmr()
-{
-  struct netif *netif = netif_list;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_coarse_tmr()\n"));
-  /* iterate through all network interfaces */
-  while (netif != NULL) {
-    /* only act on DHCP configured interfaces */
-    if (netif->dhcp != NULL) {
-      /* timer is active (non zero), and triggers (zeroes) now? */
-      if (netif->dhcp->t2_timeout-- == 1) {
-        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
-        /* this clients' rebind timeout triggered */
-        dhcp_t2_timeout(netif);
-      /* timer is active (non zero), and triggers (zeroes) now */
-      } else if (netif->dhcp->t1_timeout-- == 1) {
-        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
-        /* this clients' renewal timeout triggered */
-        dhcp_t1_timeout(netif);
-      }
-    }
-    /* proceed to next netif */
-    netif = netif->next;
-  }
-}
-
-/**
- * DHCP transaction timeout handling
- *
- * A DHCP server is expected to respond within a short period of time.
- * This timer checks whether an outstanding DHCP request is timed out.
- * 
- */
-void dhcp_fine_tmr()
-{
-  struct netif *netif = netif_list;
-  /* loop through netif's */
-  while (netif != NULL) {
-    /* only act on DHCP configured interfaces */
-    if (netif->dhcp != NULL) {
-      /* timer is active (non zero), and is about to trigger now */      
-      if (netif->dhcp->request_timeout > 1) {
-        netif->dhcp->request_timeout--;
-      }
-      else if (netif->dhcp->request_timeout == 1) {
-        netif->dhcp->request_timeout--;
-        /* { netif->dhcp->request_timeout == 0 } */
-        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
-        /* this clients' request timeout triggered */
-        dhcp_timeout(netif);
-      }
-    }
-    /* proceed to next network interface */
-    netif = netif->next;
-  }
-}
-
-/**
- * A DHCP negotiation transaction, or ARP request, has timed out.
- *
- * The timer that was started with the DHCP or ARP request has
- * timed out, indicating no response was received in time.
- *
- * @param netif the netif under DHCP control
- *
- */
-static void dhcp_timeout(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_timeout()\n"));
-  /* back-off period has passed, or server selection timed out */
-  if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
-    dhcp_discover(netif);
-  /* receiving the requested lease timed out */
-  } else if (dhcp->state == DHCP_REQUESTING) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
-    if (dhcp->tries <= 5) {
-      dhcp_select(netif);
-    } else {
-      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
-      dhcp_release(netif);
-      dhcp_discover(netif);
-    }
-  /* received no ARP reply for the offered address (which is good) */
-  } else if (dhcp->state == DHCP_CHECKING) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
-    if (dhcp->tries <= 1) {
-      dhcp_check(netif);
-    /* no ARP replies on the offered address,
-       looks like the IP address is indeed free */
-    } else {
-      /* bind the interface to the offered address */
-      dhcp_bind(netif);
-    }
-  }
-  /* did not get response to renew request? */
-  else if (dhcp->state == DHCP_RENEWING) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));
-    /* just retry renewal */
-    /* note that the rebind timer will eventually time-out if renew does not work */
-    dhcp_renew(netif);
-  /* did not get response to rebind request? */
-  } else if (dhcp->state == DHCP_REBINDING) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));
-    if (dhcp->tries <= 8) {
-      dhcp_rebind(netif);
-    } else {
-      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
-      dhcp_release(netif);
-      dhcp_discover(netif);
-    }
-  }
-}
-
-/**
- * The renewal period has timed out.
- *
- * @param netif the netif under DHCP control
- */
-static void dhcp_t1_timeout(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_t1_timeout()\n"));
-  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
-    /* just retry to renew - note that the rebind timer (t2) will
-     * eventually time-out if renew tries fail. */
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));
-    dhcp_renew(netif);
-  }
-}
-
-/**
- * The rebind period has timed out.
- *
- */
-static void dhcp_t2_timeout(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout()\n"));
-  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
-    /* just retry to rebind */
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));
-    dhcp_rebind(netif);
-  }
-}
-
-/**
- *
- * @param netif the netif under DHCP control
- */
-static void dhcp_handle_ack(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  u8_t *option_ptr;
-  /* clear options we might not get from the ACK */
-  dhcp->offered_sn_mask.addr = 0;
-  dhcp->offered_gw_addr.addr = 0;
-  dhcp->offered_bc_addr.addr = 0;
-
-  /* lease time given? */
-  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);
-  if (option_ptr != NULL) {
-    /* remember offered lease time */
-    dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);
-  }
-  /* renewal period given? */
-  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);
-  if (option_ptr != NULL) {
-    /* remember given renewal period */
-    dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);
-  } else {
-    /* calculate safe periods for renewal */
-    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
-  }
-
-  /* renewal period given? */
-  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);
-  if (option_ptr != NULL) {
-    /* remember given rebind period */
-    dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);
-  } else {
-    /* calculate safe periods for rebinding */
-    dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
-  }
-
-  /* (y)our internet address */
-  ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);
-
-/**
- * Patch #1308
- * TODO: we must check if the file field is not overloaded by DHCP options!
- */
-#if 0
-  /* boot server address */
-  ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);
-  /* boot file name */
-  if (dhcp->msg_in->file[0]) {
-    dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);
-    strcpy(dhcp->boot_file_name, dhcp->msg_in->file);
-  }
-#endif
-
-  /* subnet mask */
-  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);
-  /* subnet mask given? */
-  if (option_ptr != NULL) {
-    dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
-  }
-
-  /* gateway router */
-  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);
-  if (option_ptr != NULL) {
-    dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
-  }
-
-  /* broadcast address */
-  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);
-  if (option_ptr != NULL) {
-    dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
-  }
-  
-  /* DNS servers */
-  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);
-  if (option_ptr != NULL) {
-    u8_t n;
-    dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);
-    /* limit to at most DHCP_MAX_DNS DNS servers */
-    if (dhcp->dns_count > DHCP_MAX_DNS)
-      dhcp->dns_count = DHCP_MAX_DNS;
-    for (n = 0; n < dhcp->dns_count; n++) {
-      dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));
-    }
-  }
-}
-
-/**
- * Start DHCP negotiation for a network interface.
- *
- * If no DHCP client instance was attached to this interface,
- * a new client is created first. If a DHCP client instance
- * was already present, it restarts negotiation.
- *
- * @param netif The lwIP network interface
- * @return lwIP error code
- * - ERR_OK - No error
- * - ERR_MEM - Out of memory
- *
- */
-err_t dhcp_start(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  err_t result = ERR_OK;
-
-  LWIP_ASSERT("netif != NULL", netif != NULL);
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
-  netif->flags &= ~NETIF_FLAG_DHCP;
-
-  /* no DHCP client attached yet? */
-  if (dhcp == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
-    dhcp = mem_malloc(sizeof(struct dhcp));
-    if (dhcp == NULL) {
-      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
-      return ERR_MEM;
-    }
-    /* store this dhcp client in the netif */
-    netif->dhcp = dhcp;
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));
-  /* already has DHCP client attached */
-  } else {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
-  }
-    
-  /* clear data structure */
-  memset(dhcp, 0, sizeof(struct dhcp));
-  /* allocate UDP PCB */
-  dhcp->pcb = udp_new();
-  if (dhcp->pcb == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG  | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
-    mem_free((void *)dhcp);
-    netif->dhcp = dhcp = NULL;
-    return ERR_MEM;
-  }
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
-  /* (re)start the DHCP negotiation */
-  result = dhcp_discover(netif);
-  if (result != ERR_OK) {
-    /* free resources allocated above */
-    dhcp_stop(netif);
-    return ERR_MEM;
-  }
-  netif->flags |= NETIF_FLAG_DHCP;
-  return result;
-}
-
-/**
- * Inform a DHCP server of our manual configuration.
- *
- * This informs DHCP servers of our fixed IP address configuration
- * by sending an INFORM message. It does not involve DHCP address
- * configuration, it is just here to be nice to the network.
- *
- * @param netif The lwIP network interface
- *
- */
-void dhcp_inform(struct netif *netif)
-{
-  struct dhcp *dhcp;
-  err_t result = ERR_OK;
-  dhcp = mem_malloc(sizeof(struct dhcp));
-  if (dhcp == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));
-    return;
-  }
-  netif->dhcp = dhcp;
-  memset(dhcp, 0, sizeof(struct dhcp));
-
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));
-  dhcp->pcb = udp_new();
-  if (dhcp->pcb == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));
-    mem_free((void *)dhcp);
-    return;
-  }
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
-  /* create and initialize the DHCP message header */
-  result = dhcp_create_request(netif);
-  if (result == ERR_OK) {
-
-    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
-    dhcp_option_byte(dhcp, DHCP_INFORM);
-
-    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
-    /* TODO: use netif->mtu ?! */
-    dhcp_option_short(dhcp, 576);
-
-    dhcp_option_trailer(dhcp);
-
-    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
-    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_inform: INFORMING\n"));
-    udp_send(dhcp->pcb, dhcp->p_out);
-    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
-    dhcp_delete_request(netif);
-  } else {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
-  }
-
-  if (dhcp != NULL)
-  {
-    if (dhcp->pcb != NULL) udp_remove(dhcp->pcb);
-    dhcp->pcb = NULL;
-    mem_free((void *)dhcp);
-    netif->dhcp = NULL;
-  }
-}
-
-#if DHCP_DOES_ARP_CHECK
-/**
- * Match an ARP reply with the offered IP address.
- *
- * @param addr The IP address we received a reply from
- *
- */
-void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
-{
-  LWIP_ASSERT("netif != NULL", netif != NULL);
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_arp_reply()\n"));
-  /* is a DHCP client doing an ARP check? */
-  if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));
-    /* did a host respond with the address we
-       were offered by the DHCP server? */
-    if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
-      /* we will not accept the offered address */
-      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
-      dhcp_decline(netif);
-    }
-  }
-}
-
-/**
- * Decline an offered lease.
- *
- * Tell the DHCP server we do not accept the offered address.
- * One reason to decline the lease is when we find out the address
- * is already in use by another host (through ARP).
- */
-static err_t dhcp_decline(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  err_t result = ERR_OK;
-  u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_decline()\n"));
-  dhcp_set_state(dhcp, DHCP_BACKING_OFF);
-  /* create and initialize the DHCP message header */
-  result = dhcp_create_request(netif);
-  if (result == ERR_OK)
-  {
-    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
-    dhcp_option_byte(dhcp, DHCP_DECLINE);
-
-    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
-    dhcp_option_short(dhcp, 576);
-
-    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
-    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
-
-    dhcp_option_trailer(dhcp);
-    /* resize pbuf to reflect true size of options */
-    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
-    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-    /* @todo: should we really connect here? we are performing sendto() */
-    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
-    /* per section 4.4.4, broadcast DECLINE messages */
-    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
-    dhcp_delete_request(netif);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
-  } else {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));
-  }
-  dhcp->tries++;
-  msecs = 10*1000;
-  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
-   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));
-  return result;
-}
-#endif
-
-
-/**
- * Start the DHCP process, discover a DHCP server.
- *
- */
-static err_t dhcp_discover(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  err_t result = ERR_OK;
-  u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_discover()\n"));
-  ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
-  /* create and initialize the DHCP message header */
-  result = dhcp_create_request(netif);
-  if (result == ERR_OK)
-  {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: making request\n"));
-    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
-    dhcp_option_byte(dhcp, DHCP_DISCOVER);
-
-    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
-    dhcp_option_short(dhcp, 576);
-
-    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
-    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
-    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
-    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
-    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
-
-    dhcp_option_trailer(dhcp);
-
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
-    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
-    /* set receive callback function with netif as user data */
-    udp_recv(dhcp->pcb, dhcp_recv, netif);
-    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
-    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
-    dhcp_delete_request(netif);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover: SELECTING\n"));
-    dhcp_set_state(dhcp, DHCP_SELECTING);
-  } else {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
-  }
-  dhcp->tries++;
-  msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;
-  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));
-  return result;
-}
-
-
-/**
- * Bind the interface to the offered IP address.
- *
- * @param netif network interface to bind to the offered address
- */
-static void dhcp_bind(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  struct ip_addr sn_mask, gw_addr;
-  LWIP_ASSERT("dhcp_bind: netif != NULL", netif != NULL);
-  LWIP_ASSERT("dhcp_bind: dhcp != NULL", dhcp != NULL);
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
-
-  /* temporary DHCP lease? */
-  if (dhcp->offered_t1_renew != 0xffffffffUL) {
-    /* set renewal period timer */
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));
-    dhcp->t1_timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
-    if (dhcp->t1_timeout == 0) dhcp->t1_timeout = 1;
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));
-  }
-  /* set renewal period timer */
-  if (dhcp->offered_t2_rebind != 0xffffffffUL) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));
-    dhcp->t2_timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
-    if (dhcp->t2_timeout == 0) dhcp->t2_timeout = 1;
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));
-  }
-  /* copy offered network mask */
-  ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);
-
-  /* subnet mask not given? */
-  /* TODO: this is not a valid check. what if the network mask is 0? */
-  if (sn_mask.addr == 0) {
-    /* choose a safe subnet mask given the network class */
-    u8_t first_octet = ip4_addr1(&sn_mask);
-    if (first_octet <= 127) sn_mask.addr = htonl(0xff000000);
-    else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00);
-    else sn_mask.addr = htonl(0xffff0000);
-  }
-
-  ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);
-  /* gateway address not given? */
-  if (gw_addr.addr == 0) {
-    /* copy network address */
-    gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);
-    /* use first host address on network as gateway */
-    gw_addr.addr |= htonl(0x00000001);
-  }
-
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
-  netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));
-  netif_set_netmask(netif, &sn_mask);
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));
-  netif_set_gw(netif, &gw_addr);
-  /* bring the interface up */
-  netif_set_up(netif);
-  /* netif is now bound to DHCP leased address */
-  dhcp_set_state(dhcp, DHCP_BOUND);
-}
-
-/**
- * Renew an existing DHCP lease at the involved DHCP server.
- *
- * @param netif network interface which must renew its lease
- */
-err_t dhcp_renew(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  err_t result;
-  u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_renew()\n"));
-  dhcp_set_state(dhcp, DHCP_RENEWING);
-
-  /* create and initialize the DHCP message header */
-  result = dhcp_create_request(netif);
-  if (result == ERR_OK) {
-
-    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
-    dhcp_option_byte(dhcp, DHCP_REQUEST);
-
-    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
-    /* TODO: use netif->mtu in some way */
-    dhcp_option_short(dhcp, 576);
-
-#if 0
-    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
-    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
-#endif
-
-#if 0
-    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
-    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
-#endif
-    /* append DHCP message trailer */
-    dhcp_option_trailer(dhcp);
-
-    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
-    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
-    udp_send(dhcp->pcb, dhcp->p_out);
-    dhcp_delete_request(netif);
-
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew: RENEWING\n"));
-  } else {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));
-  }
-  dhcp->tries++;
-  /* back-off on retries, but to a maximum of 20 seconds */
-  msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;
-  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
-   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));
-  return result;
-}
-
-/**
- * Rebind with a DHCP server for an existing DHCP lease.
- *
- * @param netif network interface which must rebind with a DHCP server
- */
-static err_t dhcp_rebind(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  err_t result;
-  u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind()\n"));
-  dhcp_set_state(dhcp, DHCP_REBINDING);
-
-  /* create and initialize the DHCP message header */
-  result = dhcp_create_request(netif);
-  if (result == ERR_OK)
-  {
-
-    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
-    dhcp_option_byte(dhcp, DHCP_REQUEST);
-
-    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
-    dhcp_option_short(dhcp, 576);
-
-#if 0
-    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
-    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
-
-    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
-    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
-#endif
-
-    dhcp_option_trailer(dhcp);
-
-    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
-    /* set remote IP association to any DHCP server */
-    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
-    /* broadcast to server */
-    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
-    dhcp_delete_request(netif);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind: REBINDING\n"));
-  } else {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));
-  }
-  dhcp->tries++;
-  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
-  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
-   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));
-  return result;
-}
-
-/**
- * Release a DHCP lease.
- *
- * @param netif network interface which must release its lease
- */
-err_t dhcp_release(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  err_t result;
-  u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_release()\n"));
-
-  /* idle DHCP client */
-  dhcp_set_state(dhcp, DHCP_OFF);
-  /* clean old DHCP offer */
-  dhcp->server_ip_addr.addr = 0;
-  dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;
-  dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;
-  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
-  dhcp->dns_count = 0;
-  
-  /* create and initialize the DHCP message header */
-  result = dhcp_create_request(netif);
-  if (result == ERR_OK) {
-    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
-    dhcp_option_byte(dhcp, DHCP_RELEASE);
-
-    dhcp_option_trailer(dhcp);
-
-    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
-    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
-    udp_send(dhcp->pcb, dhcp->p_out);
-    dhcp_delete_request(netif);
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
-  } else {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));
-  }
-  dhcp->tries++;
-  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
-  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));
-  /* bring the interface down */
-  netif_set_down(netif);
-  /* remove IP address from interface */
-  netif_set_ipaddr(netif, IP_ADDR_ANY);
-  netif_set_gw(netif, IP_ADDR_ANY);
-  netif_set_netmask(netif, IP_ADDR_ANY);
-  
-  /* TODO: netif_down(netif); */
-  return result;
-}
-/**
- * Remove the DHCP client from the interface.
- *
- * @param netif The network interface to stop DHCP on
- */
-void dhcp_stop(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  LWIP_ASSERT("dhcp_stop: netif != NULL", netif != NULL);
-
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_stop()\n"));
-  /* netif is DHCP configured? */
-  if (dhcp != NULL)
-  {
-    if (dhcp->pcb != NULL)
-    {
-      udp_remove(dhcp->pcb);
-      dhcp->pcb = NULL;
-    }
-    if (dhcp->p != NULL)
-    {
-      pbuf_free(dhcp->p);
-      dhcp->p = NULL;
-    }
-    /* free unfolded reply */
-    dhcp_free_reply(dhcp);
-    mem_free((void *)dhcp);
-    netif->dhcp = NULL;
-  }
-}
-
-/*
- * Set the DHCP state of a DHCP client.
- *
- * If the state changed, reset the number of tries.
- *
- * TODO: we might also want to reset the timeout here?
- */
-static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
-{
-  if (new_state != dhcp->state)
-  {
-    dhcp->state = new_state;
-    dhcp->tries = 0;
-  }
-}
-
-/*
- * Concatenate an option type and length field to the outgoing
- * DHCP message.
- *
- */
-static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
-{
-  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN);
-  dhcp->msg_out->options[dhcp->options_out_len++] = option_type;
-  dhcp->msg_out->options[dhcp->options_out_len++] = option_len;
-}
-/*
- * Concatenate a single byte to the outgoing DHCP message.
- *
- */
-static void dhcp_option_byte(struct dhcp *dhcp, u8_t value)
-{
-  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);
-  dhcp->msg_out->options[dhcp->options_out_len++] = value;
-}
-static void dhcp_option_short(struct dhcp *dhcp, u16_t value)
-{
-  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN);
-  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff00U) >> 8;
-  dhcp->msg_out->options[dhcp->options_out_len++] =  value & 0x00ffU;
-}
-static void dhcp_option_long(struct dhcp *dhcp, u32_t value)
-{
-  LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN);
-  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff000000UL) >> 24;
-  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x00ff0000UL) >> 16;
-  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x0000ff00UL) >> 8;
-  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x000000ffUL);
-}
-
-/**
- * Extract the DHCP message and the DHCP options.
- *
- * Extract the DHCP message and the DHCP options, each into a contiguous
- * piece of memory. As a DHCP message is variable sized by its options,
- * and also allows overriding some fields for options, the easy approach
- * is to first unfold the options into a conitguous piece of memory, and
- * use that further on.
- *
- */
-static err_t dhcp_unfold_reply(struct dhcp *dhcp)
-{
-  struct pbuf *p = dhcp->p;
-  u8_t *ptr;
-  u16_t i;
-  u16_t j = 0;
-  LWIP_ASSERT("dhcp->p != NULL", dhcp->p != NULL);
-  /* free any left-overs from previous unfolds */
-  dhcp_free_reply(dhcp);
-  /* options present? */
-  if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN))
-  {
-    dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
-    dhcp->options_in = mem_malloc(dhcp->options_in_len);
-    if (dhcp->options_in == NULL)
-    {
-      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
-      return ERR_MEM;
-    }
-  }
-  dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
-  if (dhcp->msg_in == NULL)
-  {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));
-    mem_free((void *)dhcp->options_in);
-    dhcp->options_in = NULL;
-    return ERR_MEM;
-  }
-
-  ptr = (u8_t *)dhcp->msg_in;
-  /* proceed through struct dhcp_msg */
-  for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++)
-  {
-    *ptr++ = ((u8_t *)p->payload)[j++];
-    /* reached end of pbuf? */
-    if (j == p->len)
-    {
-      /* proceed to next pbuf in chain */
-      p = p->next;
-      j = 0;
-    }
-  }
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", i));
-  if (dhcp->options_in != NULL) {
-    ptr = (u8_t *)dhcp->options_in;
-    /* proceed through options */
-    for (i = 0; i < dhcp->options_in_len; i++) {
-      *ptr++ = ((u8_t *)p->payload)[j++];
-      /* reached end of pbuf? */
-      if (j == p->len) {
-        /* proceed to next pbuf in chain */
-        p = p->next;
-        j = 0;
-      }
-    }
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", i));
-  }
-  return ERR_OK;
-}
-
-/**
- * Free the incoming DHCP message including contiguous copy of
- * its DHCP options.
- *
- */
-static void dhcp_free_reply(struct dhcp *dhcp)
-{
-  if (dhcp->msg_in != NULL) {
-    mem_free((void *)dhcp->msg_in);
-    dhcp->msg_in = NULL;
-  }
-  if (dhcp->options_in) {
-    mem_free((void *)dhcp->options_in);
-    dhcp->options_in = NULL;
-    dhcp->options_in_len = 0;
-  }
-  LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));
-}
-
-
-/**
- * If an incoming DHCP message is in response to us, then trigger the state machine
- */
-static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
-{
-  struct netif *netif = (struct netif *)arg;
-  struct dhcp *dhcp = netif->dhcp;
-  struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
-  u8_t *options_ptr;
-  u8_t msg_type;
-  u8_t i;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
-    (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),
-    (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
-  /* prevent warnings about unused arguments */
-  (void)pcb; (void)addr; (void)port;
-  dhcp->p = p;
-  /* TODO: check packet length before reading them */
-  if (reply_msg->op != DHCP_BOOTREPLY) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
-    pbuf_free(p);
-    dhcp->p = NULL;
-    return;
-  }
-  /* iterate through hardware address and match against DHCP message */
-  for (i = 0; i < netif->hwaddr_len; i++) {
-    if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
-      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
-        (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
-      pbuf_free(p);
-      dhcp->p = NULL;
-      return;
-    }
-  }
-  /* match transaction ID against what we expected */
-  if (ntohl(reply_msg->xid) != dhcp->xid) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
-    pbuf_free(p);
-    dhcp->p = NULL;
-    return;
-  }
-  /* option fields could be unfold? */
-  if (dhcp_unfold_reply(dhcp) != ERR_OK) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));
-    pbuf_free(p);
-    dhcp->p = NULL;
-    return;
-  }
-
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
-  /* obtain pointer to DHCP message type */
-  options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);
-  if (options_ptr == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
-    pbuf_free(p);
-    dhcp->p = NULL;
-    return;
-  }
-
-  /* read DHCP message type */
-  msg_type = dhcp_get_option_byte(options_ptr + 2);
-  /* message type is DHCP ACK? */
-  if (msg_type == DHCP_ACK) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_ACK received\n"));
-    /* in requesting state? */
-    if (dhcp->state == DHCP_REQUESTING) {
-      dhcp_handle_ack(netif);
-      dhcp->request_timeout = 0;
-#if DHCP_DOES_ARP_CHECK
-      /* check if the acknowledged lease address is already in use */
-      dhcp_check(netif);
-#else
-      /* bind interface to the acknowledged lease address */
-      dhcp_bind(netif);
-#endif
-    }
-    /* already bound to the given lease address? */
-    else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
-      dhcp->request_timeout = 0;
-      dhcp_bind(netif);
-    }
-  }
-  /* received a DHCP_NAK in appropriate state? */
-  else if ((msg_type == DHCP_NAK) &&
-    ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
-     (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_NAK received\n"));
-    dhcp->request_timeout = 0;
-    dhcp_handle_nak(netif);
-  }
-  /* received a DHCP_OFFER in DHCP_SELECTING state? */
-  else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
-    dhcp->request_timeout = 0;
-    /* remember offered lease */
-    dhcp_handle_offer(netif);
-  }
-  pbuf_free(p);
-  dhcp->p = NULL;
-}
-
-
-static err_t dhcp_create_request(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  u16_t i;
-  LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);
-  LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
-  dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
-  if (dhcp->p_out == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));
-    return ERR_MEM;
-  }
-  /* give unique transaction identifier to this request */
-  dhcp->xid = xid++;
-  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));
-
-  dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
-
-  dhcp->msg_out->op = DHCP_BOOTREQUEST;
-  /* TODO: make link layer independent */
-  dhcp->msg_out->htype = DHCP_HTYPE_ETH;
-  /* TODO: make link layer independent */
-  dhcp->msg_out->hlen = DHCP_HLEN_ETH;
-  dhcp->msg_out->hops = 0;
-  dhcp->msg_out->xid = htonl(dhcp->xid);
-  dhcp->msg_out->secs = 0;
-  dhcp->msg_out->flags = 0;
-  dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;
-  dhcp->msg_out->yiaddr.addr = 0;
-  dhcp->msg_out->siaddr.addr = 0;
-  dhcp->msg_out->giaddr.addr = 0;
-  for (i = 0; i < DHCP_CHADDR_LEN; i++) {
-    /* copy netif hardware address, pad with zeroes */
-    dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
-  }
-  for (i = 0; i < DHCP_SNAME_LEN; i++) dhcp->msg_out->sname[i] = 0;
-  for (i = 0; i < DHCP_FILE_LEN; i++) dhcp->msg_out->file[i] = 0;
-  dhcp->msg_out->cookie = htonl(0x63825363UL);
-  dhcp->options_out_len = 0;
-  /* fill options field with an incrementing array (for debugging purposes) */
-  for (i = 0; i < DHCP_OPTIONS_LEN; i++) dhcp->msg_out->options[i] = i;
-  return ERR_OK;
-}
-
-static void dhcp_delete_request(struct netif *netif)
-{
-  struct dhcp *dhcp = netif->dhcp;
-  LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
-  LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
-  pbuf_free(dhcp->p_out);
-  dhcp->p_out = NULL;
-  dhcp->msg_out = NULL;
-}
-
-/**
- * Add a DHCP message trailer
- *
- * Adds the END option to the DHCP message, and if
- * necessary, up to three padding bytes.
- */
-
-static void dhcp_option_trailer(struct dhcp *dhcp)
-{
-  LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
-  LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
-  dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
-  /* packet is too small, or not 4 byte aligned? */
-  while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
-    /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
-    LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
-    /* add a fill/padding byte */
-    dhcp->msg_out->options[dhcp->options_out_len++] = 0;
-  }
-}
-
-/**
- * Find the offset of a DHCP option inside the DHCP message.
- *
- * @param client DHCP client
- * @param option_type
- *
- * @return a byte offset into the UDP message where the option was found, or
- * zero if the given option was not found.
- */
-static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
-{
-  u8_t overload = DHCP_OVERLOAD_NONE;
-
-  /* options available? */
-  if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {
-    /* start with options field */
-    u8_t *options = (u8_t *)dhcp->options_in;
-    u16_t offset = 0;
-    /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
-    while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {
-      /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
-      /* are the sname and/or file field overloaded with options? */
-      if (options[offset] == DHCP_OPTION_OVERLOAD) {
-        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("overloaded message detected\n"));
-        /* skip option type and length */
-        offset += 2;
-        overload = options[offset++];
-      }
-      /* requested option found */
-      else if (options[offset] == option_type) {
-        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));
-        return &options[offset];
-      /* skip option */
-      } else {
-         LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));
-        /* skip option type */
-        offset++;
-        /* skip option length, and then length bytes */
-        offset += 1 + options[offset];
-      }
-    }
-    /* is this an overloaded message? */
-    if (overload != DHCP_OVERLOAD_NONE) {
-      u16_t field_len;
-      if (overload == DHCP_OVERLOAD_FILE) {
-        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded file field\n"));
-        options = (u8_t *)&dhcp->msg_in->file;
-        field_len = DHCP_FILE_LEN;
-      } else if (overload == DHCP_OVERLOAD_SNAME) {
-        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname field\n"));
-        options = (u8_t *)&dhcp->msg_in->sname;
-        field_len = DHCP_SNAME_LEN;
-      /* TODO: check if else if () is necessary */
-      } else {
-        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname and file field\n"));
-        options = (u8_t *)&dhcp->msg_in->sname;
-        field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;
-      }
-      offset = 0;
-
-      /* at least 1 byte to read and no end marker */
-      while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {
-        if (options[offset] == option_type) {
-           LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));
-          return &options[offset];
-        /* skip option */
-        } else {
-          LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));
-          /* skip option type */
-          offset++;
-          offset += 1 + options[offset];
-        }
-      }
-    }
-  }
-  return NULL;
-}
-
-/**
- * Return the byte of DHCP option data.
- *
- * @param client DHCP client.
- * @param ptr pointer obtained by dhcp_get_option_ptr().
- *
- * @return byte value at the given address.
- */
-static u8_t dhcp_get_option_byte(u8_t *ptr)
-{
-  LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));
-  return *ptr;
-}
-
-#if 0
-/**
- * Return the 16-bit value of DHCP option data.
- *
- * @param client DHCP client.
- * @param ptr pointer obtained by dhcp_get_option_ptr().
- *
- * @return byte value at the given address.
- */
-static u16_t dhcp_get_option_short(u8_t *ptr)
-{
-  u16_t value;
-  value = *ptr++ << 8;
-  value |= *ptr;
-  LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));
-  return value;
-}
-#endif
-
-/**
- * Return the 32-bit value of DHCP option data.
- *
- * @param client DHCP client.
- * @param ptr pointer obtained by dhcp_get_option_ptr().
- *
- * @return byte value at the given address.
- */
-static u32_t dhcp_get_option_long(u8_t *ptr)
-{
-  u32_t value;
-  value = (u32_t)(*ptr++) << 24;
-  value |= (u32_t)(*ptr++) << 16;
-  value |= (u32_t)(*ptr++) << 8;
-  value |= (u32_t)(*ptr++);
-  LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));
-  return value;
-}
-
-#endif /* LWIP_DHCP */
+/**

+ * @file

+ *

+ * Dynamic Host Configuration Protocol client

+ */

+

+/*

+ *

+ * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>

+ * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.

+ * 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 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.

+ *

+ * Author: Leon Woestenberg <leon.woestenberg@gmx.net>

+ *

+ * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform

+ * with RFC 2131 and RFC 2132.

+ *

+ * TODO:

+ * - Proper parsing of DHCP messages exploiting file/sname field overloading.

+ * - Add JavaDoc style documentation (API, internals).

+ * - Support for interfaces other than Ethernet (SLIP, PPP, ...)

+ *

+ * Please coordinate changes and requests with Leon Woestenberg

+ * <leon.woestenberg@gmx.net>

+ *

+ * Integration with your code:

+ *

+ * In lwip/dhcp.h

+ * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)

+ * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)

+ *

+ * Then have your application call dhcp_coarse_tmr() and

+ * dhcp_fine_tmr() on the defined intervals.

+ *

+ * dhcp_start(struct netif *netif);

+ * starts a DHCP client instance which configures the interface by

+ * obtaining an IP address lease and maintaining it.

+ *

+ * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)

+ * to remove the DHCP client.

+ *

+ */

+ 

+#include <string.h>

+ 

+#include "lwip/stats.h"

+#include "lwip/mem.h"

+#include "lwip/udp.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/inet.h"

+#include "netif/etharp.h"

+

+#include "lwip/sys.h"

+#include "lwip/opt.h"

+#include "lwip/dhcp.h"

+

+#if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */

+

+/** global transaction identifier, must be

+ *  unique for each DHCP request. We simply increment, starting

+ *  with this value (easy to match with a packet analyzer) */

+static u32_t xid = 0xABCD0000;

+

+/** DHCP client state machine functions */

+static void dhcp_handle_ack(struct netif *netif);

+static void dhcp_handle_nak(struct netif *netif);

+static void dhcp_handle_offer(struct netif *netif);

+

+static err_t dhcp_discover(struct netif *netif);

+static err_t dhcp_select(struct netif *netif);

+static void dhcp_check(struct netif *netif);

+static void dhcp_bind(struct netif *netif);

+static err_t dhcp_decline(struct netif *netif);

+static err_t dhcp_rebind(struct netif *netif);

+static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);

+

+/** receive, unfold, parse and free incoming messages */

+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);

+static err_t dhcp_unfold_reply(struct dhcp *dhcp);

+static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);

+static u8_t dhcp_get_option_byte(u8_t *ptr);

+#if 0

+static u16_t dhcp_get_option_short(u8_t *ptr);

+#endif

+static u32_t dhcp_get_option_long(u8_t *ptr);

+static void dhcp_free_reply(struct dhcp *dhcp);

+

+/** set the DHCP timers */

+static void dhcp_timeout(struct netif *netif);

+static void dhcp_t1_timeout(struct netif *netif);

+static void dhcp_t2_timeout(struct netif *netif);

+

+/** build outgoing messages */

+/** create a DHCP request, fill in common headers */

+static err_t dhcp_create_request(struct netif *netif);

+/** free a DHCP request */

+static void dhcp_delete_request(struct netif *netif);

+/** add a DHCP option (type, then length in bytes) */

+static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);

+/** add option values */

+static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);

+static void dhcp_option_short(struct dhcp *dhcp, u16_t value);

+static void dhcp_option_long(struct dhcp *dhcp, u32_t value);

+/** always add the DHCP options trailer to end and pad */

+static void dhcp_option_trailer(struct dhcp *dhcp);

+

+/**

+ * Back-off the DHCP client (because of a received NAK response).

+ *

+ * Back-off the DHCP client because of a received NAK. Receiving a

+ * NAK means the client asked for something non-sensible, for

+ * example when it tries to renew a lease obtained on another network.

+ *

+ * We back-off and will end up restarting a fresh DHCP negotiation later.

+ *

+ * @param state pointer to DHCP state structure

+ */

+static void dhcp_handle_nak(struct netif *netif) {

+  struct dhcp *dhcp = netif->dhcp;

+  u16_t msecs = 10 * 1000;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", 

+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_handle_nak(): set request timeout %"U16_F" msecs\n", msecs));

+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);

+}

+

+/**

+ * Checks if the offered IP address is already in use.

+ *

+ * It does so by sending an ARP request for the offered address and

+ * entering CHECKING state. If no ARP reply is received within a small

+ * interval, the address is assumed to be free for use by us.

+ */

+static void dhcp_check(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],

+    (s16_t)netif->name[1]));

+  /* create an ARP query for the offered IP address, expecting that no host

+     responds, as the IP address should not be in use. */

+  result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);

+  if (result != ERR_OK) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));

+  }

+  dhcp->tries++;

+  msecs = 500;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));

+  dhcp_set_state(dhcp, DHCP_CHECKING);

+}

+

+/**

+ * Remember the configuration offered by a DHCP server.

+ *

+ * @param state pointer to DHCP state structure

+ */

+static void dhcp_handle_offer(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  /* obtain the server address */

+  u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",

+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+  if (option_ptr != NULL)

+  {

+    dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));

+    /* remember offered address */

+    ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));

+

+    dhcp_select(netif);

+  }

+}

+

+/**

+ * Select a DHCP server offer out of all offers.

+ *

+ * Simply select the first offer received.

+ *

+ * @param netif the netif under DHCP control

+ * @return lwIP specific error (see error.h)

+ */

+static err_t dhcp_select(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u32_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK)

+  {

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_REQUEST);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    dhcp_option_short(dhcp, 576);

+

+    /* MUST request the offered IP address */

+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));

+

+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));

+

+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);

+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);

+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);

+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);

+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);

+

+    dhcp_option_trailer(dhcp);

+    /* shrink the pbuf to the actual content length */

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    /* TODO: we really should bind to a specific local interface here

+       but we cannot specify an unconfigured netif as it is addressless */

+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+    /* send broadcast to any DHCP server */

+    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);

+    udp_send(dhcp->pcb, dhcp->p_out);

+    /* reconnect to any (or to server here?!) */

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_select: REQUESTING\n"));

+    dhcp_set_state(dhcp, DHCP_REQUESTING);

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_select(): set request timeout %"U32_F" msecs\n", msecs));

+  return result;

+}

+

+/**

+ * The DHCP timer that checks for lease renewal/rebind timeouts.

+ *

+ */

+void dhcp_coarse_tmr()

+{

+  struct netif *netif = netif_list;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_coarse_tmr()\n"));

+  /* iterate through all network interfaces */

+  while (netif != NULL) {

+    /* only act on DHCP configured interfaces */

+    if (netif->dhcp != NULL) {

+      /* timer is active (non zero), and triggers (zeroes) now? */

+      if (netif->dhcp->t2_timeout-- == 1) {

+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));

+        /* this clients' rebind timeout triggered */

+        dhcp_t2_timeout(netif);

+      /* timer is active (non zero), and triggers (zeroes) now */

+      } else if (netif->dhcp->t1_timeout-- == 1) {

+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));

+        /* this clients' renewal timeout triggered */

+        dhcp_t1_timeout(netif);

+      }

+    }

+    /* proceed to next netif */

+    netif = netif->next;

+  }

+}

+

+/**

+ * DHCP transaction timeout handling

+ *

+ * A DHCP server is expected to respond within a short period of time.

+ * This timer checks whether an outstanding DHCP request is timed out.

+ * 

+ */

+void dhcp_fine_tmr()

+{

+  struct netif *netif = netif_list;

+  /* loop through netif's */

+  while (netif != NULL) {

+    /* only act on DHCP configured interfaces */

+    if (netif->dhcp != NULL) {

+      /* timer is active (non zero), and is about to trigger now */      

+      if (netif->dhcp->request_timeout > 1) {

+        netif->dhcp->request_timeout--;

+      }

+      else if (netif->dhcp->request_timeout == 1) {

+        netif->dhcp->request_timeout--;

+        /* { netif->dhcp->request_timeout == 0 } */

+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));

+        /* this clients' request timeout triggered */

+        dhcp_timeout(netif);

+      }

+    }

+    /* proceed to next network interface */

+    netif = netif->next;

+  }

+}

+

+/**

+ * A DHCP negotiation transaction, or ARP request, has timed out.

+ *

+ * The timer that was started with the DHCP or ARP request has

+ * timed out, indicating no response was received in time.

+ *

+ * @param netif the netif under DHCP control

+ *

+ */

+static void dhcp_timeout(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_timeout()\n"));

+  /* back-off period has passed, or server selection timed out */

+  if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));

+    dhcp_discover(netif);

+  /* receiving the requested lease timed out */

+  } else if (dhcp->state == DHCP_REQUESTING) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));

+    if (dhcp->tries <= 5) {

+      dhcp_select(netif);

+    } else {

+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));

+      dhcp_release(netif);

+      dhcp_discover(netif);

+    }

+  /* received no ARP reply for the offered address (which is good) */

+  } else if (dhcp->state == DHCP_CHECKING) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));

+    if (dhcp->tries <= 1) {

+      dhcp_check(netif);

+    /* no ARP replies on the offered address,

+       looks like the IP address is indeed free */

+    } else {

+      /* bind the interface to the offered address */

+      dhcp_bind(netif);

+    }

+  }

+  /* did not get response to renew request? */

+  else if (dhcp->state == DHCP_RENEWING) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));

+    /* just retry renewal */

+    /* note that the rebind timer will eventually time-out if renew does not work */

+    dhcp_renew(netif);

+  /* did not get response to rebind request? */

+  } else if (dhcp->state == DHCP_REBINDING) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));

+    if (dhcp->tries <= 8) {

+      dhcp_rebind(netif);

+    } else {

+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));

+      dhcp_release(netif);

+      dhcp_discover(netif);

+    }

+  }

+}

+

+/**

+ * The renewal period has timed out.

+ *

+ * @param netif the netif under DHCP control

+ */

+static void dhcp_t1_timeout(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_t1_timeout()\n"));

+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {

+    /* just retry to renew - note that the rebind timer (t2) will

+     * eventually time-out if renew tries fail. */

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));

+    dhcp_renew(netif);

+  }

+}

+

+/**

+ * The rebind period has timed out.

+ *

+ */

+static void dhcp_t2_timeout(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout()\n"));

+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {

+    /* just retry to rebind */

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));

+    dhcp_rebind(netif);

+  }

+}

+

+/**

+ *

+ * @param netif the netif under DHCP control

+ */

+static void dhcp_handle_ack(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  u8_t *option_ptr;

+  /* clear options we might not get from the ACK */

+  dhcp->offered_sn_mask.addr = 0;

+  dhcp->offered_gw_addr.addr = 0;

+  dhcp->offered_bc_addr.addr = 0;

+

+  /* lease time given? */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);

+  if (option_ptr != NULL) {

+    /* remember offered lease time */

+    dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);

+  }

+  /* renewal period given? */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);

+  if (option_ptr != NULL) {

+    /* remember given renewal period */

+    dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);

+  } else {

+    /* calculate safe periods for renewal */

+    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;

+  }

+

+  /* renewal period given? */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);

+  if (option_ptr != NULL) {

+    /* remember given rebind period */

+    dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);

+  } else {

+    /* calculate safe periods for rebinding */

+    dhcp->offered_t2_rebind = dhcp->offered_t0_lease;

+  }

+

+  /* (y)our internet address */

+  ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);

+

+/**

+ * Patch #1308

+ * TODO: we must check if the file field is not overloaded by DHCP options!

+ */

+#if 0

+  /* boot server address */

+  ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);

+  /* boot file name */

+  if (dhcp->msg_in->file[0]) {

+    dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);

+    strcpy(dhcp->boot_file_name, dhcp->msg_in->file);

+  }

+#endif

+

+  /* subnet mask */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);

+  /* subnet mask given? */

+  if (option_ptr != NULL) {

+    dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));

+  }

+

+  /* gateway router */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);

+  if (option_ptr != NULL) {

+    dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));

+  }

+

+  /* broadcast address */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);

+  if (option_ptr != NULL) {

+    dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));

+  }

+  

+  /* DNS servers */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);

+  if (option_ptr != NULL) {

+    u8_t n;

+    dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);

+    /* limit to at most DHCP_MAX_DNS DNS servers */

+    if (dhcp->dns_count > DHCP_MAX_DNS)

+      dhcp->dns_count = DHCP_MAX_DNS;

+    for (n = 0; n < dhcp->dns_count; n++) {

+      dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));

+    }

+  }

+}

+

+/**

+ * Start DHCP negotiation for a network interface.

+ *

+ * If no DHCP client instance was attached to this interface,

+ * a new client is created first. If a DHCP client instance

+ * was already present, it restarts negotiation.

+ *

+ * @param netif The lwIP network interface

+ * @return lwIP error code

+ * - ERR_OK - No error

+ * - ERR_MEM - Out of memory

+ *

+ */

+err_t dhcp_start(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result = ERR_OK;

+

+  LWIP_ASSERT("netif != NULL", netif != NULL);

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+  netif->flags &= ~NETIF_FLAG_DHCP;

+

+  /* no DHCP client attached yet? */

+  if (dhcp == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));

+    dhcp = mem_malloc(sizeof(struct dhcp));

+    if (dhcp == NULL) {

+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));

+      return ERR_MEM;

+    }

+    /* store this dhcp client in the netif */

+    netif->dhcp = dhcp;

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));

+  /* already has DHCP client attached */

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));

+  }

+    

+  /* clear data structure */

+  memset(dhcp, 0, sizeof(struct dhcp));

+  /* allocate UDP PCB */

+  dhcp->pcb = udp_new();

+  if (dhcp->pcb == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG  | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));

+    mem_free((void *)dhcp);

+    netif->dhcp = dhcp = NULL;

+    return ERR_MEM;

+  }

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));

+  /* (re)start the DHCP negotiation */

+  result = dhcp_discover(netif);

+  if (result != ERR_OK) {

+    /* free resources allocated above */

+    dhcp_stop(netif);

+    return ERR_MEM;

+  }

+  netif->flags |= NETIF_FLAG_DHCP;

+  return result;

+}

+

+/**

+ * Inform a DHCP server of our manual configuration.

+ *

+ * This informs DHCP servers of our fixed IP address configuration

+ * by sending an INFORM message. It does not involve DHCP address

+ * configuration, it is just here to be nice to the network.

+ *

+ * @param netif The lwIP network interface

+ *

+ */

+void dhcp_inform(struct netif *netif)

+{

+  struct dhcp *dhcp;

+  err_t result = ERR_OK;

+  dhcp = mem_malloc(sizeof(struct dhcp));

+  if (dhcp == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));

+    return;

+  }

+  netif->dhcp = dhcp;

+  memset(dhcp, 0, sizeof(struct dhcp));

+

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));

+  dhcp->pcb = udp_new();

+  if (dhcp->pcb == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));

+    mem_free((void *)dhcp);

+    return;

+  }

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_INFORM);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    /* TODO: use netif->mtu ?! */

+    dhcp_option_short(dhcp, 576);

+

+    dhcp_option_trailer(dhcp);

+

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_inform: INFORMING\n"));

+    udp_send(dhcp->pcb, dhcp->p_out);

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    dhcp_delete_request(netif);

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));

+  }

+

+  if (dhcp != NULL)

+  {

+    if (dhcp->pcb != NULL) udp_remove(dhcp->pcb);

+    dhcp->pcb = NULL;

+    mem_free((void *)dhcp);

+    netif->dhcp = NULL;

+  }

+}

+

+#if DHCP_DOES_ARP_CHECK

+/**

+ * Match an ARP reply with the offered IP address.

+ *

+ * @param addr The IP address we received a reply from

+ *

+ */

+void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)

+{

+  LWIP_ASSERT("netif != NULL", netif != NULL);

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_arp_reply()\n"));

+  /* is a DHCP client doing an ARP check? */

+  if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));

+    /* did a host respond with the address we

+       were offered by the DHCP server? */

+    if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {

+      /* we will not accept the offered address */

+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));

+      dhcp_decline(netif);

+    }

+  }

+}

+

+/**

+ * Decline an offered lease.

+ *

+ * Tell the DHCP server we do not accept the offered address.

+ * One reason to decline the lease is when we find out the address

+ * is already in use by another host (through ARP).

+ */

+static err_t dhcp_decline(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result = ERR_OK;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_decline()\n"));

+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK)

+  {

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_DECLINE);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    dhcp_option_short(dhcp, 576);

+

+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));

+

+    dhcp_option_trailer(dhcp);

+    /* resize pbuf to reflect true size of options */

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+    /* @todo: should we really connect here? we are performing sendto() */

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    /* per section 4.4.4, broadcast DECLINE messages */

+    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n"));

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = 10*1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+#endif

+

+

+/**

+ * Start the DHCP process, discover a DHCP server.

+ *

+ */

+static err_t dhcp_discover(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result = ERR_OK;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_discover()\n"));

+  ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK)

+  {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: making request\n"));

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_DISCOVER);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    dhcp_option_short(dhcp, 576);

+

+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);

+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);

+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);

+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);

+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);

+

+    dhcp_option_trailer(dhcp);

+

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: realloc()ing\n"));

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    /* set receive callback function with netif as user data */

+    udp_recv(dhcp->pcb, dhcp_recv, netif);

+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));

+    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: deleting()ing\n"));

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover: SELECTING\n"));

+    dhcp_set_state(dhcp, DHCP_SELECTING);

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+

+

+/**

+ * Bind the interface to the offered IP address.

+ *

+ * @param netif network interface to bind to the offered address

+ */

+static void dhcp_bind(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  struct ip_addr sn_mask, gw_addr;

+  LWIP_ASSERT("dhcp_bind: netif != NULL", netif != NULL);

+  LWIP_ASSERT("dhcp_bind: dhcp != NULL", dhcp != NULL);

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+

+  /* temporary DHCP lease? */

+  if (dhcp->offered_t1_renew != 0xffffffffUL) {

+    /* set renewal period timer */

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));

+    dhcp->t1_timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;

+    if (dhcp->t1_timeout == 0) dhcp->t1_timeout = 1;

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));

+  }

+  /* set renewal period timer */

+  if (dhcp->offered_t2_rebind != 0xffffffffUL) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));

+    dhcp->t2_timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;

+    if (dhcp->t2_timeout == 0) dhcp->t2_timeout = 1;

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));

+  }

+  /* copy offered network mask */

+  ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);

+

+  /* subnet mask not given? */

+  /* TODO: this is not a valid check. what if the network mask is 0? */

+  if (sn_mask.addr == 0) {

+    /* choose a safe subnet mask given the network class */

+    u8_t first_octet = ip4_addr1(&sn_mask);

+    if (first_octet <= 127) sn_mask.addr = htonl(0xff000000);

+    else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00);

+    else sn_mask.addr = htonl(0xffff0000);

+  }

+

+  ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);

+  /* gateway address not given? */

+  if (gw_addr.addr == 0) {

+    /* copy network address */

+    gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);

+    /* use first host address on network as gateway */

+    gw_addr.addr |= htonl(0x00000001);

+  }

+

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));

+  netif_set_ipaddr(netif, &dhcp->offered_ip_addr);

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));

+  netif_set_netmask(netif, &sn_mask);

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));

+  netif_set_gw(netif, &gw_addr);

+  /* bring the interface up */

+  netif_set_up(netif);

+  /* netif is now bound to DHCP leased address */

+  dhcp_set_state(dhcp, DHCP_BOUND);

+}

+

+/**

+ * Renew an existing DHCP lease at the involved DHCP server.

+ *

+ * @param netif network interface which must renew its lease

+ */

+err_t dhcp_renew(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_renew()\n"));

+  dhcp_set_state(dhcp, DHCP_RENEWING);

+

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_REQUEST);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    /* TODO: use netif->mtu in some way */

+    dhcp_option_short(dhcp, 576);

+

+#if 0

+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));

+#endif

+

+#if 0

+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));

+#endif

+    /* append DHCP message trailer */

+    dhcp_option_trailer(dhcp);

+

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);

+    udp_send(dhcp->pcb, dhcp->p_out);

+    dhcp_delete_request(netif);

+

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew: RENEWING\n"));

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  /* back-off on retries, but to a maximum of 20 seconds */

+  msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+

+/**

+ * Rebind with a DHCP server for an existing DHCP lease.

+ *

+ * @param netif network interface which must rebind with a DHCP server

+ */

+static err_t dhcp_rebind(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind()\n"));

+  dhcp_set_state(dhcp, DHCP_REBINDING);

+

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK)

+  {

+

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_REQUEST);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    dhcp_option_short(dhcp, 576);

+

+#if 0

+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));

+

+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));

+#endif

+

+    dhcp_option_trailer(dhcp);

+

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    /* set remote IP association to any DHCP server */

+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    /* broadcast to server */

+    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind: REBINDING\n"));

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+

+/**

+ * Release a DHCP lease.

+ *

+ * @param netif network interface which must release its lease

+ */

+err_t dhcp_release(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_release()\n"));

+

+  /* idle DHCP client */

+  dhcp_set_state(dhcp, DHCP_OFF);

+  /* clean old DHCP offer */

+  dhcp->server_ip_addr.addr = 0;

+  dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;

+  dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;

+  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;

+  dhcp->dns_count = 0;

+  

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_RELEASE);

+

+    dhcp_option_trailer(dhcp);

+

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);

+    udp_send(dhcp->pcb, dhcp->p_out);

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));

+  /* bring the interface down */

+  netif_set_down(netif);

+  /* remove IP address from interface */

+  netif_set_ipaddr(netif, IP_ADDR_ANY);

+  netif_set_gw(netif, IP_ADDR_ANY);

+  netif_set_netmask(netif, IP_ADDR_ANY);

+  

+  /* TODO: netif_down(netif); */

+  return result;

+}

+/**

+ * Remove the DHCP client from the interface.

+ *

+ * @param netif The network interface to stop DHCP on

+ */

+void dhcp_stop(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_ASSERT("dhcp_stop: netif != NULL", netif != NULL);

+

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_stop()\n"));

+  /* netif is DHCP configured? */

+  if (dhcp != NULL)

+  {

+    if (dhcp->pcb != NULL)

+    {

+      udp_remove(dhcp->pcb);

+      dhcp->pcb = NULL;

+    }

+    if (dhcp->p != NULL)

+    {

+      pbuf_free(dhcp->p);

+      dhcp->p = NULL;

+    }

+    /* free unfolded reply */

+    dhcp_free_reply(dhcp);

+    mem_free((void *)dhcp);

+    netif->dhcp = NULL;

+  }

+}

+

+/*

+ * Set the DHCP state of a DHCP client.

+ *

+ * If the state changed, reset the number of tries.

+ *

+ * TODO: we might also want to reset the timeout here?

+ */

+static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state)

+{

+  if (new_state != dhcp->state)

+  {

+    dhcp->state = new_state;

+    dhcp->tries = 0;

+  }

+}

+

+/*

+ * Concatenate an option type and length field to the outgoing

+ * DHCP message.

+ *

+ */

+static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)

+{

+  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = option_type;

+  dhcp->msg_out->options[dhcp->options_out_len++] = option_len;

+}

+/*

+ * Concatenate a single byte to the outgoing DHCP message.

+ *

+ */

+static void dhcp_option_byte(struct dhcp *dhcp, u8_t value)

+{

+  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = value;

+}

+static void dhcp_option_short(struct dhcp *dhcp, u16_t value)

+{

+  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff00U) >> 8;

+  dhcp->msg_out->options[dhcp->options_out_len++] =  value & 0x00ffU;

+}

+static void dhcp_option_long(struct dhcp *dhcp, u32_t value)

+{

+  LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff000000UL) >> 24;

+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x00ff0000UL) >> 16;

+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x0000ff00UL) >> 8;

+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x000000ffUL);

+}

+

+/**

+ * Extract the DHCP message and the DHCP options.

+ *

+ * Extract the DHCP message and the DHCP options, each into a contiguous

+ * piece of memory. As a DHCP message is variable sized by its options,

+ * and also allows overriding some fields for options, the easy approach

+ * is to first unfold the options into a conitguous piece of memory, and

+ * use that further on.

+ *

+ */

+static err_t dhcp_unfold_reply(struct dhcp *dhcp)

+{

+  struct pbuf *p = dhcp->p;

+  u8_t *ptr;

+  u16_t i;

+  u16_t j = 0;

+  LWIP_ASSERT("dhcp->p != NULL", dhcp->p != NULL);

+  /* free any left-overs from previous unfolds */

+  dhcp_free_reply(dhcp);

+  /* options present? */

+  if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN))

+  {

+    dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);

+    dhcp->options_in = mem_malloc(dhcp->options_in_len);

+    if (dhcp->options_in == NULL)

+    {

+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));

+      return ERR_MEM;

+    }

+  }

+  dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);

+  if (dhcp->msg_in == NULL)

+  {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));

+    mem_free((void *)dhcp->options_in);

+    dhcp->options_in = NULL;

+    return ERR_MEM;

+  }

+

+  ptr = (u8_t *)dhcp->msg_in;

+  /* proceed through struct dhcp_msg */

+  for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++)

+  {

+    *ptr++ = ((u8_t *)p->payload)[j++];

+    /* reached end of pbuf? */

+    if (j == p->len)

+    {

+      /* proceed to next pbuf in chain */

+      p = p->next;

+      j = 0;

+    }

+  }

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", i));

+  if (dhcp->options_in != NULL) {

+    ptr = (u8_t *)dhcp->options_in;

+    /* proceed through options */

+    for (i = 0; i < dhcp->options_in_len; i++) {

+      *ptr++ = ((u8_t *)p->payload)[j++];

+      /* reached end of pbuf? */

+      if (j == p->len) {

+        /* proceed to next pbuf in chain */

+        p = p->next;

+        j = 0;

+      }

+    }

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", i));

+  }

+  return ERR_OK;

+}

+

+/**

+ * Free the incoming DHCP message including contiguous copy of

+ * its DHCP options.

+ *

+ */

+static void dhcp_free_reply(struct dhcp *dhcp)

+{

+  if (dhcp->msg_in != NULL) {

+    mem_free((void *)dhcp->msg_in);

+    dhcp->msg_in = NULL;

+  }

+  if (dhcp->options_in) {

+    mem_free((void *)dhcp->options_in);

+    dhcp->options_in = NULL;

+    dhcp->options_in_len = 0;

+  }

+  LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));

+}

+

+

+/**

+ * If an incoming DHCP message is in response to us, then trigger the state machine

+ */

+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)

+{

+  struct netif *netif = (struct netif *)arg;

+  struct dhcp *dhcp = netif->dhcp;

+  struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;

+  u8_t *options_ptr;

+  u8_t msg_type;

+  u8_t i;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,

+    (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),

+    (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));

+  /* prevent warnings about unused arguments */

+  (void)pcb; (void)addr; (void)port;

+  dhcp->p = p;

+  /* TODO: check packet length before reading them */

+  if (reply_msg->op != DHCP_BOOTREPLY) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));

+    pbuf_free(p);

+    dhcp->p = NULL;

+    return;

+  }

+  /* iterate through hardware address and match against DHCP message */

+  for (i = 0; i < netif->hwaddr_len; i++) {

+    if (netif->hwaddr[i] != reply_msg->chaddr[i]) {

+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",

+        (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));

+      pbuf_free(p);

+      dhcp->p = NULL;

+      return;

+    }

+  }

+  /* match transaction ID against what we expected */

+  if (ntohl(reply_msg->xid) != dhcp->xid) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));

+    pbuf_free(p);

+    dhcp->p = NULL;

+    return;

+  }

+  /* option fields could be unfold? */

+  if (dhcp_unfold_reply(dhcp) != ERR_OK) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));

+    pbuf_free(p);

+    dhcp->p = NULL;

+    return;

+  }

+

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));

+  /* obtain pointer to DHCP message type */

+  options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);

+  if (options_ptr == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));

+    pbuf_free(p);

+    dhcp->p = NULL;

+    return;

+  }

+

+  /* read DHCP message type */

+  msg_type = dhcp_get_option_byte(options_ptr + 2);

+  /* message type is DHCP ACK? */

+  if (msg_type == DHCP_ACK) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_ACK received\n"));

+    /* in requesting state? */

+    if (dhcp->state == DHCP_REQUESTING) {

+      dhcp_handle_ack(netif);

+      dhcp->request_timeout = 0;

+#if DHCP_DOES_ARP_CHECK

+      /* check if the acknowledged lease address is already in use */

+      dhcp_check(netif);

+#else

+      /* bind interface to the acknowledged lease address */

+      dhcp_bind(netif);

+#endif

+    }

+    /* already bound to the given lease address? */

+    else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {

+      dhcp->request_timeout = 0;

+      dhcp_bind(netif);

+    }

+  }

+  /* received a DHCP_NAK in appropriate state? */

+  else if ((msg_type == DHCP_NAK) &&

+    ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||

+     (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_NAK received\n"));

+    dhcp->request_timeout = 0;

+    dhcp_handle_nak(netif);

+  }

+  /* received a DHCP_OFFER in DHCP_SELECTING state? */

+  else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));

+    dhcp->request_timeout = 0;

+    /* remember offered lease */

+    dhcp_handle_offer(netif);

+  }

+  pbuf_free(p);

+  dhcp->p = NULL;

+}

+

+

+static err_t dhcp_create_request(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  u16_t i;

+  LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);

+  LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);

+  dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);

+  if (dhcp->p_out == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));

+    return ERR_MEM;

+  }

+  /* give unique transaction identifier to this request */

+  dhcp->xid = xid++;

+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));

+

+  dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;

+

+  dhcp->msg_out->op = DHCP_BOOTREQUEST;

+  /* TODO: make link layer independent */

+  dhcp->msg_out->htype = DHCP_HTYPE_ETH;

+  /* TODO: make link layer independent */

+  dhcp->msg_out->hlen = DHCP_HLEN_ETH;

+  dhcp->msg_out->hops = 0;

+  dhcp->msg_out->xid = htonl(dhcp->xid);

+  dhcp->msg_out->secs = 0;

+  dhcp->msg_out->flags = 0;

+  dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;

+  dhcp->msg_out->yiaddr.addr = 0;

+  dhcp->msg_out->siaddr.addr = 0;

+  dhcp->msg_out->giaddr.addr = 0;

+  for (i = 0; i < DHCP_CHADDR_LEN; i++) {

+    /* copy netif hardware address, pad with zeroes */

+    dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;

+  }

+  for (i = 0; i < DHCP_SNAME_LEN; i++) dhcp->msg_out->sname[i] = 0;

+  for (i = 0; i < DHCP_FILE_LEN; i++) dhcp->msg_out->file[i] = 0;

+  dhcp->msg_out->cookie = htonl(0x63825363UL);

+  dhcp->options_out_len = 0;

+  /* fill options field with an incrementing array (for debugging purposes) */

+  for (i = 0; i < DHCP_OPTIONS_LEN; i++) dhcp->msg_out->options[i] = i;

+  return ERR_OK;

+}

+

+static void dhcp_delete_request(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);

+  LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);

+  pbuf_free(dhcp->p_out);

+  dhcp->p_out = NULL;

+  dhcp->msg_out = NULL;

+}

+

+/**

+ * Add a DHCP message trailer

+ *

+ * Adds the END option to the DHCP message, and if

+ * necessary, up to three padding bytes.

+ */

+

+static void dhcp_option_trailer(struct dhcp *dhcp)

+{

+  LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);

+  LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;

+  /* packet is too small, or not 4 byte aligned? */

+  while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {

+    /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */

+    LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);

+    /* add a fill/padding byte */

+    dhcp->msg_out->options[dhcp->options_out_len++] = 0;

+  }

+}

+

+/**

+ * Find the offset of a DHCP option inside the DHCP message.

+ *

+ * @param client DHCP client

+ * @param option_type

+ *

+ * @return a byte offset into the UDP message where the option was found, or

+ * zero if the given option was not found.

+ */

+static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)

+{

+  u8_t overload = DHCP_OVERLOAD_NONE;

+

+  /* options available? */

+  if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {

+    /* start with options field */

+    u8_t *options = (u8_t *)dhcp->options_in;

+    u16_t offset = 0;

+    /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */

+    while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {

+      /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */

+      /* are the sname and/or file field overloaded with options? */

+      if (options[offset] == DHCP_OPTION_OVERLOAD) {

+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("overloaded message detected\n"));

+        /* skip option type and length */

+        offset += 2;

+        overload = options[offset++];

+      }

+      /* requested option found */

+      else if (options[offset] == option_type) {

+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));

+        return &options[offset];

+      /* skip option */

+      } else {

+         LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));

+        /* skip option type */

+        offset++;

+        /* skip option length, and then length bytes */

+        offset += 1 + options[offset];

+      }

+    }

+    /* is this an overloaded message? */

+    if (overload != DHCP_OVERLOAD_NONE) {

+      u16_t field_len;

+      if (overload == DHCP_OVERLOAD_FILE) {

+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded file field\n"));

+        options = (u8_t *)&dhcp->msg_in->file;

+        field_len = DHCP_FILE_LEN;

+      } else if (overload == DHCP_OVERLOAD_SNAME) {

+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname field\n"));

+        options = (u8_t *)&dhcp->msg_in->sname;

+        field_len = DHCP_SNAME_LEN;

+      /* TODO: check if else if () is necessary */

+      } else {

+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname and file field\n"));

+        options = (u8_t *)&dhcp->msg_in->sname;

+        field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;

+      }

+      offset = 0;

+

+      /* at least 1 byte to read and no end marker */

+      while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {

+        if (options[offset] == option_type) {

+           LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));

+          return &options[offset];

+        /* skip option */

+        } else {

+          LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));

+          /* skip option type */

+          offset++;

+          offset += 1 + options[offset];

+        }

+      }

+    }

+  }

+  return NULL;

+}

+

+/**

+ * Return the byte of DHCP option data.

+ *

+ * @param client DHCP client.

+ * @param ptr pointer obtained by dhcp_get_option_ptr().

+ *

+ * @return byte value at the given address.

+ */

+static u8_t dhcp_get_option_byte(u8_t *ptr)

+{

+  LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));

+  return *ptr;

+}

+

+#if 0

+/**

+ * Return the 16-bit value of DHCP option data.

+ *

+ * @param client DHCP client.

+ * @param ptr pointer obtained by dhcp_get_option_ptr().

+ *

+ * @return byte value at the given address.

+ */

+static u16_t dhcp_get_option_short(u8_t *ptr)

+{

+  u16_t value;

+  value = *ptr++ << 8;

+  value |= *ptr;

+  LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));

+  return value;

+}

+#endif

+

+/**

+ * Return the 32-bit value of DHCP option data.

+ *

+ * @param client DHCP client.

+ * @param ptr pointer obtained by dhcp_get_option_ptr().

+ *

+ * @return byte value at the given address.

+ */

+static u32_t dhcp_get_option_long(u8_t *ptr)

+{

+  u32_t value;

+  value = (u32_t)(*ptr++) << 24;

+  value |= (u32_t)(*ptr++) << 16;

+  value |= (u32_t)(*ptr++) << 8;

+  value |= (u32_t)(*ptr++);

+  LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));

+  return value;

+}

+

+#endif /* LWIP_DHCP */

diff --git a/Demo/Common/ethernet/lwIP/core/inet.c b/Demo/Common/ethernet/lwIP/core/inet.c
index 2c54389..d9d52c5 100644
--- a/Demo/Common/ethernet/lwIP/core/inet.c
+++ b/Demo/Common/ethernet/lwIP/core/inet.c
@@ -1,537 +1,537 @@
-/*
- * 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>
- *
- */
-
-
-/* inet.c
- *
- * Functions common to all TCP/IP modules, such as the Internet checksum and the
- * byte order functions.
- *
- */
-
-
-#include "lwip/opt.h"
-
-#include "lwip/arch.h"
-
-#include "lwip/def.h"
-#include "lwip/inet.h"
-
-#include "lwip/sys.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 sys_arch.h put:
- * 
- * #define LWIP_CHKSUM <your_checksum_routine> 
-*/
-#ifndef LWIP_CHKSUM
-#define LWIP_CHKSUM lwip_standard_chksum
-
-#if 1 /* Version A */
-/**
- * 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 & 0xffff0000) != 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 0 /* Version B */
-/*
- * 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
- */
-
-static u16_t
-lwip_standard_chksum(void *dataptr, int len)
-{
-  u8_t *pb = dataptr;
-  u16_t *ps, t = 0;
-  u32_t sum = 0;
-  int odd = ((u32_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 *)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 */
-  while (sum >> 16)
-    sum = (sum & 0xffff) + (sum >> 16);
-
-  /* Swap if alignment was odd */
-  if (odd)
-    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
-
-  return sum;
-}
-#endif
-
-#if 0 /* Version C */
-/**
- * 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.
- * 
- * by Curt McDowell, Broadcom Corp. December 8th, 2005
- */
-
-static u16_t
-lwip_standard_chksum(void *dataptr, int len)
-{
-  u8_t *pb = dataptr;
-  u16_t *ps, t = 0;
-  u32_t *pl;
-  u32_t sum = 0, tmp;
-  /* starts at odd byte address? */
-  int odd = ((u32_t)pb & 1);
-
-  if (odd && len > 0) {
-    ((u8_t *)&t)[1] = *pb++;
-    len--;
-  }
-
-  ps = (u16_t *)pb;
-
-  if (((u32_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 = (sum >> 16) + (sum & 0xffff);
-
-  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 */
-
-  while (sum >> 16)             /* combine halves */
-    sum = (sum >> 16) + (sum & 0xffff);
-
-  if (odd)
-    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
-
-  return sum;
-}
-#endif
-
-#endif /* LWIP_CHKSUM */
-
-/* inet_chksum_pseudo:
- *
- * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
- */
-
-u16_t
-inet_chksum_pseudo(struct pbuf *p,
-       struct ip_addr *src, struct ip_addr *dest,
-       u8_t proto, u16_t proto_len)
-{
-  u32_t acc;
-  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));*/
-    while (acc >> 16) {
-      acc = (acc & 0xffffUL) + (acc >> 16);
-    }
-    if (q->len % 2 != 0) {
-      swapped = 1 - swapped;
-      acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
-    }
-    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
-  }
-
-  if (swapped) {
-    acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
-  }
-  acc += (src->addr & 0xffffUL);
-  acc += ((src->addr >> 16) & 0xffffUL);
-  acc += (dest->addr & 0xffffUL);
-  acc += ((dest->addr >> 16) & 0xffffUL);
-  acc += (u32_t)htons((u16_t)proto);
-  acc += (u32_t)htons(proto_len);
-
-  while (acc >> 16) {
-    acc = (acc & 0xffffUL) + (acc >> 16);
-  }
-  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.
- */
-
-u16_t
-inet_chksum(void *dataptr, u16_t len)
-{
-  u32_t acc;
-
-  acc = LWIP_CHKSUM(dataptr, len);
-  while (acc >> 16) {
-    acc = (acc & 0xffff) + (acc >> 16);
-  }
-  return (u16_t)~(acc & 0xffff);
-}
-
-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);
-    while (acc >> 16) {
-      acc = (acc & 0xffffUL) + (acc >> 16);
-    }
-    if (q->len % 2 != 0) {
-      swapped = 1 - swapped;
-      acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);
-    }
-  }
-
-  if (swapped) {
-    acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);
-  }
-  return (u16_t)~(acc & 0xffffUL);
-}
-
-/* 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.
- */
-
-u32_t
-inet_addr(const char *cp)
-{
-  struct in_addr val;
-
-  if (inet_aton(cp, &val)) {
-    return (val.s_addr);
-  }
-  return (INADDR_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.
- */
-int
-inet_aton(const char *cp, struct in_addr *addr)
-{
-  u32_t val;
-  int base, n, 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' && (!isprint(c) || !isspace(c)))
-    return (0);
-  /*
-   * Concoct the address according to
-   * the number of parts specified.
-   */
-  n = pp - parts + 1;
-  switch (n) {
-
-  case 0:
-    return (0);       /* initial nondigit */
-
-  case 1:             /* a -- 32 bits */
-    break;
-
-  case 2:             /* a.b -- 8.24 bits */
-    if (val > 0xffffff)
-      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;
-  }
-  if (addr)
-    addr->s_addr = htonl(val);
-  return (1);
-}
-
-/* Convert numeric IP address into decimal dotted ASCII representation.
- * returns ptr to static buffer; not reentrant!
- */
-char *
-inet_ntoa(struct in_addr addr)
-{
-  static char str[16];
-  u32_t s_addr = addr.s_addr;
-  char inv[3];
-  char *rp;
-  u8_t *ap;
-  u8_t rem;
-  u8_t n;
-  u8_t i;
-
-  rp = str;
-  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--)
-      *rp++ = inv[i];
-    *rp++ = '.';
-    ap++;
-  }
-  *--rp = 0;
-  return str;
-}
-
-/*
- * These are reference implementations of the byte swapping functions.
- * Again with the aim of being simple, correct and fully portable.
- * Byte swapping is the second thing you would want to optimize. You will
- * need to port it to your architecture and in your cc.h:
- * 
- * #define LWIP_PLATFORM_BYTESWAP 1
- * #define LWIP_PLATFORM_HTONS(x) <your_htons>
- * #define LWIP_PLATFORM_HTONL(x) <your_htonl>
- *
- * Note ntohs() and ntohl() are merely references to the htonx counterparts.
- */
-
-#ifndef BYTE_ORDER
-#error BYTE_ORDER is not defined
-#endif
-#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
-
-u16_t
-htons(u16_t n)
-{
-  return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
-}
-
-u16_t
-ntohs(u16_t n)
-{
-  return htons(n);
-}
-
-u32_t
-htonl(u32_t n)
-{
-  return ((n & 0xff) << 24) |
-    ((n & 0xff00) << 8) |
-    ((n & 0xff0000) >> 8) |
-    ((n & 0xff000000) >> 24);
-}
-
-u32_t
-ntohl(u32_t n)
-{
-  return htonl(n);
-}
-
-#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
+/*

+ * 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>

+ *

+ */

+

+

+/* inet.c

+ *

+ * Functions common to all TCP/IP modules, such as the Internet checksum and the

+ * byte order functions.

+ *

+ */

+

+

+#include "lwip/opt.h"

+

+#include "lwip/arch.h"

+

+#include "lwip/def.h"

+#include "lwip/inet.h"

+

+#include "lwip/sys.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 sys_arch.h put:

+ * 

+ * #define LWIP_CHKSUM <your_checksum_routine> 

+*/

+#ifndef LWIP_CHKSUM

+#define LWIP_CHKSUM lwip_standard_chksum

+

+#if 1 /* Version A */

+/**

+ * 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 & 0xffff0000) != 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 0 /* Version B */

+/*

+ * 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

+ */

+

+static u16_t

+lwip_standard_chksum(void *dataptr, int len)

+{

+  u8_t *pb = dataptr;

+  u16_t *ps, t = 0;

+  u32_t sum = 0;

+  int odd = ((u32_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 *)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 */

+  while (sum >> 16)

+    sum = (sum & 0xffff) + (sum >> 16);

+

+  /* Swap if alignment was odd */

+  if (odd)

+    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);

+

+  return sum;

+}

+#endif

+

+#if 0 /* Version C */

+/**

+ * 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.

+ * 

+ * by Curt McDowell, Broadcom Corp. December 8th, 2005

+ */

+

+static u16_t

+lwip_standard_chksum(void *dataptr, int len)

+{

+  u8_t *pb = dataptr;

+  u16_t *ps, t = 0;

+  u32_t *pl;

+  u32_t sum = 0, tmp;

+  /* starts at odd byte address? */

+  int odd = ((u32_t)pb & 1);

+

+  if (odd && len > 0) {

+    ((u8_t *)&t)[1] = *pb++;

+    len--;

+  }

+

+  ps = (u16_t *)pb;

+

+  if (((u32_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 = (sum >> 16) + (sum & 0xffff);

+

+  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 */

+

+  while (sum >> 16)             /* combine halves */

+    sum = (sum >> 16) + (sum & 0xffff);

+

+  if (odd)

+    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);

+

+  return sum;

+}

+#endif

+

+#endif /* LWIP_CHKSUM */

+

+/* inet_chksum_pseudo:

+ *

+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.

+ */

+

+u16_t

+inet_chksum_pseudo(struct pbuf *p,

+       struct ip_addr *src, struct ip_addr *dest,

+       u8_t proto, u16_t proto_len)

+{

+  u32_t acc;

+  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));*/

+    while (acc >> 16) {

+      acc = (acc & 0xffffUL) + (acc >> 16);

+    }

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);

+    }

+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/

+  }

+

+  if (swapped) {

+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);

+  }

+  acc += (src->addr & 0xffffUL);

+  acc += ((src->addr >> 16) & 0xffffUL);

+  acc += (dest->addr & 0xffffUL);

+  acc += ((dest->addr >> 16) & 0xffffUL);

+  acc += (u32_t)htons((u16_t)proto);

+  acc += (u32_t)htons(proto_len);

+

+  while (acc >> 16) {

+    acc = (acc & 0xffffUL) + (acc >> 16);

+  }

+  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.

+ */

+

+u16_t

+inet_chksum(void *dataptr, u16_t len)

+{

+  u32_t acc;

+

+  acc = LWIP_CHKSUM(dataptr, len);

+  while (acc >> 16) {

+    acc = (acc & 0xffff) + (acc >> 16);

+  }

+  return (u16_t)~(acc & 0xffff);

+}

+

+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);

+    while (acc >> 16) {

+      acc = (acc & 0xffffUL) + (acc >> 16);

+    }

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);

+    }

+  }

+

+  if (swapped) {

+    acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);

+  }

+  return (u16_t)~(acc & 0xffffUL);

+}

+

+/* 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.

+ */

+

+u32_t

+inet_addr(const char *cp)

+{

+  struct in_addr val;

+

+  if (inet_aton(cp, &val)) {

+    return (val.s_addr);

+  }

+  return (INADDR_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.

+ */

+int

+inet_aton(const char *cp, struct in_addr *addr)

+{

+  u32_t val;

+  int base, n, 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' && (!isprint(c) || !isspace(c)))

+    return (0);

+  /*

+   * Concoct the address according to

+   * the number of parts specified.

+   */

+  n = pp - parts + 1;

+  switch (n) {

+

+  case 0:

+    return (0);       /* initial nondigit */

+

+  case 1:             /* a -- 32 bits */

+    break;

+

+  case 2:             /* a.b -- 8.24 bits */

+    if (val > 0xffffff)

+      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;

+  }

+  if (addr)

+    addr->s_addr = htonl(val);

+  return (1);

+}

+

+/* Convert numeric IP address into decimal dotted ASCII representation.

+ * returns ptr to static buffer; not reentrant!

+ */

+char *

+inet_ntoa(struct in_addr addr)

+{

+  static char str[16];

+  u32_t s_addr = addr.s_addr;

+  char inv[3];

+  char *rp;

+  u8_t *ap;

+  u8_t rem;

+  u8_t n;

+  u8_t i;

+

+  rp = str;

+  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--)

+      *rp++ = inv[i];

+    *rp++ = '.';

+    ap++;

+  }

+  *--rp = 0;

+  return str;

+}

+

+/*

+ * These are reference implementations of the byte swapping functions.

+ * Again with the aim of being simple, correct and fully portable.

+ * Byte swapping is the second thing you would want to optimize. You will

+ * need to port it to your architecture and in your cc.h:

+ * 

+ * #define LWIP_PLATFORM_BYTESWAP 1

+ * #define LWIP_PLATFORM_HTONS(x) <your_htons>

+ * #define LWIP_PLATFORM_HTONL(x) <your_htonl>

+ *

+ * Note ntohs() and ntohl() are merely references to the htonx counterparts.

+ */

+

+#ifndef BYTE_ORDER

+#error BYTE_ORDER is not defined

+#endif

+#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)

+

+u16_t

+htons(u16_t n)

+{

+  return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);

+}

+

+u16_t

+ntohs(u16_t n)

+{

+  return htons(n);

+}

+

+u32_t

+htonl(u32_t n)

+{

+  return ((n & 0xff) << 24) |

+    ((n & 0xff00) << 8) |

+    ((n & 0xff0000) >> 8) |

+    ((n & 0xff000000) >> 24);

+}

+

+u32_t

+ntohl(u32_t n)

+{

+  return htonl(n);

+}

+

+#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */

diff --git a/Demo/Common/ethernet/lwIP/core/inet6.c b/Demo/Common/ethernet/lwIP/core/inet6.c
index c04915b..aebc6f3 100644
--- a/Demo/Common/ethernet/lwIP/core/inet6.c
+++ b/Demo/Common/ethernet/lwIP/core/inet6.c
@@ -1,168 +1,168 @@
-/*
- * 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>
- *
- */
-
-
-/* inet6.c
- *
- * Functions common to all TCP/IP modules, such as the Internet checksum and the
- * byte order functions.
- *
- */
-
-
-#include "lwip/opt.h"
-
-#include "lwip/def.h"
-#include "lwip/inet.h"
-
-
-
-/* chksum:
- *
- * Sums up all 16 bit words in a memory portion. Also includes any odd byte.
- * This function is used by the other checksum functions.
- *
- * For now, this is not optimized. Must be optimized for the particular processor
- * arcitecture on which it is to run. Preferebly coded in assembler.
- */
-
-static u32_t
-chksum(void *dataptr, u16_t len)
-{
-  u16_t *sdataptr = dataptr;
-  u32_t acc;
-  
-  
-  for(acc = 0; len > 1; len -= 2) {
-    acc += *sdataptr++;
-  }
-
-  /* add up any odd byte */
-  if (len == 1) {
-    acc += htons((u16_t)(*(u8_t *)dataptr) << 8);
-  }
-
-  return acc;
-
-}
-
-/* inet_chksum_pseudo:
- *
- * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
- */
-
-u16_t
-inet_chksum_pseudo(struct pbuf *p,
-       struct ip_addr *src, struct ip_addr *dest,
-       u8_t proto, u32_t proto_len)
-{
-  u32_t acc;
-  struct pbuf *q;
-  u8_t swapped, i;
-
-  acc = 0;
-  swapped = 0;
-  for(q = p; q != NULL; q = q->next) {    
-    acc += chksum(q->payload, q->len);
-    while (acc >> 16) {
-      acc = (acc & 0xffff) + (acc >> 16);
-    }
-    if (q->len % 2 != 0) {
-      swapped = 1 - swapped;
-      acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
-    }
-  }
-
-  if (swapped) {
-    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
-  }
-  
-  for(i = 0; i < 8; i++) {
-    acc += ((u16_t *)src->addr)[i] & 0xffff;
-    acc += ((u16_t *)dest->addr)[i] & 0xffff;
-    while (acc >> 16) {
-      acc = (acc & 0xffff) + (acc >> 16);
-    }
-  }
-  acc += (u16_t)htons((u16_t)proto);
-  acc += ((u16_t *)&proto_len)[0] & 0xffff;
-  acc += ((u16_t *)&proto_len)[1] & 0xffff;
-
-  while (acc >> 16) {
-    acc = (acc & 0xffff) + (acc >> 16);
-  }
-  return ~(acc & 0xffff);
-}
-
-/* inet_chksum:
- *
- * Calculates the Internet checksum over a portion of memory. Used primarely for IP
- * and ICMP.
- */
-
-u16_t
-inet_chksum(void *dataptr, u16_t len)
-{
-  u32_t acc, sum;
-
-  acc = chksum(dataptr, len);
-  sum = (acc & 0xffff) + (acc >> 16);
-  sum += (sum >> 16);
-  return ~(sum & 0xffff);
-}
-
-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 += chksum(q->payload, q->len);
-    while (acc >> 16) {
-      acc = (acc & 0xffff) + (acc >> 16);
-    }    
-    if (q->len % 2 != 0) {
-      swapped = 1 - swapped;
-      acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
-    }
-  }
- 
-  if (swapped) {
-    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
-  }
-  return ~(acc & 0xffff);
-}
-
+/*

+ * 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>

+ *

+ */

+

+

+/* inet6.c

+ *

+ * Functions common to all TCP/IP modules, such as the Internet checksum and the

+ * byte order functions.

+ *

+ */

+

+

+#include "lwip/opt.h"

+

+#include "lwip/def.h"

+#include "lwip/inet.h"

+

+

+

+/* chksum:

+ *

+ * Sums up all 16 bit words in a memory portion. Also includes any odd byte.

+ * This function is used by the other checksum functions.

+ *

+ * For now, this is not optimized. Must be optimized for the particular processor

+ * arcitecture on which it is to run. Preferebly coded in assembler.

+ */

+

+static u32_t

+chksum(void *dataptr, u16_t len)

+{

+  u16_t *sdataptr = dataptr;

+  u32_t acc;

+  

+  

+  for(acc = 0; len > 1; len -= 2) {

+    acc += *sdataptr++;

+  }

+

+  /* add up any odd byte */

+  if (len == 1) {

+    acc += htons((u16_t)(*(u8_t *)dataptr) << 8);

+  }

+

+  return acc;

+

+}

+

+/* inet_chksum_pseudo:

+ *

+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.

+ */

+

+u16_t

+inet_chksum_pseudo(struct pbuf *p,

+       struct ip_addr *src, struct ip_addr *dest,

+       u8_t proto, u32_t proto_len)

+{

+  u32_t acc;

+  struct pbuf *q;

+  u8_t swapped, i;

+

+  acc = 0;

+  swapped = 0;

+  for(q = p; q != NULL; q = q->next) {    

+    acc += chksum(q->payload, q->len);

+    while (acc >> 16) {

+      acc = (acc & 0xffff) + (acc >> 16);

+    }

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);

+    }

+  }

+

+  if (swapped) {

+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);

+  }

+  

+  for(i = 0; i < 8; i++) {

+    acc += ((u16_t *)src->addr)[i] & 0xffff;

+    acc += ((u16_t *)dest->addr)[i] & 0xffff;

+    while (acc >> 16) {

+      acc = (acc & 0xffff) + (acc >> 16);

+    }

+  }

+  acc += (u16_t)htons((u16_t)proto);

+  acc += ((u16_t *)&proto_len)[0] & 0xffff;

+  acc += ((u16_t *)&proto_len)[1] & 0xffff;

+

+  while (acc >> 16) {

+    acc = (acc & 0xffff) + (acc >> 16);

+  }

+  return ~(acc & 0xffff);

+}

+

+/* inet_chksum:

+ *

+ * Calculates the Internet checksum over a portion of memory. Used primarely for IP

+ * and ICMP.

+ */

+

+u16_t

+inet_chksum(void *dataptr, u16_t len)

+{

+  u32_t acc, sum;

+

+  acc = chksum(dataptr, len);

+  sum = (acc & 0xffff) + (acc >> 16);

+  sum += (sum >> 16);

+  return ~(sum & 0xffff);

+}

+

+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 += chksum(q->payload, q->len);

+    while (acc >> 16) {

+      acc = (acc & 0xffff) + (acc >> 16);

+    }    

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);

+    }

+  }

+ 

+  if (swapped) {

+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);

+  }

+  return ~(acc & 0xffff);

+}

+

diff --git a/Demo/Common/ethernet/lwIP/core/ipv4/icmp.c b/Demo/Common/ethernet/lwIP/core/ipv4/icmp.c
index 248f2c6..e4028b1 100644
--- a/Demo/Common/ethernet/lwIP/core/ipv4/icmp.c
+++ b/Demo/Common/ethernet/lwIP/core/ipv4/icmp.c
@@ -1,202 +1,202 @@
-/*
- * 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 <string.h>
-
-#include "lwip/opt.h"
-#include "lwip/icmp.h"
-#include "lwip/inet.h"
-#include "lwip/ip.h"
-#include "lwip/def.h"
-#include "lwip/stats.h"
-#include "lwip/snmp.h"
-
-void
-icmp_input(struct pbuf *p, struct netif *inp)
-{
-  u8_t type;
-  u8_t code;
-  struct icmp_echo_hdr *iecho;
-  struct ip_hdr *iphdr;
-  struct ip_addr tmpaddr;
-  u16_t hlen;
-
-  ICMP_STATS_INC(icmp.recv);
-  snmp_inc_icmpinmsgs();
-
-
-  iphdr = p->payload;
-  hlen = IPH_HL(iphdr) * 4;
-  if (pbuf_header(p, -((s16_t)hlen)) || (p->tot_len < sizeof(u16_t)*2)) {
-    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
-    pbuf_free(p);
-    ICMP_STATS_INC(icmp.lenerr);
-    snmp_inc_icmpinerrors();
-    return;
-  }
-
-  type = *((u8_t *)p->payload);
-  code = *(((u8_t *)p->payload)+1);
-  switch (type) {
-  case ICMP_ECHO:
-    /* broadcast or multicast destination address? */
-    if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {
-      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
-      ICMP_STATS_INC(icmp.err);
-      pbuf_free(p);
-      return;
-    }
-    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"));
-      pbuf_free(p);
-      ICMP_STATS_INC(icmp.lenerr);
-      snmp_inc_icmpinerrors();
-
-      return;
-    }
-    iecho = p->payload;
-    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;
-    }
-    tmpaddr.addr = iphdr->src.addr;
-    iphdr->src.addr = iphdr->dest.addr;
-    iphdr->dest.addr = tmpaddr.addr;
-    ICMPH_TYPE_SET(iecho, ICMP_ER);
-    /* adjust the checksum */
-    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
-      iecho->chksum += htons(ICMP_ECHO << 8) + 1;
-    } else {
-      iecho->chksum += htons(ICMP_ECHO << 8);
-    }
-    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();
-
-    pbuf_header(p, hlen);
-    ip_output_if(p, &(iphdr->src), IP_HDRINCL,
-     IPH_TTL(iphdr), 0, IP_PROTO_ICMP, inp);
-    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);
-}
-
-void
-icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
-{
-  struct pbuf *q;
-  struct ip_hdr *iphdr;
-  struct icmp_dur_hdr *idur;
-
-  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
-  /* ICMP header + IP header + 8 bytes of data */
-
-  iphdr = p->payload;
-
-  idur = q->payload;
-  ICMPH_TYPE_SET(idur, ICMP_DUR);
-  ICMPH_CODE_SET(idur, t);
-
-  memcpy((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
-
-  /* calculate checksum */
-  idur->chksum = 0;
-  idur->chksum = inet_chksum(idur, 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_icmpoutdestunreachs();
-
-  ip_output(q, NULL, &(iphdr->src),
-      ICMP_TTL, 0, IP_PROTO_ICMP);
-  pbuf_free(q);
-}
-
-#if IP_FORWARD
-void
-icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
-{
-  struct pbuf *q;
-  struct ip_hdr *iphdr;
-  struct icmp_te_hdr *tehdr;
-
-  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
-
-  iphdr = 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"));
-
-  tehdr = q->payload;
-  ICMPH_TYPE_SET(tehdr, ICMP_TE);
-  ICMPH_CODE_SET(tehdr, t);
-
-  /* copy fields from original packet */
-  memcpy((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
-
-  /* calculate checksum */
-  tehdr->chksum = 0;
-  tehdr->chksum = inet_chksum(tehdr, 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_output(q, NULL, &(iphdr->src),
-      ICMP_TTL, 0, IP_PROTO_ICMP);
-  pbuf_free(q);
-}
-
-#endif /* IP_FORWARD */
-
-
-
-
-
-
-
+/*

+ * 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 <string.h>

+

+#include "lwip/opt.h"

+#include "lwip/icmp.h"

+#include "lwip/inet.h"

+#include "lwip/ip.h"

+#include "lwip/def.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+

+void

+icmp_input(struct pbuf *p, struct netif *inp)

+{

+  u8_t type;

+  u8_t code;

+  struct icmp_echo_hdr *iecho;

+  struct ip_hdr *iphdr;

+  struct ip_addr tmpaddr;

+  u16_t hlen;

+

+  ICMP_STATS_INC(icmp.recv);

+  snmp_inc_icmpinmsgs();

+

+

+  iphdr = p->payload;

+  hlen = IPH_HL(iphdr) * 4;

+  if (pbuf_header(p, -((s16_t)hlen)) || (p->tot_len < sizeof(u16_t)*2)) {

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));

+    pbuf_free(p);

+    ICMP_STATS_INC(icmp.lenerr);

+    snmp_inc_icmpinerrors();

+    return;

+  }

+

+  type = *((u8_t *)p->payload);

+  code = *(((u8_t *)p->payload)+1);

+  switch (type) {

+  case ICMP_ECHO:

+    /* broadcast or multicast destination address? */

+    if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {

+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));

+      ICMP_STATS_INC(icmp.err);

+      pbuf_free(p);

+      return;

+    }

+    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"));

+      pbuf_free(p);

+      ICMP_STATS_INC(icmp.lenerr);

+      snmp_inc_icmpinerrors();

+

+      return;

+    }

+    iecho = p->payload;

+    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;

+    }

+    tmpaddr.addr = iphdr->src.addr;

+    iphdr->src.addr = iphdr->dest.addr;

+    iphdr->dest.addr = tmpaddr.addr;

+    ICMPH_TYPE_SET(iecho, ICMP_ER);

+    /* adjust the checksum */

+    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {

+      iecho->chksum += htons(ICMP_ECHO << 8) + 1;

+    } else {

+      iecho->chksum += htons(ICMP_ECHO << 8);

+    }

+    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();

+

+    pbuf_header(p, hlen);

+    ip_output_if(p, &(iphdr->src), IP_HDRINCL,

+     IPH_TTL(iphdr), 0, IP_PROTO_ICMP, inp);

+    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);

+}

+

+void

+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)

+{

+  struct pbuf *q;

+  struct ip_hdr *iphdr;

+  struct icmp_dur_hdr *idur;

+

+  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);

+  /* ICMP header + IP header + 8 bytes of data */

+

+  iphdr = p->payload;

+

+  idur = q->payload;

+  ICMPH_TYPE_SET(idur, ICMP_DUR);

+  ICMPH_CODE_SET(idur, t);

+

+  memcpy((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);

+

+  /* calculate checksum */

+  idur->chksum = 0;

+  idur->chksum = inet_chksum(idur, 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_icmpoutdestunreachs();

+

+  ip_output(q, NULL, &(iphdr->src),

+      ICMP_TTL, 0, IP_PROTO_ICMP);

+  pbuf_free(q);

+}

+

+#if IP_FORWARD

+void

+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)

+{

+  struct pbuf *q;

+  struct ip_hdr *iphdr;

+  struct icmp_te_hdr *tehdr;

+

+  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);

+

+  iphdr = 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"));

+

+  tehdr = q->payload;

+  ICMPH_TYPE_SET(tehdr, ICMP_TE);

+  ICMPH_CODE_SET(tehdr, t);

+

+  /* copy fields from original packet */

+  memcpy((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);

+

+  /* calculate checksum */

+  tehdr->chksum = 0;

+  tehdr->chksum = inet_chksum(tehdr, 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_output(q, NULL, &(iphdr->src),

+      ICMP_TTL, 0, IP_PROTO_ICMP);

+  pbuf_free(q);

+}

+

+#endif /* IP_FORWARD */

+

+

+

+

+

+

+

diff --git a/Demo/Common/ethernet/lwIP/core/ipv4/ip.c b/Demo/Common/ethernet/lwIP/core/ipv4/ip.c
index 496d76e..31d29a9 100644
--- a/Demo/Common/ethernet/lwIP/core/ipv4/ip.c
+++ b/Demo/Common/ethernet/lwIP/core/ipv4/ip.c
@@ -1,515 +1,515 @@
-/* @file
- *
- * This is the IP 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/def.h"
-#include "lwip/mem.h"
-#include "lwip/ip.h"
-#include "lwip/ip_frag.h"
-#include "lwip/inet.h"
-#include "lwip/netif.h"
-#include "lwip/icmp.h"
-#include "lwip/raw.h"
-#include "lwip/udp.h"
-#include "lwip/tcp.h"
-
-#include "lwip/stats.h"
-
-#include "arch/perf.h"
-
-#include "lwip/snmp.h"
-#if LWIP_DHCP
-#  include "lwip/dhcp.h"
-#endif /* LWIP_DHCP */
+/* @file

+ *

+ * This is the IP 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>

+ *

+ */

 

-/**
- * Initializes the IP layer.
- */
-
-void
-ip_init(void)
-{
-#if IP_FRAG
-  ip_frag_init();
-#endif
-}
-
-/**
- * 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.
- */
-
-struct netif *
-ip_route(struct ip_addr *dest)
-{
-  struct netif *netif;
-
-  /* iterate through netifs */
-  for(netif = netif_list; netif != NULL; netif = netif->next) {
-    /* network mask matches? */
-    if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
-      /* return netif on which to forward IP packet */
-      return netif;
-    }
-  }
-  /* 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.
- */
-
-static struct netif *
-ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
-{
-  struct netif *netif;
-
-  PERF_START;
-  /* Find network interface where to forward this IP packet to. */
-  netif = ip_route((struct ip_addr *)&(iphdr->dest));
-  if (netif == NULL) {
-    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",
-                      iphdr->dest.addr));
-    snmp_inc_ipoutnoroutes();
-    return (struct netif *)NULL;
-  }
-  /* 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"));
-    snmp_inc_ipoutnoroutes();
-    return (struct netif *)NULL;
-  }
-
-  /* decrement TTL */
-  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
-  /* send ICMP if TTL == 0 */
-  if (IPH_TTL(iphdr) == 0) {
-    snmp_inc_ipinhdrerrors();
-    /* Don't send ICMP messages in response to ICMP messages */
-    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
-      icmp_time_exceeded(p, ICMP_TE_TTL);
-    }
-    return (struct netif *)NULL;
-  }
-
-  /* Incrementally update the IP checksum. */
-  if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
-    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
-  } else {
-    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));
-  }
-
-  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",
-                    iphdr->dest.addr));
-
-  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, (struct ip_addr *)&(iphdr->dest));
-  return netif;
-}
-#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.
- * 
- * 
- * 
- */
-
-err_t
-ip_input(struct pbuf *p, struct netif *inp) {
-  struct ip_hdr *iphdr;
-  struct netif *netif;
-  u16_t iphdrlen;
+#include "lwip/opt.h"

 

-  IP_STATS_INC(ip.recv);
-  snmp_inc_ipinreceives();
-
-  /* identify the IP header */
-  iphdr = p->payload;
-  if (IPH_V(iphdr) != 4) {
+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/ip.h"

+#include "lwip/ip_frag.h"

+#include "lwip/inet.h"

+#include "lwip/netif.h"

+#include "lwip/icmp.h"

+#include "lwip/raw.h"

+#include "lwip/udp.h"

+#include "lwip/tcp.h"

+

+#include "lwip/stats.h"

+

+#include "arch/perf.h"

+

+#include "lwip/snmp.h"

+#if LWIP_DHCP

+#  include "lwip/dhcp.h"

+#endif /* LWIP_DHCP */

+

+/**

+ * Initializes the IP layer.

+ */

+

+void

+ip_init(void)

+{

+#if IP_FRAG

+  ip_frag_init();

+#endif

+}

+

+/**

+ * 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.

+ */

+

+struct netif *

+ip_route(struct ip_addr *dest)

+{

+  struct netif *netif;

+

+  /* iterate through netifs */

+  for(netif = netif_list; netif != NULL; netif = netif->next) {

+    /* network mask matches? */

+    if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {

+      /* return netif on which to forward IP packet */

+      return netif;

+    }

+  }

+  /* 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.

+ */

+

+static struct netif *

+ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)

+{

+  struct netif *netif;

+

+  PERF_START;

+  /* Find network interface where to forward this IP packet to. */

+  netif = ip_route((struct ip_addr *)&(iphdr->dest));

+  if (netif == NULL) {

+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",

+                      iphdr->dest.addr));

+    snmp_inc_ipoutnoroutes();

+    return (struct netif *)NULL;

+  }

+  /* 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"));

+    snmp_inc_ipoutnoroutes();

+    return (struct netif *)NULL;

+  }

+

+  /* decrement TTL */

+  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);

+  /* send ICMP if TTL == 0 */

+  if (IPH_TTL(iphdr) == 0) {

+    snmp_inc_ipinhdrerrors();

+    /* Don't send ICMP messages in response to ICMP messages */

+    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {

+      icmp_time_exceeded(p, ICMP_TE_TTL);

+    }

+    return (struct netif *)NULL;

+  }

+

+  /* Incrementally update the IP checksum. */

+  if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {

+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);

+  } else {

+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));

+  }

+

+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",

+                    iphdr->dest.addr));

+

+  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, (struct ip_addr *)&(iphdr->dest));

+  return netif;

+}

+#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.

+ * 

+ * 

+ * 

+ */

+

+err_t

+ip_input(struct pbuf *p, struct netif *inp) {

+  struct ip_hdr *iphdr;

+  struct netif *netif;

+  u16_t iphdrlen;

+

+  IP_STATS_INC(ip.recv);

+  snmp_inc_ipinreceives();

+

+  /* identify the IP header */

+  iphdr = p->payload;

+  if (IPH_V(iphdr) != 4) {

     LWIP_DEBUGF(IP_DEBUG | 1, ("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 */
-  iphdrlen = IPH_HL(iphdr);
-  /* calculate IP header length in bytes */
-  iphdrlen *= 4;
-
-  /* header length exceeds first pbuf length? */
-  if (iphdrlen > p->len) {
-    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet droppped.\n",
-      iphdrlen, p->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, iphdrlen) != 0) {
-
-    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen)));
-    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, ntohs(IPH_LEN(iphdr)));
-
-  /* match packet against an interface, i.e. is this packet for us? */
-  for (netif = netif_list; netif != NULL; netif = netif->next) {
-
-    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",
-      iphdr->dest.addr, netif->ip_addr.addr,
-      iphdr->dest.addr & netif->netmask.addr,
-      netif->ip_addr.addr & netif->netmask.addr,
-      iphdr->dest.addr & ~(netif->netmask.addr)));
-
-    /* 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(&(iphdr->dest), &(netif->ip_addr)) ||
-         /* or broadcast on this interface network address? */
-         ip_addr_isbroadcast(&(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_DHCP
-  /* 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 (netif == NULL) {
-    /* remote port is DHCP server? */
-    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
-      LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
-        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest)));
-      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) {
-        LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
-        netif = inp;
-      }
-    }
-  }
-#endif /* LWIP_DHCP */
-  /* packet not for us? */
-  if (netif == NULL) {
-    /* packet not for us, route or discard */
-    LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
-#if IP_FORWARD
-    /* non-broadcast packet? */
-    if (!ip_addr_isbroadcast(&(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) & 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) & 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 = p->payload;
-#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
-    pbuf_free(p);
-    LWIP_DEBUGF(IP_DEBUG | 2, ("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 == 0 /* no support for IP options in the IP header? */
-  if (iphdrlen > IP_HLEN) {
-    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 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 == 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));
-
-#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:
-  case IP_PROTO_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 */
-  case IP_PROTO_ICMP:
-    snmp_inc_ipindelivers();
-    icmp_input(p, inp);
-    break;
-  default:
-    /* send ICMP destination protocol unreachable unless is was a broadcast */
-    if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
-        !ip_addr_ismulticast(&(iphdr->dest))) {
-      p->payload = iphdr;
-      icmp_dest_unreach(p, ICMP_DUR_PROTO);
-    }
-    pbuf_free(p);
-
-    LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
-
-    IP_STATS_INC(ip.proterr);
-    IP_STATS_INC(ip.drop);
-    snmp_inc_ipinunknownprotos();
-  }
-#if LWIP_RAW
-  } /* LWIP_RAW */
-#endif
-  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.
- *
- * @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, struct ip_addr *src, struct ip_addr *dest,
-             u8_t ttl, u8_t tos,
-             u8_t proto, struct netif *netif)
-{
-  struct ip_hdr *iphdr;
-  static u16_t ip_id = 0;
-
-  snmp_inc_ipoutrequests();
-
-  if (dest != IP_HDRINCL) {
-    if (pbuf_header(p, IP_HLEN)) {
-      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
-
-      IP_STATS_INC(ip.err);
-      snmp_inc_ipoutdiscards();
-      return ERR_BUF;
-    }
-
-    iphdr = p->payload;
-
-    IPH_TTL_SET(iphdr, ttl);
-    IPH_PROTO_SET(iphdr, proto);
-
-    ip_addr_set(&(iphdr->dest), dest);
-
-    IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);
-    IPH_LEN_SET(iphdr, htons(p->tot_len));
-    IPH_OFFSET_SET(iphdr, htons(IP_DF));
-    IPH_ID_SET(iphdr, htons(ip_id));
-    ++ip_id;
-
-    if (ip_addr_isany(src)) {
-      ip_addr_set(&(iphdr->src), &(netif->ip_addr));
-    } else {
-      ip_addr_set(&(iphdr->src), src);
-    }
-
-    IPH_CHKSUM_SET(iphdr, 0);
-#if CHECKSUM_GEN_IP
-    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
-#endif
-  } else {
-    iphdr = p->payload;
-    dest = &(iphdr->dest);
-  }
-
-#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_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);
-
-  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.
- */
-
-err_t
-ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
-          u8_t ttl, u8_t tos, u8_t proto)
-{
-  struct netif *netif;
-
-  if ((netif = ip_route(dest)) == NULL) {
-    LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
-
-    IP_STATS_INC(ip.rterr);
-    snmp_inc_ipoutnoroutes();
-    return ERR_RTE;
-  }
-
-  return ip_output_if(p, src, dest, ttl, tos, proto, netif);
-}
-
-#if IP_DEBUG
-void
-ip_debug_print(struct pbuf *p)
-{
-  struct ip_hdr *iphdr = 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(&iphdr->src),
-                    ip4_addr2(&iphdr->src),
-                    ip4_addr3(&iphdr->src),
-                    ip4_addr4(&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(&iphdr->dest),
-                    ip4_addr2(&iphdr->dest),
-                    ip4_addr3(&iphdr->dest),
-                    ip4_addr4(&iphdr->dest)));
-  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
-}
-#endif /* IP_DEBUG */
+    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 */

+  iphdrlen = IPH_HL(iphdr);

+  /* calculate IP header length in bytes */

+  iphdrlen *= 4;

 

-
-
-
-
-
+  /* header length exceeds first pbuf length? */

+  if (iphdrlen > p->len) {

+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet droppped.\n",

+      iphdrlen, p->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, iphdrlen) != 0) {

+

+    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen)));

+    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, ntohs(IPH_LEN(iphdr)));

+

+  /* match packet against an interface, i.e. is this packet for us? */

+  for (netif = netif_list; netif != NULL; netif = netif->next) {

+

+    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",

+      iphdr->dest.addr, netif->ip_addr.addr,

+      iphdr->dest.addr & netif->netmask.addr,

+      netif->ip_addr.addr & netif->netmask.addr,

+      iphdr->dest.addr & ~(netif->netmask.addr)));

+

+    /* 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(&(iphdr->dest), &(netif->ip_addr)) ||

+         /* or broadcast on this interface network address? */

+         ip_addr_isbroadcast(&(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_DHCP

+  /* 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 (netif == NULL) {

+    /* remote port is DHCP server? */

+    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {

+      LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",

+        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest)));

+      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) {

+        LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));

+        netif = inp;

+      }

+    }

+  }

+#endif /* LWIP_DHCP */

+  /* packet not for us? */

+  if (netif == NULL) {

+    /* packet not for us, route or discard */

+    LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n"));

+#if IP_FORWARD

+    /* non-broadcast packet? */

+    if (!ip_addr_isbroadcast(&(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) & 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) & 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 = p->payload;

+#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */

+    pbuf_free(p);

+    LWIP_DEBUGF(IP_DEBUG | 2, ("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 == 0 /* no support for IP options in the IP header? */

+  if (iphdrlen > IP_HLEN) {

+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 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 == 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));

+

+#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:

+  case IP_PROTO_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 */

+  case IP_PROTO_ICMP:

+    snmp_inc_ipindelivers();

+    icmp_input(p, inp);

+    break;

+  default:

+    /* send ICMP destination protocol unreachable unless is was a broadcast */

+    if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&

+        !ip_addr_ismulticast(&(iphdr->dest))) {

+      p->payload = iphdr;

+      icmp_dest_unreach(p, ICMP_DUR_PROTO);

+    }

+    pbuf_free(p);

+

+    LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));

+

+    IP_STATS_INC(ip.proterr);

+    IP_STATS_INC(ip.drop);

+    snmp_inc_ipinunknownprotos();

+  }

+#if LWIP_RAW

+  } /* LWIP_RAW */

+#endif

+  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.

+ *

+ * @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, struct ip_addr *src, struct ip_addr *dest,

+             u8_t ttl, u8_t tos,

+             u8_t proto, struct netif *netif)

+{

+  struct ip_hdr *iphdr;

+  static u16_t ip_id = 0;

+

+  snmp_inc_ipoutrequests();

+

+  if (dest != IP_HDRINCL) {

+    if (pbuf_header(p, IP_HLEN)) {

+      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));

+

+      IP_STATS_INC(ip.err);

+      snmp_inc_ipoutdiscards();

+      return ERR_BUF;

+    }

+

+    iphdr = p->payload;

+

+    IPH_TTL_SET(iphdr, ttl);

+    IPH_PROTO_SET(iphdr, proto);

+

+    ip_addr_set(&(iphdr->dest), dest);

+

+    IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);

+    IPH_LEN_SET(iphdr, htons(p->tot_len));

+    IPH_OFFSET_SET(iphdr, htons(IP_DF));

+    IPH_ID_SET(iphdr, htons(ip_id));

+    ++ip_id;

+

+    if (ip_addr_isany(src)) {

+      ip_addr_set(&(iphdr->src), &(netif->ip_addr));

+    } else {

+      ip_addr_set(&(iphdr->src), src);

+    }

+

+    IPH_CHKSUM_SET(iphdr, 0);

+#if CHECKSUM_GEN_IP

+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

+#endif

+  } else {

+    iphdr = p->payload;

+    dest = &(iphdr->dest);

+  }

+

+#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_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);

+

+  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.

+ */

+

+err_t

+ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+          u8_t ttl, u8_t tos, u8_t proto)

+{

+  struct netif *netif;

+

+  if ((netif = ip_route(dest)) == NULL) {

+    LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));

+

+    IP_STATS_INC(ip.rterr);

+    snmp_inc_ipoutnoroutes();

+    return ERR_RTE;

+  }

+

+  return ip_output_if(p, src, dest, ttl, tos, proto, netif);

+}

+

+#if IP_DEBUG

+void

+ip_debug_print(struct pbuf *p)

+{

+  struct ip_hdr *iphdr = 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(&iphdr->src),

+                    ip4_addr2(&iphdr->src),

+                    ip4_addr3(&iphdr->src),

+                    ip4_addr4(&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(&iphdr->dest),

+                    ip4_addr2(&iphdr->dest),

+                    ip4_addr3(&iphdr->dest),

+                    ip4_addr4(&iphdr->dest)));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+}

+#endif /* IP_DEBUG */

+

+

+

+

+

+

diff --git a/Demo/Common/ethernet/lwIP/core/ipv4/ip_addr.c b/Demo/Common/ethernet/lwIP/core/ipv4/ip_addr.c
index 70be286..56b1cd7 100644
--- a/Demo/Common/ethernet/lwIP/core/ipv4/ip_addr.c
+++ b/Demo/Common/ethernet/lwIP/core/ipv4/ip_addr.c
@@ -1,78 +1,78 @@
-/*
- * 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/ip_addr.h"
-#include "lwip/inet.h"
-#include "lwip/netif.h"
-
-#define IP_ADDR_ANY_VALUE 0x00000000UL
-#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL
-
-/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
-const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };
-const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };
-
-/* 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 ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
-{
-  u32_t addr2test;
-
-  addr2test = addr->addr;
-  /* all ones (broadcast) or all zeroes (old skool broadcast) */
-  if ((~addr2test == IP_ADDR_ANY_VALUE) ||
-      (addr2test == IP_ADDR_ANY_VALUE))
-    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 (addr2test == netif->ip_addr.addr)
-    return 0;
-  /*  on the same (sub) network... */
-  else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
-         /* ...and host identifier bits are all ones? =>... */
-          && ((addr2test & ~netif->netmask.addr) ==
-           (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))
-    /* => network broadcast address */
-    return 1;
-  else
-    return 0;
-}
+/*

+ * 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/ip_addr.h"

+#include "lwip/inet.h"

+#include "lwip/netif.h"

+

+#define IP_ADDR_ANY_VALUE 0x00000000UL

+#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL

+

+/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */

+const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };

+const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };

+

+/* 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 ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)

+{

+  u32_t addr2test;

+

+  addr2test = addr->addr;

+  /* all ones (broadcast) or all zeroes (old skool broadcast) */

+  if ((~addr2test == IP_ADDR_ANY_VALUE) ||

+      (addr2test == IP_ADDR_ANY_VALUE))

+    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 (addr2test == netif->ip_addr.addr)

+    return 0;

+  /*  on the same (sub) network... */

+  else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))

+         /* ...and host identifier bits are all ones? =>... */

+          && ((addr2test & ~netif->netmask.addr) ==

+           (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))

+    /* => network broadcast address */

+    return 1;

+  else

+    return 0;

+}

diff --git a/Demo/Common/ethernet/lwIP/core/ipv4/ip_frag.c b/Demo/Common/ethernet/lwIP/core/ipv4/ip_frag.c
index c43422c..0256a50 100644
--- a/Demo/Common/ethernet/lwIP/core/ipv4/ip_frag.c
+++ b/Demo/Common/ethernet/lwIP/core/ipv4/ip_frag.c
@@ -1,388 +1,388 @@
-/* @file
- * 
- * This is the IP 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> 
- * original reassembly code by Adam Dunkels <adam@sics.se>
- * 
- */
-
-#include <string.h>
-
-#include "lwip/opt.h"
-#include "lwip/ip.h"
-#include "lwip/ip_frag.h"
-#include "lwip/netif.h"
-#include "lwip/snmp.h"
-#include "lwip/stats.h"
-
-static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];
-static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8) + 1];
-static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,
-  0x0f, 0x07, 0x03, 0x01
-};
-static u16_t ip_reasslen;
-static u8_t ip_reassflags;
-#define IP_REASS_FLAG_LASTFRAG 0x01
-
-static u8_t ip_reasstmr;
-
-/*
- * Copy len bytes from offset in pbuf to buffer 
- *
- * helper used by both ip_reass and ip_frag
- */
-static struct pbuf *
-copy_from_pbuf(struct pbuf *p, u16_t * offset,
-           u8_t * buffer, u16_t len)
-{
-  u16_t l;
-
-  p->payload = (u8_t *)p->payload + *offset;
-  p->len -= *offset;
-  while (len) {
-    l = len < p->len ? len : p->len;
-    memcpy(buffer, p->payload, l);
-    buffer += l;
-    len -= l;
-    if (len)
-      p = p->next;
-    else
-      *offset = l;
-  }
-  return p;
-}
-
-
-/**
- * Initializes IP reassembly and fragmentation states.
- */
-void
-ip_frag_init(void)
-{
-  ip_reasstmr = 0;
-  ip_reassflags = 0;
-  ip_reasslen = 0;
-  memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
-}
-
-/**
- * Reassembly timer base function
- * for both NO_SYS == 0 and 1 (!).
- *
- * Should be called every 1000 msec.
- */
-void
-ip_reass_tmr(void)
-{
-  if (ip_reasstmr > 0) {
-    ip_reasstmr--;
-    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)ip_reasstmr));
-    if (ip_reasstmr == 0) {
-      /* reassembly timed out */
-      snmp_inc_ipreasmfails();
-    }
-  }
-}
-
-/**
- * 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 *q;
-  struct ip_hdr *fraghdr, *iphdr;
-  u16_t offset, len;
-  u16_t i;
-
-  IPFRAG_STATS_INC(ip_frag.recv);
-  snmp_inc_ipreasmreqds();
-
-  iphdr = (struct ip_hdr *) ip_reassbuf;
-  fraghdr = (struct ip_hdr *) p->payload;
-  /* If ip_reasstmr is zero, no packet is present in the buffer, so we
-     write the IP header of the fragment into the reassembly
-     buffer. The timer is updated with the maximum age. */
-  if (ip_reasstmr == 0) {
-    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));
-    memcpy(iphdr, fraghdr, IP_HLEN);
-    ip_reasstmr = IP_REASS_MAXAGE;
-    ip_reassflags = 0;
-    /* Clear the bitmap. */
-    memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
-  }
-
-  /* Check if the incoming fragment matches the one currently present
-     in the reasembly buffer. If so, we proceed with copying the
-     fragment into the buffer. */
-  if (ip_addr_cmp(&iphdr->src, &fraghdr->src) &&
-      ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&
-      IPH_ID(iphdr) == IPH_ID(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);
-    /* Find out the offset in the reassembly buffer where we should
-       copy the fragment. */
-    len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
-    offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
-
-    /* If the offset or the offset + fragment length overflows the
-       reassembly buffer, we discard the entire packet. */
-    if ((offset > IP_REASS_BUFSIZE) || ((offset + len) > IP_REASS_BUFSIZE)) {
-      LWIP_DEBUGF(IP_REASS_DEBUG,
-       ("ip_reass: fragment outside of buffer (%"S16_F":%"S16_F"/%"S16_F").\n", offset,
-        offset + len, IP_REASS_BUFSIZE));
-      ip_reasstmr = 0;
-      snmp_inc_ipreasmfails();
-      goto nullreturn;
-    }
-
-    /* Copy the fragment into the reassembly buffer, at the right
-       offset. */
-    LWIP_DEBUGF(IP_REASS_DEBUG,
-     ("ip_reass: copying with offset %"S16_F" into %"S16_F":%"S16_F"\n", offset,
-      IP_HLEN + offset, IP_HLEN + offset + len));
-    i = IPH_HL(fraghdr) * 4;
-    copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);
-
-    /* Update the bitmap. */
-    if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
-      LWIP_DEBUGF(IP_REASS_DEBUG,
-       ("ip_reass: updating single byte in bitmap.\n"));
-      /* If the two endpoints are in the same byte, we only update that byte. */
-      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",
-                   offset / (8 * 8) < sizeof(ip_reassbitmap));
-      ip_reassbitmap[offset / (8 * 8)] |=
-        bitmap_bits[(offset / 8) & 7] &
-        ~bitmap_bits[((offset + len) / 8) & 7];
-    } else {
-      /* If the two endpoints are in different bytes, we update the
-         bytes in the endpoints and fill the stuff inbetween with
-         0xff. */
-      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",
-                   offset / (8 * 8) < sizeof(ip_reassbitmap));
-      ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];
-      LWIP_DEBUGF(IP_REASS_DEBUG,
-       ("ip_reass: updating many bytes in bitmap (%"S16_F":%"S16_F").\n",
-        1 + offset / (8 * 8), (offset + len) / (8 * 8)));
-      for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
-        ip_reassbitmap[i] = 0xff;
-      }
-      LWIP_ASSERT("(offset + len) / (8 * 8) < sizeof(ip_reassbitmap)",
-                   (offset + len) / (8 * 8) < sizeof(ip_reassbitmap));
-      ip_reassbitmap[(offset + len) / (8 * 8)] |=
-        ~bitmap_bits[((offset + len) / 8) & 7];
-    }
-
-    /* If this fragment has the More Fragments flag set to zero, we
-       know that this is the last fragment, so we can calculate the
-       size of the entire packet. We also set the
-       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
-       the final fragment. */
-
-    if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
-      ip_reassflags |= IP_REASS_FLAG_LASTFRAG;
-      ip_reasslen = offset + len;
-      LWIP_DEBUGF(IP_REASS_DEBUG,
-       ("ip_reass: last fragment seen, total len %"S16_F"\n",
-        ip_reasslen));
-    }
-
-    /* Finally, we check if we have a full packet in the buffer. We do
-       this by checking if we have the last fragment and if all bits
-       in the bitmap are set. */
-    if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
-      /* Check all bytes up to and including all but the last byte in
-         the bitmap. */
-      LWIP_ASSERT("ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)",
-                   ip_reasslen / (8 * 8) - 1 < ((u16_t) sizeof(ip_reassbitmap)));
-      for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
-        if (ip_reassbitmap[i] != 0xff) {
-          LWIP_DEBUGF(IP_REASS_DEBUG,
-           ("ip_reass: last fragment seen, bitmap %"S16_F"/%"S16_F" failed (%"X16_F")\n",
-            i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));
-          goto nullreturn;
-        }
-      }
-      /* Check the last byte in the bitmap. It should contain just the
-         right amount of bits. */
-      LWIP_ASSERT("ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)",
-                   ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap));
-      if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=
-        (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {
-         LWIP_DEBUGF(IP_REASS_DEBUG,
-          ("ip_reass: last fragment seen, bitmap %"S16_F" didn't contain %"X16_F" (%"X16_F")\n",
-        ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],
-        ip_reassbitmap[ip_reasslen / (8 * 8)]));
-        goto nullreturn;
-      }
-
-      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
-         from now on. */
-      ip_reasslen += IP_HLEN;
-
-      IPH_LEN_SET(iphdr, htons(ip_reasslen));
-      IPH_OFFSET_SET(iphdr, 0);
-      IPH_CHKSUM_SET(iphdr, 0);
-      IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
-
-      /* If we have come this far, we have a full packet in the
-         buffer, so we allocate a pbuf and copy the packet into it. We
-         also reset the timer. */
-      ip_reasstmr = 0;
-      pbuf_free(p);
-      p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);
-      if (p != NULL) {
-        i = 0;
-        for (q = p; q != NULL; q = q->next) {
-          /* Copy enough bytes to fill this pbuf in the chain. The
-             available data in the pbuf is given by the q->len variable. */
-          LWIP_DEBUGF(IP_REASS_DEBUG,
-           ("ip_reass: memcpy from %p (%"S16_F") to %p, %"S16_F" bytes\n",
-            (void *)&ip_reassbuf[i], i, q->payload,
-            q->len > ip_reasslen - i ? ip_reasslen - i : q->len));
-          memcpy(q->payload, &ip_reassbuf[i],
-            q->len > ip_reasslen - i ? ip_reasslen - i : q->len);
-          i += q->len;
-        }
-        IPFRAG_STATS_INC(ip_frag.fw);
-        snmp_inc_ipreasmoks();
-      } else {
-        LWIP_DEBUGF(IP_REASS_DEBUG,
-          ("ip_reass: pbuf_alloc(PBUF_LINK, ip_reasslen=%"U16_F", PBUF_POOL) failed\n", ip_reasslen));
-        IPFRAG_STATS_INC(ip_frag.memerr);
-        snmp_inc_ipreasmfails();
-      }
-      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p));
-      return p;
-    }
-  }
-
-nullreturn:
-  IPFRAG_STATS_INC(ip_frag.drop);
-  pbuf_free(p);
-  return NULL;
-}
-
-static u8_t buf[MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];
-
-/**
- * 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_ROM)
- */
-err_t 
-ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
-{
-  struct pbuf *rambuf;
-  struct pbuf *header;
-  struct ip_hdr *iphdr;
-  u16_t nfb = 0;
-  u16_t left, cop;
-  u16_t mtu = netif->mtu;
-  u16_t ofo, omf;
-  u16_t last;
-  u16_t poff = IP_HLEN;
-  u16_t tmp;
-
-  /* Get a RAM based MTU sized pbuf */
-  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 = MEM_ALIGN((void *)buf);
-
-  /* Copy the IP header in it */
-  iphdr = rambuf->payload;
-  memcpy(iphdr, p->payload, IP_HLEN);
-
-  /* Save original offset */
-  tmp = ntohs(IPH_OFFSET(iphdr));
-  ofo = tmp & IP_OFFMASK;
-  omf = tmp & IP_MF;
-
-  left = p->tot_len - IP_HLEN;
-
-  while (left) {
-    last = (left <= mtu - IP_HLEN);
-
-    /* Set new offset and MF flag */
-    ofo += nfb;
-    tmp = omf | (IP_OFFMASK & (ofo));
-    if (!last)
-      tmp = tmp | IP_MF;
-    IPH_OFFSET_SET(iphdr, htons(tmp));
-
-    /* Fill this fragment */
-    nfb = (mtu - IP_HLEN) / 8;
-    cop = last ? left : nfb * 8;
-
-    p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);
-
-    /* Correct header */
-    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
-    IPH_CHKSUM_SET(iphdr, 0);
-    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
-
-    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;    
-    }
-    left -= cop;
-  }
-  pbuf_free(rambuf);
-  snmp_inc_ipfragoks();
-  return ERR_OK;
-}
+/* @file

+ * 

+ * This is the IP 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> 

+ * original reassembly code by Adam Dunkels <adam@sics.se>

+ * 

+ */

+

+#include <string.h>

+

+#include "lwip/opt.h"

+#include "lwip/ip.h"

+#include "lwip/ip_frag.h"

+#include "lwip/netif.h"

+#include "lwip/snmp.h"

+#include "lwip/stats.h"

+

+static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];

+static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8) + 1];

+static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,

+  0x0f, 0x07, 0x03, 0x01

+};

+static u16_t ip_reasslen;

+static u8_t ip_reassflags;

+#define IP_REASS_FLAG_LASTFRAG 0x01

+

+static u8_t ip_reasstmr;

+

+/*

+ * Copy len bytes from offset in pbuf to buffer 

+ *

+ * helper used by both ip_reass and ip_frag

+ */

+static struct pbuf *

+copy_from_pbuf(struct pbuf *p, u16_t * offset,

+           u8_t * buffer, u16_t len)

+{

+  u16_t l;

+

+  p->payload = (u8_t *)p->payload + *offset;

+  p->len -= *offset;

+  while (len) {

+    l = len < p->len ? len : p->len;

+    memcpy(buffer, p->payload, l);

+    buffer += l;

+    len -= l;

+    if (len)

+      p = p->next;

+    else

+      *offset = l;

+  }

+  return p;

+}

+

+

+/**

+ * Initializes IP reassembly and fragmentation states.

+ */

+void

+ip_frag_init(void)

+{

+  ip_reasstmr = 0;

+  ip_reassflags = 0;

+  ip_reasslen = 0;

+  memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));

+}

+

+/**

+ * Reassembly timer base function

+ * for both NO_SYS == 0 and 1 (!).

+ *

+ * Should be called every 1000 msec.

+ */

+void

+ip_reass_tmr(void)

+{

+  if (ip_reasstmr > 0) {

+    ip_reasstmr--;

+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)ip_reasstmr));

+    if (ip_reasstmr == 0) {

+      /* reassembly timed out */

+      snmp_inc_ipreasmfails();

+    }

+  }

+}

+

+/**

+ * 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 *q;

+  struct ip_hdr *fraghdr, *iphdr;

+  u16_t offset, len;

+  u16_t i;

+

+  IPFRAG_STATS_INC(ip_frag.recv);

+  snmp_inc_ipreasmreqds();

+

+  iphdr = (struct ip_hdr *) ip_reassbuf;

+  fraghdr = (struct ip_hdr *) p->payload;

+  /* If ip_reasstmr is zero, no packet is present in the buffer, so we

+     write the IP header of the fragment into the reassembly

+     buffer. The timer is updated with the maximum age. */

+  if (ip_reasstmr == 0) {

+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));

+    memcpy(iphdr, fraghdr, IP_HLEN);

+    ip_reasstmr = IP_REASS_MAXAGE;

+    ip_reassflags = 0;

+    /* Clear the bitmap. */

+    memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));

+  }

+

+  /* Check if the incoming fragment matches the one currently present

+     in the reasembly buffer. If so, we proceed with copying the

+     fragment into the buffer. */

+  if (ip_addr_cmp(&iphdr->src, &fraghdr->src) &&

+      ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&

+      IPH_ID(iphdr) == IPH_ID(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);

+    /* Find out the offset in the reassembly buffer where we should

+       copy the fragment. */

+    len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;

+    offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;

+

+    /* If the offset or the offset + fragment length overflows the

+       reassembly buffer, we discard the entire packet. */

+    if ((offset > IP_REASS_BUFSIZE) || ((offset + len) > IP_REASS_BUFSIZE)) {

+      LWIP_DEBUGF(IP_REASS_DEBUG,

+       ("ip_reass: fragment outside of buffer (%"S16_F":%"S16_F"/%"S16_F").\n", offset,

+        offset + len, IP_REASS_BUFSIZE));

+      ip_reasstmr = 0;

+      snmp_inc_ipreasmfails();

+      goto nullreturn;

+    }

+

+    /* Copy the fragment into the reassembly buffer, at the right

+       offset. */

+    LWIP_DEBUGF(IP_REASS_DEBUG,

+     ("ip_reass: copying with offset %"S16_F" into %"S16_F":%"S16_F"\n", offset,

+      IP_HLEN + offset, IP_HLEN + offset + len));

+    i = IPH_HL(fraghdr) * 4;

+    copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);

+

+    /* Update the bitmap. */

+    if (offset / (8 * 8) == (offset + len) / (8 * 8)) {

+      LWIP_DEBUGF(IP_REASS_DEBUG,

+       ("ip_reass: updating single byte in bitmap.\n"));

+      /* If the two endpoints are in the same byte, we only update that byte. */

+      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",

+                   offset / (8 * 8) < sizeof(ip_reassbitmap));

+      ip_reassbitmap[offset / (8 * 8)] |=

+        bitmap_bits[(offset / 8) & 7] &

+        ~bitmap_bits[((offset + len) / 8) & 7];

+    } else {

+      /* If the two endpoints are in different bytes, we update the

+         bytes in the endpoints and fill the stuff inbetween with

+         0xff. */

+      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",

+                   offset / (8 * 8) < sizeof(ip_reassbitmap));

+      ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];

+      LWIP_DEBUGF(IP_REASS_DEBUG,

+       ("ip_reass: updating many bytes in bitmap (%"S16_F":%"S16_F").\n",

+        1 + offset / (8 * 8), (offset + len) / (8 * 8)));

+      for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {

+        ip_reassbitmap[i] = 0xff;

+      }

+      LWIP_ASSERT("(offset + len) / (8 * 8) < sizeof(ip_reassbitmap)",

+                   (offset + len) / (8 * 8) < sizeof(ip_reassbitmap));

+      ip_reassbitmap[(offset + len) / (8 * 8)] |=

+        ~bitmap_bits[((offset + len) / 8) & 7];

+    }

+

+    /* If this fragment has the More Fragments flag set to zero, we

+       know that this is the last fragment, so we can calculate the

+       size of the entire packet. We also set the

+       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received

+       the final fragment. */

+

+    if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {

+      ip_reassflags |= IP_REASS_FLAG_LASTFRAG;

+      ip_reasslen = offset + len;

+      LWIP_DEBUGF(IP_REASS_DEBUG,

+       ("ip_reass: last fragment seen, total len %"S16_F"\n",

+        ip_reasslen));

+    }

+

+    /* Finally, we check if we have a full packet in the buffer. We do

+       this by checking if we have the last fragment and if all bits

+       in the bitmap are set. */

+    if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {

+      /* Check all bytes up to and including all but the last byte in

+         the bitmap. */

+      LWIP_ASSERT("ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)",

+                   ip_reasslen / (8 * 8) - 1 < ((u16_t) sizeof(ip_reassbitmap)));

+      for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {

+        if (ip_reassbitmap[i] != 0xff) {

+          LWIP_DEBUGF(IP_REASS_DEBUG,

+           ("ip_reass: last fragment seen, bitmap %"S16_F"/%"S16_F" failed (%"X16_F")\n",

+            i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));

+          goto nullreturn;

+        }

+      }

+      /* Check the last byte in the bitmap. It should contain just the

+         right amount of bits. */

+      LWIP_ASSERT("ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)",

+                   ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap));

+      if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=

+        (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {

+         LWIP_DEBUGF(IP_REASS_DEBUG,

+          ("ip_reass: last fragment seen, bitmap %"S16_F" didn't contain %"X16_F" (%"X16_F")\n",

+        ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],

+        ip_reassbitmap[ip_reasslen / (8 * 8)]));

+        goto nullreturn;

+      }

+

+      /* Pretend to be a "normal" (i.e., not fragmented) IP packet

+         from now on. */

+      ip_reasslen += IP_HLEN;

+

+      IPH_LEN_SET(iphdr, htons(ip_reasslen));

+      IPH_OFFSET_SET(iphdr, 0);

+      IPH_CHKSUM_SET(iphdr, 0);

+      IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

+

+      /* If we have come this far, we have a full packet in the

+         buffer, so we allocate a pbuf and copy the packet into it. We

+         also reset the timer. */

+      ip_reasstmr = 0;

+      pbuf_free(p);

+      p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);

+      if (p != NULL) {

+        i = 0;

+        for (q = p; q != NULL; q = q->next) {

+          /* Copy enough bytes to fill this pbuf in the chain. The

+             available data in the pbuf is given by the q->len variable. */

+          LWIP_DEBUGF(IP_REASS_DEBUG,

+           ("ip_reass: memcpy from %p (%"S16_F") to %p, %"S16_F" bytes\n",

+            (void *)&ip_reassbuf[i], i, q->payload,

+            q->len > ip_reasslen - i ? ip_reasslen - i : q->len));

+          memcpy(q->payload, &ip_reassbuf[i],

+            q->len > ip_reasslen - i ? ip_reasslen - i : q->len);

+          i += q->len;

+        }

+        IPFRAG_STATS_INC(ip_frag.fw);

+        snmp_inc_ipreasmoks();

+      } else {

+        LWIP_DEBUGF(IP_REASS_DEBUG,

+          ("ip_reass: pbuf_alloc(PBUF_LINK, ip_reasslen=%"U16_F", PBUF_POOL) failed\n", ip_reasslen));

+        IPFRAG_STATS_INC(ip_frag.memerr);

+        snmp_inc_ipreasmfails();

+      }

+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p));

+      return p;

+    }

+  }

+

+nullreturn:

+  IPFRAG_STATS_INC(ip_frag.drop);

+  pbuf_free(p);

+  return NULL;

+}

+

+static u8_t buf[MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];

+

+/**

+ * 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_ROM)

+ */

+err_t 

+ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)

+{

+  struct pbuf *rambuf;

+  struct pbuf *header;

+  struct ip_hdr *iphdr;

+  u16_t nfb = 0;

+  u16_t left, cop;

+  u16_t mtu = netif->mtu;

+  u16_t ofo, omf;

+  u16_t last;

+  u16_t poff = IP_HLEN;

+  u16_t tmp;

+

+  /* Get a RAM based MTU sized pbuf */

+  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 = MEM_ALIGN((void *)buf);

+

+  /* Copy the IP header in it */

+  iphdr = rambuf->payload;

+  memcpy(iphdr, p->payload, IP_HLEN);

+

+  /* Save original offset */

+  tmp = ntohs(IPH_OFFSET(iphdr));

+  ofo = tmp & IP_OFFMASK;

+  omf = tmp & IP_MF;

+

+  left = p->tot_len - IP_HLEN;

+

+  while (left) {

+    last = (left <= mtu - IP_HLEN);

+

+    /* Set new offset and MF flag */

+    ofo += nfb;

+    tmp = omf | (IP_OFFMASK & (ofo));

+    if (!last)

+      tmp = tmp | IP_MF;

+    IPH_OFFSET_SET(iphdr, htons(tmp));

+

+    /* Fill this fragment */

+    nfb = (mtu - IP_HLEN) / 8;

+    cop = last ? left : nfb * 8;

+

+    p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);

+

+    /* Correct header */

+    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));

+    IPH_CHKSUM_SET(iphdr, 0);

+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

+

+    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;    

+    }

+    left -= cop;

+  }

+  pbuf_free(rambuf);

+  snmp_inc_ipfragoks();

+  return ERR_OK;

+}

diff --git a/Demo/Common/ethernet/lwIP/core/mem.c b/Demo/Common/ethernet/lwIP/core/mem.c
index 6ef311d..4d4cb1d 100644
--- a/Demo/Common/ethernet/lwIP/core/mem.c
+++ b/Demo/Common/ethernet/lwIP/core/mem.c
@@ -1,414 +1,414 @@
-/** @file
- *
- * Dynamic memory manager
- *
- */
-
-/*
- * 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 <string.h>
-
-#include "lwip/arch.h"
-#include "lwip/opt.h"
-#include "lwip/def.h"
-#include "lwip/mem.h"
-
-#include "lwip/sys.h"
-
-#include "lwip/stats.h"
-
-#if (MEM_LIBC_MALLOC == 0)
-/* lwIP replacement for your libc malloc() */
-
-struct mem {
-  mem_size_t next, prev;
-#if MEM_ALIGNMENT == 1
-  u8_t used;
-#elif MEM_ALIGNMENT == 2
-  u16_t used;
-#elif MEM_ALIGNMENT == 4
-  u32_t used;
-#elif MEM_ALIGNMENT == 8
-  u64_t used;
-#else
-#error "unhandled MEM_ALIGNMENT size"
-#endif /* MEM_ALIGNMENT */
-};
-
-static struct mem *ram_end;
-#if 1
-/* Adam original */
-static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT];
-#else
-/* Christiaan alignment fix */
-static u8_t *ram;
-static struct mem ram_heap[1 + ( (MEM_SIZE + sizeof(struct mem) - 1) / sizeof(struct mem))];
-#endif
-
-#define MIN_SIZE 12
-#if 0 /* this one does not align correctly for some, resulting in crashes */
-#define SIZEOF_STRUCT_MEM (unsigned int)MEM_ALIGN_SIZE(sizeof(struct mem))
-#else
-#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \
-                          (((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \
-                          (4 - (sizeof(struct mem) % MEM_ALIGNMENT))))
-#endif
-
-static struct mem *lfree;   /* pointer to the lowest free block */
-
-static sys_sem_t mem_sem;
-
-static void
-plug_holes(struct mem *mem)
-{
-  struct mem *nmem;
-  struct mem *pmem;
-
-  LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
-  LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
-  LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
-
-  /* plug hole forward */
-  LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE", mem->next <= MEM_SIZE);
-
-  nmem = (struct mem *)&ram[mem->next];
-  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
-    if (lfree == nmem) {
-      lfree = mem;
-    }
-    mem->next = nmem->next;
-    ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
-  }
-
-  /* plug hole backward */
-  pmem = (struct mem *)&ram[mem->prev];
-  if (pmem != mem && pmem->used == 0) {
-    if (lfree == mem) {
-      lfree = pmem;
-    }
-    pmem->next = mem->next;
-    ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
-  }
-}
-
-void
-mem_init(void)
-{
-  struct mem *mem;
-
-#if 1
-  /* Adam original */
-#else
-  /* Christiaan alignment fix */
-  ram = (u8_t*)ram_heap;
-#endif
-  memset(ram, 0, MEM_SIZE);
-  mem = (struct mem *)ram;
-  mem->next = MEM_SIZE;
-  mem->prev = 0;
-  mem->used = 0;
-  ram_end = (struct mem *)&ram[MEM_SIZE];
-  ram_end->used = 1;
-  ram_end->next = MEM_SIZE;
-  ram_end->prev = MEM_SIZE;
-
-  mem_sem = sys_sem_new(1);
-
-  lfree = (struct mem *)ram;
-
-#if MEM_STATS
-  lwip_stats.mem.avail = MEM_SIZE;
-#endif /* MEM_STATS */
-}
-
-void
-mem_free(void *rmem)
-{
-  struct mem *mem;
-
-  if (rmem == NULL) {
-    LWIP_DEBUGF(MEM_DEBUG | DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
-    return;
-  }
-
-  sys_sem_wait(mem_sem);
-
-  LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
-    (u8_t *)rmem < (u8_t *)ram_end);
-
-  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
-    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
-#if MEM_STATS
-    ++lwip_stats.mem.err;
-#endif /* MEM_STATS */
-    sys_sem_signal(mem_sem);
-    return;
-  }
-  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
-
-  LWIP_ASSERT("mem_free: mem->used", mem->used);
-
-  mem->used = 0;
-
-  if (mem < lfree) {
-    lfree = mem;
-  }
-
-#if MEM_STATS
-  lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);
-
-#endif /* MEM_STATS */
-  plug_holes(mem);
-  sys_sem_signal(mem_sem);
-}
-
-void *
-mem_realloc(void *rmem, mem_size_t newsize)
-{
-  mem_size_t size;
-  mem_size_t ptr, ptr2;
-  struct mem *mem, *mem2;
-
-  /* Expand the size of the allocated memory region so that we can
-     adjust for alignment. */
-  if ((newsize % MEM_ALIGNMENT) != 0) {
-   newsize += MEM_ALIGNMENT - ((newsize + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
-  }
-
-  if (newsize > MEM_SIZE) {
-    return NULL;
-  }
-
-  sys_sem_wait(mem_sem);
-
-  LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
-   (u8_t *)rmem < (u8_t *)ram_end);
-
-  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
-    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
-    return rmem;
-  }
-  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
-
-  ptr = (u8_t *)mem - ram;
-
-  size = mem->next - ptr - SIZEOF_STRUCT_MEM;
-#if MEM_STATS
-  lwip_stats.mem.used -= (size - newsize);
-#endif /* MEM_STATS */
-
-  if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) {
-    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
-    mem2 = (struct mem *)&ram[ptr2];
-    mem2->used = 0;
-    mem2->next = mem->next;
-    mem2->prev = ptr;
-    mem->next = ptr2;
-    if (mem2->next != MEM_SIZE) {
-      ((struct mem *)&ram[mem2->next])->prev = ptr2;
-    }
-
-    plug_holes(mem2);
-  }
-  sys_sem_signal(mem_sem);
-  return rmem;
-}
-
-#if 1
-/**
- * Adam's mem_malloc(), suffers from bug #17922
- * Set if to 0 for alternative mem_malloc().
- */
-void *
-mem_malloc(mem_size_t size)
-{
-  mem_size_t ptr, ptr2;
-  struct mem *mem, *mem2;
-
-  if (size == 0) {
-    return NULL;
-  }
-
-  /* Expand the size of the allocated memory region so that we can
-     adjust for alignment. */
-  if ((size % MEM_ALIGNMENT) != 0) {
-    size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
-  }
-
-  if (size > MEM_SIZE) {
-    return NULL;
-  }
-
-  sys_sem_wait(mem_sem);
-
-  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE; ptr = ((struct mem *)&ram[ptr])->next) {
-    mem = (struct mem *)&ram[ptr];
-    if (!mem->used &&
-       mem->next - (ptr + SIZEOF_STRUCT_MEM) >= size + SIZEOF_STRUCT_MEM) {
-      ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
-      mem2 = (struct mem *)&ram[ptr2];
-
-      mem2->prev = ptr;
-      mem2->next = mem->next;
-      mem->next = ptr2;
-      if (mem2->next != MEM_SIZE) {
-        ((struct mem *)&ram[mem2->next])->prev = ptr2;
-      }
-
-      mem2->used = 0;
-      mem->used = 1;
-#if MEM_STATS
-      lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);
-      /*      if (lwip_stats.mem.max < lwip_stats.mem.used) {
-        lwip_stats.mem.max = lwip_stats.mem.used;
-        } */
-      if (lwip_stats.mem.max < ptr2) {
-        lwip_stats.mem.max = ptr2;
-      }
-#endif /* MEM_STATS */
-
-      if (mem == lfree) {
-        /* Find next free block after mem */
-        while (lfree->used && lfree != ram_end) {
-          lfree = (struct mem *)&ram[lfree->next];
-        }
-        LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);
-      }
-      sys_sem_signal(mem_sem);
-      LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
-       (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
-      LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
-       (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
-      return (u8_t *)mem + SIZEOF_STRUCT_MEM;
-    }
-  }
-  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
-#if MEM_STATS
-  ++lwip_stats.mem.err;
-#endif /* MEM_STATS */
-  sys_sem_signal(mem_sem);
-  return NULL;
-}
-#else
-/**
- * Adam's mem_malloc() plus solution for bug #17922
- */
-void *
-mem_malloc(mem_size_t size)
-{
-  mem_size_t ptr, ptr2;
-  struct mem *mem, *mem2;
-
-  if (size == 0) {
-    return NULL;
-  }
-
-  /* Expand the size of the allocated memory region so that we can
-     adjust for alignment. */
-  if ((size % MEM_ALIGNMENT) != 0) {
-    size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
-  }
-
-  if (size > MEM_SIZE) {
-    return NULL;
-  }
-
-  sys_sem_wait(mem_sem);
-
-  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE - size; ptr = ((struct mem *)&ram[ptr])->next) {
-    mem = (struct mem *)&ram[ptr];
-
-    if (!mem->used) {
-
-      ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
-
-      if (mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) >= size) {
-        /* split large block, create empty remainder */
-        mem->next = ptr2;
-        mem->used = 1;
-        /* create mem2 struct */
-        mem2 = (struct mem *)&ram[ptr2];
-        mem2->used = 0;
-        mem2->next = mem->next;
-        mem2->prev = ptr;
-
-        if (mem2->next != MEM_SIZE) {
-          ((struct mem *)&ram[mem2->next])->prev = ptr2;
-        }
-      }
-      else if (mem->next - (ptr + SIZEOF_STRUCT_MEM) > size) {
-        /* near fit, no split, no mem2 creation,
-           round up to mem->next */
-        ptr2 = mem->next;
-        mem->used = 1;
-      }
-      else if (mem->next - (ptr + SIZEOF_STRUCT_MEM) == size) {
-        /* exact fit, do not split, no mem2 creation */
-        mem->next = ptr2;
-        mem->used = 1;
-      }
-
-      if (mem->used) {
-#if MEM_STATS
-        lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);
-        if (lwip_stats.mem.max < ptr2) {
-          lwip_stats.mem.max = ptr2;
-        }
-#endif /* MEM_STATS */
-        if (mem == lfree) {
-          /* Find next free block after mem */
-          while (lfree->used && lfree != ram_end) {
-            lfree = (struct mem *)&ram[lfree->next];
-          }
-          LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);
-        }
-        sys_sem_signal(mem_sem);
-        LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
-         (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
-        LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
-         (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
-        return (u8_t *)mem + SIZEOF_STRUCT_MEM;
-      }
-    }
-  }
-  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
-#if MEM_STATS
-  ++lwip_stats.mem.err;
-#endif /* MEM_STATS */
-  sys_sem_signal(mem_sem);
-  return NULL;
-}
-#endif
-
-#endif /* MEM_LIBC_MALLOC == 0 */
-
+/** @file

+ *

+ * Dynamic memory manager

+ *

+ */

+

+/*

+ * 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 <string.h>

+

+#include "lwip/arch.h"

+#include "lwip/opt.h"

+#include "lwip/def.h"

+#include "lwip/mem.h"

+

+#include "lwip/sys.h"

+

+#include "lwip/stats.h"

+

+#if (MEM_LIBC_MALLOC == 0)

+/* lwIP replacement for your libc malloc() */

+

+struct mem {

+  mem_size_t next, prev;

+#if MEM_ALIGNMENT == 1

+  u8_t used;

+#elif MEM_ALIGNMENT == 2

+  u16_t used;

+#elif MEM_ALIGNMENT == 4

+  u32_t used;

+#elif MEM_ALIGNMENT == 8

+  u64_t used;

+#else

+#error "unhandled MEM_ALIGNMENT size"

+#endif /* MEM_ALIGNMENT */

+};

+

+static struct mem *ram_end;

+#if 1

+/* Adam original */

+static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT];

+#else

+/* Christiaan alignment fix */

+static u8_t *ram;

+static struct mem ram_heap[1 + ( (MEM_SIZE + sizeof(struct mem) - 1) / sizeof(struct mem))];

+#endif

+

+#define MIN_SIZE 12

+#if 0 /* this one does not align correctly for some, resulting in crashes */

+#define SIZEOF_STRUCT_MEM (unsigned int)MEM_ALIGN_SIZE(sizeof(struct mem))

+#else

+#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \

+                          (((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \

+                          (4 - (sizeof(struct mem) % MEM_ALIGNMENT))))

+#endif

+

+static struct mem *lfree;   /* pointer to the lowest free block */

+

+static sys_sem_t mem_sem;

+

+static void

+plug_holes(struct mem *mem)

+{

+  struct mem *nmem;

+  struct mem *pmem;

+

+  LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);

+  LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);

+  LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);

+

+  /* plug hole forward */

+  LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE", mem->next <= MEM_SIZE);

+

+  nmem = (struct mem *)&ram[mem->next];

+  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {

+    if (lfree == nmem) {

+      lfree = mem;

+    }

+    mem->next = nmem->next;

+    ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;

+  }

+

+  /* plug hole backward */

+  pmem = (struct mem *)&ram[mem->prev];

+  if (pmem != mem && pmem->used == 0) {

+    if (lfree == mem) {

+      lfree = pmem;

+    }

+    pmem->next = mem->next;

+    ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;

+  }

+}

+

+void

+mem_init(void)

+{

+  struct mem *mem;

+

+#if 1

+  /* Adam original */

+#else

+  /* Christiaan alignment fix */

+  ram = (u8_t*)ram_heap;

+#endif

+  memset(ram, 0, MEM_SIZE);

+  mem = (struct mem *)ram;

+  mem->next = MEM_SIZE;

+  mem->prev = 0;

+  mem->used = 0;

+  ram_end = (struct mem *)&ram[MEM_SIZE];

+  ram_end->used = 1;

+  ram_end->next = MEM_SIZE;

+  ram_end->prev = MEM_SIZE;

+

+  mem_sem = sys_sem_new(1);

+

+  lfree = (struct mem *)ram;

+

+#if MEM_STATS

+  lwip_stats.mem.avail = MEM_SIZE;

+#endif /* MEM_STATS */

+}

+

+void

+mem_free(void *rmem)

+{

+  struct mem *mem;

+

+  if (rmem == NULL) {

+    LWIP_DEBUGF(MEM_DEBUG | DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));

+    return;

+  }

+

+  sys_sem_wait(mem_sem);

+

+  LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&

+    (u8_t *)rmem < (u8_t *)ram_end);

+

+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {

+    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));

+#if MEM_STATS

+    ++lwip_stats.mem.err;

+#endif /* MEM_STATS */

+    sys_sem_signal(mem_sem);

+    return;

+  }

+  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);

+

+  LWIP_ASSERT("mem_free: mem->used", mem->used);

+

+  mem->used = 0;

+

+  if (mem < lfree) {

+    lfree = mem;

+  }

+

+#if MEM_STATS

+  lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);

+

+#endif /* MEM_STATS */

+  plug_holes(mem);

+  sys_sem_signal(mem_sem);

+}

+

+void *

+mem_realloc(void *rmem, mem_size_t newsize)

+{

+  mem_size_t size;

+  mem_size_t ptr, ptr2;

+  struct mem *mem, *mem2;

+

+  /* Expand the size of the allocated memory region so that we can

+     adjust for alignment. */

+  if ((newsize % MEM_ALIGNMENT) != 0) {

+   newsize += MEM_ALIGNMENT - ((newsize + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);

+  }

+

+  if (newsize > MEM_SIZE) {

+    return NULL;

+  }

+

+  sys_sem_wait(mem_sem);

+

+  LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&

+   (u8_t *)rmem < (u8_t *)ram_end);

+

+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {

+    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));

+    return rmem;

+  }

+  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);

+

+  ptr = (u8_t *)mem - ram;

+

+  size = mem->next - ptr - SIZEOF_STRUCT_MEM;

+#if MEM_STATS

+  lwip_stats.mem.used -= (size - newsize);

+#endif /* MEM_STATS */

+

+  if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) {

+    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;

+    mem2 = (struct mem *)&ram[ptr2];

+    mem2->used = 0;

+    mem2->next = mem->next;

+    mem2->prev = ptr;

+    mem->next = ptr2;

+    if (mem2->next != MEM_SIZE) {

+      ((struct mem *)&ram[mem2->next])->prev = ptr2;

+    }

+

+    plug_holes(mem2);

+  }

+  sys_sem_signal(mem_sem);

+  return rmem;

+}

+

+#if 1

+/**

+ * Adam's mem_malloc(), suffers from bug #17922

+ * Set if to 0 for alternative mem_malloc().

+ */

+void *

+mem_malloc(mem_size_t size)

+{

+  mem_size_t ptr, ptr2;

+  struct mem *mem, *mem2;

+

+  if (size == 0) {

+    return NULL;

+  }

+

+  /* Expand the size of the allocated memory region so that we can

+     adjust for alignment. */

+  if ((size % MEM_ALIGNMENT) != 0) {

+    size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);

+  }

+

+  if (size > MEM_SIZE) {

+    return NULL;

+  }

+

+  sys_sem_wait(mem_sem);

+

+  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE; ptr = ((struct mem *)&ram[ptr])->next) {

+    mem = (struct mem *)&ram[ptr];

+    if (!mem->used &&

+       mem->next - (ptr + SIZEOF_STRUCT_MEM) >= size + SIZEOF_STRUCT_MEM) {

+      ptr2 = ptr + SIZEOF_STRUCT_MEM + size;

+      mem2 = (struct mem *)&ram[ptr2];

+

+      mem2->prev = ptr;

+      mem2->next = mem->next;

+      mem->next = ptr2;

+      if (mem2->next != MEM_SIZE) {

+        ((struct mem *)&ram[mem2->next])->prev = ptr2;

+      }

+

+      mem2->used = 0;

+      mem->used = 1;

+#if MEM_STATS

+      lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);

+      /*      if (lwip_stats.mem.max < lwip_stats.mem.used) {

+        lwip_stats.mem.max = lwip_stats.mem.used;

+        } */

+      if (lwip_stats.mem.max < ptr2) {

+        lwip_stats.mem.max = ptr2;

+      }

+#endif /* MEM_STATS */

+

+      if (mem == lfree) {

+        /* Find next free block after mem */

+        while (lfree->used && lfree != ram_end) {

+          lfree = (struct mem *)&ram[lfree->next];

+        }

+        LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);

+      }

+      sys_sem_signal(mem_sem);

+      LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",

+       (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);

+      LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",

+       (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);

+      return (u8_t *)mem + SIZEOF_STRUCT_MEM;

+    }

+  }

+  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));

+#if MEM_STATS

+  ++lwip_stats.mem.err;

+#endif /* MEM_STATS */

+  sys_sem_signal(mem_sem);

+  return NULL;

+}

+#else

+/**

+ * Adam's mem_malloc() plus solution for bug #17922

+ */

+void *

+mem_malloc(mem_size_t size)

+{

+  mem_size_t ptr, ptr2;

+  struct mem *mem, *mem2;

+

+  if (size == 0) {

+    return NULL;

+  }

+

+  /* Expand the size of the allocated memory region so that we can

+     adjust for alignment. */

+  if ((size % MEM_ALIGNMENT) != 0) {

+    size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);

+  }

+

+  if (size > MEM_SIZE) {

+    return NULL;

+  }

+

+  sys_sem_wait(mem_sem);

+

+  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE - size; ptr = ((struct mem *)&ram[ptr])->next) {

+    mem = (struct mem *)&ram[ptr];

+

+    if (!mem->used) {

+

+      ptr2 = ptr + SIZEOF_STRUCT_MEM + size;

+

+      if (mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) >= size) {

+        /* split large block, create empty remainder */

+        mem->next = ptr2;

+        mem->used = 1;

+        /* create mem2 struct */

+        mem2 = (struct mem *)&ram[ptr2];

+        mem2->used = 0;

+        mem2->next = mem->next;

+        mem2->prev = ptr;

+

+        if (mem2->next != MEM_SIZE) {

+          ((struct mem *)&ram[mem2->next])->prev = ptr2;

+        }

+      }

+      else if (mem->next - (ptr + SIZEOF_STRUCT_MEM) > size) {

+        /* near fit, no split, no mem2 creation,

+           round up to mem->next */

+        ptr2 = mem->next;

+        mem->used = 1;

+      }

+      else if (mem->next - (ptr + SIZEOF_STRUCT_MEM) == size) {

+        /* exact fit, do not split, no mem2 creation */

+        mem->next = ptr2;

+        mem->used = 1;

+      }

+

+      if (mem->used) {

+#if MEM_STATS

+        lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);

+        if (lwip_stats.mem.max < ptr2) {

+          lwip_stats.mem.max = ptr2;

+        }

+#endif /* MEM_STATS */

+        if (mem == lfree) {

+          /* Find next free block after mem */

+          while (lfree->used && lfree != ram_end) {

+            lfree = (struct mem *)&ram[lfree->next];

+          }

+          LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);

+        }

+        sys_sem_signal(mem_sem);

+        LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",

+         (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);

+        LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",

+         (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);

+        return (u8_t *)mem + SIZEOF_STRUCT_MEM;

+      }

+    }

+  }

+  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));

+#if MEM_STATS

+  ++lwip_stats.mem.err;

+#endif /* MEM_STATS */

+  sys_sem_signal(mem_sem);

+  return NULL;

+}

+#endif

+

+#endif /* MEM_LIBC_MALLOC == 0 */

+

diff --git a/Demo/Common/ethernet/lwIP/core/memp.c b/Demo/Common/ethernet/lwIP/core/memp.c
index b31812d..3912009 100644
--- a/Demo/Common/ethernet/lwIP/core/memp.c
+++ b/Demo/Common/ethernet/lwIP/core/memp.c
@@ -1,238 +1,238 @@
-/*
- * 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/memp.h"
-
-#include "lwip/pbuf.h"
-#include "lwip/udp.h"
-#include "lwip/raw.h"
-#include "lwip/tcp.h"
-#include "lwip/api.h"
-#include "lwip/api_msg.h"
-#include "lwip/tcpip.h"
-
-#include "lwip/sys.h"
-#include "lwip/stats.h"
-
-struct memp {
-  struct memp *next;
-};
-
-#define MEMP_SIZE MEM_ALIGN_SIZE(sizeof(struct memp))
-
-static struct memp *memp_tab[MEMP_MAX];
-
-static const u16_t memp_sizes[MEMP_MAX] = {
-  MEM_ALIGN_SIZE(sizeof(struct pbuf)),
-  MEM_ALIGN_SIZE(sizeof(struct raw_pcb)),
-  MEM_ALIGN_SIZE(sizeof(struct udp_pcb)),
-  MEM_ALIGN_SIZE(sizeof(struct tcp_pcb)),
-  MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen)),
-  MEM_ALIGN_SIZE(sizeof(struct tcp_seg)),
-  MEM_ALIGN_SIZE(sizeof(struct netbuf)),
-  MEM_ALIGN_SIZE(sizeof(struct netconn)),
-  MEM_ALIGN_SIZE(sizeof(struct api_msg)),
-  MEM_ALIGN_SIZE(sizeof(struct tcpip_msg)),
-  MEM_ALIGN_SIZE(sizeof(struct sys_timeo))
-};
-
-static const u16_t memp_num[MEMP_MAX] = {
-  MEMP_NUM_PBUF,
-  MEMP_NUM_RAW_PCB,
-  MEMP_NUM_UDP_PCB,
-  MEMP_NUM_TCP_PCB,
-  MEMP_NUM_TCP_PCB_LISTEN,
-  MEMP_NUM_TCP_SEG,
-  MEMP_NUM_NETBUF,
-  MEMP_NUM_NETCONN,
-  MEMP_NUM_API_MSG,
-  MEMP_NUM_TCPIP_MSG,
-  MEMP_NUM_SYS_TIMEOUT
-};
-
-#define MEMP_TYPE_SIZE(qty, type) \
-  ((qty) * (MEMP_SIZE + MEM_ALIGN_SIZE(sizeof(type))))
-
-static u8_t memp_memory[MEM_ALIGNMENT - 1 + 
-  MEMP_TYPE_SIZE(MEMP_NUM_PBUF, struct pbuf) +
-  MEMP_TYPE_SIZE(MEMP_NUM_RAW_PCB, struct raw_pcb) +
-  MEMP_TYPE_SIZE(MEMP_NUM_UDP_PCB, struct udp_pcb) +
-  MEMP_TYPE_SIZE(MEMP_NUM_TCP_PCB, struct tcp_pcb) +
-  MEMP_TYPE_SIZE(MEMP_NUM_TCP_PCB_LISTEN, struct tcp_pcb_listen) +
-  MEMP_TYPE_SIZE(MEMP_NUM_TCP_SEG, struct tcp_seg) +
-  MEMP_TYPE_SIZE(MEMP_NUM_NETBUF, struct netbuf) +
-  MEMP_TYPE_SIZE(MEMP_NUM_NETCONN, struct netconn) +
-  MEMP_TYPE_SIZE(MEMP_NUM_API_MSG, struct api_msg) +
-  MEMP_TYPE_SIZE(MEMP_NUM_TCPIP_MSG, struct tcpip_msg) +
-  MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)];
-
-#if !SYS_LIGHTWEIGHT_PROT
-static sys_sem_t mutex;
-#endif
-
-#if MEMP_SANITY_CHECK
-static int
-memp_sanity(void)
-{
-  s16_t i, c;
-  struct memp *m, *n;
-
-  for (i = 0; i < MEMP_MAX; i++) {
-    for (m = memp_tab[i]; m != NULL; m = m->next) {
-      c = 1;
-      for (n = memp_tab[i]; n != NULL; n = n->next) {
-        if (n == m && --c < 0) {
-          return 0; /* LW was: abort(); */
-        }
-      }
-    }
-  }
-  return 1;
-}
-#endif /* MEMP_SANITY_CHECK*/
-
-void
-memp_init(void)
-{
-  struct memp *memp;
-  u16_t i, j;
-
-#if MEMP_STATS
-  for (i = 0; i < MEMP_MAX; ++i) {
-    lwip_stats.memp[i].used = lwip_stats.memp[i].max =
-      lwip_stats.memp[i].err = 0;
-    lwip_stats.memp[i].avail = memp_num[i];
-  }
-#endif /* MEMP_STATS */
-
-  memp = MEM_ALIGN(memp_memory);
-  for (i = 0; i < MEMP_MAX; ++i) {
-    memp_tab[i] = NULL;
-    for (j = 0; j < memp_num[i]; ++j) {
-      memp->next = memp_tab[i];
-      memp_tab[i] = memp;
-      memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);
-    }
-  }
-
-#if !SYS_LIGHTWEIGHT_PROT
-  mutex = sys_sem_new(1);
-#endif
-}
-
-void *
-memp_malloc(memp_t type)
-{
-  struct memp *memp;
-  void *mem;
-#if SYS_LIGHTWEIGHT_PROT
-  SYS_ARCH_DECL_PROTECT(old_level);
-#endif
- 
-  LWIP_ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX);
-
-#if SYS_LIGHTWEIGHT_PROT
-  SYS_ARCH_PROTECT(old_level);
-#else /* SYS_LIGHTWEIGHT_PROT */  
-  sys_sem_wait(mutex);
-#endif /* SYS_LIGHTWEIGHT_PROT */  
-
-  memp = memp_tab[type];
-  
-  if (memp != NULL) {    
-    memp_tab[type] = memp->next;    
-    memp->next = NULL;
-#if MEMP_STATS
-    ++lwip_stats.memp[type].used;
-    if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {
-      lwip_stats.memp[type].max = lwip_stats.memp[type].used;
-    }
-#endif /* MEMP_STATS */
-    mem = (u8_t *)memp + MEMP_SIZE;
-    LWIP_ASSERT("memp_malloc: memp properly aligned",
-                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
-  } else {
-    LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %"S16_F"\n", type));
-#if MEMP_STATS
-    ++lwip_stats.memp[type].err;
-#endif /* MEMP_STATS */
-    mem = NULL;
-  }
-
-#if SYS_LIGHTWEIGHT_PROT
-  SYS_ARCH_UNPROTECT(old_level);
-#else /* SYS_LIGHTWEIGHT_PROT */
-  sys_sem_signal(mutex);
-#endif /* SYS_LIGHTWEIGHT_PROT */  
-
-  return mem;
-}
-
-void
-memp_free(memp_t type, void *mem)
-{
-  struct memp *memp;
-#if SYS_LIGHTWEIGHT_PROT
-  SYS_ARCH_DECL_PROTECT(old_level);
-#endif /* SYS_LIGHTWEIGHT_PROT */  
-
-  if (mem == NULL) {
-    return;
-  }
-
-  memp = (struct memp *)((u8_t *)mem - MEMP_SIZE);
-
-#if SYS_LIGHTWEIGHT_PROT
-  SYS_ARCH_PROTECT(old_level);
-#else /* SYS_LIGHTWEIGHT_PROT */  
-  sys_sem_wait(mutex);
-#endif /* SYS_LIGHTWEIGHT_PROT */  
-
-#if MEMP_STATS
-  lwip_stats.memp[type].used--; 
-#endif /* MEMP_STATS */
-  
-  memp->next = memp_tab[type]; 
-  memp_tab[type] = memp;
-
-#if MEMP_SANITY_CHECK
-  LWIP_ASSERT("memp sanity", memp_sanity());
-#endif  
-
-#if SYS_LIGHTWEIGHT_PROT
-  SYS_ARCH_UNPROTECT(old_level);
-#else /* SYS_LIGHTWEIGHT_PROT */
-  sys_sem_signal(mutex);
-#endif /* SYS_LIGHTWEIGHT_PROT */  
-}
+/*

+ * 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/memp.h"

+

+#include "lwip/pbuf.h"

+#include "lwip/udp.h"

+#include "lwip/raw.h"

+#include "lwip/tcp.h"

+#include "lwip/api.h"

+#include "lwip/api_msg.h"

+#include "lwip/tcpip.h"

+

+#include "lwip/sys.h"

+#include "lwip/stats.h"

+

+struct memp {

+  struct memp *next;

+};

+

+#define MEMP_SIZE MEM_ALIGN_SIZE(sizeof(struct memp))

+

+static struct memp *memp_tab[MEMP_MAX];

+

+static const u16_t memp_sizes[MEMP_MAX] = {

+  MEM_ALIGN_SIZE(sizeof(struct pbuf)),

+  MEM_ALIGN_SIZE(sizeof(struct raw_pcb)),

+  MEM_ALIGN_SIZE(sizeof(struct udp_pcb)),

+  MEM_ALIGN_SIZE(sizeof(struct tcp_pcb)),

+  MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen)),

+  MEM_ALIGN_SIZE(sizeof(struct tcp_seg)),

+  MEM_ALIGN_SIZE(sizeof(struct netbuf)),

+  MEM_ALIGN_SIZE(sizeof(struct netconn)),

+  MEM_ALIGN_SIZE(sizeof(struct api_msg)),

+  MEM_ALIGN_SIZE(sizeof(struct tcpip_msg)),

+  MEM_ALIGN_SIZE(sizeof(struct sys_timeo))

+};

+

+static const u16_t memp_num[MEMP_MAX] = {

+  MEMP_NUM_PBUF,

+  MEMP_NUM_RAW_PCB,

+  MEMP_NUM_UDP_PCB,

+  MEMP_NUM_TCP_PCB,

+  MEMP_NUM_TCP_PCB_LISTEN,

+  MEMP_NUM_TCP_SEG,

+  MEMP_NUM_NETBUF,

+  MEMP_NUM_NETCONN,

+  MEMP_NUM_API_MSG,

+  MEMP_NUM_TCPIP_MSG,

+  MEMP_NUM_SYS_TIMEOUT

+};

+

+#define MEMP_TYPE_SIZE(qty, type) \

+  ((qty) * (MEMP_SIZE + MEM_ALIGN_SIZE(sizeof(type))))

+

+static u8_t memp_memory[MEM_ALIGNMENT - 1 + 

+  MEMP_TYPE_SIZE(MEMP_NUM_PBUF, struct pbuf) +

+  MEMP_TYPE_SIZE(MEMP_NUM_RAW_PCB, struct raw_pcb) +

+  MEMP_TYPE_SIZE(MEMP_NUM_UDP_PCB, struct udp_pcb) +

+  MEMP_TYPE_SIZE(MEMP_NUM_TCP_PCB, struct tcp_pcb) +

+  MEMP_TYPE_SIZE(MEMP_NUM_TCP_PCB_LISTEN, struct tcp_pcb_listen) +

+  MEMP_TYPE_SIZE(MEMP_NUM_TCP_SEG, struct tcp_seg) +

+  MEMP_TYPE_SIZE(MEMP_NUM_NETBUF, struct netbuf) +

+  MEMP_TYPE_SIZE(MEMP_NUM_NETCONN, struct netconn) +

+  MEMP_TYPE_SIZE(MEMP_NUM_API_MSG, struct api_msg) +

+  MEMP_TYPE_SIZE(MEMP_NUM_TCPIP_MSG, struct tcpip_msg) +

+  MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)];

+

+#if !SYS_LIGHTWEIGHT_PROT

+static sys_sem_t mutex;

+#endif

+

+#if MEMP_SANITY_CHECK

+static int

+memp_sanity(void)

+{

+  s16_t i, c;

+  struct memp *m, *n;

+

+  for (i = 0; i < MEMP_MAX; i++) {

+    for (m = memp_tab[i]; m != NULL; m = m->next) {

+      c = 1;

+      for (n = memp_tab[i]; n != NULL; n = n->next) {

+        if (n == m && --c < 0) {

+          return 0; /* LW was: abort(); */

+        }

+      }

+    }

+  }

+  return 1;

+}

+#endif /* MEMP_SANITY_CHECK*/

+

+void

+memp_init(void)

+{

+  struct memp *memp;

+  u16_t i, j;

+

+#if MEMP_STATS

+  for (i = 0; i < MEMP_MAX; ++i) {

+    lwip_stats.memp[i].used = lwip_stats.memp[i].max =

+      lwip_stats.memp[i].err = 0;

+    lwip_stats.memp[i].avail = memp_num[i];

+  }

+#endif /* MEMP_STATS */

+

+  memp = MEM_ALIGN(memp_memory);

+  for (i = 0; i < MEMP_MAX; ++i) {

+    memp_tab[i] = NULL;

+    for (j = 0; j < memp_num[i]; ++j) {

+      memp->next = memp_tab[i];

+      memp_tab[i] = memp;

+      memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);

+    }

+  }

+

+#if !SYS_LIGHTWEIGHT_PROT

+  mutex = sys_sem_new(1);

+#endif

+}

+

+void *

+memp_malloc(memp_t type)

+{

+  struct memp *memp;

+  void *mem;

+#if SYS_LIGHTWEIGHT_PROT

+  SYS_ARCH_DECL_PROTECT(old_level);

+#endif

+ 

+  LWIP_ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX);

+

+#if SYS_LIGHTWEIGHT_PROT

+  SYS_ARCH_PROTECT(old_level);

+#else /* SYS_LIGHTWEIGHT_PROT */  

+  sys_sem_wait(mutex);

+#endif /* SYS_LIGHTWEIGHT_PROT */  

+

+  memp = memp_tab[type];

+  

+  if (memp != NULL) {    

+    memp_tab[type] = memp->next;    

+    memp->next = NULL;

+#if MEMP_STATS

+    ++lwip_stats.memp[type].used;

+    if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {

+      lwip_stats.memp[type].max = lwip_stats.memp[type].used;

+    }

+#endif /* MEMP_STATS */

+    mem = (u8_t *)memp + MEMP_SIZE;

+    LWIP_ASSERT("memp_malloc: memp properly aligned",

+                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);

+  } else {

+    LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %"S16_F"\n", type));

+#if MEMP_STATS

+    ++lwip_stats.memp[type].err;

+#endif /* MEMP_STATS */

+    mem = NULL;

+  }

+

+#if SYS_LIGHTWEIGHT_PROT

+  SYS_ARCH_UNPROTECT(old_level);

+#else /* SYS_LIGHTWEIGHT_PROT */

+  sys_sem_signal(mutex);

+#endif /* SYS_LIGHTWEIGHT_PROT */  

+

+  return mem;

+}

+

+void

+memp_free(memp_t type, void *mem)

+{

+  struct memp *memp;

+#if SYS_LIGHTWEIGHT_PROT

+  SYS_ARCH_DECL_PROTECT(old_level);

+#endif /* SYS_LIGHTWEIGHT_PROT */  

+

+  if (mem == NULL) {

+    return;

+  }

+

+  memp = (struct memp *)((u8_t *)mem - MEMP_SIZE);

+

+#if SYS_LIGHTWEIGHT_PROT

+  SYS_ARCH_PROTECT(old_level);

+#else /* SYS_LIGHTWEIGHT_PROT */  

+  sys_sem_wait(mutex);

+#endif /* SYS_LIGHTWEIGHT_PROT */  

+

+#if MEMP_STATS

+  lwip_stats.memp[type].used--; 

+#endif /* MEMP_STATS */

+  

+  memp->next = memp_tab[type]; 

+  memp_tab[type] = memp;

+

+#if MEMP_SANITY_CHECK

+  LWIP_ASSERT("memp sanity", memp_sanity());

+#endif  

+

+#if SYS_LIGHTWEIGHT_PROT

+  SYS_ARCH_UNPROTECT(old_level);

+#else /* SYS_LIGHTWEIGHT_PROT */

+  sys_sem_signal(mutex);

+#endif /* SYS_LIGHTWEIGHT_PROT */  

+}

diff --git a/Demo/Common/ethernet/lwIP/core/netif.c b/Demo/Common/ethernet/lwIP/core/netif.c
index b1e2bc1..0a78661 100644
--- a/Demo/Common/ethernet/lwIP/core/netif.c
+++ b/Demo/Common/ethernet/lwIP/core/netif.c
@@ -1,325 +1,325 @@
-/**
- * @file
- *
- * lwIP network interface abstraction
- */
-
-/*
- * 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/def.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/tcp.h"
-#include "lwip/snmp.h"
-
-struct netif *netif_list = NULL;
-struct netif *netif_default = NULL;
-
-/**
- * Add a network interface to the list of lwIP netifs.
- *
- * @param netif a pre-allocated netif structure
- * @param ipaddr IP address for the new netif
- * @param netmask network mask for the new netif
- * @param gw default gateway IP address for the new netif
- * @param state opaque data passed to the new netif
- * @param init callback function that initializes the interface
- * @param input callback function that is called to pass
- * ingress packets up in the protocol layer stack.
- *
- * @return netif, or NULL if failed.
- */
-struct netif *
-netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
-  struct ip_addr *gw,
-  void *state,
-  err_t (* init)(struct netif *netif),
-  err_t (* input)(struct pbuf *p, struct netif *netif))
-{
-  static s16_t netifnum = 0;
-
-  /* reset new interface configuration state */
-  netif->ip_addr.addr = 0;
-  netif->netmask.addr = 0;
-  netif->gw.addr = 0;
-  netif->flags = 0;
-#if LWIP_DHCP
-  /* netif not under DHCP control by default */
-  netif->dhcp = NULL;
-#endif
-  /* remember netif specific state information data */
-  netif->state = state;
-  netif->num = netifnum++;
-  netif->input = input;
-
-  netif_set_addr(netif, ipaddr, netmask, gw);
-
-  /* call user specified initialization function for netif */
-  if (init(netif) != ERR_OK) {
-    return NULL;
-  }
-
-  /* add this netif to the list */
-  netif->next = netif_list;
-  netif_list = netif;
-  snmp_inc_iflist();
-
-  LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
-    netif->name[0], netif->name[1]));
-  ip_addr_debug_print(NETIF_DEBUG, ipaddr);
-  LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
-  ip_addr_debug_print(NETIF_DEBUG, netmask);
-  LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
-  ip_addr_debug_print(NETIF_DEBUG, gw);
-  LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
-  return netif;
-}
-
-void
-netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,
-    struct ip_addr *gw)
-{
-  netif_set_ipaddr(netif, ipaddr);
-  netif_set_netmask(netif, netmask);
-  netif_set_gw(netif, gw);
-}
-
-void netif_remove(struct netif * netif)
-{
-  if ( netif == NULL ) return;
-
-  snmp_delete_ipaddridx_tree(netif);
-
-  /*  is it the first netif? */
-  if (netif_list == netif) {
-    netif_list = netif->next;
-    snmp_dec_iflist();
-  }
-  else {
-    /*  look for netif further down the list */
-    struct netif * tmpNetif;
-    for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
-      if (tmpNetif->next == netif) {
-        tmpNetif->next = netif->next;
-        snmp_dec_iflist();
-        break;
-      }
-    }
-    if (tmpNetif == NULL)
-      return; /*  we didn't find any netif today */
-  }
-  /* this netif is default? */
-  if (netif_default == netif)
-    /* reset default netif */
-    netif_default = NULL;
-  LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
-}
-
-struct netif *
-netif_find(char *name)
-{
-  struct netif *netif;
-  u8_t num;
-
-  if (name == NULL) {
-    return NULL;
-  }
-
-  num = name[2] - '0';
-
-  for(netif = netif_list; netif != NULL; netif = netif->next) {
-    if (num == netif->num &&
-       name[0] == netif->name[0] &&
-       name[1] == netif->name[1]) {
-      LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
-      return netif;
-    }
-  }
-  LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
-  return NULL;
-}
-
-void
-netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
-{
-  /* TODO: Handling of obsolete pcbs */
-  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
-#if LWIP_TCP
-  struct tcp_pcb *pcb;
-  struct tcp_pcb_listen *lpcb;
-
-  /* address is actually being changed? */
-  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)
-  {
-    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
-    LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));
-    pcb = tcp_active_pcbs;
-    while (pcb != NULL) {
-      /* PCB bound to current local interface address? */
-      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
-        /* this connection must be aborted */
-        struct tcp_pcb *next = pcb->next;
-        LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
-        tcp_abort(pcb);
-        pcb = next;
-      } else {
-        pcb = pcb->next;
-      }
-    }
-    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
-      /* PCB bound to current local interface address? */
-      if (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr))) {
-        /* The PCB is listening to the old ipaddr and
-         * is set to listen to the new one instead */
-        ip_addr_set(&(lpcb->local_ip), ipaddr);
-      }
-    }
-  }
-#endif
-  snmp_delete_ipaddridx_tree(netif);
-  snmp_delete_iprteidx_tree(0,netif);
-  /* set new IP address to netif */
-  ip_addr_set(&(netif->ip_addr), ipaddr);
-  snmp_insert_ipaddridx_tree(netif);
-  snmp_insert_iprteidx_tree(0,netif);
-
-#if 0 /* only allowed for Ethernet interfaces TODO: how can we check? */
-  /** For Ethernet network interfaces, we would like to send a
-   *  "gratuitous ARP"; this is an ARP packet sent by a node in order
-   *  to spontaneously cause other nodes to update an entry in their
-   *  ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
-   */ 
-  etharp_query(netif, ipaddr, NULL);
-#endif
-  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
-    netif->name[0], netif->name[1],
-    ip4_addr1(&netif->ip_addr),
-    ip4_addr2(&netif->ip_addr),
-    ip4_addr3(&netif->ip_addr),
-    ip4_addr4(&netif->ip_addr)));
-}
-
-void
-netif_set_gw(struct netif *netif, struct ip_addr *gw)
-{
-  ip_addr_set(&(netif->gw), gw);
-  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
-    netif->name[0], netif->name[1],
-    ip4_addr1(&netif->gw),
-    ip4_addr2(&netif->gw),
-    ip4_addr3(&netif->gw),
-    ip4_addr4(&netif->gw)));
-}
-
-void
-netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
-{
-  snmp_delete_iprteidx_tree(0, netif);
-  /* set new netmask to netif */
-  ip_addr_set(&(netif->netmask), netmask);
-  snmp_insert_iprteidx_tree(0, netif);
-  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
-    netif->name[0], netif->name[1],
-    ip4_addr1(&netif->netmask),
-    ip4_addr2(&netif->netmask),
-    ip4_addr3(&netif->netmask),
-    ip4_addr4(&netif->netmask)));
-}
-
-void
-netif_set_default(struct netif *netif)
-{
-  if (netif == NULL)
-  {
-    /* remove default route */
-    snmp_delete_iprteidx_tree(1, netif);
-  }
-  else
-  {
-    /* install default route */
-    snmp_insert_iprteidx_tree(1, netif);
-  }
-  netif_default = netif;
-  LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
-           netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
-}
-
-/**
- * Bring an interface up, available for processing
- * traffic.
- * 
- * @note: Enabling DHCP on a down interface will make it come
- * up once configured.
- * 
- * @see dhcp_start()
- */ 
-void netif_set_up(struct netif *netif)
-{
-  netif->flags |= NETIF_FLAG_UP;
-#if LWIP_SNMP
-  snmp_get_sysuptime(&netif->ts);
-#endif
-}
-
-/**
- * Ask if an interface is up
- */ 
-u8_t netif_is_up(struct netif *netif)
-{
-  return (netif->flags & NETIF_FLAG_UP)?1:0;
-}
-
-/**
- * Bring an interface down, disabling any traffic processing.
- *
- * @note: Enabling DHCP on a down interface will make it come
- * up once configured.
- * 
- * @see dhcp_start()
- */ 
-void netif_set_down(struct netif *netif)
-{
-  netif->flags &= ~NETIF_FLAG_UP;
-#if LWIP_SNMP
-  snmp_get_sysuptime(&netif->ts);
-#endif
-}
-
-void
-netif_init(void)
-{
-  netif_list = netif_default = NULL;
-}
-
+/**

+ * @file

+ *

+ * lwIP network interface abstraction

+ */

+

+/*

+ * 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/def.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/tcp.h"

+#include "lwip/snmp.h"

+

+struct netif *netif_list = NULL;

+struct netif *netif_default = NULL;

+

+/**

+ * Add a network interface to the list of lwIP netifs.

+ *

+ * @param netif a pre-allocated netif structure

+ * @param ipaddr IP address for the new netif

+ * @param netmask network mask for the new netif

+ * @param gw default gateway IP address for the new netif

+ * @param state opaque data passed to the new netif

+ * @param init callback function that initializes the interface

+ * @param input callback function that is called to pass

+ * ingress packets up in the protocol layer stack.

+ *

+ * @return netif, or NULL if failed.

+ */

+struct netif *

+netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,

+  struct ip_addr *gw,

+  void *state,

+  err_t (* init)(struct netif *netif),

+  err_t (* input)(struct pbuf *p, struct netif *netif))

+{

+  static s16_t netifnum = 0;

+

+  /* reset new interface configuration state */

+  netif->ip_addr.addr = 0;

+  netif->netmask.addr = 0;

+  netif->gw.addr = 0;

+  netif->flags = 0;

+#if LWIP_DHCP

+  /* netif not under DHCP control by default */

+  netif->dhcp = NULL;

+#endif

+  /* remember netif specific state information data */

+  netif->state = state;

+  netif->num = netifnum++;

+  netif->input = input;

+

+  netif_set_addr(netif, ipaddr, netmask, gw);

+

+  /* call user specified initialization function for netif */

+  if (init(netif) != ERR_OK) {

+    return NULL;

+  }

+

+  /* add this netif to the list */

+  netif->next = netif_list;

+  netif_list = netif;

+  snmp_inc_iflist();

+

+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",

+    netif->name[0], netif->name[1]));

+  ip_addr_debug_print(NETIF_DEBUG, ipaddr);

+  LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));

+  ip_addr_debug_print(NETIF_DEBUG, netmask);

+  LWIP_DEBUGF(NETIF_DEBUG, (" gw "));

+  ip_addr_debug_print(NETIF_DEBUG, gw);

+  LWIP_DEBUGF(NETIF_DEBUG, ("\n"));

+  return netif;

+}

+

+void

+netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,

+    struct ip_addr *gw)

+{

+  netif_set_ipaddr(netif, ipaddr);

+  netif_set_netmask(netif, netmask);

+  netif_set_gw(netif, gw);

+}

+

+void netif_remove(struct netif * netif)

+{

+  if ( netif == NULL ) return;

+

+  snmp_delete_ipaddridx_tree(netif);

+

+  /*  is it the first netif? */

+  if (netif_list == netif) {

+    netif_list = netif->next;

+    snmp_dec_iflist();

+  }

+  else {

+    /*  look for netif further down the list */

+    struct netif * tmpNetif;

+    for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {

+      if (tmpNetif->next == netif) {

+        tmpNetif->next = netif->next;

+        snmp_dec_iflist();

+        break;

+      }

+    }

+    if (tmpNetif == NULL)

+      return; /*  we didn't find any netif today */

+  }

+  /* this netif is default? */

+  if (netif_default == netif)

+    /* reset default netif */

+    netif_default = NULL;

+  LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );

+}

+

+struct netif *

+netif_find(char *name)

+{

+  struct netif *netif;

+  u8_t num;

+

+  if (name == NULL) {

+    return NULL;

+  }

+

+  num = name[2] - '0';

+

+  for(netif = netif_list; netif != NULL; netif = netif->next) {

+    if (num == netif->num &&

+       name[0] == netif->name[0] &&

+       name[1] == netif->name[1]) {

+      LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));

+      return netif;

+    }

+  }

+  LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));

+  return NULL;

+}

+

+void

+netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)

+{

+  /* TODO: Handling of obsolete pcbs */

+  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */

+#if LWIP_TCP

+  struct tcp_pcb *pcb;

+  struct tcp_pcb_listen *lpcb;

+

+  /* address is actually being changed? */

+  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)

+  {

+    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */

+    LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));

+    pcb = tcp_active_pcbs;

+    while (pcb != NULL) {

+      /* PCB bound to current local interface address? */

+      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {

+        /* this connection must be aborted */

+        struct tcp_pcb *next = pcb->next;

+        LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));

+        tcp_abort(pcb);

+        pcb = next;

+      } else {

+        pcb = pcb->next;

+      }

+    }

+    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {

+      /* PCB bound to current local interface address? */

+      if (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr))) {

+        /* The PCB is listening to the old ipaddr and

+         * is set to listen to the new one instead */

+        ip_addr_set(&(lpcb->local_ip), ipaddr);

+      }

+    }

+  }

+#endif

+  snmp_delete_ipaddridx_tree(netif);

+  snmp_delete_iprteidx_tree(0,netif);

+  /* set new IP address to netif */

+  ip_addr_set(&(netif->ip_addr), ipaddr);

+  snmp_insert_ipaddridx_tree(netif);

+  snmp_insert_iprteidx_tree(0,netif);

+

+#if 0 /* only allowed for Ethernet interfaces TODO: how can we check? */

+  /** For Ethernet network interfaces, we would like to send a

+   *  "gratuitous ARP"; this is an ARP packet sent by a node in order

+   *  to spontaneously cause other nodes to update an entry in their

+   *  ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.

+   */ 

+  etharp_query(netif, ipaddr, NULL);

+#endif

+  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+    netif->name[0], netif->name[1],

+    ip4_addr1(&netif->ip_addr),

+    ip4_addr2(&netif->ip_addr),

+    ip4_addr3(&netif->ip_addr),

+    ip4_addr4(&netif->ip_addr)));

+}

+

+void

+netif_set_gw(struct netif *netif, struct ip_addr *gw)

+{

+  ip_addr_set(&(netif->gw), gw);

+  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+    netif->name[0], netif->name[1],

+    ip4_addr1(&netif->gw),

+    ip4_addr2(&netif->gw),

+    ip4_addr3(&netif->gw),

+    ip4_addr4(&netif->gw)));

+}

+

+void

+netif_set_netmask(struct netif *netif, struct ip_addr *netmask)

+{

+  snmp_delete_iprteidx_tree(0, netif);

+  /* set new netmask to netif */

+  ip_addr_set(&(netif->netmask), netmask);

+  snmp_insert_iprteidx_tree(0, netif);

+  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+    netif->name[0], netif->name[1],

+    ip4_addr1(&netif->netmask),

+    ip4_addr2(&netif->netmask),

+    ip4_addr3(&netif->netmask),

+    ip4_addr4(&netif->netmask)));

+}

+

+void

+netif_set_default(struct netif *netif)

+{

+  if (netif == NULL)

+  {

+    /* remove default route */

+    snmp_delete_iprteidx_tree(1, netif);

+  }

+  else

+  {

+    /* install default route */

+    snmp_insert_iprteidx_tree(1, netif);

+  }

+  netif_default = netif;

+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",

+           netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));

+}

+

+/**

+ * Bring an interface up, available for processing

+ * traffic.

+ * 

+ * @note: Enabling DHCP on a down interface will make it come

+ * up once configured.

+ * 

+ * @see dhcp_start()

+ */ 

+void netif_set_up(struct netif *netif)

+{

+  netif->flags |= NETIF_FLAG_UP;

+#if LWIP_SNMP

+  snmp_get_sysuptime(&netif->ts);

+#endif

+}

+

+/**

+ * Ask if an interface is up

+ */ 

+u8_t netif_is_up(struct netif *netif)

+{

+  return (netif->flags & NETIF_FLAG_UP)?1:0;

+}

+

+/**

+ * Bring an interface down, disabling any traffic processing.

+ *

+ * @note: Enabling DHCP on a down interface will make it come

+ * up once configured.

+ * 

+ * @see dhcp_start()

+ */ 

+void netif_set_down(struct netif *netif)

+{

+  netif->flags &= ~NETIF_FLAG_UP;

+#if LWIP_SNMP

+  snmp_get_sysuptime(&netif->ts);

+#endif

+}

+

+void

+netif_init(void)

+{

+  netif_list = netif_default = NULL;

+}

+

diff --git a/Demo/Common/ethernet/lwIP/core/pbuf.c b/Demo/Common/ethernet/lwIP/core/pbuf.c
index bca0725..1f6516d 100644
--- a/Demo/Common/ethernet/lwIP/core/pbuf.c
+++ b/Demo/Common/ethernet/lwIP/core/pbuf.c
@@ -1,964 +1,964 @@
-/**
- * @file
- * Packet buffer management
- *
- * Packets are built from the pbuf data structure. It supports dynamic
- * memory allocation for packet contents or can reference externally
- * managed packet contents both in RAM and ROM. Quick allocation for
- * incoming packets is provided through pools with fixed sized pbufs.
- *
- * A packet may span over multiple pbufs, chained as a singly linked
- * list. This is called a "pbuf chain".
- *
- * Multiple packets may be queued, also using this singly linked list.
- * This is called a "packet queue".
- * 
- * So, a packet queue consists of one or more pbuf chains, each of
- * which consist of one or more pbufs. Currently, queues are only
- * supported in a limited section of lwIP, this is the etharp queueing
- * code. Outside of this section no packet queues are supported yet.
- * 
- * The differences between a pbuf chain and a packet queue are very
- * precise but subtle. 
- *
- * The last pbuf of a packet has a ->tot_len field that equals the
- * ->len field. It can be found by traversing the list. If the last
- * pbuf of a packet has a ->next field other than NULL, more packets
- * are on the queue.
- *
- * Therefore, looping through a pbuf of a single packet, has an
- * loop end condition (tot_len == p->len), NOT (next == NULL).
- */
-
-/*
- * 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 <string.h>
-
-#include "lwip/opt.h"
-#include "lwip/stats.h"
-#include "lwip/def.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/pbuf.h"
-#include "lwip/sys.h"
-#include "arch/perf.h"
+/**

+ * @file

+ * Packet buffer management

+ *

+ * Packets are built from the pbuf data structure. It supports dynamic

+ * memory allocation for packet contents or can reference externally

+ * managed packet contents both in RAM and ROM. Quick allocation for

+ * incoming packets is provided through pools with fixed sized pbufs.

+ *

+ * A packet may span over multiple pbufs, chained as a singly linked

+ * list. This is called a "pbuf chain".

+ *

+ * Multiple packets may be queued, also using this singly linked list.

+ * This is called a "packet queue".

+ * 

+ * So, a packet queue consists of one or more pbuf chains, each of

+ * which consist of one or more pbufs. Currently, queues are only

+ * supported in a limited section of lwIP, this is the etharp queueing

+ * code. Outside of this section no packet queues are supported yet.

+ * 

+ * The differences between a pbuf chain and a packet queue are very

+ * precise but subtle. 

+ *

+ * The last pbuf of a packet has a ->tot_len field that equals the

+ * ->len field. It can be found by traversing the list. If the last

+ * pbuf of a packet has a ->next field other than NULL, more packets

+ * are on the queue.

+ *

+ * Therefore, looping through a pbuf of a single packet, has an

+ * loop end condition (tot_len == p->len), NOT (next == NULL).

+ */

 

-static u8_t pbuf_pool_memory[MEM_ALIGNMENT - 1 + PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf))];
-
-#if !SYS_LIGHTWEIGHT_PROT
-static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;
-static sys_sem_t pbuf_pool_free_sem;
-#endif
-
-static struct pbuf *pbuf_pool = NULL;
-
-/**
- * Initializes the pbuf module.
- *
- * A large part of memory is allocated for holding the pool of pbufs.
- * The size of the individual pbufs in the pool is given by the size
- * parameter, and the number of pbufs in the pool by the num parameter.
- *
- * After the memory has been allocated, the pbufs are set up. The
- * ->next pointer in each pbuf is set up to point to the next pbuf in
- * the pool.
- *
- */
-void
-pbuf_init(void)
-{
-  struct pbuf *p, *q = NULL;
-  u16_t i;
-
-  pbuf_pool = (struct pbuf *)MEM_ALIGN(pbuf_pool_memory);
-
-#if PBUF_STATS
-  lwip_stats.pbuf.avail = PBUF_POOL_SIZE;
-#endif /* PBUF_STATS */
-
-  /* Set up ->next pointers to link the pbufs of the pool together */
-  p = pbuf_pool;
-
-  for(i = 0; i < PBUF_POOL_SIZE; ++i) {
-    p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));
-    p->len = p->tot_len = PBUF_POOL_BUFSIZE;
-    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));
-    p->flags = PBUF_FLAG_POOL;
-    q = p;
-    p = p->next;
-  }
-
-  /* The ->next pointer of last pbuf is NULL to indicate that there
-     are no more pbufs in the pool */
-  q->next = NULL;
-
-#if !SYS_LIGHTWEIGHT_PROT
-  pbuf_pool_alloc_lock = 0;
-  pbuf_pool_free_lock = 0;
-  pbuf_pool_free_sem = sys_sem_new(1);
-#endif
-}
-
-/**
- * @internal only called from pbuf_alloc()
- */
-static struct pbuf *
-pbuf_pool_alloc(void)
-{
-  struct pbuf *p = NULL;
-
-  SYS_ARCH_DECL_PROTECT(old_level);
-  SYS_ARCH_PROTECT(old_level);
-
-#if !SYS_LIGHTWEIGHT_PROT
-  /* Next, check the actual pbuf pool, but if the pool is locked, we
-     pretend to be out of buffers and return NULL. */
-  if (pbuf_pool_free_lock) {
-#if PBUF_STATS
-    ++lwip_stats.pbuf.alloc_locked;
-#endif /* PBUF_STATS */
-    return NULL;
-  }
-  pbuf_pool_alloc_lock = 1;
-  if (!pbuf_pool_free_lock) {
-#endif /* SYS_LIGHTWEIGHT_PROT */
-    p = pbuf_pool;
-    if (p) {
-      pbuf_pool = p->next;
-    }
-#if !SYS_LIGHTWEIGHT_PROT
-#if PBUF_STATS
-  } else {
-    ++lwip_stats.pbuf.alloc_locked;
-#endif /* PBUF_STATS */
-  }
-  pbuf_pool_alloc_lock = 0;
-#endif /* SYS_LIGHTWEIGHT_PROT */
-
-#if PBUF_STATS
-  if (p != NULL) {
-    ++lwip_stats.pbuf.used;
-    if (lwip_stats.pbuf.used > lwip_stats.pbuf.max) {
-      lwip_stats.pbuf.max = lwip_stats.pbuf.used;
-    }
-  }
-#endif /* PBUF_STATS */
-
-  SYS_ARCH_UNPROTECT(old_level);
-  return p;
-}
-
-
-/**
- * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
- *
- * The actual memory allocated for the pbuf is determined by the
- * layer at which the pbuf is allocated and the requested size
- * (from the size parameter).
- *
- * @param flag this parameter decides how and where the pbuf
- * should be allocated as follows:
- *
- * - PBUF_RAM: buffer memory for pbuf is allocated as one large
- *             chunk. This includes protocol headers as well.
- * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
- *             protocol headers. Additional headers must be prepended
- *             by allocating another pbuf and chain in to the front of
- *             the ROM pbuf. It is assumed that the memory used is really
- *             similar to ROM in that it is immutable and will not be
- *             changed. Memory which is dynamic should generally not
- *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
- * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
- *             protocol headers. It is assumed that the pbuf is only
- *             being used in a single thread. If the pbuf gets queued,
- *             then pbuf_take should be called to copy the buffer.
- * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
- *              the pbuf pool that is allocated during pbuf_init().
- *
- * @return the allocated pbuf. If multiple pbufs where allocated, this
- * is the first pbuf of a pbuf chain.
- */
-struct pbuf *
-pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
-{
-  struct pbuf *p, *q, *r;
-  u16_t offset;
-  s32_t rem_len; /* remaining length */
-  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));
-
-  /* determine header offset */
-  offset = 0;
-  switch (l) {
-  case PBUF_TRANSPORT:
-    /* add room for transport (often TCP) layer header */
-    offset += PBUF_TRANSPORT_HLEN;
-    /* FALLTHROUGH */
-  case PBUF_IP:
-    /* add room for IP layer header */
-    offset += PBUF_IP_HLEN;
-    /* FALLTHROUGH */
-  case PBUF_LINK:
-    /* add room for link layer header */
-    offset += PBUF_LINK_HLEN;
-    break;
-  case PBUF_RAW:
-    break;
-  default:
-    LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);

-    return NULL;
-  }
-
-  switch (flag) {
-  case PBUF_POOL:
-    /* allocate head of pbuf chain into p */
-    p = pbuf_pool_alloc();
-    LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
-    if (p == NULL) {
-#if PBUF_STATS
-      ++lwip_stats.pbuf.err;
+/*

+ * 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 <string.h>

+

+#include "lwip/opt.h"

+#include "lwip/stats.h"

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+#include "lwip/pbuf.h"

+#include "lwip/sys.h"

+#include "arch/perf.h"

+

+static u8_t pbuf_pool_memory[MEM_ALIGNMENT - 1 + PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf))];

+

+#if !SYS_LIGHTWEIGHT_PROT

+static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;

+static sys_sem_t pbuf_pool_free_sem;

+#endif

+

+static struct pbuf *pbuf_pool = NULL;

+

+/**

+ * Initializes the pbuf module.

+ *

+ * A large part of memory is allocated for holding the pool of pbufs.

+ * The size of the individual pbufs in the pool is given by the size

+ * parameter, and the number of pbufs in the pool by the num parameter.

+ *

+ * After the memory has been allocated, the pbufs are set up. The

+ * ->next pointer in each pbuf is set up to point to the next pbuf in

+ * the pool.

+ *

+ */

+void

+pbuf_init(void)

+{

+  struct pbuf *p, *q = NULL;

+  u16_t i;

+

+  pbuf_pool = (struct pbuf *)MEM_ALIGN(pbuf_pool_memory);

+

+#if PBUF_STATS

+  lwip_stats.pbuf.avail = PBUF_POOL_SIZE;

 #endif /* PBUF_STATS */

-      return NULL;
-    }
-    p->next = NULL;
-
-    /* make the payload pointer point 'offset' bytes into pbuf data memory */
-    p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));
-    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
-            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
-    /* the total length of the pbuf chain is the requested size */
-    p->tot_len = length;
-    /* set the length of the first pbuf in the chain */
-    p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;
-    /* set reference count (needed here in case we fail) */
-    p->ref = 1;
-
-    /* now allocate the tail of the pbuf chain */
-
-    /* remember first pbuf for linkage in next iteration */
-    r = p;
-    /* remaining length to be allocated */
-    rem_len = length - p->len;
-    /* any remaining pbufs to be allocated? */
-    while (rem_len > 0) {
-      q = pbuf_pool_alloc();
-      if (q == NULL) {
-       LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));
-#if PBUF_STATS
-        ++lwip_stats.pbuf.err;
-#endif /* PBUF_STATS */
-        /* free chain so far allocated */
-        pbuf_free(p);
-        /* bail out unsuccesfully */

-        return NULL;
-      }
-      q->next = NULL;
-      /* make previous pbuf point to this pbuf */
-      r->next = q;
-      /* set total length of this pbuf and next in chain */
-      q->tot_len = rem_len;
-      /* this pbuf length is pool size, unless smaller sized tail */
-      q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;
-      q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));
-      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
-              ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
-      q->ref = 1;
-      /* calculate remaining length to be allocated */
-      rem_len -= q->len;
-      /* remember this pbuf for linkage in next iteration */
-      r = q;
-    }
-    /* end of chain */
-    /*r->next = NULL;*/
-
-    break;
-  case PBUF_RAM:
-    /* If pbuf is to be allocated in RAM, allocate memory for it. */
-    p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + offset) + MEM_ALIGN_SIZE(length));
+

+  /* Set up ->next pointers to link the pbufs of the pool together */

+  p = pbuf_pool;

+

+  for(i = 0; i < PBUF_POOL_SIZE; ++i) {

+    p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));

+    p->len = p->tot_len = PBUF_POOL_BUFSIZE;

+    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));

+    p->flags = PBUF_FLAG_POOL;

+    q = p;

+    p = p->next;

+  }

+

+  /* The ->next pointer of last pbuf is NULL to indicate that there

+     are no more pbufs in the pool */

+  q->next = NULL;

+

+#if !SYS_LIGHTWEIGHT_PROT

+  pbuf_pool_alloc_lock = 0;

+  pbuf_pool_free_lock = 0;

+  pbuf_pool_free_sem = sys_sem_new(1);

+#endif

+}

+

+/**

+ * @internal only called from pbuf_alloc()

+ */

+static struct pbuf *

+pbuf_pool_alloc(void)

+{

+  struct pbuf *p = NULL;

+

+  SYS_ARCH_DECL_PROTECT(old_level);

+  SYS_ARCH_PROTECT(old_level);

+

+#if !SYS_LIGHTWEIGHT_PROT

+  /* Next, check the actual pbuf pool, but if the pool is locked, we

+     pretend to be out of buffers and return NULL. */

+  if (pbuf_pool_free_lock) {

+#if PBUF_STATS

+    ++lwip_stats.pbuf.alloc_locked;

+#endif /* PBUF_STATS */

+    return NULL;

+  }

+  pbuf_pool_alloc_lock = 1;

+  if (!pbuf_pool_free_lock) {

+#endif /* SYS_LIGHTWEIGHT_PROT */

+    p = pbuf_pool;

+    if (p) {

+      pbuf_pool = p->next;

+    }

+#if !SYS_LIGHTWEIGHT_PROT

+#if PBUF_STATS

+  } else {

+    ++lwip_stats.pbuf.alloc_locked;

+#endif /* PBUF_STATS */

+  }

+  pbuf_pool_alloc_lock = 0;

+#endif /* SYS_LIGHTWEIGHT_PROT */

+

+#if PBUF_STATS

+  if (p != NULL) {

+    ++lwip_stats.pbuf.used;

+    if (lwip_stats.pbuf.used > lwip_stats.pbuf.max) {

+      lwip_stats.pbuf.max = lwip_stats.pbuf.used;

+    }

+  }

+#endif /* PBUF_STATS */

+

+  SYS_ARCH_UNPROTECT(old_level);

+  return p;

+}

+

+

+/**

+ * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).

+ *

+ * The actual memory allocated for the pbuf is determined by the

+ * layer at which the pbuf is allocated and the requested size

+ * (from the size parameter).

+ *

+ * @param flag this parameter decides how and where the pbuf

+ * should be allocated as follows:

+ *

+ * - PBUF_RAM: buffer memory for pbuf is allocated as one large

+ *             chunk. This includes protocol headers as well.

+ * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for

+ *             protocol headers. Additional headers must be prepended

+ *             by allocating another pbuf and chain in to the front of

+ *             the ROM pbuf. It is assumed that the memory used is really

+ *             similar to ROM in that it is immutable and will not be

+ *             changed. Memory which is dynamic should generally not

+ *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.

+ * - PBUF_REF: no buffer memory is allocated for the pbuf, even for

+ *             protocol headers. It is assumed that the pbuf is only

+ *             being used in a single thread. If the pbuf gets queued,

+ *             then pbuf_take should be called to copy the buffer.

+ * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from

+ *              the pbuf pool that is allocated during pbuf_init().

+ *

+ * @return the allocated pbuf. If multiple pbufs where allocated, this

+ * is the first pbuf of a pbuf chain.

+ */

+struct pbuf *

+pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)

+{

+  struct pbuf *p, *q, *r;

+  u16_t offset;

+  s32_t rem_len; /* remaining length */

+  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));

+

+  /* determine header offset */

+  offset = 0;

+  switch (l) {

+  case PBUF_TRANSPORT:

+    /* add room for transport (often TCP) layer header */

+    offset += PBUF_TRANSPORT_HLEN;

+    /* FALLTHROUGH */

+  case PBUF_IP:

+    /* add room for IP layer header */

+    offset += PBUF_IP_HLEN;

+    /* FALLTHROUGH */

+  case PBUF_LINK:

+    /* add room for link layer header */

+    offset += PBUF_LINK_HLEN;

+    break;

+  case PBUF_RAW:

+    break;

+  default:

+    LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);

+    return NULL;

+  }

+

+  switch (flag) {

+  case PBUF_POOL:

+    /* allocate head of pbuf chain into p */

+    p = pbuf_pool_alloc();

+    LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));

     if (p == NULL) {

-      return NULL;
-    }
-    /* Set up internal structure of the pbuf. */
-    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));
-    p->len = p->tot_len = length;
-    p->next = NULL;
-    p->flags = PBUF_FLAG_RAM;
-
-    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
-           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
-    break;
-  /* pbuf references existing (non-volatile static constant) ROM payload? */
-  case PBUF_ROM:
-  /* pbuf references existing (externally allocated) RAM payload? */
-  case PBUF_REF:
-    /* only allocate memory for the pbuf structure */
-    p = memp_malloc(MEMP_PBUF);
-    if (p == NULL) {
+#if PBUF_STATS

+      ++lwip_stats.pbuf.err;

+#endif /* PBUF_STATS */

+      return NULL;

+    }

+    p->next = NULL;

+

+    /* make the payload pointer point 'offset' bytes into pbuf data memory */

+    p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));

+    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",

+            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);

+    /* the total length of the pbuf chain is the requested size */

+    p->tot_len = length;

+    /* set the length of the first pbuf in the chain */

+    p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;

+    /* set reference count (needed here in case we fail) */

+    p->ref = 1;

+

+    /* now allocate the tail of the pbuf chain */

+

+    /* remember first pbuf for linkage in next iteration */

+    r = p;

+    /* remaining length to be allocated */

+    rem_len = length - p->len;

+    /* any remaining pbufs to be allocated? */

+    while (rem_len > 0) {

+      q = pbuf_pool_alloc();

+      if (q == NULL) {

+       LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));

+#if PBUF_STATS

+        ++lwip_stats.pbuf.err;

+#endif /* PBUF_STATS */

+        /* free chain so far allocated */

+        pbuf_free(p);

+        /* bail out unsuccesfully */

+        return NULL;

+      }

+      q->next = NULL;

+      /* make previous pbuf point to this pbuf */

+      r->next = q;

+      /* set total length of this pbuf and next in chain */

+      q->tot_len = rem_len;

+      /* this pbuf length is pool size, unless smaller sized tail */

+      q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;

+      q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));

+      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",

+              ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);

+      q->ref = 1;

+      /* calculate remaining length to be allocated */

+      rem_len -= q->len;

+      /* remember this pbuf for linkage in next iteration */

+      r = q;

+    }

+    /* end of chain */

+    /*r->next = NULL;*/

+

+    break;

+  case PBUF_RAM:

+    /* If pbuf is to be allocated in RAM, allocate memory for it. */

+    p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + offset) + MEM_ALIGN_SIZE(length));

+    if (p == NULL) {

+      return NULL;

+    }

+    /* Set up internal structure of the pbuf. */

+    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));

+    p->len = p->tot_len = length;

+    p->next = NULL;

+    p->flags = PBUF_FLAG_RAM;

+

+    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",

+           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);

+    break;

+  /* pbuf references existing (non-volatile static constant) ROM payload? */

+  case PBUF_ROM:

+  /* pbuf references existing (externally allocated) RAM payload? */

+  case PBUF_REF:

+    /* only allocate memory for the pbuf structure */

+    p = memp_malloc(MEMP_PBUF);

+    if (p == NULL) {

       LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", flag == PBUF_ROM?"ROM":"REF"));

-
-      return NULL;
-    }
-    /* caller must set this field properly, afterwards */
-    p->payload = NULL;
-    p->len = p->tot_len = length;
-    p->next = NULL;
-    p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);
-    break;
-  default:
+

+      return NULL;

+    }

+    /* caller must set this field properly, afterwards */

+    p->payload = NULL;

+    p->len = p->tot_len = length;

+    p->next = NULL;

+    p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);

+    break;

+  default:

     LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);

-    return NULL;
-  }
-  /* set reference count */
-  p->ref = 1;
+    return NULL;

+  }

+  /* set reference count */

+  p->ref = 1;

   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));

-  return p;
-}
-
-
-#if PBUF_STATS
-#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)
-#else /* PBUF_STATS */
-#define DEC_PBUF_STATS
-#endif /* PBUF_STATS */
-
-#define PBUF_POOL_FAST_FREE(p)  do {                                    \
-                                  p->next = pbuf_pool;                  \
-                                  pbuf_pool = p;                        \
-                                  DEC_PBUF_STATS;                       \
-                                } while (0)
-
-#if SYS_LIGHTWEIGHT_PROT
-#define PBUF_POOL_FREE(p)  do {                                         \
-                                SYS_ARCH_DECL_PROTECT(old_level);       \
-                                SYS_ARCH_PROTECT(old_level);            \
-                                PBUF_POOL_FAST_FREE(p);                 \
-                                SYS_ARCH_UNPROTECT(old_level);          \
-                               } while (0)
-#else /* SYS_LIGHTWEIGHT_PROT */
-#define PBUF_POOL_FREE(p)  do {                                         \
-                             sys_sem_wait(pbuf_pool_free_sem);          \
-                             PBUF_POOL_FAST_FREE(p);                    \
-                             sys_sem_signal(pbuf_pool_free_sem);        \
-                           } while (0)
-#endif /* SYS_LIGHTWEIGHT_PROT */
-
-/**
- * Shrink a pbuf chain to a desired length.
- *
- * @param p pbuf to shrink.
- * @param new_len desired new length of pbuf chain
- *
- * Depending on the desired length, the first few pbufs in a chain might
- * be skipped and left unchanged. The new last pbuf in the chain will be
- * resized, and any remaining pbufs will be freed.
- *
- * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
- * @note May not be called on a packet queue.
- *
- * @bug Cannot grow the size of a pbuf (chain) (yet).
- */
-void
-pbuf_realloc(struct pbuf *p, u16_t new_len)
-{
-  struct pbuf *q;
-  u16_t rem_len; /* remaining length */
-  s16_t grow;
-
-  LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||
-              p->flags == PBUF_FLAG_ROM ||
-              p->flags == PBUF_FLAG_RAM ||
-              p->flags == PBUF_FLAG_REF);
-
-  /* desired length larger than current length? */
-  if (new_len >= p->tot_len) {
-    /* enlarging not yet supported */
-    return;
-  }
-
-  /* the pbuf chain grows by (new_len - p->tot_len) bytes
-   * (which may be negative in case of shrinking) */
-  grow = new_len - p->tot_len;
-
-  /* first, step over any pbufs that should remain in the chain */
-  rem_len = new_len;
-  q = p;
-  /* should this pbuf be kept? */
-  while (rem_len > q->len) {
-    /* decrease remaining length by pbuf length */
-    rem_len -= q->len;
-    /* decrease total length indicator */
-    q->tot_len += grow;
-    /* proceed to next pbuf in chain */
-    q = q->next;
-  }
-  /* we have now reached the new last pbuf (in q) */
-  /* rem_len == desired length for pbuf q */
-
-  /* shrink allocated memory for PBUF_RAM */
-  /* (other types merely adjust their length fields */
-  if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {
-    /* reallocate and adjust the length of the pbuf that will be split */
-    mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
-  }
-  /* adjust length fields for new last pbuf */
-  q->len = rem_len;
-  q->tot_len = q->len;
-
-  /* any remaining pbufs in chain? */
-  if (q->next != NULL) {
-    /* free remaining pbufs in chain */
-    pbuf_free(q->next);
-  }
-  /* q is last packet in chain */
-  q->next = NULL;
-
-}
-
-/**
- * Adjusts the payload pointer to hide or reveal headers in the payload.
- *
- * Adjusts the ->payload pointer so that space for a header
- * (dis)appears in the pbuf payload.
- *
- * The ->payload, ->tot_len and ->len fields are adjusted.
- *
- * @param hdr_size_inc Number of bytes to increment header size which
- * increases the size of the pbuf. New space is on the front.
- * (Using a negative value decreases the header size.)
- * If hdr_size_inc is 0, this function does nothing and returns succesful.
- *
- * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
- * the call will fail. A check is made that the increase in header size does
- * not move the payload pointer in front of the start of the buffer.
- * @return non-zero on failure, zero on success.
- *
- */
-u8_t
-pbuf_header(struct pbuf *p, s16_t header_size_increment)
-{
-  u16_t flags;
-  void *payload;
-
-  LWIP_ASSERT("p != NULL", p != NULL);
-  if ((header_size_increment == 0) || (p == NULL)) return 0;
- 
-  flags = p->flags;
-  /* remember current payload pointer */
-  payload = p->payload;
-
-  /* pbuf types containing payloads? */
-  if (flags == PBUF_FLAG_RAM || flags == PBUF_FLAG_POOL) {
-    /* set new payload pointer */
-    p->payload = (u8_t *)p->payload - header_size_increment;
-    /* boundary check fails? */
-    if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {
-      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
-        (void *)p->payload,
-        (void *)(p + 1)));\
-      /* restore old payload pointer */
-      p->payload = payload;
-      /* bail out unsuccesfully */
-      return 1;
-    }
-  /* pbuf types refering to external payloads? */
-  } else if (flags == PBUF_FLAG_REF || flags == PBUF_FLAG_ROM) {
-    /* hide a header in the payload? */
-    if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) {
-      /* increase payload pointer */
-      p->payload = (u8_t *)p->payload - header_size_increment;
-    } else {
-      /* cannot expand payload to front (yet!)
-       * bail out unsuccesfully */
-      return 1;
-    }
-  }
-  /* modify pbuf length fields */
-  p->len += header_size_increment;
-  p->tot_len += header_size_increment;
-
-  LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",
-    (void *)payload, (void *)p->payload, header_size_increment));
-
-  return 0;
-}
-
-/**
- * Dereference a pbuf chain or queue and deallocate any no-longer-used
- * pbufs at the head of this chain or queue.
- *
- * Decrements the pbuf reference count. If it reaches zero, the pbuf is
- * deallocated.
- *
- * For a pbuf chain, this is repeated for each pbuf in the chain,
- * up to the first pbuf which has a non-zero reference count after
- * decrementing. So, when all reference counts are one, the whole
- * chain is free'd.
- *
- * @param pbuf The pbuf (chain) to be dereferenced.
- *
- * @return the number of pbufs that were de-allocated
- * from the head of the chain.
- *
- * @note MUST NOT be called on a packet queue (Not verified to work yet).
- * @note the reference counter of a pbuf equals the number of pointers
- * that refer to the pbuf (or into the pbuf).
- *
- * @internal examples:
- *
- * Assuming existing chains a->b->c with the following reference
- * counts, calling pbuf_free(a) results in:
- * 
- * 1->2->3 becomes ...1->3
- * 3->3->3 becomes 2->3->3
- * 1->1->2 becomes ......1
- * 2->1->1 becomes 1->1->1
- * 1->1->1 becomes .......
- *
- */
-u8_t
-pbuf_free(struct pbuf *p)
-{
-  u16_t flags;
-  struct pbuf *q;
-  u8_t count;
-  SYS_ARCH_DECL_PROTECT(old_level);
-
+  return p;

+}

+

+

+#if PBUF_STATS

+#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)

+#else /* PBUF_STATS */

+#define DEC_PBUF_STATS

+#endif /* PBUF_STATS */

+

+#define PBUF_POOL_FAST_FREE(p)  do {                                    \

+                                  p->next = pbuf_pool;                  \

+                                  pbuf_pool = p;                        \

+                                  DEC_PBUF_STATS;                       \

+                                } while (0)

+

+#if SYS_LIGHTWEIGHT_PROT

+#define PBUF_POOL_FREE(p)  do {                                         \

+                                SYS_ARCH_DECL_PROTECT(old_level);       \

+                                SYS_ARCH_PROTECT(old_level);            \

+                                PBUF_POOL_FAST_FREE(p);                 \

+                                SYS_ARCH_UNPROTECT(old_level);          \

+                               } while (0)

+#else /* SYS_LIGHTWEIGHT_PROT */

+#define PBUF_POOL_FREE(p)  do {                                         \

+                             sys_sem_wait(pbuf_pool_free_sem);          \

+                             PBUF_POOL_FAST_FREE(p);                    \

+                             sys_sem_signal(pbuf_pool_free_sem);        \

+                           } while (0)

+#endif /* SYS_LIGHTWEIGHT_PROT */

+

+/**

+ * Shrink a pbuf chain to a desired length.

+ *

+ * @param p pbuf to shrink.

+ * @param new_len desired new length of pbuf chain

+ *

+ * Depending on the desired length, the first few pbufs in a chain might

+ * be skipped and left unchanged. The new last pbuf in the chain will be

+ * resized, and any remaining pbufs will be freed.

+ *

+ * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.

+ * @note May not be called on a packet queue.

+ *

+ * @bug Cannot grow the size of a pbuf (chain) (yet).

+ */

+void

+pbuf_realloc(struct pbuf *p, u16_t new_len)

+{

+  struct pbuf *q;

+  u16_t rem_len; /* remaining length */

+  s16_t grow;

+

+  LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||

+              p->flags == PBUF_FLAG_ROM ||

+              p->flags == PBUF_FLAG_RAM ||

+              p->flags == PBUF_FLAG_REF);

+

+  /* desired length larger than current length? */

+  if (new_len >= p->tot_len) {

+    /* enlarging not yet supported */

+    return;

+  }

+

+  /* the pbuf chain grows by (new_len - p->tot_len) bytes

+   * (which may be negative in case of shrinking) */

+  grow = new_len - p->tot_len;

+

+  /* first, step over any pbufs that should remain in the chain */

+  rem_len = new_len;

+  q = p;

+  /* should this pbuf be kept? */

+  while (rem_len > q->len) {

+    /* decrease remaining length by pbuf length */

+    rem_len -= q->len;

+    /* decrease total length indicator */

+    q->tot_len += grow;

+    /* proceed to next pbuf in chain */

+    q = q->next;

+  }

+  /* we have now reached the new last pbuf (in q) */

+  /* rem_len == desired length for pbuf q */

+

+  /* shrink allocated memory for PBUF_RAM */

+  /* (other types merely adjust their length fields */

+  if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {

+    /* reallocate and adjust the length of the pbuf that will be split */

+    mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);

+  }

+  /* adjust length fields for new last pbuf */

+  q->len = rem_len;

+  q->tot_len = q->len;

+

+  /* any remaining pbufs in chain? */

+  if (q->next != NULL) {

+    /* free remaining pbufs in chain */

+    pbuf_free(q->next);

+  }

+  /* q is last packet in chain */

+  q->next = NULL;

+

+}

+

+/**

+ * Adjusts the payload pointer to hide or reveal headers in the payload.

+ *

+ * Adjusts the ->payload pointer so that space for a header

+ * (dis)appears in the pbuf payload.

+ *

+ * The ->payload, ->tot_len and ->len fields are adjusted.

+ *

+ * @param hdr_size_inc Number of bytes to increment header size which

+ * increases the size of the pbuf. New space is on the front.

+ * (Using a negative value decreases the header size.)

+ * If hdr_size_inc is 0, this function does nothing and returns succesful.

+ *

+ * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so

+ * the call will fail. A check is made that the increase in header size does

+ * not move the payload pointer in front of the start of the buffer.

+ * @return non-zero on failure, zero on success.

+ *

+ */

+u8_t

+pbuf_header(struct pbuf *p, s16_t header_size_increment)

+{

+  u16_t flags;

+  void *payload;

+

   LWIP_ASSERT("p != NULL", p != NULL);

-
-  /* if assertions are disabled, proceed with debug output */
-  if (p == NULL) {
-    LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
-    return 0;
-  }
-  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));
-
-  PERF_START;
-
-  LWIP_ASSERT("pbuf_free: sane flags",
-    p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM ||
-    p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL);
-
-  count = 0;
-  /* Since decrementing ref cannot be guaranteed to be a single machine operation
-   * we must protect it. Also, the later test of ref must be protected.
-   */
-  SYS_ARCH_PROTECT(old_level);
-  /* de-allocate all consecutive pbufs from the head of the chain that
-   * obtain a zero reference count after decrementing*/
-  while (p != NULL) {
-    /* all pbufs in a chain are referenced at least once */
-    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
-    /* decrease reference count (number of pointers to pbuf) */
-    p->ref--;
-    /* this pbuf is no longer referenced to? */
-    if (p->ref == 0) {
-      /* remember next pbuf in chain for next iteration */
-      q = p->next;
-      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));
-      flags = p->flags;
-      /* is this a pbuf from the pool? */
-      if (flags == PBUF_FLAG_POOL) {
-        p->len = p->tot_len = PBUF_POOL_BUFSIZE;
-        p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));
-        PBUF_POOL_FREE(p);
-      /* is this a ROM or RAM referencing pbuf? */
-      } else if (flags == PBUF_FLAG_ROM || flags == PBUF_FLAG_REF) {
-        memp_free(MEMP_PBUF, p);
-      /* flags == PBUF_FLAG_RAM */
-      } else {
-        mem_free(p);
-      }
-      count++;
-      /* proceed to next pbuf */
-      p = q;
-    /* p->ref > 0, this pbuf is still referenced to */
-    /* (and so the remaining pbufs in chain as well) */
-    } else {
-      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)p->ref));
-      /* stop walking through the chain */
-      p = NULL;
-    }
-  }
-  SYS_ARCH_UNPROTECT(old_level);
-  PERF_STOP("pbuf_free");
+  if ((header_size_increment == 0) || (p == NULL)) return 0;

+ 

+  flags = p->flags;

+  /* remember current payload pointer */

+  payload = p->payload;

+

+  /* pbuf types containing payloads? */

+  if (flags == PBUF_FLAG_RAM || flags == PBUF_FLAG_POOL) {

+    /* set new payload pointer */

+    p->payload = (u8_t *)p->payload - header_size_increment;

+    /* boundary check fails? */

+    if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {

+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",

+        (void *)p->payload,

+        (void *)(p + 1)));\

+      /* restore old payload pointer */

+      p->payload = payload;

+      /* bail out unsuccesfully */

+      return 1;

+    }

+  /* pbuf types refering to external payloads? */

+  } else if (flags == PBUF_FLAG_REF || flags == PBUF_FLAG_ROM) {

+    /* hide a header in the payload? */

+    if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) {

+      /* increase payload pointer */

+      p->payload = (u8_t *)p->payload - header_size_increment;

+    } else {

+      /* cannot expand payload to front (yet!)

+       * bail out unsuccesfully */

+      return 1;

+    }

+  }

+  /* modify pbuf length fields */

+  p->len += header_size_increment;

+  p->tot_len += header_size_increment;

+

+  LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",

+    (void *)payload, (void *)p->payload, header_size_increment));

+

+  return 0;

+}

+

+/**

+ * Dereference a pbuf chain or queue and deallocate any no-longer-used

+ * pbufs at the head of this chain or queue.

+ *

+ * Decrements the pbuf reference count. If it reaches zero, the pbuf is

+ * deallocated.

+ *

+ * For a pbuf chain, this is repeated for each pbuf in the chain,

+ * up to the first pbuf which has a non-zero reference count after

+ * decrementing. So, when all reference counts are one, the whole

+ * chain is free'd.

+ *

+ * @param pbuf The pbuf (chain) to be dereferenced.

+ *

+ * @return the number of pbufs that were de-allocated

+ * from the head of the chain.

+ *

+ * @note MUST NOT be called on a packet queue (Not verified to work yet).

+ * @note the reference counter of a pbuf equals the number of pointers

+ * that refer to the pbuf (or into the pbuf).

+ *

+ * @internal examples:

+ *

+ * Assuming existing chains a->b->c with the following reference

+ * counts, calling pbuf_free(a) results in:

+ * 

+ * 1->2->3 becomes ...1->3

+ * 3->3->3 becomes 2->3->3

+ * 1->1->2 becomes ......1

+ * 2->1->1 becomes 1->1->1

+ * 1->1->1 becomes .......

+ *

+ */

+u8_t

+pbuf_free(struct pbuf *p)

+{

+  u16_t flags;

+  struct pbuf *q;

+  u8_t count;

+  SYS_ARCH_DECL_PROTECT(old_level);

+

+  LWIP_ASSERT("p != NULL", p != NULL);

+

+  /* if assertions are disabled, proceed with debug output */

+  if (p == NULL) {

+    LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));

+    return 0;

+  }

+  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));

+

+  PERF_START;

+

+  LWIP_ASSERT("pbuf_free: sane flags",

+    p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM ||

+    p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL);

+

+  count = 0;

+  /* Since decrementing ref cannot be guaranteed to be a single machine operation

+   * we must protect it. Also, the later test of ref must be protected.

+   */

+  SYS_ARCH_PROTECT(old_level);

+  /* de-allocate all consecutive pbufs from the head of the chain that

+   * obtain a zero reference count after decrementing*/

+  while (p != NULL) {

+    /* all pbufs in a chain are referenced at least once */

+    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);

+    /* decrease reference count (number of pointers to pbuf) */

+    p->ref--;

+    /* this pbuf is no longer referenced to? */

+    if (p->ref == 0) {

+      /* remember next pbuf in chain for next iteration */

+      q = p->next;

+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));

+      flags = p->flags;

+      /* is this a pbuf from the pool? */

+      if (flags == PBUF_FLAG_POOL) {

+        p->len = p->tot_len = PBUF_POOL_BUFSIZE;

+        p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));

+        PBUF_POOL_FREE(p);

+      /* is this a ROM or RAM referencing pbuf? */

+      } else if (flags == PBUF_FLAG_ROM || flags == PBUF_FLAG_REF) {

+        memp_free(MEMP_PBUF, p);

+      /* flags == PBUF_FLAG_RAM */

+      } else {

+        mem_free(p);

+      }

+      count++;

+      /* proceed to next pbuf */

+      p = q;

+    /* p->ref > 0, this pbuf is still referenced to */

+    /* (and so the remaining pbufs in chain as well) */

+    } else {

+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)p->ref));

+      /* stop walking through the chain */

+      p = NULL;

+    }

+  }

+  SYS_ARCH_UNPROTECT(old_level);

+  PERF_STOP("pbuf_free");

   /* return number of de-allocated pbufs */

 

-  return count;
-}
-
-/**
- * Count number of pbufs in a chain
- *
- * @param p first pbuf of chain
- * @return the number of pbufs in a chain
- */
-
-u8_t
-pbuf_clen(struct pbuf *p)
-{
-  u8_t len;
-
-  len = 0;
-  while (p != NULL) {
-    ++len;
-    p = p->next;
-  }
-  return len;
-}
-
-/**
- * Increment the reference count of the pbuf.
- *
- * @param p pbuf to increase reference counter of
- *
- */
-void
-pbuf_ref(struct pbuf *p)
-{
-  SYS_ARCH_DECL_PROTECT(old_level);
-  /* pbuf given? */
-  if (p != NULL) {
-    SYS_ARCH_PROTECT(old_level);
-    ++(p->ref);
-    SYS_ARCH_UNPROTECT(old_level);
-  }
-}
-
-/**
- * Concatenate two pbufs (each may be a pbuf chain) and take over
- * the caller's reference of the tail pbuf.
- * 
- * @note The caller MAY NOT reference the tail pbuf afterwards.
- * Use pbuf_chain() for that purpose.
- * 
- * @see pbuf_chain()
- */
-
-void
-pbuf_cat(struct pbuf *h, struct pbuf *t)
-{
-  struct pbuf *p;
-
-  LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);
-  LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL);
-  if ((h == NULL) || (t == NULL)) return;
-
-  /* proceed to last pbuf of chain */
-  for (p = h; p->next != NULL; p = p->next) {
-    /* add total length of second chain to all totals of first chain */
-    p->tot_len += t->tot_len;
-  }
-  /* { p is last pbuf of first h chain, p->next == NULL } */
-  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
-  LWIP_ASSERT("p->next == NULL", p->next == NULL);
-  /* add total length of second chain to last pbuf total of first chain */
-  p->tot_len += t->tot_len;
-  /* chain last pbuf of head (p) with first of tail (t) */
-  p->next = t;
-  /* p->next now references t, but the caller will drop its reference to t,
-   * so netto there is no change to the reference count of t.
-   */
-}
-
-/**
- * Chain two pbufs (or pbuf chains) together.
- * 
- * The caller MUST call pbuf_free(t) once it has stopped
- * using it. Use pbuf_cat() instead if you no longer use t.
- * 
- * @param h head pbuf (chain)
- * @param t tail pbuf (chain)
- * @note The pbufs MUST belong to the same packet.
- * @note MAY NOT be called on a packet queue.
- *
- * The ->tot_len fields of all pbufs of the head chain are adjusted.
- * The ->next field of the last pbuf of the head chain is adjusted.
- * The ->ref field of the first pbuf of the tail chain is adjusted.
- *
- */
-void
-pbuf_chain(struct pbuf *h, struct pbuf *t)
-{
-  pbuf_cat(h, t);
-  /* t is now referenced by h */
-  pbuf_ref(t);
-  LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
-}
-
-/* For packet queueing. Note that queued packets MUST be dequeued first
- * using pbuf_dequeue() before calling other pbuf_() functions. */
-#if ARP_QUEUEING
-/**
- * Add a packet to the end of a queue.
- *
- * @param q pointer to first packet on the queue
- * @param n packet to be queued
- *
- * Both packets MUST be given, and must be different.
- */
-void
-pbuf_queue(struct pbuf *p, struct pbuf *n)
-{
-#if PBUF_DEBUG /* remember head of queue */
-  struct pbuf *q = p;
-#endif
-  /* programmer stupidity checks */
-  LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);
-  LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);
-  LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);
-  if ((p == NULL) || (n == NULL) || (p == n)){
-    LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"));
-    return;
-  }
-
-  /* iterate through all packets on queue */
-  while (p->next != NULL) {
-/* be very picky about pbuf chain correctness */
-#if PBUF_DEBUG
-    /* iterate through all pbufs in packet */
-    while (p->tot_len != p->len) {
-      /* make sure invariant condition holds */
-      LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);
-      /* make sure each packet is complete */
-      LWIP_ASSERT("p->next != NULL", p->next != NULL);
-      p = p->next;
-      /* { p->tot_len == p->len => p is last pbuf of a packet } */
-    }
-    /* { p is last pbuf of a packet } */
-    /* proceed to next packet on queue */
-#endif
-    /* proceed to next pbuf */
-    if (p->next != NULL) p = p->next;
-  }
-  /* { p->tot_len == p->len and p->next == NULL } ==>
-   * { p is last pbuf of last packet on queue } */
-  /* chain last pbuf of queue with n */
-  p->next = n;
-  /* n is now referenced to by the (packet p in the) queue */
-  pbuf_ref(n);
-#if PBUF_DEBUG
-  LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2,
-    ("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n",
-    (void *)n, (void *)p, (void *)q));
-#endif
-}
-
-/**
- * Remove a packet from the head of a queue.
- *
- * The caller MUST reference the remainder of the queue (as returned). The
- * caller MUST NOT call pbuf_ref() as it implicitly takes over the reference
- * from p.
- * 
- * @param p pointer to first packet on the queue which will be dequeued.
- * @return first packet on the remaining queue (NULL if no further packets).
- *
- */
-struct pbuf *
-pbuf_dequeue(struct pbuf *p)
-{
-  struct pbuf *q;
-  LWIP_ASSERT("p != NULL", p != NULL);
-
-  /* iterate through all pbufs in packet p */
-  while (p->tot_len != p->len) {
-    /* make sure invariant condition holds */
-    LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);
-    /* make sure each packet is complete */
-    LWIP_ASSERT("p->next != NULL", p->next != NULL);
-    p = p->next;
-  }
-  /* { p->tot_len == p->len } => p is the last pbuf of the first packet */
-  /* remember next packet on queue in q */
-  q = p->next;
-  /* dequeue packet p from queue */
-  p->next = NULL;
-  /* any next packet on queue? */
-  if (q != NULL) {
-    /* although q is no longer referenced by p, it MUST be referenced by
-     * the caller, who is maintaining this packet queue. So, we do not call
-     * pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */
-    LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q));
-  } else {
-    LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n"));
-  }
-  return q;
-}
-#endif
-
-/**
- *
- * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.
- *
- * Used to queue packets on behalf of the lwIP stack, such as
- * ARP based queueing.
- *
- * Go through a pbuf chain and replace any PBUF_REF buffers
- * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of
- * the referenced data.
- *
- * @note You MUST explicitly use p = pbuf_take(p);
- * The pbuf you give as argument, may have been replaced
- * by a (differently located) copy through pbuf_take()!
- *
- * @note Any replaced pbufs will be freed through pbuf_free().
- * This may deallocate them if they become no longer referenced.
- *
- * @param p Head of pbuf chain to process
- *
- * @return Pointer to head of pbuf chain
- */
-struct pbuf *
-pbuf_take(struct pbuf *p)
-{
-  struct pbuf *q , *prev, *head;
-  LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);
-  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));
-
-  prev = NULL;
-  head = p;
-  /* iterate through pbuf chain */
-  do
-  {
-    /* pbuf is of type PBUF_REF? */
-    if (p->flags == PBUF_FLAG_REF) {
-      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));
-      /* allocate a pbuf (w/ payload) fully in RAM */
-      /* PBUF_POOL buffers are faster if we can use them */
-      if (p->len <= PBUF_POOL_BUFSIZE) {
-        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
-        if (q == NULL) {
-          LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
-        }
-      } else {
-        /* no replacement pbuf yet */
-        q = NULL;
-        LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));
-      }
-      /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */
-      if (q == NULL) {
-        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
-        if (q == NULL) {
-          LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));
-        }
-      }
-      /* replacement pbuf could be allocated? */
-      if (q != NULL)
-      {
-        /* copy p to q */
-        /* copy successor */
-        q->next = p->next;
-        /* remove linkage from original pbuf */
-        p->next = NULL;
-        /* remove linkage to original pbuf */
-        if (prev != NULL) {
-          /* prev->next == p at this point */
-          LWIP_ASSERT("prev->next == p", prev->next == p);
-          /* break chain and insert new pbuf instead */
-          prev->next = q;
-        /* prev == NULL, so we replaced the head pbuf of the chain */
-        } else {
-          head = q;
-        }
-        /* copy pbuf payload */
-        memcpy(q->payload, p->payload, p->len);
-        q->tot_len = p->tot_len;
-        q->len = p->len;
-        /* in case p was the first pbuf, it is no longer refered to by
-         * our caller, as the caller MUST do p = pbuf_take(p);
-         * in case p was not the first pbuf, it is no longer refered to
-         * by prev. we can safely free the pbuf here.
-         * (note that we have set p->next to NULL already so that
-         * we will not free the rest of the chain by accident.)
-         */
-        pbuf_free(p);
-        /* do not copy ref, since someone else might be using the old buffer */
-        LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));
-        p = q;
-      } else {
-        /* deallocate chain */
-        pbuf_free(head);
-        LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));
-        return NULL;
-      }
-    /* p->flags != PBUF_FLAG_REF */
-    } else {
-      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));
-    }
-    /* remember this pbuf */
-    prev = p;
-    /* proceed to next pbuf in original chain */
-    p = p->next;
-  } while (p);
-  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));
-
-  return head;
-}
-
-/**
- * Dechains the first pbuf from its succeeding pbufs in the chain.
- *
- * Makes p->tot_len field equal to p->len.
- * @param p pbuf to dechain
- * @return remainder of the pbuf chain, or NULL if it was de-allocated.
- * @note May not be called on a packet queue.
- */
-struct pbuf *
-pbuf_dechain(struct pbuf *p)
-{
-  struct pbuf *q;
-  u8_t tail_gone = 1;
-  /* tail */
-  q = p->next;
-  /* pbuf has successor in chain? */
-  if (q != NULL) {
-    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
-    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
-    /* enforce invariant if assertion is disabled */
-    q->tot_len = p->tot_len - p->len;
-    /* decouple pbuf from remainder */
-    p->next = NULL;
-    /* total length of pbuf p is its own length only */
-    p->tot_len = p->len;
-    /* q is no longer referenced by p, free it */
-    LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
-    tail_gone = pbuf_free(q);
-    if (tail_gone > 0) {
-      LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE,
-                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
-    }
-    /* return remaining tail or NULL if deallocated */
-  }
-  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
-  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
-  return (tail_gone > 0? NULL: q);
-}
+  return count;

+}

+

+/**

+ * Count number of pbufs in a chain

+ *

+ * @param p first pbuf of chain

+ * @return the number of pbufs in a chain

+ */

+

+u8_t

+pbuf_clen(struct pbuf *p)

+{

+  u8_t len;

+

+  len = 0;

+  while (p != NULL) {

+    ++len;

+    p = p->next;

+  }

+  return len;

+}

+

+/**

+ * Increment the reference count of the pbuf.

+ *

+ * @param p pbuf to increase reference counter of

+ *

+ */

+void

+pbuf_ref(struct pbuf *p)

+{

+  SYS_ARCH_DECL_PROTECT(old_level);

+  /* pbuf given? */

+  if (p != NULL) {

+    SYS_ARCH_PROTECT(old_level);

+    ++(p->ref);

+    SYS_ARCH_UNPROTECT(old_level);

+  }

+}

+

+/**

+ * Concatenate two pbufs (each may be a pbuf chain) and take over

+ * the caller's reference of the tail pbuf.

+ * 

+ * @note The caller MAY NOT reference the tail pbuf afterwards.

+ * Use pbuf_chain() for that purpose.

+ * 

+ * @see pbuf_chain()

+ */

+

+void

+pbuf_cat(struct pbuf *h, struct pbuf *t)

+{

+  struct pbuf *p;

+

+  LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);

+  LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL);

+  if ((h == NULL) || (t == NULL)) return;

+

+  /* proceed to last pbuf of chain */

+  for (p = h; p->next != NULL; p = p->next) {

+    /* add total length of second chain to all totals of first chain */

+    p->tot_len += t->tot_len;

+  }

+  /* { p is last pbuf of first h chain, p->next == NULL } */

+  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);

+  LWIP_ASSERT("p->next == NULL", p->next == NULL);

+  /* add total length of second chain to last pbuf total of first chain */

+  p->tot_len += t->tot_len;

+  /* chain last pbuf of head (p) with first of tail (t) */

+  p->next = t;

+  /* p->next now references t, but the caller will drop its reference to t,

+   * so netto there is no change to the reference count of t.

+   */

+}

+

+/**

+ * Chain two pbufs (or pbuf chains) together.

+ * 

+ * The caller MUST call pbuf_free(t) once it has stopped

+ * using it. Use pbuf_cat() instead if you no longer use t.

+ * 

+ * @param h head pbuf (chain)

+ * @param t tail pbuf (chain)

+ * @note The pbufs MUST belong to the same packet.

+ * @note MAY NOT be called on a packet queue.

+ *

+ * The ->tot_len fields of all pbufs of the head chain are adjusted.

+ * The ->next field of the last pbuf of the head chain is adjusted.

+ * The ->ref field of the first pbuf of the tail chain is adjusted.

+ *

+ */

+void

+pbuf_chain(struct pbuf *h, struct pbuf *t)

+{

+  pbuf_cat(h, t);

+  /* t is now referenced by h */

+  pbuf_ref(t);

+  LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));

+}

+

+/* For packet queueing. Note that queued packets MUST be dequeued first

+ * using pbuf_dequeue() before calling other pbuf_() functions. */

+#if ARP_QUEUEING

+/**

+ * Add a packet to the end of a queue.

+ *

+ * @param q pointer to first packet on the queue

+ * @param n packet to be queued

+ *

+ * Both packets MUST be given, and must be different.

+ */

+void

+pbuf_queue(struct pbuf *p, struct pbuf *n)

+{

+#if PBUF_DEBUG /* remember head of queue */

+  struct pbuf *q = p;

+#endif

+  /* programmer stupidity checks */

+  LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);

+  LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);

+  LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);

+  if ((p == NULL) || (n == NULL) || (p == n)){

+    LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"));

+    return;

+  }

+

+  /* iterate through all packets on queue */

+  while (p->next != NULL) {

+/* be very picky about pbuf chain correctness */

+#if PBUF_DEBUG

+    /* iterate through all pbufs in packet */

+    while (p->tot_len != p->len) {

+      /* make sure invariant condition holds */

+      LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);

+      /* make sure each packet is complete */

+      LWIP_ASSERT("p->next != NULL", p->next != NULL);

+      p = p->next;

+      /* { p->tot_len == p->len => p is last pbuf of a packet } */

+    }

+    /* { p is last pbuf of a packet } */

+    /* proceed to next packet on queue */

+#endif

+    /* proceed to next pbuf */

+    if (p->next != NULL) p = p->next;

+  }

+  /* { p->tot_len == p->len and p->next == NULL } ==>

+   * { p is last pbuf of last packet on queue } */

+  /* chain last pbuf of queue with n */

+  p->next = n;

+  /* n is now referenced to by the (packet p in the) queue */

+  pbuf_ref(n);

+#if PBUF_DEBUG

+  LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2,

+    ("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n",

+    (void *)n, (void *)p, (void *)q));

+#endif

+}

+

+/**

+ * Remove a packet from the head of a queue.

+ *

+ * The caller MUST reference the remainder of the queue (as returned). The

+ * caller MUST NOT call pbuf_ref() as it implicitly takes over the reference

+ * from p.

+ * 

+ * @param p pointer to first packet on the queue which will be dequeued.

+ * @return first packet on the remaining queue (NULL if no further packets).

+ *

+ */

+struct pbuf *

+pbuf_dequeue(struct pbuf *p)

+{

+  struct pbuf *q;

+  LWIP_ASSERT("p != NULL", p != NULL);

+

+  /* iterate through all pbufs in packet p */

+  while (p->tot_len != p->len) {

+    /* make sure invariant condition holds */

+    LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);

+    /* make sure each packet is complete */

+    LWIP_ASSERT("p->next != NULL", p->next != NULL);

+    p = p->next;

+  }

+  /* { p->tot_len == p->len } => p is the last pbuf of the first packet */

+  /* remember next packet on queue in q */

+  q = p->next;

+  /* dequeue packet p from queue */

+  p->next = NULL;

+  /* any next packet on queue? */

+  if (q != NULL) {

+    /* although q is no longer referenced by p, it MUST be referenced by

+     * the caller, who is maintaining this packet queue. So, we do not call

+     * pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */

+    LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q));

+  } else {

+    LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n"));

+  }

+  return q;

+}

+#endif

+

+/**

+ *

+ * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.

+ *

+ * Used to queue packets on behalf of the lwIP stack, such as

+ * ARP based queueing.

+ *

+ * Go through a pbuf chain and replace any PBUF_REF buffers

+ * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of

+ * the referenced data.

+ *

+ * @note You MUST explicitly use p = pbuf_take(p);

+ * The pbuf you give as argument, may have been replaced

+ * by a (differently located) copy through pbuf_take()!

+ *

+ * @note Any replaced pbufs will be freed through pbuf_free().

+ * This may deallocate them if they become no longer referenced.

+ *

+ * @param p Head of pbuf chain to process

+ *

+ * @return Pointer to head of pbuf chain

+ */

+struct pbuf *

+pbuf_take(struct pbuf *p)

+{

+  struct pbuf *q , *prev, *head;

+  LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);

+  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));

+

+  prev = NULL;

+  head = p;

+  /* iterate through pbuf chain */

+  do

+  {

+    /* pbuf is of type PBUF_REF? */

+    if (p->flags == PBUF_FLAG_REF) {

+      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));

+      /* allocate a pbuf (w/ payload) fully in RAM */

+      /* PBUF_POOL buffers are faster if we can use them */

+      if (p->len <= PBUF_POOL_BUFSIZE) {

+        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);

+        if (q == NULL) {

+          LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));

+        }

+      } else {

+        /* no replacement pbuf yet */

+        q = NULL;

+        LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));

+      }

+      /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */

+      if (q == NULL) {

+        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);

+        if (q == NULL) {

+          LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));

+        }

+      }

+      /* replacement pbuf could be allocated? */

+      if (q != NULL)

+      {

+        /* copy p to q */

+        /* copy successor */

+        q->next = p->next;

+        /* remove linkage from original pbuf */

+        p->next = NULL;

+        /* remove linkage to original pbuf */

+        if (prev != NULL) {

+          /* prev->next == p at this point */

+          LWIP_ASSERT("prev->next == p", prev->next == p);

+          /* break chain and insert new pbuf instead */

+          prev->next = q;

+        /* prev == NULL, so we replaced the head pbuf of the chain */

+        } else {

+          head = q;

+        }

+        /* copy pbuf payload */

+        memcpy(q->payload, p->payload, p->len);

+        q->tot_len = p->tot_len;

+        q->len = p->len;

+        /* in case p was the first pbuf, it is no longer refered to by

+         * our caller, as the caller MUST do p = pbuf_take(p);

+         * in case p was not the first pbuf, it is no longer refered to

+         * by prev. we can safely free the pbuf here.

+         * (note that we have set p->next to NULL already so that

+         * we will not free the rest of the chain by accident.)

+         */

+        pbuf_free(p);

+        /* do not copy ref, since someone else might be using the old buffer */

+        LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));

+        p = q;

+      } else {

+        /* deallocate chain */

+        pbuf_free(head);

+        LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));

+        return NULL;

+      }

+    /* p->flags != PBUF_FLAG_REF */

+    } else {

+      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));

+    }

+    /* remember this pbuf */

+    prev = p;

+    /* proceed to next pbuf in original chain */

+    p = p->next;

+  } while (p);

+  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));

+

+  return head;

+}

+

+/**

+ * Dechains the first pbuf from its succeeding pbufs in the chain.

+ *

+ * Makes p->tot_len field equal to p->len.

+ * @param p pbuf to dechain

+ * @return remainder of the pbuf chain, or NULL if it was de-allocated.

+ * @note May not be called on a packet queue.

+ */

+struct pbuf *

+pbuf_dechain(struct pbuf *p)

+{

+  struct pbuf *q;

+  u8_t tail_gone = 1;

+  /* tail */

+  q = p->next;

+  /* pbuf has successor in chain? */

+  if (q != NULL) {

+    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */

+    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);

+    /* enforce invariant if assertion is disabled */

+    q->tot_len = p->tot_len - p->len;

+    /* decouple pbuf from remainder */

+    p->next = NULL;

+    /* total length of pbuf p is its own length only */

+    p->tot_len = p->len;

+    /* q is no longer referenced by p, free it */

+    LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));

+    tail_gone = pbuf_free(q);

+    if (tail_gone > 0) {

+      LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE,

+                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));

+    }

+    /* return remaining tail or NULL if deallocated */

+  }

+  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */

+  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);

+  return (tail_gone > 0? NULL: q);

+}

diff --git a/Demo/Common/ethernet/lwIP/core/raw.c b/Demo/Common/ethernet/lwIP/core/raw.c
index 3019980..b0e18b0 100644
--- a/Demo/Common/ethernet/lwIP/core/raw.c
+++ b/Demo/Common/ethernet/lwIP/core/raw.c
@@ -1,326 +1,326 @@
-/**
- * @file
- * 
- * Implementation of raw protocol PCBs for low-level handling of
- * different types of protocols besides (or overriding) those
- * already available in lwIP.
- *
- */
-/*
- * 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 <string.h>
-
-#include "lwip/opt.h"
-
-#include "lwip/def.h"
-#include "lwip/memp.h"
-#include "lwip/inet.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/raw.h"
-
-#include "lwip/stats.h"
-
-#include "arch/perf.h"
-#include "lwip/snmp.h"
-
-#if LWIP_RAW
-
-/** The list of RAW PCBs */
-static struct raw_pcb *raw_pcbs = NULL;
-
-void
-raw_init(void)
-{
-  raw_pcbs = NULL;
-}
-
-/**
- * Determine if in incoming IP packet is covered by a RAW PCB
- * and if so, pass it to a user-provided receive callback function.
- *
- * Given an incoming IP datagram (as a chain of pbufs) this function
- * finds a corresponding RAW PCB and calls the corresponding receive
- * callback function.
- *
- * @param pbuf pbuf to be demultiplexed to a RAW PCB.
- * @param netif network interface on which the datagram was received.
- * @Return - 1 if the packet has been eaten by a RAW PCB receive
- *           callback function. The caller MAY NOT not reference the
- *           packet any longer, and MAY NOT call pbuf_free().
- * @return - 0 if packet is not eaten (pbuf is still referenced by the
- *           caller).
- *
- */
-u8_t
-raw_input(struct pbuf *p, struct netif *inp)
-{
-  struct raw_pcb *pcb;
-  struct ip_hdr *iphdr;
-  s16_t proto;
-  u8_t eaten = 0;
-
-  iphdr = p->payload;
-  proto = IPH_PROTO(iphdr);
-
-  pcb = raw_pcbs;
-  /* loop through all raw pcbs until the packet is eaten by one */
-  /* this allows multiple pcbs to match against the packet by design */
-  while ((eaten == 0) && (pcb != NULL)) {
-    if (pcb->protocol == proto) {
-      /* receive callback function available? */
-      if (pcb->recv != NULL) {
-        /* the receive callback function did not eat the packet? */
-        if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)
-        {
-          /* receive function ate the packet */
-          p = NULL;
-          eaten = 1;
-        }
-      }
-      /* no receive callback function was set for this raw PCB */
-      /* drop the packet */
-    }
-    pcb = pcb->next;
-  }
-  return eaten;
-}
-
-/**
- * Bind a RAW PCB.
- *
- * @param pcb RAW PCB to be bound with a local address ipaddr.
- * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
- * bind to all local interfaces.
- *
- * @return lwIP error code.
- * - ERR_OK. Successful. No error occured.
- * - ERR_USE. The specified IP address is already bound to by
- * another RAW PCB.
- *
- * @see raw_disconnect()
- */
-err_t
-raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
-{
-  ip_addr_set(&pcb->local_ip, ipaddr);
-  return ERR_OK;
-}
-
-/**
- * Connect an RAW PCB. This function is required by upper layers
- * of lwip. Using the raw api you could use raw_sendto() instead
- *
- * This will associate the RAW PCB with the remote address.
- *
- * @param pcb RAW PCB to be connected with remote address ipaddr and port.
- * @param ipaddr remote IP address to connect with.
- *
- * @return lwIP error code
- *
- * @see raw_disconnect() and raw_sendto()
- */
-err_t
-raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
-{
-  ip_addr_set(&pcb->remote_ip, ipaddr);
-  return ERR_OK;
-}
-
-
-/**
- * Set the callback function for received packets that match the
- * raw PCB's protocol and binding. 
- * 
- * The callback function MUST either
- * - eat the packet by calling pbuf_free() and returning non-zero. The
- *   packet will not be passed to other raw PCBs or other protocol layers.
- * - not free the packet, and return zero. The packet will be matched
- *   against further PCBs and/or forwarded to another protocol layers.
- * 
- * @return non-zero if the packet was free()d, zero if the packet remains
- * available for others.
- */
-void
-raw_recv(struct raw_pcb *pcb,
-         u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,
-                      struct ip_addr *addr),
-         void *recv_arg)
-{
-  /* remember recv() callback and user data */
-  pcb->recv = recv;
-  pcb->recv_arg = recv_arg;
-}
-
-/**
- * Send the raw IP packet to the given address. Note that actually you cannot
- * modify the IP headers (this is inconsistent with the receive callback where
- * you actually get the IP headers), you can only specify the IP payload here.
- * It requires some more changes in lwIP. (there will be a raw_send() function
- * then.)
- *
- * @param pcb the raw pcb which to send
- * @param p the IP payload to send
- * @param ipaddr the destination address of the IP packet
- *
- */
-err_t
-raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
-{
-  err_t err;
-  struct netif *netif;
-  struct ip_addr *src_ip;
-  struct pbuf *q; /* q will be sent down the stack */
-  
-  LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_sendto\n"));
-  
-  /* not enough space to add an IP header to first pbuf in given p chain? */
-  if (pbuf_header(p, IP_HLEN)) {
-    /* allocate header in new pbuf */
-    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
-    /* new header pbuf could not be allocated? */
-    if (q == NULL) {
-      LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));
-      return ERR_MEM;
-    }
-    /* chain header q in front of given pbuf p */
-    pbuf_chain(q, p);
-    /* { first pbuf q points to header pbuf } */
-    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
-  }  else {
-    /* first pbuf q equals given pbuf */
-    q = p;
-    pbuf_header(q, -IP_HLEN);
-  }
-  
-  if ((netif = ip_route(ipaddr)) == NULL) {
-    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
-#if RAW_STATS
-    /*    ++lwip_stats.raw.rterr;*/
-#endif /* RAW_STATS */
-    /* free any temporary header pbuf allocated by pbuf_header() */
-    if (q != p) {
-      pbuf_free(q);
-    }
-    return ERR_RTE;
-  }
-
-  if (ip_addr_isany(&pcb->local_ip)) {
-    /* use outgoing network interface IP address as source address */
-    src_ip = &(netif->ip_addr);
-  } else {
-    /* use RAW PCB local IP address as source address */
-    src_ip = &(pcb->local_ip);
-  }
-
-  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
-
-  /* did we chain a header earlier? */
-  if (q != p) {
-    /* free the header */
-    pbuf_free(q);
-  }
-  return err;
-}
-
-/**
- * Send the raw IP packet to the address given by raw_connect()
- *
- * @param pcb the raw pcb which to send
- * @param p the IP payload to send
- * @param ipaddr the destination address of the IP packet
- *
- */
-err_t
-raw_send(struct raw_pcb *pcb, struct pbuf *p)
-{
-  return raw_sendto(pcb, p, &pcb->remote_ip);
-}
-
-/**
- * Remove an RAW PCB.
- *
- * @param pcb RAW PCB to be removed. The PCB is removed from the list of
- * RAW PCB's and the data structure is freed from memory.
- *
- * @see raw_new()
- */
-void
-raw_remove(struct raw_pcb *pcb)
-{
-  struct raw_pcb *pcb2;
-  /* pcb to be removed is first in list? */
-  if (raw_pcbs == pcb) {
-    /* make list start at 2nd pcb */
-    raw_pcbs = raw_pcbs->next;
-    /* pcb not 1st in list */
-  } else for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
-    /* find pcb in raw_pcbs list */
-    if (pcb2->next != NULL && pcb2->next == pcb) {
-      /* remove pcb from list */
-      pcb2->next = pcb->next;
-    }
-  }
-  memp_free(MEMP_RAW_PCB, pcb);
-}
-
-/**
- * Create a RAW PCB.
- *
- * @return The RAW PCB which was created. NULL if the PCB data structure
- * could not be allocated.
- *
- * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
- *
- * @see raw_remove()
- */
-struct raw_pcb *
-raw_new(u16_t proto) {
-  struct raw_pcb *pcb;
-
-  LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_new\n"));
-
-  pcb = memp_malloc(MEMP_RAW_PCB);
-  /* could allocate RAW PCB? */
-  if (pcb != NULL) {
-    /* initialize PCB to all zeroes */
-    memset(pcb, 0, sizeof(struct raw_pcb));
-    pcb->protocol = proto;
-    pcb->ttl = RAW_TTL;
-    pcb->next = raw_pcbs;
-    raw_pcbs = pcb;
-  }
-  return pcb;
-}
-
-#endif /* LWIP_RAW */
+/**

+ * @file

+ * 

+ * Implementation of raw protocol PCBs for low-level handling of

+ * different types of protocols besides (or overriding) those

+ * already available in lwIP.

+ *

+ */

+/*

+ * 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 <string.h>

+

+#include "lwip/opt.h"

+

+#include "lwip/def.h"

+#include "lwip/memp.h"

+#include "lwip/inet.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/raw.h"

+

+#include "lwip/stats.h"

+

+#include "arch/perf.h"

+#include "lwip/snmp.h"

+

+#if LWIP_RAW

+

+/** The list of RAW PCBs */

+static struct raw_pcb *raw_pcbs = NULL;

+

+void

+raw_init(void)

+{

+  raw_pcbs = NULL;

+}

+

+/**

+ * Determine if in incoming IP packet is covered by a RAW PCB

+ * and if so, pass it to a user-provided receive callback function.

+ *

+ * Given an incoming IP datagram (as a chain of pbufs) this function

+ * finds a corresponding RAW PCB and calls the corresponding receive

+ * callback function.

+ *

+ * @param pbuf pbuf to be demultiplexed to a RAW PCB.

+ * @param netif network interface on which the datagram was received.

+ * @Return - 1 if the packet has been eaten by a RAW PCB receive

+ *           callback function. The caller MAY NOT not reference the

+ *           packet any longer, and MAY NOT call pbuf_free().

+ * @return - 0 if packet is not eaten (pbuf is still referenced by the

+ *           caller).

+ *

+ */

+u8_t

+raw_input(struct pbuf *p, struct netif *inp)

+{

+  struct raw_pcb *pcb;

+  struct ip_hdr *iphdr;

+  s16_t proto;

+  u8_t eaten = 0;

+

+  iphdr = p->payload;

+  proto = IPH_PROTO(iphdr);

+

+  pcb = raw_pcbs;

+  /* loop through all raw pcbs until the packet is eaten by one */

+  /* this allows multiple pcbs to match against the packet by design */

+  while ((eaten == 0) && (pcb != NULL)) {

+    if (pcb->protocol == proto) {

+      /* receive callback function available? */

+      if (pcb->recv != NULL) {

+        /* the receive callback function did not eat the packet? */

+        if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)

+        {

+          /* receive function ate the packet */

+          p = NULL;

+          eaten = 1;

+        }

+      }

+      /* no receive callback function was set for this raw PCB */

+      /* drop the packet */

+    }

+    pcb = pcb->next;

+  }

+  return eaten;

+}

+

+/**

+ * Bind a RAW PCB.

+ *

+ * @param pcb RAW PCB to be bound with a local address ipaddr.

+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to

+ * bind to all local interfaces.

+ *

+ * @return lwIP error code.

+ * - ERR_OK. Successful. No error occured.

+ * - ERR_USE. The specified IP address is already bound to by

+ * another RAW PCB.

+ *

+ * @see raw_disconnect()

+ */

+err_t

+raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)

+{

+  ip_addr_set(&pcb->local_ip, ipaddr);

+  return ERR_OK;

+}

+

+/**

+ * Connect an RAW PCB. This function is required by upper layers

+ * of lwip. Using the raw api you could use raw_sendto() instead

+ *

+ * This will associate the RAW PCB with the remote address.

+ *

+ * @param pcb RAW PCB to be connected with remote address ipaddr and port.

+ * @param ipaddr remote IP address to connect with.

+ *

+ * @return lwIP error code

+ *

+ * @see raw_disconnect() and raw_sendto()

+ */

+err_t

+raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)

+{

+  ip_addr_set(&pcb->remote_ip, ipaddr);

+  return ERR_OK;

+}

+

+

+/**

+ * Set the callback function for received packets that match the

+ * raw PCB's protocol and binding. 

+ * 

+ * The callback function MUST either

+ * - eat the packet by calling pbuf_free() and returning non-zero. The

+ *   packet will not be passed to other raw PCBs or other protocol layers.

+ * - not free the packet, and return zero. The packet will be matched

+ *   against further PCBs and/or forwarded to another protocol layers.

+ * 

+ * @return non-zero if the packet was free()d, zero if the packet remains

+ * available for others.

+ */

+void

+raw_recv(struct raw_pcb *pcb,

+         u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,

+                      struct ip_addr *addr),

+         void *recv_arg)

+{

+  /* remember recv() callback and user data */

+  pcb->recv = recv;

+  pcb->recv_arg = recv_arg;

+}

+

+/**

+ * Send the raw IP packet to the given address. Note that actually you cannot

+ * modify the IP headers (this is inconsistent with the receive callback where

+ * you actually get the IP headers), you can only specify the IP payload here.

+ * It requires some more changes in lwIP. (there will be a raw_send() function

+ * then.)

+ *

+ * @param pcb the raw pcb which to send

+ * @param p the IP payload to send

+ * @param ipaddr the destination address of the IP packet

+ *

+ */

+err_t

+raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)

+{

+  err_t err;

+  struct netif *netif;

+  struct ip_addr *src_ip;

+  struct pbuf *q; /* q will be sent down the stack */

+  

+  LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_sendto\n"));

+  

+  /* not enough space to add an IP header to first pbuf in given p chain? */

+  if (pbuf_header(p, IP_HLEN)) {

+    /* allocate header in new pbuf */

+    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);

+    /* new header pbuf could not be allocated? */

+    if (q == NULL) {

+      LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));

+      return ERR_MEM;

+    }

+    /* chain header q in front of given pbuf p */

+    pbuf_chain(q, p);

+    /* { first pbuf q points to header pbuf } */

+    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));

+  }  else {

+    /* first pbuf q equals given pbuf */

+    q = p;

+    pbuf_header(q, -IP_HLEN);

+  }

+  

+  if ((netif = ip_route(ipaddr)) == NULL) {

+    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));

+#if RAW_STATS

+    /*    ++lwip_stats.raw.rterr;*/

+#endif /* RAW_STATS */

+    /* free any temporary header pbuf allocated by pbuf_header() */

+    if (q != p) {

+      pbuf_free(q);

+    }

+    return ERR_RTE;

+  }

+

+  if (ip_addr_isany(&pcb->local_ip)) {

+    /* use outgoing network interface IP address as source address */

+    src_ip = &(netif->ip_addr);

+  } else {

+    /* use RAW PCB local IP address as source address */

+    src_ip = &(pcb->local_ip);

+  }

+

+  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);

+

+  /* did we chain a header earlier? */

+  if (q != p) {

+    /* free the header */

+    pbuf_free(q);

+  }

+  return err;

+}

+

+/**

+ * Send the raw IP packet to the address given by raw_connect()

+ *

+ * @param pcb the raw pcb which to send

+ * @param p the IP payload to send

+ * @param ipaddr the destination address of the IP packet

+ *

+ */

+err_t

+raw_send(struct raw_pcb *pcb, struct pbuf *p)

+{

+  return raw_sendto(pcb, p, &pcb->remote_ip);

+}

+

+/**

+ * Remove an RAW PCB.

+ *

+ * @param pcb RAW PCB to be removed. The PCB is removed from the list of

+ * RAW PCB's and the data structure is freed from memory.

+ *

+ * @see raw_new()

+ */

+void

+raw_remove(struct raw_pcb *pcb)

+{

+  struct raw_pcb *pcb2;

+  /* pcb to be removed is first in list? */

+  if (raw_pcbs == pcb) {

+    /* make list start at 2nd pcb */

+    raw_pcbs = raw_pcbs->next;

+    /* pcb not 1st in list */

+  } else for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {

+    /* find pcb in raw_pcbs list */

+    if (pcb2->next != NULL && pcb2->next == pcb) {

+      /* remove pcb from list */

+      pcb2->next = pcb->next;

+    }

+  }

+  memp_free(MEMP_RAW_PCB, pcb);

+}

+

+/**

+ * Create a RAW PCB.

+ *

+ * @return The RAW PCB which was created. NULL if the PCB data structure

+ * could not be allocated.

+ *

+ * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)

+ *

+ * @see raw_remove()

+ */

+struct raw_pcb *

+raw_new(u16_t proto) {

+  struct raw_pcb *pcb;

+

+  LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_new\n"));

+

+  pcb = memp_malloc(MEMP_RAW_PCB);

+  /* could allocate RAW PCB? */

+  if (pcb != NULL) {

+    /* initialize PCB to all zeroes */

+    memset(pcb, 0, sizeof(struct raw_pcb));

+    pcb->protocol = proto;

+    pcb->ttl = RAW_TTL;

+    pcb->next = raw_pcbs;

+    raw_pcbs = pcb;

+  }

+  return pcb;

+}

+

+#endif /* LWIP_RAW */

diff --git a/Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c b/Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c
index 5e04b38..a556edd 100644
--- a/Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c
+++ b/Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c
@@ -1,652 +1,652 @@
-/**
- * @file
- * Abstract Syntax Notation One (ISO 8824, 8825) decoding
- *
- * @todo not optimised (yet), favor correctness over speed, favor speed over size
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * 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: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_SNMP
-#include "lwip/snmp_asn1.h"
-
-/**
- * Retrieves type field from incoming pbuf chain.
- *
- * @param p points to a pbuf holding an ASN1 coded type field
- * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
- * @param type return ASN1 type
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
- */
-err_t
-snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-      *type = *msg_ptr;
-      return ERR_OK;
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Decodes length field from incoming pbuf chain into host length.
- *
- * @param p points to a pbuf holding an ASN1 coded length
- * @param ofs points to the offset within the pbuf chain of the ASN1 coded length
- * @param octets_used returns number of octets used by the length code
- * @param length return host order length, upto 64k
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
- */
-err_t
-snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-
-      if (*msg_ptr < 0x80)
-      {
-        /* primitive definite length format */
-        *octets_used = 1;
-        *length = *msg_ptr;
-        return ERR_OK;
-      }
-      else if (*msg_ptr == 0x80)
-      {
-        /* constructed indefinite length format, termination with two zero octets */
-        u8_t zeros;
-        u8_t i;
-
-        *length = 0;
-        zeros = 0;
-        while (zeros != 2)
-        {
-          i = 2;
-          while (i > 0)
-          {
-            i--;
-            (*length) += 1;
-            ofs += 1;
-            if (ofs >= plen)
-            {
-              /* next octet in next pbuf */
-              p = p->next;
-              if (p == NULL) { return ERR_ARG; }
-              msg_ptr = p->payload;
-              plen += p->len;
-            }
-            else
-            {
-              /* next octet in same pbuf */
-              msg_ptr++;
-            }
-            if (*msg_ptr == 0)
-            {
-              zeros++;
-              if (zeros == 2)
-              {
-                /* stop while (i > 0) */
-                i = 0;
-              }
-            }
-            else
-            {
-              zeros = 0;
-            }
-          }
-        }
-        *octets_used = 1;
-        return ERR_OK;
-      }
-      else if (*msg_ptr == 0x81)
-      {
-        /* constructed definite length format, one octet */
-        ofs += 1;
-        if (ofs >= plen)
-        {
-          /* next octet in next pbuf */
-          p = p->next;
-          if (p == NULL) { return ERR_ARG; }
-          msg_ptr = p->payload;
-        }
-        else
-        {
-          /* next octet in same pbuf */
-          msg_ptr++;
-        }
-        *length = *msg_ptr;
-        *octets_used = 2;
-        return ERR_OK;
-      }
-      else if (*msg_ptr == 0x82)
-      {
-        u8_t i;
-
-        /* constructed definite length format, two octets */
-        i = 2;
-        while (i > 0)
-        {
-          i--;
-          ofs += 1;
-          if (ofs >= plen)
-          {
-            /* next octet in next pbuf */
-            p = p->next;
-            if (p == NULL) { return ERR_ARG; }
-            msg_ptr = p->payload;
-            plen += p->len;
-          }
-          else
-          {
-            /* next octet in same pbuf */
-            msg_ptr++;
-          }
-          if (i == 0)
-          {
-            /* least significant length octet */
-            *length |= *msg_ptr;
-          }
-          else
-          {
-            /* most significant length octet */
-            *length = (*msg_ptr) << 8;
-          }
-        }
-        *octets_used = 3;
-        return ERR_OK;
-      }
-      else
-      {
-        /* constructed definite length format 3..127 octets, this is too big (>64k) */
-        /**  @todo: do we need to accept inefficient codings with many leading zero's? */
-        *octets_used = 1 + ((*msg_ptr) & 0x7f);
-        return ERR_ARG;
-      }
-    }
-    p = p->next;
-  }
-
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Decodes positive integer (counter, gauge, timeticks) into u32_t.
- *
- * @param p points to a pbuf holding an ASN1 coded integer
- * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
- * @param len length of the coded integer field
- * @param value return host order integer
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
- *
- * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
- * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
- * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
- */
-err_t
-snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-      if ((len > 0) && (len < 6))
-      {
-        /* start from zero */
-        *value = 0;
-        if (*msg_ptr & 0x80)
-        {
-          /* negative, expecting zero sign bit! */
-          return ERR_ARG;
-        }
-        else
-        {
-          /* positive */
-          if ((len > 1) && (*msg_ptr == 0))
-          {
-            /* skip leading "sign byte" octet 0x00 */
-            len--;
-            ofs += 1;
-            if (ofs >= plen)
-            {
-              /* next octet in next pbuf */
-              p = p->next;
-              if (p == NULL) { return ERR_ARG; }
-              msg_ptr = p->payload;
-              plen += p->len;
-            }
-            else
-            {
-              /* next octet in same pbuf */
-              msg_ptr++;
-            }
-          }
-        }
-        /* OR octets with value */
-        while (len > 1)
-        {
-          len--;
-          *value |= *msg_ptr;
-          *value <<= 8;
-          ofs += 1;
-          if (ofs >= plen)
-          {
-            /* next octet in next pbuf */
-            p = p->next;
-            if (p == NULL) { return ERR_ARG; }
-            msg_ptr = p->payload;
-            plen += p->len;
-          }
-          else
-          {
-            /* next octet in same pbuf */
-            msg_ptr++;
-          }
-        }
-        *value |= *msg_ptr;
-        return ERR_OK;
-      }
-      else
-      {
-        return ERR_ARG;
-      }
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Decodes integer into s32_t.
- *
- * @param p points to a pbuf holding an ASN1 coded integer
- * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
- * @param len length of the coded integer field
- * @param value return host order integer
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
- *
- * @note ASN coded integers are _always_ signed!
- */
-err_t
-snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-  u8_t *lsb_ptr = (u8_t*)value;
-  u8_t sign;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-      if ((len > 0) && (len < 5))
-      {
-        if (*msg_ptr & 0x80)
-        {
-          /* negative, start from -1 */
-          *value = -1;
-          sign = 1;
-        }
-        else
-        {
-          /* positive, start from 0 */
-          *value = 0;
-          sign = 0;
-        }
-        /* OR/AND octets with value */
-        while (len > 1)
-        {
-          len--;
-          if (sign)
-          {
-            *lsb_ptr &= *msg_ptr;
-            *value <<= 8;
-            *lsb_ptr |= 255;
-          }
-          else
-          {
-            *lsb_ptr |= *msg_ptr;
-            *value <<= 8;
-          }
-          ofs += 1;
-          if (ofs >= plen)
-          {
-            /* next octet in next pbuf */
-            p = p->next;
-            if (p == NULL) { return ERR_ARG; }
-            msg_ptr = p->payload;
-            plen += p->len;
-          }
-          else
-          {
-            /* next octet in same pbuf */
-            msg_ptr++;
-          }
-        }
-        if (sign)
-        {
-          *lsb_ptr &= *msg_ptr;
-        }
-        else
-        {
-          *lsb_ptr |= *msg_ptr;
-        }
-        return ERR_OK;
-      }
-      else
-      {
-        return ERR_ARG;
-      }
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Decodes object identifier from incoming message into array of s32_t.
- *
- * @param p points to a pbuf holding an ASN1 coded object identifier
- * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
- * @param len length of the coded object identifier
- * @param oid return object identifier struct
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
- */
-err_t
-snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-  s32_t *oid_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-
-      oid->len = 0;
-      oid_ptr = &oid->id[0];
-      if (len > 0)
-      {
-        /* first compressed octet */
-        if (*msg_ptr == 0x2B)
-        {
-          /* (most) common case 1.3 (iso.org) */
-          *oid_ptr = 1;
-          oid_ptr++;
-          *oid_ptr = 3;
-          oid_ptr++;
-        }
-        else if (*msg_ptr < 40)
-        {
-          *oid_ptr = 0;
-          oid_ptr++;
-          *oid_ptr = *msg_ptr;
-          oid_ptr++;
-        }
-        else if (*msg_ptr < 80)
-        {
-          *oid_ptr = 1;
-          oid_ptr++;
-          *oid_ptr = (*msg_ptr) - 40;
-          oid_ptr++;
-        }
-        else
-        {
-          *oid_ptr = 2;
-          oid_ptr++;
-          *oid_ptr = (*msg_ptr) - 80;
-          oid_ptr++;
-        }
-        oid->len = 2;
-      }
-      else
-      {
-        /* accepting zero length identifiers e.g. for
-           getnext operation. uncommon but valid */
-        return ERR_OK;
-      }
-      len--;
-      if (len > 0)
-      {
-        ofs += 1;
-        if (ofs >= plen)
-        {
-          /* next octet in next pbuf */
-          p = p->next;
-          if (p == NULL) { return ERR_ARG; }
-          msg_ptr = p->payload;
-          plen += p->len;
-        }
-        else
-        {
-          /* next octet in same pbuf */
-          msg_ptr++;
-        }
-      }
-      while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
-      {
-        /* sub-identifier uses multiple octets */
-        if (*msg_ptr & 0x80)
-        {
-          s32_t sub_id = 0;
-
-          while ((*msg_ptr & 0x80) && (len > 1))
-          {
-            len--;
-            sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
-            ofs += 1;
-            if (ofs >= plen)
-            {
-              /* next octet in next pbuf */
-              p = p->next;
-              if (p == NULL) { return ERR_ARG; }
-              msg_ptr = p->payload;
-              plen += p->len;
-            }
-            else
-            {
-              /* next octet in same pbuf */
-              msg_ptr++;
-            }
-          }
-          if (!(*msg_ptr & 0x80) && (len > 0))
-          {
-            /* last octet sub-identifier */
-            len--;
-            sub_id = (sub_id << 7) + *msg_ptr;
-            *oid_ptr = sub_id;
-          }
-        }
-        else
-        {
-          /* !(*msg_ptr & 0x80) sub-identifier uses single octet */
-          len--;
-          *oid_ptr = *msg_ptr;
-        }
-        if (len > 0)
-        {
-          /* remaining oid bytes available ... */
-          ofs += 1;
-          if (ofs >= plen)
-          {
-            /* next octet in next pbuf */
-            p = p->next;
-            if (p == NULL) { return ERR_ARG; }
-            msg_ptr = p->payload;
-            plen += p->len;
-          }
-          else
-          {
-            /* next octet in same pbuf */
-            msg_ptr++;
-          }
-        }
-        oid_ptr++;
-        oid->len++;
-      }
-      if (len == 0)
-      {
-        /* len == 0, end of oid */
-        return ERR_OK;
-      }
-      else
-      {
-        /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
-        return ERR_ARG;
-      }
-
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
- * from incoming message into array.
- *
- * @param p points to a pbuf holding an ASN1 coded raw data
- * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
- * @param len length of the coded raw data (zero is valid, e.g. empty string!)
- * @param raw_len length of the raw return value
- * @param raw return raw bytes
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
- */
-err_t
-snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  if (len > 0)
-  {
-    plen = 0;
-    while (p != NULL)
-    {
-      base = plen;
-      plen += p->len;
-      if (ofs < plen)
-      {
-        msg_ptr = p->payload;
-        msg_ptr += ofs - base;
-        if (raw_len >= len)
-        {
-          while (len > 1)
-          {
-            /* copy len - 1 octets */
-            len--;
-            *raw = *msg_ptr;
-            raw++;
-            ofs += 1;
-            if (ofs >= plen)
-            {
-              /* next octet in next pbuf */
-              p = p->next;
-              if (p == NULL) { return ERR_ARG; }
-              msg_ptr = p->payload;
-              plen += p->len;
-            }
-            else
-            {
-              /* next octet in same pbuf */
-              msg_ptr++;
-            }
-          }
-          /* copy last octet */
-          *raw = *msg_ptr;
-          return ERR_OK;
-        }
-        else
-        {
-          /* raw_len < len, not enough dst space */
-          return ERR_ARG;
-        }
-      }
-      p = p->next;
-    }
-    /* p == NULL, ofs >= plen */
-    return ERR_ARG;
-  }
-  else
-  {
-    /* len == 0, empty string */
-    return ERR_OK;
-  }
-}
-
-#endif /* LWIP_SNMP */
-
+/**

+ * @file

+ * Abstract Syntax Notation One (ISO 8824, 8825) decoding

+ *

+ * @todo not optimised (yet), favor correctness over speed, favor speed over size

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * 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: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP

+#include "lwip/snmp_asn1.h"

+

+/**

+ * Retrieves type field from incoming pbuf chain.

+ *

+ * @param p points to a pbuf holding an ASN1 coded type field

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field

+ * @param type return ASN1 type

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ */

+err_t

+snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+      *type = *msg_ptr;

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes length field from incoming pbuf chain into host length.

+ *

+ * @param p points to a pbuf holding an ASN1 coded length

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded length

+ * @param octets_used returns number of octets used by the length code

+ * @param length return host order length, upto 64k

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ */

+err_t

+snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      if (*msg_ptr < 0x80)

+      {

+        /* primitive definite length format */

+        *octets_used = 1;

+        *length = *msg_ptr;

+        return ERR_OK;

+      }

+      else if (*msg_ptr == 0x80)

+      {

+        /* constructed indefinite length format, termination with two zero octets */

+        u8_t zeros;

+        u8_t i;

+

+        *length = 0;

+        zeros = 0;

+        while (zeros != 2)

+        {

+          i = 2;

+          while (i > 0)

+          {

+            i--;

+            (*length) += 1;

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+            if (*msg_ptr == 0)

+            {

+              zeros++;

+              if (zeros == 2)

+              {

+                /* stop while (i > 0) */

+                i = 0;

+              }

+            }

+            else

+            {

+              zeros = 0;

+            }

+          }

+        }

+        *octets_used = 1;

+        return ERR_OK;

+      }

+      else if (*msg_ptr == 0x81)

+      {

+        /* constructed definite length format, one octet */

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+        *length = *msg_ptr;

+        *octets_used = 2;

+        return ERR_OK;

+      }

+      else if (*msg_ptr == 0x82)

+      {

+        u8_t i;

+

+        /* constructed definite length format, two octets */

+        i = 2;

+        while (i > 0)

+        {

+          i--;

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+          if (i == 0)

+          {

+            /* least significant length octet */

+            *length |= *msg_ptr;

+          }

+          else

+          {

+            /* most significant length octet */

+            *length = (*msg_ptr) << 8;

+          }

+        }

+        *octets_used = 3;

+        return ERR_OK;

+      }

+      else

+      {

+        /* constructed definite length format 3..127 octets, this is too big (>64k) */

+        /**  @todo: do we need to accept inefficient codings with many leading zero's? */

+        *octets_used = 1 + ((*msg_ptr) & 0x7f);

+        return ERR_ARG;

+      }

+    }

+    p = p->next;

+  }

+

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes positive integer (counter, gauge, timeticks) into u32_t.

+ *

+ * @param p points to a pbuf holding an ASN1 coded integer

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer

+ * @param len length of the coded integer field

+ * @param value return host order integer

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ *

+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded

+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value

+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!

+ */

+err_t

+snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+      if ((len > 0) && (len < 6))

+      {

+        /* start from zero */

+        *value = 0;

+        if (*msg_ptr & 0x80)

+        {

+          /* negative, expecting zero sign bit! */

+          return ERR_ARG;

+        }

+        else

+        {

+          /* positive */

+          if ((len > 1) && (*msg_ptr == 0))

+          {

+            /* skip leading "sign byte" octet 0x00 */

+            len--;

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+          }

+        }

+        /* OR octets with value */

+        while (len > 1)

+        {

+          len--;

+          *value |= *msg_ptr;

+          *value <<= 8;

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+        }

+        *value |= *msg_ptr;

+        return ERR_OK;

+      }

+      else

+      {

+        return ERR_ARG;

+      }

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes integer into s32_t.

+ *

+ * @param p points to a pbuf holding an ASN1 coded integer

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer

+ * @param len length of the coded integer field

+ * @param value return host order integer

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ *

+ * @note ASN coded integers are _always_ signed!

+ */

+err_t

+snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+  u8_t *lsb_ptr = (u8_t*)value;

+  u8_t sign;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+      if ((len > 0) && (len < 5))

+      {

+        if (*msg_ptr & 0x80)

+        {

+          /* negative, start from -1 */

+          *value = -1;

+          sign = 1;

+        }

+        else

+        {

+          /* positive, start from 0 */

+          *value = 0;

+          sign = 0;

+        }

+        /* OR/AND octets with value */

+        while (len > 1)

+        {

+          len--;

+          if (sign)

+          {

+            *lsb_ptr &= *msg_ptr;

+            *value <<= 8;

+            *lsb_ptr |= 255;

+          }

+          else

+          {

+            *lsb_ptr |= *msg_ptr;

+            *value <<= 8;

+          }

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+        }

+        if (sign)

+        {

+          *lsb_ptr &= *msg_ptr;

+        }

+        else

+        {

+          *lsb_ptr |= *msg_ptr;

+        }

+        return ERR_OK;

+      }

+      else

+      {

+        return ERR_ARG;

+      }

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes object identifier from incoming message into array of s32_t.

+ *

+ * @param p points to a pbuf holding an ASN1 coded object identifier

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier

+ * @param len length of the coded object identifier

+ * @param oid return object identifier struct

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ */

+err_t

+snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+  s32_t *oid_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      oid->len = 0;

+      oid_ptr = &oid->id[0];

+      if (len > 0)

+      {

+        /* first compressed octet */

+        if (*msg_ptr == 0x2B)

+        {

+          /* (most) common case 1.3 (iso.org) */

+          *oid_ptr = 1;

+          oid_ptr++;

+          *oid_ptr = 3;

+          oid_ptr++;

+        }

+        else if (*msg_ptr < 40)

+        {

+          *oid_ptr = 0;

+          oid_ptr++;

+          *oid_ptr = *msg_ptr;

+          oid_ptr++;

+        }

+        else if (*msg_ptr < 80)

+        {

+          *oid_ptr = 1;

+          oid_ptr++;

+          *oid_ptr = (*msg_ptr) - 40;

+          oid_ptr++;

+        }

+        else

+        {

+          *oid_ptr = 2;

+          oid_ptr++;

+          *oid_ptr = (*msg_ptr) - 80;

+          oid_ptr++;

+        }

+        oid->len = 2;

+      }

+      else

+      {

+        /* accepting zero length identifiers e.g. for

+           getnext operation. uncommon but valid */

+        return ERR_OK;

+      }

+      len--;

+      if (len > 0)

+      {

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))

+      {

+        /* sub-identifier uses multiple octets */

+        if (*msg_ptr & 0x80)

+        {

+          s32_t sub_id = 0;

+

+          while ((*msg_ptr & 0x80) && (len > 1))

+          {

+            len--;

+            sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+          }

+          if (!(*msg_ptr & 0x80) && (len > 0))

+          {

+            /* last octet sub-identifier */

+            len--;

+            sub_id = (sub_id << 7) + *msg_ptr;

+            *oid_ptr = sub_id;

+          }

+        }

+        else

+        {

+          /* !(*msg_ptr & 0x80) sub-identifier uses single octet */

+          len--;

+          *oid_ptr = *msg_ptr;

+        }

+        if (len > 0)

+        {

+          /* remaining oid bytes available ... */

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+        }

+        oid_ptr++;

+        oid->len++;

+      }

+      if (len == 0)

+      {

+        /* len == 0, end of oid */

+        return ERR_OK;

+      }

+      else

+      {

+        /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */

+        return ERR_ARG;

+      }

+

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)

+ * from incoming message into array.

+ *

+ * @param p points to a pbuf holding an ASN1 coded raw data

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data

+ * @param len length of the coded raw data (zero is valid, e.g. empty string!)

+ * @param raw_len length of the raw return value

+ * @param raw return raw bytes

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ */

+err_t

+snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  if (len > 0)

+  {

+    plen = 0;

+    while (p != NULL)

+    {

+      base = plen;

+      plen += p->len;

+      if (ofs < plen)

+      {

+        msg_ptr = p->payload;

+        msg_ptr += ofs - base;

+        if (raw_len >= len)

+        {

+          while (len > 1)

+          {

+            /* copy len - 1 octets */

+            len--;

+            *raw = *msg_ptr;

+            raw++;

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+          }

+          /* copy last octet */

+          *raw = *msg_ptr;

+          return ERR_OK;

+        }

+        else

+        {

+          /* raw_len < len, not enough dst space */

+          return ERR_ARG;

+        }

+      }

+      p = p->next;

+    }

+    /* p == NULL, ofs >= plen */

+    return ERR_ARG;

+  }

+  else

+  {

+    /* len == 0, empty string */

+    return ERR_OK;

+  }

+}

+

+#endif /* LWIP_SNMP */

+

diff --git a/Demo/Common/ethernet/lwIP/core/snmp/asn1_enc.c b/Demo/Common/ethernet/lwIP/core/snmp/asn1_enc.c
index 4d04f28..80f8d37 100644
--- a/Demo/Common/ethernet/lwIP/core/snmp/asn1_enc.c
+++ b/Demo/Common/ethernet/lwIP/core/snmp/asn1_enc.c
@@ -1,610 +1,610 @@
-/**
- * @file
- * Abstract Syntax Notation One (ISO 8824, 8825) encoding
- *
- * @todo not optimised (yet), favor correctness over speed, favor speed over size
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * 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: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_SNMP
-#include "lwip/snmp_asn1.h"
-
-/**
- * Returns octet count for length.
- *
- * @param length
- * @param octets_needed points to the return value
- */
-void
-snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
-{
-  if (length < 0x80U)
-  {
-    *octets_needed = 1;
-  }
-  else if (length < 0x100U)
-  {
-    *octets_needed = 2;
-  }
-  else
-  {
-    *octets_needed = 3;
-  }
-}
-
-/**
- * Returns octet count for an u32_t.
- *
- * @param value
- * @param octets_needed points to the return value
- *
- * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
- * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
- * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
- */
-void
-snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
-{
-  if (value < 0x80UL)
-  {
-    *octets_needed = 1;
-  }
-  else if (value < 0x8000UL)
-  {
-    *octets_needed = 2;
-  }
-  else if (value < 0x800000UL)
-  {
-    *octets_needed = 3;
-  }
-  else if (value < 0x80000000UL)
-  {
-    *octets_needed = 4;
-  }
-  else
-  {
-    *octets_needed = 5;
-  }
-}
-
-/**
- * Returns octet count for an s32_t.
- *
- * @param value
- * @param octets_needed points to the return value
- *
- * @note ASN coded integers are _always_ signed.
- */
-void
-snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
-{
-  if (value < 0)
-  {
-    value = ~value;
-  }
-  if (value < 0x80L)
-  {
-    *octets_needed = 1;
-  }
-  else if (value < 0x8000L)
-  {
-    *octets_needed = 2;
-  }
-  else if (value < 0x800000L)
-  {
-    *octets_needed = 3;
-  }
-  else
-  {
-    *octets_needed = 4;
-  }
-}
-
-/**
- * Returns octet count for an object identifier.
- *
- * @param ident_len object identifier array length
- * @param ident points to object identifier array
- * @param octets_needed points to the return value
- */
-void
-snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)
-{
-  s32_t sub_id;
-  u8_t cnt;
-
-  cnt = 0;
-  if (ident_len > 1)
-  {
-    /* compressed prefix in one octet */
-    cnt++;
-    ident_len -= 2;
-    ident += 2;
-  }
-  while(ident_len > 0)
-  {
-    ident_len--;
-    sub_id = *ident;
-
-    sub_id >>= 7;
-    cnt++;
-    while(sub_id > 0)
-    {
-      sub_id >>= 7;
-      cnt++;
-    }
-    ident++;
-  }
-  *octets_needed = cnt;
-}
-
-/**
- * Encodes ASN type field into a pbuf chained ASN1 msg.
- *
- * @param p points to output pbuf to encode value into
- * @param ofs points to the offset within the pbuf chain
- * @param type input ASN1 type
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
- */
-err_t
-snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-      *msg_ptr = type;
-      return ERR_OK;
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Encodes host order length field into a pbuf chained ASN1 msg.
- *
- * @param p points to output pbuf to encode length into
- * @param ofs points to the offset within the pbuf chain
- * @param length is the host order length to be encoded
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
- */
-err_t
-snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-
-      if (length < 0x80)
-      {
-        *msg_ptr = length;
-        return ERR_OK;
-      }
-      else if (length < 0x100)
-      {
-        *msg_ptr = 0x81;
-        ofs += 1;
-        if (ofs >= plen)
-        {
-          /* next octet in next pbuf */
-          p = p->next;
-          if (p == NULL) { return ERR_ARG; }
-          msg_ptr = p->payload;
-        }
-        else
-        {
-          /* next octet in same pbuf */
-          msg_ptr++;
-        }
-        *msg_ptr = length;
-        return ERR_OK;
-      }
-      else
-      {
-        u8_t i;
-
-        /* length >= 0x100 && length <= 0xFFFF */
-        *msg_ptr = 0x82;
-        i = 2;
-        while (i > 0)
-        {
-          i--;
-          ofs += 1;
-          if (ofs >= plen)
-          {
-            /* next octet in next pbuf */
-            p = p->next;
-            if (p == NULL) { return ERR_ARG; }
-            msg_ptr = p->payload;
-            plen += p->len;
-          }
-          else
-          {
-            /* next octet in same pbuf */
-            msg_ptr++;
-          }
-          if (i == 0)
-          {
-            /* least significant length octet */
-            *msg_ptr = length;
-          }
-          else
-          {
-            /* most significant length octet */
-            *msg_ptr = length >> 8;
-          }
-        }
-        return ERR_OK;
-      }
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
- *
- * @param p points to output pbuf to encode value into
- * @param ofs points to the offset within the pbuf chain
- * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
- * @param value is the host order u32_t value to be encoded
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
- *
- * @see snmp_asn1_enc_u32t_cnt()
- */
-err_t
-snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-
-      if (octets_needed == 5)
-      {
-        /* not enough bits in 'value' add leading 0x00 */
-        octets_needed--;
-        *msg_ptr = 0x00;
-        ofs += 1;
-        if (ofs >= plen)
-        {
-          /* next octet in next pbuf */
-          p = p->next;
-          if (p == NULL) { return ERR_ARG; }
-          msg_ptr = p->payload;
-          plen += p->len;
-        }
-        else
-        {
-          /* next octet in same pbuf */
-          msg_ptr++;
-        }
-      }
-      while (octets_needed > 1)
-      {
-        octets_needed--;
-        *msg_ptr = value >> (octets_needed << 3);
-        ofs += 1;
-        if (ofs >= plen)
-        {
-          /* next octet in next pbuf */
-          p = p->next;
-          if (p == NULL) { return ERR_ARG; }
-          msg_ptr = p->payload;
-          plen += p->len;
-        }
-        else
-        {
-          /* next octet in same pbuf */
-          msg_ptr++;
-        }
-      }
-      /* (only) one least significant octet */
-      *msg_ptr = value;
-      return ERR_OK;
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Encodes s32_t integer into a pbuf chained ASN1 msg.
- *
- * @param p points to output pbuf to encode value into
- * @param ofs points to the offset within the pbuf chain
- * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
- * @param value is the host order s32_t value to be encoded
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
- *
- * @see snmp_asn1_enc_s32t_cnt()
- */
-err_t
-snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-
-      while (octets_needed > 1)
-      {
-        octets_needed--;
-        *msg_ptr = value >> (octets_needed << 3);
-        ofs += 1;
-        if (ofs >= plen)
-        {
-          /* next octet in next pbuf */
-          p = p->next;
-          if (p == NULL) { return ERR_ARG; }
-          msg_ptr = p->payload;
-          plen += p->len;
-        }
-        else
-        {
-          /* next octet in same pbuf */
-          msg_ptr++;
-        }
-      }
-      /* (only) one least significant octet */
-      *msg_ptr = value;
-      return ERR_OK;
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Encodes object identifier into a pbuf chained ASN1 msg.
- *
- * @param p points to output pbuf to encode oid into
- * @param ofs points to the offset within the pbuf chain
- * @param ident_len object identifier array length
- * @param ident points to object identifier array
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
- */
-err_t
-snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-
-      if (ident_len > 1)
-      {
-        if ((ident[0] == 1) && (ident[1] == 3))
-        {
-          /* compressed (most common) prefix .iso.org */
-          *msg_ptr = 0x2b;
-        }
-        else
-        {
-          /* calculate prefix */
-          *msg_ptr = (ident[0] * 40) + ident[1];
-        }
-        ofs += 1;
-        if (ofs >= plen)
-        {
-          /* next octet in next pbuf */
-          p = p->next;
-          if (p == NULL) { return ERR_ARG; }
-          msg_ptr = p->payload;
-          plen += p->len;
-        }
-        else
-        {
-          /* next octet in same pbuf */
-          msg_ptr++;
-        }
-        ident_len -= 2;
-        ident += 2;
-      }
-      else
-      {
-/* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression??  */
-        /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
-        return ERR_ARG;
-      }
-      while (ident_len > 0)
-      {
-        s32_t sub_id;
-        u8_t shift, tail;
-
-        ident_len--;
-        sub_id = *ident;
-        tail = 0;
-        shift = 28;
-        while(shift > 0)
-        {
-          u8_t code;
-
-          code = sub_id >> shift;
-          if ((code != 0) || (tail != 0))
-          {
-            tail = 1;
-            *msg_ptr = code | 0x80;
-            ofs += 1;
-            if (ofs >= plen)
-            {
-              /* next octet in next pbuf */
-              p = p->next;
-              if (p == NULL) { return ERR_ARG; }
-              msg_ptr = p->payload;
-              plen += p->len;
-            }
-            else
-            {
-              /* next octet in same pbuf */
-              msg_ptr++;
-            }
-          }
-          shift -= 7;
-        }
-        *msg_ptr = (u8_t)sub_id & 0x7F;
-        if (ident_len > 0)
-        {
-          ofs += 1;
-          if (ofs >= plen)
-          {
-            /* next octet in next pbuf */
-            p = p->next;
-            if (p == NULL) { return ERR_ARG; }
-            msg_ptr = p->payload;
-            plen += p->len;
-          }
-          else
-          {
-            /* next octet in same pbuf */
-            msg_ptr++;
-          }
-        }
-        /* proceed to next sub-identifier */
-        ident++;
-      }
-      return ERR_OK;
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-/**
- * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
- *
- * @param p points to output pbuf to encode raw data into
- * @param ofs points to the offset within the pbuf chain
- * @param raw_len raw data length
- * @param raw points raw data
- * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
- */
-err_t
-snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
-{
-  u16_t plen, base;
-  u8_t *msg_ptr;
-
-  plen = 0;
-  while (p != NULL)
-  {
-    base = plen;
-    plen += p->len;
-    if (ofs < plen)
-    {
-      msg_ptr = p->payload;
-      msg_ptr += ofs - base;
-
-      while (raw_len > 1)
-      {
-        /* copy raw_len - 1 octets */
-        raw_len--;
-        *msg_ptr = *raw;
-        raw++;
-        ofs += 1;
-        if (ofs >= plen)
-        {
-          /* next octet in next pbuf */
-          p = p->next;
-          if (p == NULL) { return ERR_ARG; }
-          msg_ptr = p->payload;
-          plen += p->len;
-        }
-        else
-        {
-          /* next octet in same pbuf */
-          msg_ptr++;
-        }
-      }
-      if (raw_len > 0)
-      {
-        /* copy last or single octet */
-        *msg_ptr = *raw;
-      }
-      return ERR_OK;
-    }
-    p = p->next;
-  }
-  /* p == NULL, ofs >= plen */
-  return ERR_ARG;
-}
-
-#endif /* LWIP_SNMP */
+/**

+ * @file

+ * Abstract Syntax Notation One (ISO 8824, 8825) encoding

+ *

+ * @todo not optimised (yet), favor correctness over speed, favor speed over size

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * 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: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP

+#include "lwip/snmp_asn1.h"

+

+/**

+ * Returns octet count for length.

+ *

+ * @param length

+ * @param octets_needed points to the return value

+ */

+void

+snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)

+{

+  if (length < 0x80U)

+  {

+    *octets_needed = 1;

+  }

+  else if (length < 0x100U)

+  {

+    *octets_needed = 2;

+  }

+  else

+  {

+    *octets_needed = 3;

+  }

+}

+

+/**

+ * Returns octet count for an u32_t.

+ *

+ * @param value

+ * @param octets_needed points to the return value

+ *

+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded

+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value

+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!

+ */

+void

+snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)

+{

+  if (value < 0x80UL)

+  {

+    *octets_needed = 1;

+  }

+  else if (value < 0x8000UL)

+  {

+    *octets_needed = 2;

+  }

+  else if (value < 0x800000UL)

+  {

+    *octets_needed = 3;

+  }

+  else if (value < 0x80000000UL)

+  {

+    *octets_needed = 4;

+  }

+  else

+  {

+    *octets_needed = 5;

+  }

+}

+

+/**

+ * Returns octet count for an s32_t.

+ *

+ * @param value

+ * @param octets_needed points to the return value

+ *

+ * @note ASN coded integers are _always_ signed.

+ */

+void

+snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)

+{

+  if (value < 0)

+  {

+    value = ~value;

+  }

+  if (value < 0x80L)

+  {

+    *octets_needed = 1;

+  }

+  else if (value < 0x8000L)

+  {

+    *octets_needed = 2;

+  }

+  else if (value < 0x800000L)

+  {

+    *octets_needed = 3;

+  }

+  else

+  {

+    *octets_needed = 4;

+  }

+}

+

+/**

+ * Returns octet count for an object identifier.

+ *

+ * @param ident_len object identifier array length

+ * @param ident points to object identifier array

+ * @param octets_needed points to the return value

+ */

+void

+snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)

+{

+  s32_t sub_id;

+  u8_t cnt;

+

+  cnt = 0;

+  if (ident_len > 1)

+  {

+    /* compressed prefix in one octet */

+    cnt++;

+    ident_len -= 2;

+    ident += 2;

+  }

+  while(ident_len > 0)

+  {

+    ident_len--;

+    sub_id = *ident;

+

+    sub_id >>= 7;

+    cnt++;

+    while(sub_id > 0)

+    {

+      sub_id >>= 7;

+      cnt++;

+    }

+    ident++;

+  }

+  *octets_needed = cnt;

+}

+

+/**

+ * Encodes ASN type field into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode value into

+ * @param ofs points to the offset within the pbuf chain

+ * @param type input ASN1 type

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ */

+err_t

+snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+      *msg_ptr = type;

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes host order length field into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode length into

+ * @param ofs points to the offset within the pbuf chain

+ * @param length is the host order length to be encoded

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ */

+err_t

+snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      if (length < 0x80)

+      {

+        *msg_ptr = length;

+        return ERR_OK;

+      }

+      else if (length < 0x100)

+      {

+        *msg_ptr = 0x81;

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+        *msg_ptr = length;

+        return ERR_OK;

+      }

+      else

+      {

+        u8_t i;

+

+        /* length >= 0x100 && length <= 0xFFFF */

+        *msg_ptr = 0x82;

+        i = 2;

+        while (i > 0)

+        {

+          i--;

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+          if (i == 0)

+          {

+            /* least significant length octet */

+            *msg_ptr = length;

+          }

+          else

+          {

+            /* most significant length octet */

+            *msg_ptr = length >> 8;

+          }

+        }

+        return ERR_OK;

+      }

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode value into

+ * @param ofs points to the offset within the pbuf chain

+ * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())

+ * @param value is the host order u32_t value to be encoded

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ *

+ * @see snmp_asn1_enc_u32t_cnt()

+ */

+err_t

+snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      if (octets_needed == 5)

+      {

+        /* not enough bits in 'value' add leading 0x00 */

+        octets_needed--;

+        *msg_ptr = 0x00;

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      while (octets_needed > 1)

+      {

+        octets_needed--;

+        *msg_ptr = value >> (octets_needed << 3);

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      /* (only) one least significant octet */

+      *msg_ptr = value;

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes s32_t integer into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode value into

+ * @param ofs points to the offset within the pbuf chain

+ * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())

+ * @param value is the host order s32_t value to be encoded

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ *

+ * @see snmp_asn1_enc_s32t_cnt()

+ */

+err_t

+snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      while (octets_needed > 1)

+      {

+        octets_needed--;

+        *msg_ptr = value >> (octets_needed << 3);

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      /* (only) one least significant octet */

+      *msg_ptr = value;

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes object identifier into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode oid into

+ * @param ofs points to the offset within the pbuf chain

+ * @param ident_len object identifier array length

+ * @param ident points to object identifier array

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ */

+err_t

+snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      if (ident_len > 1)

+      {

+        if ((ident[0] == 1) && (ident[1] == 3))

+        {

+          /* compressed (most common) prefix .iso.org */

+          *msg_ptr = 0x2b;

+        }

+        else

+        {

+          /* calculate prefix */

+          *msg_ptr = (ident[0] * 40) + ident[1];

+        }

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+        ident_len -= 2;

+        ident += 2;

+      }

+      else

+      {

+/* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression??  */

+        /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */

+        return ERR_ARG;

+      }

+      while (ident_len > 0)

+      {

+        s32_t sub_id;

+        u8_t shift, tail;

+

+        ident_len--;

+        sub_id = *ident;

+        tail = 0;

+        shift = 28;

+        while(shift > 0)

+        {

+          u8_t code;

+

+          code = sub_id >> shift;

+          if ((code != 0) || (tail != 0))

+          {

+            tail = 1;

+            *msg_ptr = code | 0x80;

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+          }

+          shift -= 7;

+        }

+        *msg_ptr = (u8_t)sub_id & 0x7F;

+        if (ident_len > 0)

+        {

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+        }

+        /* proceed to next sub-identifier */

+        ident++;

+      }

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode raw data into

+ * @param ofs points to the offset within the pbuf chain

+ * @param raw_len raw data length

+ * @param raw points raw data

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ */

+err_t

+snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      while (raw_len > 1)

+      {

+        /* copy raw_len - 1 octets */

+        raw_len--;

+        *msg_ptr = *raw;

+        raw++;

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      if (raw_len > 0)

+      {

+        /* copy last or single octet */

+        *msg_ptr = *raw;

+      }

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+#endif /* LWIP_SNMP */

diff --git a/Demo/Common/ethernet/lwIP/core/snmp/mib2.c b/Demo/Common/ethernet/lwIP/core/snmp/mib2.c
index 3e478ab..035c8b1 100644
--- a/Demo/Common/ethernet/lwIP/core/snmp/mib2.c
+++ b/Demo/Common/ethernet/lwIP/core/snmp/mib2.c
@@ -1,4021 +1,4021 @@
-/**
- * @file
- * Management Information Base II (RFC1213) objects and functions.
- *
- * @note the object identifiers for this MIB-2 and private MIB tree
- * must be kept in sorted ascending order. This to ensure correct getnext operation.
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * 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: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#include "arch/cc.h"
-#include "lwip/opt.h"
-
-#if LWIP_SNMP
-#include "lwip/snmp.h"
-#include "lwip/netif.h"
-#include "netif/etharp.h"
-#include "lwip/ip.h"
-#include "lwip/ip_frag.h"
-#include "lwip/tcp.h"
-#include "lwip/udp.h"
-#include "lwip/snmp_asn1.h"
-#include "lwip/snmp_structs.h"
-
-/**
- * IANA assigned enterprise ID for lwIP is 26381
- * @see http://www.iana.org/assignments/enterprise-numbers
- *
- * @note this enterprise ID is assigned to the lwIP project,
- * all object identifiers living under this ID are assigned
- * by the lwIP maintainers (contact Christiaan Simons)!
- * @note don't change this define, use snmp_set_sysobjid()
- *
- * If you need to create your own private MIB you'll need
- * to apply for your own enterprise ID with IANA:
- * http://www.iana.org/numbers.html
- */
-#define SNMP_ENTERPRISE_ID 26381
-#define SNMP_SYSOBJID_LEN 7
-#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID}
-
-#ifndef SNMP_SYSSERVICES
-#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2))
-#endif
-
-static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void system_get_value(struct obj_def *od, u16_t len, void *value);
-static u8_t system_set_test(struct obj_def *od, u16_t len, void *value);
-static void system_set_value(struct obj_def *od, u16_t len, void *value);
-static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void interfaces_get_value(struct obj_def *od, u16_t len, void *value);
-static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void ifentry_get_value(struct obj_def *od, u16_t len, void *value);
-static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void atentry_get_value(struct obj_def *od, u16_t len, void *value);
-static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void ip_get_value(struct obj_def *od, u16_t len, void *value);
-static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value);
-static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value);
-static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value);
-static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value);
-static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void icmp_get_value(struct obj_def *od, u16_t len, void *value);
-#if LWIP_TCP
-static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void tcp_get_value(struct obj_def *od, u16_t len, void *value);
-static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value);
-#endif
-static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void udp_get_value(struct obj_def *od, u16_t len, void *value);
-static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void udpentry_get_value(struct obj_def *od, u16_t len, void *value);
-static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-static void snmp_get_value(struct obj_def *od, u16_t len, void *value);
-static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value);
-static void snmp_set_value(struct obj_def *od, u16_t len, void *value);
-
-
-/* snmp .1.3.6.1.2.1.11 */
-const mib_scalar_node snmp_scalar = {
-  &snmp_get_object_def,
-  &snmp_get_value,
-  &snmp_set_test,
-  &snmp_set_value,
-  MIB_NODE_SC,
-  0
-};
-const s32_t snmp_ids[28] = {
-  1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-  17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30
-};
-struct mib_node* const snmp_nodes[28] = {
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,
-  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar
-};
-const struct mib_array_node snmp = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  28,
-  snmp_ids,
-  snmp_nodes
-};
-
-/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */
-/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */
-/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */
-
-/* udp .1.3.6.1.2.1.7 */
-/** index root node for udpTable */
-struct mib_list_rootnode udp_root = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_LR,
-  0,
-  NULL,
-  NULL,
-  0
-};
-const s32_t udpentry_ids[2] = { 1, 2 };
-struct mib_node* const udpentry_nodes[2] = {
-  (struct mib_node* const)&udp_root, (struct mib_node* const)&udp_root,
-};
-const struct mib_array_node udpentry = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  2,
-  udpentry_ids,
-  udpentry_nodes
-};
-
-s32_t udptable_id = 1;
-struct mib_node* udptable_node = (struct mib_node* const)&udpentry;
-struct mib_ram_array_node udptable = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_RA,
-  0,
-  &udptable_id,
-  &udptable_node
-};
-
-const mib_scalar_node udp_scalar = {
-  &udp_get_object_def,
-  &udp_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_SC,
-  0
-};
-const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 };
-struct mib_node* const udp_nodes[5] = {
-  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,
-  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,
-  (struct mib_node* const)&udptable
-};
-const struct mib_array_node udp = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  5,
-  udp_ids,
-  udp_nodes
-};
-
-/* tcp .1.3.6.1.2.1.6 */
-#if LWIP_TCP
-/* only if the TCP protocol is available may implement this group */
-/** index root node for tcpConnTable */
-struct mib_list_rootnode tcpconntree_root = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_LR,
-  0,
-  NULL,
-  NULL,
-  0
-};
-const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 };
-struct mib_node* const tcpconnentry_nodes[5] = {
-  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,
-  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,
-  (struct mib_node* const)&tcpconntree_root
-};
-const struct mib_array_node tcpconnentry = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  5,
-  tcpconnentry_ids,
-  tcpconnentry_nodes
-};
-
-s32_t tcpconntable_id = 1;
-struct mib_node* tcpconntable_node = (struct mib_node* const)&tcpconnentry;
-struct mib_ram_array_node tcpconntable = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_RA,
-/** @todo update maxlength when inserting / deleting from table
-   0 when table is empty, 1 when more than one entry */
-  0,
-  &tcpconntable_id,
-  &tcpconntable_node
-};
-
-const mib_scalar_node tcp_scalar = {
-  &tcp_get_object_def,
-  &tcp_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_SC,
-  0
-};
-const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
-struct mib_node* const tcp_nodes[15] = {
-  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,
-  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,
-  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,
-  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,
-  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,
-  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,
-  (struct mib_node* const)&tcpconntable, (struct mib_node* const)&tcp_scalar,
-  (struct mib_node* const)&tcp_scalar
-};
-const struct mib_array_node tcp = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  15,
-  tcp_ids,
-  tcp_nodes
-};
-#endif
-
-/* icmp .1.3.6.1.2.1.5 */
-const mib_scalar_node icmp_scalar = {
-  &icmp_get_object_def,
-  &icmp_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_SC,
-  0
-};
-const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
-struct mib_node* const icmp_nodes[26] = {
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,
-  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar
-};
-const struct mib_array_node icmp = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  26,
-  icmp_ids,
-  icmp_nodes
-};
-
-/** index root node for ipNetToMediaTable */
-struct mib_list_rootnode ipntomtree_root = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_LR,
-  0,
-  NULL,
-  NULL,
-  0
-};
-const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 };
-struct mib_node* const ipntomentry_nodes[4] = {
-  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root,
-  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root
-};
-const struct mib_array_node ipntomentry = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  4,
-  ipntomentry_ids,
-  ipntomentry_nodes
-};
-
-s32_t ipntomtable_id = 1;
-struct mib_node* ipntomtable_node = (struct mib_node* const)&ipntomentry;
-struct mib_ram_array_node ipntomtable = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_RA,
-  0,
-  &ipntomtable_id,
-  &ipntomtable_node
-};
-
-/** index root node for ipRouteTable */
-struct mib_list_rootnode iprtetree_root = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_LR,
-  0,
-  NULL,
-  NULL,
-  0
-};
-const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
-struct mib_node* const iprteentry_nodes[13] = {
-  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,
-  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,
-  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,
-  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,
-  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,
-  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,
-  (struct mib_node* const)&iprtetree_root
-};
-const struct mib_array_node iprteentry = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  13,
-  iprteentry_ids,
-  iprteentry_nodes
-};
-
-s32_t iprtetable_id = 1;
-struct mib_node* iprtetable_node = (struct mib_node* const)&iprteentry;
-struct mib_ram_array_node iprtetable = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_RA,
-  0,
-  &iprtetable_id,
-  &iprtetable_node
-};
-
-/** index root node for ipAddrTable */
-struct mib_list_rootnode ipaddrtree_root = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_LR,
-  0,
-  NULL,
-  NULL,
-  0
-};
-const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 };
-struct mib_node* const ipaddrentry_nodes[5] = {
-  (struct mib_node* const)&ipaddrtree_root,
-  (struct mib_node* const)&ipaddrtree_root,
-  (struct mib_node* const)&ipaddrtree_root,
-  (struct mib_node* const)&ipaddrtree_root,
-  (struct mib_node* const)&ipaddrtree_root
-};
-const struct mib_array_node ipaddrentry = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  5,
-  ipaddrentry_ids,
-  ipaddrentry_nodes
-};
-
-s32_t ipaddrtable_id = 1;
-struct mib_node* ipaddrtable_node = (struct mib_node* const)&ipaddrentry;
-struct mib_ram_array_node ipaddrtable = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_RA,
-  0,
-  &ipaddrtable_id,
-  &ipaddrtable_node
-};
-
-/* ip .1.3.6.1.2.1.4 */
-const mib_scalar_node ip_scalar = {
-  &ip_get_object_def,
-  &ip_get_value,
-  &ip_set_test,
-  &noleafs_set_value,
-  MIB_NODE_SC,
-  0
-};
-const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
-struct mib_node* const ip_nodes[23] = {
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,
-  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ipaddrtable,
-  (struct mib_node* const)&iprtetable, (struct mib_node* const)&ipntomtable,
-  (struct mib_node* const)&ip_scalar
-};
-const struct mib_array_node ip = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  23,
-  ip_ids,
-  ip_nodes
-};
-
-/** index root node for atTable */
-struct mib_list_rootnode arptree_root = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_LR,
-  0,
-  NULL,
-  NULL,
-  0
-};
-const s32_t atentry_ids[3] = { 1, 2, 3 };
-struct mib_node* const atentry_nodes[3] = {
-  (struct mib_node* const)&arptree_root,
-  (struct mib_node* const)&arptree_root,
-  (struct mib_node* const)&arptree_root
-};
-const struct mib_array_node atentry = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  3,
-  atentry_ids,
-  atentry_nodes
-};
-
-const s32_t attable_id = 1;
-struct mib_node* const attable_node = (struct mib_node* const)&atentry;
-const struct mib_array_node attable = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  1,
-  &attable_id,
-  &attable_node
-};
-
-/* at .1.3.6.1.2.1.3 */
-s32_t at_id = 1;
-struct mib_node* at_node = (struct mib_node* const)&attable;
-struct mib_ram_array_node at = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_RA,
-  0,
-  &at_id,
-  &at_node
-};
-
-/** index root node for ifTable */
-struct mib_list_rootnode iflist_root = {
-  &ifentry_get_object_def,
-  &ifentry_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_LR,
-  0,
-  NULL,
-  NULL,
-  0
-};
-const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 };
-struct mib_node* const ifentry_nodes[22] = {
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,
-  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root
-};
-const struct mib_array_node ifentry = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  22,
-  ifentry_ids,
-  ifentry_nodes
-};
-
-s32_t iftable_id = 1;
-struct mib_node* iftable_node = (struct mib_node* const)&ifentry;
-struct mib_ram_array_node iftable = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_RA,
-  0,
-  &iftable_id,
-  &iftable_node
-};
-
-/* interfaces .1.3.6.1.2.1.2 */
-const mib_scalar_node interfaces_scalar = {
-  &interfaces_get_object_def,
-  &interfaces_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_SC,
-  0
-};
-const s32_t interfaces_ids[2] = { 1, 2 };
-struct mib_node* const interfaces_nodes[2] = {
-  (struct mib_node* const)&interfaces_scalar, (struct mib_node* const)&iftable
-};
-const struct mib_array_node interfaces = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  2,
-  interfaces_ids,
-  interfaces_nodes
-};
-
-
-/*             0 1 2 3 4 5 6 */
-/* system .1.3.6.1.2.1.1 */
-const mib_scalar_node sys_tem_scalar = {
-  &system_get_object_def,
-  &system_get_value,
-  &system_set_test,
-  &system_set_value,
-  MIB_NODE_SC,
-  0
-};
-const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 };
-struct mib_node* const sys_tem_nodes[7] = {
-  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,
-  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,
-  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,
-  (struct mib_node* const)&sys_tem_scalar
-};
-/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */
-const struct mib_array_node sys_tem = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  7,
-  sys_tem_ids,
-  sys_tem_nodes
-};
-
-/* mib-2 .1.3.6.1.2.1 */
-#if LWIP_TCP
-#define MIB2_GROUPS 8
-#else
-#define MIB2_GROUPS 7
-#endif
-const s32_t mib2_ids[MIB2_GROUPS] =
-{
-  1,
-  2,
-  3,
-  4,
-  5,
-#if LWIP_TCP
-  6,
-#endif
-  7,
-  11
-};
-struct mib_node* const mib2_nodes[MIB2_GROUPS] = {
-  (struct mib_node* const)&sys_tem,
-  (struct mib_node* const)&interfaces,
-  (struct mib_node* const)&at,
-  (struct mib_node* const)&ip,
-  (struct mib_node* const)&icmp,
-#if LWIP_TCP
-  (struct mib_node* const)&tcp,
-#endif
-  (struct mib_node* const)&udp,
-  (struct mib_node* const)&snmp
-};
-
-const struct mib_array_node mib2 = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  MIB2_GROUPS,
-  mib2_ids,
-  mib2_nodes
-};
-
-/* mgmt .1.3.6.1.2 */
-const s32_t mgmt_ids[1] = { 1 };
-struct mib_node* const mgmt_nodes[1] = { (struct mib_node* const)&mib2 };
-const struct mib_array_node mgmt = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  1,
-  mgmt_ids,
-  mgmt_nodes
-};
-
-/* internet .1.3.6.1 */
-#if SNMP_PRIVATE_MIB
-s32_t internet_ids[2] = { 2, 4 };
-struct mib_node* const internet_nodes[2] = { (struct mib_node* const)&mgmt, (struct mib_node* const)&private };
-const struct mib_array_node internet = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  2,
-  internet_ids,
-  internet_nodes
-};
-#else
-const s32_t internet_ids[1] = { 2 };
-struct mib_node* const internet_nodes[1] = { (struct mib_node* const)&mgmt };
-const struct mib_array_node internet = {
-  &noleafs_get_object_def,
-  &noleafs_get_value,
-  &noleafs_set_test,
-  &noleafs_set_value,
-  MIB_NODE_AR,
-  1,
-  internet_ids,
-  internet_nodes
-};
-#endif
-
-/** mib-2.system.sysObjectID  */
-static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID};
-/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */
-static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}};
-/** mib-2.system.sysServices */
-static const s32_t sysservices = SNMP_SYSSERVICES;
-
-/** mib-2.system.sysDescr */
-static const u8_t sysdescr_len_default = 4;
-static const u8_t sysdescr_default[] = "lwIP";
-static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default;
-static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0];
-/** mib-2.system.sysContact */
-static const u8_t syscontact_len_default = 0;
-static const u8_t syscontact_default[] = "";
-static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default;
-static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0];
-/** mib-2.system.sysName */
-static const u8_t sysname_len_default = 8;
-static const u8_t sysname_default[] = "FQDN-unk";
-static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default;
-static u8_t* sysname_ptr = (u8_t*)&sysname_default[0];
-/** mib-2.system.sysLocation */
-static const u8_t syslocation_len_default = 0;
-static const u8_t syslocation_default[] = "";
-static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default;
-static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0];
-/** mib-2.snmp.snmpEnableAuthenTraps */
-static const u8_t snmpenableauthentraps_default = 2; /* disabled */
-static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default;
-
-/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */
-static const struct snmp_obj_id ifspecific = {2, {0, 0}};
-/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */
-static const struct snmp_obj_id iprouteinfo = {2, {0, 0}};
-
-
-
-/* mib-2.system counter(s) */
-static u32_t sysuptime = 0;
-
-/* mib-2.ip counter(s) */
-static u32_t ipinreceives = 0,
-             ipinhdrerrors = 0,
-             ipinaddrerrors = 0,
-             ipforwdatagrams = 0,
-             ipinunknownprotos = 0,
-             ipindiscards = 0,
-             ipindelivers = 0,
-             ipoutrequests = 0,
-             ipoutdiscards = 0,
-             ipoutnoroutes = 0,
-             ipreasmreqds = 0,
-             ipreasmoks = 0,
-             ipreasmfails = 0,
-             ipfragoks = 0,
-             ipfragfails = 0,
-             ipfragcreates = 0,
-             iproutingdiscards = 0;
-/* mib-2.icmp counter(s) */
-static u32_t icmpinmsgs = 0,
-             icmpinerrors = 0,
-             icmpindestunreachs = 0,
-             icmpintimeexcds = 0,
-             icmpinparmprobs = 0,
-             icmpinsrcquenchs = 0,
-             icmpinredirects = 0,
-             icmpinechos = 0,
-             icmpinechoreps = 0,
-             icmpintimestamps = 0,
-             icmpintimestampreps = 0,
-             icmpinaddrmasks = 0,
-             icmpinaddrmaskreps = 0,
-             icmpoutmsgs = 0,
-             icmpouterrors = 0,
-             icmpoutdestunreachs = 0,
-             icmpouttimeexcds = 0,
-             icmpoutparmprobs = 0,
-             icmpoutsrcquenchs = 0,
-             icmpoutredirects = 0,
-             icmpoutechos = 0,
-             icmpoutechoreps = 0,
-             icmpouttimestamps = 0,
-             icmpouttimestampreps = 0,
-             icmpoutaddrmasks = 0,
-             icmpoutaddrmaskreps = 0;
-/* mib-2.tcp counter(s) */
-static u32_t tcpactiveopens = 0,
-             tcppassiveopens = 0,
-             tcpattemptfails = 0,
-             tcpestabresets = 0,
-             tcpinsegs = 0,
-             tcpoutsegs = 0,
-             tcpretranssegs = 0,
-             tcpinerrs = 0,
-             tcpoutrsts = 0;
-/* mib-2.udp counter(s) */
-static u32_t udpindatagrams = 0,
-             udpnoports = 0,
-             udpinerrors = 0,
-             udpoutdatagrams = 0;
-/* mib-2.snmp counter(s) */
-static u32_t snmpinpkts = 0,
-             snmpoutpkts = 0,
-             snmpinbadversions = 0,
-             snmpinbadcommunitynames = 0,
-             snmpinbadcommunityuses = 0,
-             snmpinasnparseerrs = 0,
-             snmpintoobigs = 0,
-             snmpinnosuchnames = 0,
-             snmpinbadvalues = 0,
-             snmpinreadonlys = 0,
-             snmpingenerrs = 0,
-             snmpintotalreqvars = 0,
-             snmpintotalsetvars = 0,
-             snmpingetrequests = 0,
-             snmpingetnexts = 0,
-             snmpinsetrequests = 0,
-             snmpingetresponses = 0,
-             snmpintraps = 0,
-             snmpouttoobigs = 0,
-             snmpoutnosuchnames = 0,
-             snmpoutbadvalues = 0,
-             snmpoutgenerrs = 0,
-             snmpoutgetrequests = 0,
-             snmpoutgetnexts = 0,
-             snmpoutsetrequests = 0,
-             snmpoutgetresponses = 0,
-             snmpouttraps = 0;
-
-
-
-/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */
-/**
- * Copy octet string.
- *
- * @param dst points to destination
- * @param src points to source
- * @param n number of octets to copy.
- */
-void ocstrncpy(u8_t *dst, u8_t *src, u8_t n)
-{
-  while (n > 0)
-  {
-    n--;
-    *dst++ = *src++;
-  }
-}
-
-/**
- * Copy object identifier (s32_t) array.
- *
- * @param dst points to destination
- * @param src points to source
- * @param n number of sub identifiers to copy.
- */
-void objectidncpy(s32_t *dst, s32_t *src, u8_t n)
-{
-  while(n > 0)
-  {
-    n--;
-    *dst++ = *src++;
-  }
-}
-
-/**
- * Initializes sysDescr pointers.
- *
- * @param str if non-NULL then copy str pointer
- * @param strlen points to string length, excluding zero terminator
- */
-void snmp_set_sysdesr(u8_t *str, u8_t *strlen)
-{
-  if (str != NULL)
-  {
-    sysdescr_ptr = str;
-    sysdescr_len_ptr = strlen;
-  }
-}
-
-void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid)
-{
-  *oid = &sysobjid;
-}
-
-/**
- * Initializes sysObjectID value.
- *
- * @param oid points to stuct snmp_obj_id to copy
- */
-void snmp_set_sysobjid(struct snmp_obj_id *oid)
-{
-  sysobjid = *oid;
-}
-
-/**
- * Must be called at regular 10 msec interval from a timer interrupt
- * or signal handler depending on your runtime environment.
- */
-void snmp_inc_sysuptime(void)
-{
-  sysuptime++;
-}
-
-void snmp_get_sysuptime(u32_t *value)
-{
-  *value = sysuptime;
-}
-
-/**
- * Initializes sysContact pointers,
- * e.g. ptrs to non-volatile memory external to lwIP.
- *
- * @param str if non-NULL then copy str pointer
- * @param strlen points to string length, excluding zero terminator
- */
-void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen)
-{
-  if (ocstr != NULL)
-  {
-    syscontact_ptr = ocstr;
-    syscontact_len_ptr = ocstrlen;
-  }
-}
-
-/**
- * Initializes sysName pointers,
- * e.g. ptrs to non-volatile memory external to lwIP.
- *
- * @param str if non-NULL then copy str pointer
- * @param strlen points to string length, excluding zero terminator
- */
-void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen)
-{
-  if (ocstr != NULL)
-  {
-    sysname_ptr = ocstr;
-    sysname_len_ptr = ocstrlen;
-  }
-}
-
-/**
- * Initializes sysLocation pointers,
- * e.g. ptrs to non-volatile memory external to lwIP.
- *
- * @param str if non-NULL then copy str pointer
- * @param strlen points to string length, excluding zero terminator
- */
-void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen)
-{
-  if (ocstr != NULL)
-  {
-    syslocation_ptr = ocstr;
-    syslocation_len_ptr = ocstrlen;
-  }
-}
-
-
-void snmp_add_ifinoctets(struct netif *ni, u32_t value)
-{
-  ni->ifinoctets += value;
-}
-
-void snmp_inc_ifinucastpkts(struct netif *ni)
-{
-  (ni->ifinucastpkts)++;
-}
-
-void snmp_inc_ifinnucastpkts(struct netif *ni)
-{
-  (ni->ifinnucastpkts)++;
-}
-
-void snmp_inc_ifindiscards(struct netif *ni)
-{
-  (ni->ifindiscards)++;
-}
-
-void snmp_add_ifoutoctets(struct netif *ni, u32_t value)
-{
-  ni->ifoutoctets += value;
-}
-
-void snmp_inc_ifoutucastpkts(struct netif *ni)
-{
-  (ni->ifoutucastpkts)++;
-}
-
-void snmp_inc_ifoutnucastpkts(struct netif *ni)
-{
-  (ni->ifoutnucastpkts)++;
-}
-
-void snmp_inc_ifoutdiscards(struct netif *ni)
-{
-  (ni->ifoutdiscards)++;
-}
-
-void snmp_inc_iflist(void)
-{
-  struct mib_list_node *if_node = NULL;
-
-  snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node);
-  /* enable getnext traversal on filled table */
-  iftable.maxlength = 1;
-}
-
-void snmp_dec_iflist(void)
-{
-  snmp_mib_node_delete(&iflist_root, iflist_root.tail);
-  /* disable getnext traversal on empty table */
-  if(iflist_root.count == 0) iftable.maxlength = 0;
-}
-
-/**
- * Inserts ARP table indexes (.xIfIndex.xNetAddress)
- * into arp table index trees (both atTable and ipNetToMediaTable).
- */
-void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip)
-{
-  struct mib_list_rootnode *at_rn;
-  struct mib_list_node *at_node;
-  struct ip_addr hip;
-  s32_t arpidx[5];
-  u8_t level, tree;
-
-  LWIP_ASSERT("ni != NULL", ni != NULL);
-  snmp_netiftoifindex(ni, &arpidx[0]);
-  hip.addr = ntohl(ip->addr);
-  snmp_iptooid(&hip, &arpidx[1]);
-
-  for (tree = 0; tree < 2; tree++)
-  {
-    if (tree == 0)
-    {
-      at_rn = &arptree_root;
-    }
-    else
-    {
-      at_rn = &ipntomtree_root;
-    }
-    for (level = 0; level < 5; level++)
-    {
-      at_node = NULL;
-      snmp_mib_node_insert(at_rn, arpidx[level], &at_node);
-      if ((level != 4) && (at_node != NULL))
-      {
-        if (at_node->nptr == NULL)
-        {
-          at_rn = snmp_mib_lrn_alloc();
-          at_node->nptr = (struct mib_node*)at_rn;
-          if (at_rn != NULL)
-          {
-            if (level == 3)
-            {
-              if (tree == 0)
-              {
-                at_rn->get_object_def = atentry_get_object_def;
-                at_rn->get_value = atentry_get_value;
-              }
-              else
-              {
-                at_rn->get_object_def = ip_ntomentry_get_object_def;
-                at_rn->get_value = ip_ntomentry_get_value;
-              }
-              at_rn->set_test = noleafs_set_test;
-              at_rn->set_value = noleafs_set_value;
-            }
-          }
-          else
-          {
-            /* at_rn == NULL, malloc failure */
-            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full"));
-            break;
-          }
-        }
-        else
-        {
-          at_rn = (struct mib_list_rootnode*)at_node->nptr;
-        }
-      }
-    }
-  }
-  /* enable getnext traversal on filled tables */
-  at.maxlength = 1;
-  ipntomtable.maxlength = 1;
-}
-
-/**
- * Removes ARP table indexes (.xIfIndex.xNetAddress)
- * from arp table index trees.
- */
-void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip)
-{
-  struct mib_list_rootnode *at_rn, *next, *del_rn[5];
-  struct mib_list_node *at_n, *del_n[5];
-  struct ip_addr hip;
-  s32_t arpidx[5];
-  u8_t fc, tree, level, del_cnt;
-
-  snmp_netiftoifindex(ni, &arpidx[0]);
-  hip.addr = ntohl(ip->addr);
-  snmp_iptooid(&hip, &arpidx[1]);
-
-  for (tree = 0; tree < 2; tree++)
-  {
-    /* mark nodes for deletion */
-    if (tree == 0)
-    {
-      at_rn = &arptree_root;
-    }
-    else
-    {
-      at_rn = &ipntomtree_root;
-    }
-    level = 0;
-    del_cnt = 0;
-    while ((level < 5) && (at_rn != NULL))
-    {
-      fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n);
-      if (fc == 0)
-      {
-        /* arpidx[level] does not exist */
-        del_cnt = 0;
-        at_rn = NULL;
-      }
-      else if (fc == 1)
-      {
-        del_rn[del_cnt] = at_rn;
-        del_n[del_cnt] = at_n;
-        del_cnt++;
-        at_rn = (struct mib_list_rootnode*)(at_n->nptr);
-      }
-      else if (fc == 2)
-      {
-        /* reset delete (2 or more childs) */
-        del_cnt = 0;
-        at_rn = (struct mib_list_rootnode*)(at_n->nptr);
-      }
-      level++;
-    }
-    /* delete marked index nodes */
-    while (del_cnt > 0)
-    {
-      del_cnt--;
-
-      at_rn = del_rn[del_cnt];
-      at_n = del_n[del_cnt];
-
-      next = snmp_mib_node_delete(at_rn, at_n);
-      if (next != NULL)
-      {
-        LWIP_ASSERT("next_count == 0",next->count == 0);
-        snmp_mib_lrn_free(next);
-      }
-    }
-  }
-  /* disable getnext traversal on empty tables */
-  if(arptree_root.count == 0) at.maxlength = 0;
-  if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0;
-}
-
-void snmp_inc_ipinreceives(void)
-{
-  ipinreceives++;
-}
-
-void snmp_inc_ipinhdrerrors(void)
-{
-  ipinhdrerrors++;
-}
-
-void snmp_inc_ipinaddrerrors(void)
-{
-  ipinaddrerrors++;
-}
-
-void snmp_inc_ipforwdatagrams(void)
-{
-  ipforwdatagrams++;
-}
-
-void snmp_inc_ipinunknownprotos(void)
-{
-  ipinunknownprotos++;
-}
-
-void snmp_inc_ipindiscards(void)
-{
-  ipindiscards++;
-}
-
-void snmp_inc_ipindelivers(void)
-{
-  ipindelivers++;
-}
-
-void snmp_inc_ipoutrequests(void)
-{
-  ipoutrequests++;
-}
-
-void snmp_inc_ipoutdiscards(void)
-{
-  ipoutdiscards++;
-}
-
-void snmp_inc_ipoutnoroutes(void)
-{
-  ipoutnoroutes++;
-}
-
-void snmp_inc_ipreasmreqds(void)
-{
-  ipreasmreqds++;
-}
-
-void snmp_inc_ipreasmoks(void)
-{
-  ipreasmoks++;
-}
-
-void snmp_inc_ipreasmfails(void)
-{
-  ipreasmfails++;
-}
-
-void snmp_inc_ipfragoks(void)
-{
-  ipfragoks++;
-}
-
-void snmp_inc_ipfragfails(void)
-{
-  ipfragfails++;
-}
-
-void snmp_inc_ipfragcreates(void)
-{
-  ipfragcreates++;
-}
-
-void snmp_inc_iproutingdiscards(void)
-{
-  iproutingdiscards++;
-}
-
-/**
- * Inserts ipAddrTable indexes (.ipAdEntAddr)
- * into index tree.
- */
-void snmp_insert_ipaddridx_tree(struct netif *ni)
-{
-  struct mib_list_rootnode *ipa_rn;
-  struct mib_list_node *ipa_node;
-  struct ip_addr ip;
-  s32_t ipaddridx[4];
-  u8_t level;
-
-  LWIP_ASSERT("ni != NULL", ni != NULL);
-  ip.addr = ntohl(ni->ip_addr.addr);
-  snmp_iptooid(&ip, &ipaddridx[0]);
-
-  level = 0;
-  ipa_rn = &ipaddrtree_root;
-  while (level < 4)
-  {
-    ipa_node = NULL;
-    snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node);
-    if ((level != 3) && (ipa_node != NULL))
-    {
-      if (ipa_node->nptr == NULL)
-      {
-        ipa_rn = snmp_mib_lrn_alloc();
-        ipa_node->nptr = (struct mib_node*)ipa_rn;
-        if (ipa_rn != NULL)
-        {
-          if (level == 2)
-          {
-            ipa_rn->get_object_def = ip_addrentry_get_object_def;
-            ipa_rn->get_value = ip_addrentry_get_value;
-            ipa_rn->set_test = noleafs_set_test;
-            ipa_rn->set_value = noleafs_set_value;
-          }
-        }
-        else
-        {
-          /* ipa_rn == NULL, malloc failure */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full"));
-          break;
-        }
-      }
-      else
-      {
-        ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr;
-      }
-    }
-    level++;
-  }
-  /* enable getnext traversal on filled table */
-  ipaddrtable.maxlength = 1;
-}
-
-/**
- * Removes ipAddrTable indexes (.ipAdEntAddr)
- * from index tree.
- */
-void snmp_delete_ipaddridx_tree(struct netif *ni)
-{
-  struct mib_list_rootnode *ipa_rn, *next, *del_rn[4];
-  struct mib_list_node *ipa_n, *del_n[4];
-  struct ip_addr ip;
-  s32_t ipaddridx[4];
-  u8_t fc, level, del_cnt;
-
-  LWIP_ASSERT("ni != NULL", ni != NULL);
-  ip.addr = ntohl(ni->ip_addr.addr);
-  snmp_iptooid(&ip, &ipaddridx[0]);
-
-  /* mark nodes for deletion */
-  level = 0;
-  del_cnt = 0;
-  ipa_rn = &ipaddrtree_root;
-  while ((level < 4) && (ipa_rn != NULL))
-  {
-    fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n);
-    if (fc == 0)
-    {
-      /* ipaddridx[level] does not exist */
-      del_cnt = 0;
-      ipa_rn = NULL;
-    }
-    else if (fc == 1)
-    {
-      del_rn[del_cnt] = ipa_rn;
-      del_n[del_cnt] = ipa_n;
-      del_cnt++;
-      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);
-    }
-    else if (fc == 2)
-    {
-      /* reset delete (2 or more childs) */
-      del_cnt = 0;
-      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);
-    }
-    level++;
-  }
-  /* delete marked index nodes */
-  while (del_cnt > 0)
-  {
-    del_cnt--;
-
-    ipa_rn = del_rn[del_cnt];
-    ipa_n = del_n[del_cnt];
-
-    next = snmp_mib_node_delete(ipa_rn, ipa_n);
-    if (next != NULL)
-    {
-      LWIP_ASSERT("next_count == 0",next->count == 0);
-      snmp_mib_lrn_free(next);
-    }
-  }
-  /* disable getnext traversal on empty table */
-  if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0;
-}
-
-/**
- * Inserts ipRouteTable indexes (.ipRouteDest)
- * into index tree.
- *
- * @param dflt non-zero for the default rte, zero for network rte
- * @param netif points to network interface for this rte
- *
- * @todo record sysuptime for _this_ route when it is installed
- *   (needed for ipRouteAge) in the netif.
- */
-void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni)
-{
-  u8_t insert = 0;
-  struct ip_addr dst;
-
-  if (dflt != 0)
-  {
-    /* the default route 0.0.0.0 */
-    dst.addr = 0;
-    insert = 1;
-  }
-  else
-  {
-    /* route to the network address */
-    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);
-    /* exclude 0.0.0.0 network (reserved for default rte) */
-    if (dst.addr != 0) insert = 1;
-  }
-  if (insert)
-  {
-    struct mib_list_rootnode *iprte_rn;
-    struct mib_list_node *iprte_node;
-    s32_t iprteidx[4];
-    u8_t level;
-
-    snmp_iptooid(&dst, &iprteidx[0]);
-    level = 0;
-    iprte_rn = &iprtetree_root;
-    while (level < 4)
-    {
-      iprte_node = NULL;
-      snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node);
-      if ((level != 3) && (iprte_node != NULL))
-      {
-        if (iprte_node->nptr == NULL)
-        {
-          iprte_rn = snmp_mib_lrn_alloc();
-          iprte_node->nptr = (struct mib_node*)iprte_rn;
-          if (iprte_rn != NULL)
-          {
-            if (level == 2)
-            {
-              iprte_rn->get_object_def = ip_rteentry_get_object_def;
-              iprte_rn->get_value = ip_rteentry_get_value;
-              iprte_rn->set_test = noleafs_set_test;
-              iprte_rn->set_value = noleafs_set_value;
-            }
-          }
-          else
-          {
-            /* iprte_rn == NULL, malloc failure */
-            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full"));
-            break;
-          }
-        }
-        else
-        {
-          iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr;
-        }
-      }
-      level++;
-    }
-  }
-  /* enable getnext traversal on filled table */
-  iprtetable.maxlength = 1;
-}
-
-/**
- * Removes ipRouteTable indexes (.ipRouteDest)
- * from index tree.
- *
- * @param dflt non-zero for the default rte, zero for network rte
- * @param netif points to network interface for this rte or NULL
- *   for default route to be removed.
- */
-void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni)
-{
-  u8_t delete = 0;
-  struct ip_addr dst;
-
-  if (dflt != 0)
-  {
-    /* the default route 0.0.0.0 */
-    dst.addr = 0;
-    delete = 1;
-  }
-  else
-  {
-    /* route to the network address */
-    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);
-    /* exclude 0.0.0.0 network (reserved for default rte) */
-    if (dst.addr != 0) delete = 1;
-  }
-  if (delete)
-  {
-    struct mib_list_rootnode *iprte_rn, *next, *del_rn[4];
-    struct mib_list_node *iprte_n, *del_n[4];
-    s32_t iprteidx[4];
-    u8_t fc, level, del_cnt;
-
-    snmp_iptooid(&dst, &iprteidx[0]);
-    /* mark nodes for deletion */
-    level = 0;
-    del_cnt = 0;
-    iprte_rn = &iprtetree_root;
-    while ((level < 4) && (iprte_rn != NULL))
-    {
-      fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n);
-      if (fc == 0)
-      {
-        /* iprteidx[level] does not exist */
-        del_cnt = 0;
-        iprte_rn = NULL;
-      }
-      else if (fc == 1)
-      {
-        del_rn[del_cnt] = iprte_rn;
-        del_n[del_cnt] = iprte_n;
-        del_cnt++;
-        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);
-      }
-      else if (fc == 2)
-      {
-        /* reset delete (2 or more childs) */
-        del_cnt = 0;
-        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);
-      }
-      level++;
-    }
-    /* delete marked index nodes */
-    while (del_cnt > 0)
-    {
-      del_cnt--;
-
-      iprte_rn = del_rn[del_cnt];
-      iprte_n = del_n[del_cnt];
-
-      next = snmp_mib_node_delete(iprte_rn, iprte_n);
-      if (next != NULL)
-      {
-        LWIP_ASSERT("next_count == 0",next->count == 0);
-        snmp_mib_lrn_free(next);
-      }
-    }
-  }
-  /* disable getnext traversal on empty table */
-  if (iprtetree_root.count == 0) iprtetable.maxlength = 0;
-}
-
-
-void snmp_inc_icmpinmsgs(void)
-{
-  icmpinmsgs++;
-}
-
-void snmp_inc_icmpinerrors(void)
-{
-  icmpinerrors++;
-}
-
-void snmp_inc_icmpindestunreachs(void)
-{
-  icmpindestunreachs++;
-}
-
-void snmp_inc_icmpintimeexcds(void)
-{
-  icmpintimeexcds++;
-}
-
-void snmp_inc_icmpinparmprobs(void)
-{
-  icmpinparmprobs++;
-}
-
-void snmp_inc_icmpinsrcquenchs(void)
-{
-  icmpinsrcquenchs++;
-}
-
-void snmp_inc_icmpinredirects(void)
-{
-  icmpinredirects++;
-}
-
-void snmp_inc_icmpinechos(void)
-{
-  icmpinechos++;
-}
-
-void snmp_inc_icmpinechoreps(void)
-{
-  icmpinechoreps++;
-}
-
-void snmp_inc_icmpintimestamps(void)
-{
-  icmpintimestamps++;
-}
-
-void snmp_inc_icmpintimestampreps(void)
-{
-  icmpintimestampreps++;
-}
-
-void snmp_inc_icmpinaddrmasks(void)
-{
-  icmpinaddrmasks++;
-}
-
-void snmp_inc_icmpinaddrmaskreps(void)
-{
-  icmpinaddrmaskreps++;
-}
-
-void snmp_inc_icmpoutmsgs(void)
-{
-  icmpoutmsgs++;
-}
-
-void snmp_inc_icmpouterrors(void)
-{
-  icmpouterrors++;
-}
-
-void snmp_inc_icmpoutdestunreachs(void)
-{
-  icmpoutdestunreachs++;
-}
-
-void snmp_inc_icmpouttimeexcds(void)
-{
-  icmpouttimeexcds++;
-}
-
-void snmp_inc_icmpoutparmprobs(void)
-{
-  icmpoutparmprobs++;
-}
-
-void snmp_inc_icmpoutsrcquenchs(void)
-{
-  icmpoutsrcquenchs++;
-}
-
-void snmp_inc_icmpoutredirects(void)
-{
-  icmpoutredirects++;
-}
-
-void snmp_inc_icmpoutechos(void)
-{
-  icmpoutechos++;
-}
-
-void snmp_inc_icmpoutechoreps(void)
-{
-  icmpoutechoreps++;
-}
-
-void snmp_inc_icmpouttimestamps(void)
-{
-  icmpouttimestamps++;
-}
-
-void snmp_inc_icmpouttimestampreps(void)
-{
-  icmpouttimestampreps++;
-}
-
-void snmp_inc_icmpoutaddrmasks(void)
-{
-  icmpoutaddrmasks++;
-}
-
-void snmp_inc_icmpoutaddrmaskreps(void)
-{
-  icmpoutaddrmaskreps++;
-}
-
-void snmp_inc_tcpactiveopens(void)
-{
-  tcpactiveopens++;
-}
-
-void snmp_inc_tcppassiveopens(void)
-{
-  tcppassiveopens++;
-}
-
-void snmp_inc_tcpattemptfails(void)
-{
-  tcpattemptfails++;
-}
-
-void snmp_inc_tcpestabresets(void)
-{
-  tcpestabresets++;
-}
-
-void snmp_inc_tcpinsegs(void)
-{
-  tcpinsegs++;
-}
-
-void snmp_inc_tcpoutsegs(void)
-{
-  tcpoutsegs++;
-}
-
-void snmp_inc_tcpretranssegs(void)
-{
-  tcpretranssegs++;
-}
-
-void snmp_inc_tcpinerrs(void)
-{
-  tcpinerrs++;
-}
-
-void snmp_inc_tcpoutrsts(void)
-{
-  tcpoutrsts++;
-}
-
-void snmp_inc_udpindatagrams(void)
-{
-  udpindatagrams++;
-}
-
-void snmp_inc_udpnoports(void)
-{
-  udpnoports++;
-}
-
-void snmp_inc_udpinerrors(void)
-{
-  udpinerrors++;
-}
-
-void snmp_inc_udpoutdatagrams(void)
-{
-  udpoutdatagrams++;
-}
-
-/**
- * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort)
- * into index tree.
- */
-void snmp_insert_udpidx_tree(struct udp_pcb *pcb)
-{
-  struct mib_list_rootnode *udp_rn;
-  struct mib_list_node *udp_node;
-  struct ip_addr ip;
-  s32_t udpidx[5];
-  u8_t level;
-
-  LWIP_ASSERT("pcb != NULL", pcb != NULL);
-  ip.addr = ntohl(pcb->local_ip.addr);
-  snmp_iptooid(&ip, &udpidx[0]);
-  udpidx[4] = pcb->local_port;
-
-  udp_rn = &udp_root;
-  for (level = 0; level < 5; level++)
-  {
-    udp_node = NULL;
-    snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node);
-    if ((level != 4) && (udp_node != NULL))
-    {
-      if (udp_node->nptr == NULL)
-      {
-        udp_rn = snmp_mib_lrn_alloc();
-        udp_node->nptr = (struct mib_node*)udp_rn;
-        if (udp_rn != NULL)
-        {
-          if (level == 3)
-          {
-            udp_rn->get_object_def = udpentry_get_object_def;
-            udp_rn->get_value = udpentry_get_value;
-            udp_rn->set_test = noleafs_set_test;
-            udp_rn->set_value = noleafs_set_value;
-          }
-        }
-        else
-        {
-          /* udp_rn == NULL, malloc failure */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full"));
-          break;
-        }
-      }
-      else
-      {
-        udp_rn = (struct mib_list_rootnode*)udp_node->nptr;
-      }
-    }
-  }
-  udptable.maxlength = 1;
-}
-
-/**
- * Removes udpTable indexes (.udpLocalAddress.udpLocalPort)
- * from index tree.
- */
-void snmp_delete_udpidx_tree(struct udp_pcb *pcb)
-{
-  struct mib_list_rootnode *udp_rn, *next, *del_rn[5];
-  struct mib_list_node *udp_n, *del_n[5];
-  struct ip_addr ip;
-  s32_t udpidx[5];
-  u8_t bindings, fc, level, del_cnt;
-
-  LWIP_ASSERT("pcb != NULL", pcb != NULL);
-  ip.addr = ntohl(pcb->local_ip.addr);
-  snmp_iptooid(&ip, &udpidx[0]);
-  udpidx[4] = pcb->local_port;
-
-  /* count PCBs for a given binding
-     (e.g. when reusing ports or for temp output PCBs) */
-  bindings = 0;
-  pcb = udp_pcbs;
-  while ((pcb != NULL))
-  {
-    if ((pcb->local_ip.addr == ip.addr) &&
-        (pcb->local_port == udpidx[4]))
-    {
-      bindings++;
-    }
-    pcb = pcb->next;
-  }
-  if (bindings == 1)
-  {
-    /* selectively remove */
-    /* mark nodes for deletion */
-    level = 0;
-    del_cnt = 0;
-    udp_rn = &udp_root;
-    while ((level < 5) && (udp_rn != NULL))
-    {
-      fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n);
-      if (fc == 0)
-      {
-        /* udpidx[level] does not exist */
-        del_cnt = 0;
-        udp_rn = NULL;
-      }
-      else if (fc == 1)
-      {
-        del_rn[del_cnt] = udp_rn;
-        del_n[del_cnt] = udp_n;
-        del_cnt++;
-        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);
-      }
-      else if (fc == 2)
-      {
-        /* reset delete (2 or more childs) */
-        del_cnt = 0;
-        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);
-      }
-      level++;
-    }
-    /* delete marked index nodes */
-    while (del_cnt > 0)
-    {
-      del_cnt--;
-
-      udp_rn = del_rn[del_cnt];
-      udp_n = del_n[del_cnt];
-
-      next = snmp_mib_node_delete(udp_rn, udp_n);
-      if (next != NULL)
-      {
-        LWIP_ASSERT("next_count == 0",next->count == 0);
-        snmp_mib_lrn_free(next);
-      }
-    }
-  }
-  /* disable getnext traversal on empty table */
-  if (udp_root.count == 0) udptable.maxlength = 0;
-}
-
-
-void snmp_inc_snmpinpkts(void)
-{
-  snmpinpkts++;
-}
-
-void snmp_inc_snmpoutpkts(void)
-{
-  snmpoutpkts++;
-}
-
-void snmp_inc_snmpinbadversions(void)
-{
-  snmpinbadversions++;
-}
-
-void snmp_inc_snmpinbadcommunitynames(void)
-{
-  snmpinbadcommunitynames++;
-}
-
-void snmp_inc_snmpinbadcommunityuses(void)
-{
-  snmpinbadcommunityuses++;
-}
-
-void snmp_inc_snmpinasnparseerrs(void)
-{
-  snmpinasnparseerrs++;
-}
-
-void snmp_inc_snmpintoobigs(void)
-{
-  snmpintoobigs++;
-}
-
-void snmp_inc_snmpinnosuchnames(void)
-{
-  snmpinnosuchnames++;
-}
-
-void snmp_inc_snmpinbadvalues(void)
-{
-  snmpinbadvalues++;
-}
-
-void snmp_inc_snmpinreadonlys(void)
-{
-  snmpinreadonlys++;
-}
-
-void snmp_inc_snmpingenerrs(void)
-{
-  snmpingenerrs++;
-}
-
-void snmp_add_snmpintotalreqvars(u8_t value)
-{
-  snmpintotalreqvars += value;
-}
-
-void snmp_add_snmpintotalsetvars(u8_t value)
-{
-  snmpintotalsetvars += value;
-}
-
-void snmp_inc_snmpingetrequests(void)
-{
-  snmpingetrequests++;
-}
-
-void snmp_inc_snmpingetnexts(void)
-{
-  snmpingetnexts++;
-}
-
-void snmp_inc_snmpinsetrequests(void)
-{
-  snmpinsetrequests++;
-}
-
-void snmp_inc_snmpingetresponses(void)
-{
-  snmpingetresponses++;
-}
-
-void snmp_inc_snmpintraps(void)
-{
-  snmpintraps++;
-}
-
-void snmp_inc_snmpouttoobigs(void)
-{
-  snmpouttoobigs++;
-}
-
-void snmp_inc_snmpoutnosuchnames(void)
-{
-  snmpoutnosuchnames++;
-}
-
-void snmp_inc_snmpoutbadvalues(void)
-{
-  snmpoutbadvalues++;
-}
-
-void snmp_inc_snmpoutgenerrs(void)
-{
-  snmpoutgenerrs++;
-}
-
-void snmp_inc_snmpoutgetrequests(void)
-{
-  snmpoutgetrequests++;
-}
-
-void snmp_inc_snmpoutgetnexts(void)
-{
-  snmpoutgetnexts++;
-}
-
-void snmp_inc_snmpoutsetrequests(void)
-{
-  snmpoutsetrequests++;
-}
-
-void snmp_inc_snmpoutgetresponses(void)
-{
-  snmpoutgetresponses++;
-}
-
-void snmp_inc_snmpouttraps(void)
-{
-  snmpouttraps++;
-}
-
-void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid)
-{
-  *oid = &snmpgrp_id;
-}
-
-void snmp_set_snmpenableauthentraps(u8_t *value)
-{
-  if (value != NULL)
-  {
-    snmpenableauthentraps_ptr = value;
-  }
-}
-
-void snmp_get_snmpenableauthentraps(u8_t *value)
-{
-  *value = *snmpenableauthentraps_ptr;
-}
-
-void
-noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  if (ident_len){}
-  if (ident){}
-  od->instance = MIB_OBJECT_NONE;
-}
-
-void
-noleafs_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  if (od){}
-  if (len){}
-  if (value){}
-}
-
-u8_t
-noleafs_set_test(struct obj_def *od, u16_t len, void *value)
-{
-  if (od){}
-  if (len){}
-  if (value){}
-  /* can't set */
-  return 0;
-}
-
-void
-noleafs_set_value(struct obj_def *od, u16_t len, void *value)
-{
-  if (od){}
-  if (len){}
-  if (value){}
-}
-
-
-/**
- * Returns systems object definitions.
- *
- * @param ident_len the address length (2)
- * @param ident points to objectname.0 (object id trailer)
- * @param od points to object definition.
- */
-static void
-system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  u8_t id;
-
-  /* return to object name, adding index depth (1) */
-  ident_len += 1;
-  ident -= 1;
-  if (ident_len == 2)
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id));
-    switch (id)
-    {
-      case 1: /* sysDescr */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
-        od->v_len = *sysdescr_len_ptr;
-        break;
-      case 2: /* sysObjectID */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
-        od->v_len = sysobjid.len * sizeof(s32_t);
-        break;
-      case 3: /* sysUpTime */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);
-        od->v_len = sizeof(u32_t);
-        break;
-      case 4: /* sysContact */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
-        od->v_len = *syscontact_len_ptr;
-        break;
-      case 5: /* sysName */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
-        od->v_len = *sysname_len_ptr;
-        break;
-      case 6: /* sysLocation */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
-        od->v_len = *syslocation_len_ptr;
-        break;
-      case 7: /* sysServices */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    };
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-/**
- * Returns system object value.
- *
- * @param ident_len the address length (2)
- * @param ident points to objectname.0 (object id trailer)
- * @param len return value space (in bytes)
- * @param value points to (varbind) space to copy value into.
- */
-static void
-system_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id;
-
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 1: /* sysDescr */
-      ocstrncpy(value,sysdescr_ptr,len);
-      break;
-    case 2: /* sysObjectID */
-      objectidncpy((s32_t*)value,(s32_t*)sysobjid.id,len / sizeof(s32_t));
-      break;
-    case 3: /* sysUpTime */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = sysuptime;
-      }
-      break;
-    case 4: /* sysContact */
-      ocstrncpy(value,syscontact_ptr,len);
-      break;
-    case 5: /* sysName */
-      ocstrncpy(value,sysname_ptr,len);
-      break;
-    case 6: /* sysLocation */
-      ocstrncpy(value,syslocation_ptr,len);
-      break;
-    case 7: /* sysServices */
-      {
-        s32_t *sint_ptr = value;
-        *sint_ptr = sysservices;
-      }
-      break;
-  };
-}
-
-static u8_t
-system_set_test(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id, set_ok;
-
-  if (value) {}
-  set_ok = 0;
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 4: /* sysContact */
-      if ((syscontact_ptr != syscontact_default) &&
-          (len <= 255))
-      {
-        set_ok = 1;
-      }
-      break;
-    case 5: /* sysName */
-      if ((sysname_ptr != sysname_default) &&
-          (len <= 255))
-      {
-        set_ok = 1;
-      }
-      break;
-    case 6: /* sysLocation */
-      if ((syslocation_ptr != syslocation_default) &&
-          (len <= 255))
-      {
-        set_ok = 1;
-      }
-      break;
-  };
-  return set_ok;
-}
-
-static void
-system_set_value(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id;
-
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 4: /* sysContact */
-      ocstrncpy(syscontact_ptr,value,len);
-      *syscontact_len_ptr = len;
-      break;
-    case 5: /* sysName */
-      ocstrncpy(sysname_ptr,value,len);
-      *sysname_len_ptr = len;
-      break;
-    case 6: /* sysLocation */
-      ocstrncpy(syslocation_ptr,value,len);
-      *syslocation_len_ptr = len;
-      break;
-  };
-}
-
-/**
- * Returns interfaces.ifnumber object definition.
- *
- * @param ident_len the address length (2)
- * @param ident points to objectname.index
- * @param od points to object definition.
- */
-static void
-interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (1) */
-  ident_len += 1;
-  ident -= 1;
-  if (ident_len == 2)
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    od->instance = MIB_OBJECT_SCALAR;
-    od->access = MIB_OBJECT_READ_ONLY;
-    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-    od->v_len = sizeof(s32_t);
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-/**
- * Returns interfaces.ifnumber object value.
- *
- * @param ident_len the address length (2)
- * @param ident points to objectname.0 (object id trailer)
- * @param len return value space (in bytes)
- * @param value points to (varbind) space to copy value into.
- */
-static void
-interfaces_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  if (len){}
-  if (od->id_inst_ptr[0] == 1)
-  {
-    s32_t *sint_ptr = value;
-    *sint_ptr = iflist_root.count;
-  }
-}
-
-/**
- * Returns ifentry object definitions.
- *
- * @param ident_len the address length (2)
- * @param ident points to objectname.index
- * @param od points to object definition.
- */
-static void
-ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  u8_t id;
-
-  /* return to object name, adding index depth (1) */
-  ident_len += 1;
-  ident -= 1;
-  if (ident_len == 2)
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id));
-    switch (id)
-    {
-      case 1: /* ifIndex */
-      case 3: /* ifType */
-      case 4: /* ifMtu */
-      case 8: /* ifOperStatus */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 2: /* ifDescr */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
-        /** @todo this should be some sort of sizeof(struct netif.name) */
-        od->v_len = 2;
-        break;
-      case 5: /* ifSpeed */
-      case 21: /* ifOutQLen */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);
-        od->v_len = sizeof(u32_t);
-        break;
-      case 6: /* ifPhysAddress */
-        {
-          struct netif *netif;
-
-          snmp_ifindextonetif(ident[1], &netif);
-          od->instance = MIB_OBJECT_TAB;
-          od->access = MIB_OBJECT_READ_ONLY;
-          od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
-          od->v_len = netif->hwaddr_len;
-        }
-        break;
-      case 7: /* ifAdminStatus */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 9: /* ifLastChange */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);
-        od->v_len = sizeof(u32_t);
-        break;
-      case 10: /* ifInOctets */
-      case 11: /* ifInUcastPkts */
-      case 12: /* ifInNUcastPkts */
-      case 13: /* ifInDiscarts */
-      case 14: /* ifInErrors */
-      case 15: /* ifInUnkownProtos */
-      case 16: /* ifOutOctets */
-      case 17: /* ifOutUcastPkts */
-      case 18: /* ifOutNUcastPkts */
-      case 19: /* ifOutDiscarts */
-      case 20: /* ifOutErrors */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
-        od->v_len = sizeof(u32_t);
-        break;
-      case 22: /* ifSpecific */
-        /** @note returning zeroDotZero (0.0) no media specific MIB support */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
-        od->v_len = ifspecific.len * sizeof(s32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    };
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-/**
- * Returns ifentry object value.
- *
- * @param ident_len the address length (2)
- * @param ident points to objectname.0 (object id trailer)
- * @param len return value space (in bytes)
- * @param value points to (varbind) space to copy value into.
- */
-static void
-ifentry_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  struct netif *netif;
-  u8_t id;
-
-  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 1: /* ifIndex */
-      {
-        s32_t *sint_ptr = value;
-        *sint_ptr = od->id_inst_ptr[1];
-      }
-      break;
-    case 2: /* ifDescr */
-      ocstrncpy(value,(u8_t*)netif->name,len);
-      break;
-    case 3: /* ifType */
-      {
-        s32_t *sint_ptr = value;
-        *sint_ptr = netif->link_type;
-      }
-      break;
-    case 4: /* ifMtu */
-      {
-        s32_t *sint_ptr = value;
-        *sint_ptr = netif->mtu;
-      }
-      break;
-    case 5: /* ifSpeed */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->link_speed;
-      }
-      break;
-    case 6: /* ifPhysAddress */
-      ocstrncpy(value,netif->hwaddr,len);
-      break;
-    case 7: /* ifAdminStatus */
-    case 8: /* ifOperStatus */
-      {
-        s32_t *sint_ptr = value;
-        if (netif_is_up(netif))
-        {
-          *sint_ptr = 1;
-        }
-        else
-        {
-          *sint_ptr = 2;
-        }
-      }
-      break;
-    case 9: /* ifLastChange */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ts;
-      }
-      break;
-    case 10: /* ifInOctets */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ifinoctets;
-      }
-      break;
-    case 11: /* ifInUcastPkts */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ifinucastpkts;
-      }
-      break;
-    case 12: /* ifInNUcastPkts */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ifinnucastpkts;
-      }
-      break;
-    case 13: /* ifInDiscarts */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ifindiscards;
-      }
-      break;
-    case 14: /* ifInErrors */
-    case 15: /* ifInUnkownProtos */
-      /** @todo add these counters! */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = 0;
-      }
-      break;
-    case 16: /* ifOutOctets */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ifoutoctets;
-      }
-      break;
-    case 17: /* ifOutUcastPkts */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ifoutucastpkts;
-      }
-      break;
-    case 18: /* ifOutNUcastPkts */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ifoutnucastpkts;
-      }
-      break;
-    case 19: /* ifOutDiscarts */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = netif->ifoutdiscards;
-      }
-      break;
-    case 20: /* ifOutErrors */
-       /** @todo add this counter! */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = 0;
-      }
-      break;
-    case 21: /* ifOutQLen */
-      /** @todo figure out if this must be 0 (no queue) or 1? */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = 0;
-      }
-      break;
-    case 22: /* ifSpecific */
-      objectidncpy((s32_t*)value,(s32_t*)ifspecific.id,len / sizeof(s32_t));
-      break;
-  };
-}
-
-/**
- * Returns atentry object definitions.
- *
- * @param ident_len the address length (6)
- * @param ident points to objectname.atifindex.atnetaddress
- * @param od points to object definition.
- */
-static void
-atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (5) */
-  ident_len += 5;
-  ident -= 5;
-
-  if (ident_len == 6)
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    switch (ident[0])
-    {
-      case 1: /* atIfIndex */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 2: /* atPhysAddress */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
-        od->v_len = sizeof(struct eth_addr);
-        break;
-      case 3: /* atNetAddress */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
-        od->v_len = 4;
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    }
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-atentry_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id;
-  struct eth_addr* ethaddr_ret;
-  struct ip_addr* ipaddr_ret;
-  struct ip_addr ip;
-  struct netif *netif;
-
-  if (len) {}
-
-  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
-  snmp_oidtoip(&od->id_inst_ptr[2], &ip);
-  ip.addr = htonl(ip.addr);
-
-  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)
-  {
-    id = od->id_inst_ptr[0];
-    switch (id)
-    {
-      case 1: /* atIfIndex */
-        {
-          s32_t *sint_ptr = value;
-          *sint_ptr = od->id_inst_ptr[1];
-        }
-        break;
-      case 2: /* atPhysAddress */
-        {
-          struct eth_addr *dst = value;
-
-          *dst = *ethaddr_ret;
-        }
-        break;
-      case 3: /* atNetAddress */
-        {
-          struct ip_addr *dst = value;
-
-          *dst = *ipaddr_ret;
-        }
-        break;
-    }
-  }
-}
-
-static void
-ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  u8_t id;
-
-  /* return to object name, adding index depth (1) */
-  ident_len += 1;
-  ident -= 1;
-  if (ident_len == 2)
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id));
-    switch (id)
-    {
-      case 1: /* ipForwarding */
-      case 2: /* ipDefaultTTL */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 3: /* ipInReceives */
-      case 4: /* ipInHdrErrors */
-      case 5: /* ipInAddrErrors */
-      case 6: /* ipForwDatagrams */
-      case 7: /* ipInUnknownProtos */
-      case 8: /* ipInDiscards */
-      case 9: /* ipInDelivers */
-      case 10: /* ipOutRequests */
-      case 11: /* ipOutDiscards */
-      case 12: /* ipOutNoRoutes */
-      case 14: /* ipReasmReqds */
-      case 15: /* ipReasmOKs */
-      case 16: /* ipReasmFails */
-      case 17: /* ipFragOKs */
-      case 18: /* ipFragFails */
-      case 19: /* ipFragCreates */
-      case 23: /* ipRoutingDiscards */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
-        od->v_len = sizeof(u32_t);
-        break;
-      case 13: /* ipReasmTimeout */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    };
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-ip_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id;
-
-  if (len) {}
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 1: /* ipForwarding */
-      {
-        s32_t *sint_ptr = value;
-#if IP_FORWARD
-        /* forwarding */
-        *sint_ptr = 1;
-#else
-        /* not-forwarding */
-        *sint_ptr = 2;
-#endif
-      }
-      break;
-    case 2: /* ipDefaultTTL */
-      {
-        s32_t *sint_ptr = value;
-        *sint_ptr = IP_DEFAULT_TTL;
-      }
-      break;
-    case 3: /* ipInReceives */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipinreceives;
-      }
-      break;
-    case 4: /* ipInHdrErrors */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipinhdrerrors;
-      }
-      break;
-    case 5: /* ipInAddrErrors */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipinaddrerrors;
-      }
-      break;
-    case 6: /* ipForwDatagrams */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipforwdatagrams;
-      }
-      break;
-    case 7: /* ipInUnknownProtos */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipinunknownprotos;
-      }
-      break;
-    case 8: /* ipInDiscards */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipindiscards;
-      }
-      break;
-    case 9: /* ipInDelivers */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipindelivers;
-      }
-      break;
-    case 10: /* ipOutRequests */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipoutrequests;
-      }
-      break;
-    case 11: /* ipOutDiscards */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipoutdiscards;
-      }
-      break;
-    case 12: /* ipOutNoRoutes */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipoutnoroutes;
-      }
-      break;
-    case 13: /* ipReasmTimeout */
-      {
-        s32_t *sint_ptr = value;
-#if IP_REASSEMBLY
-        *sint_ptr = IP_REASS_MAXAGE;
-#else
-        *sint_ptr = 0;
-#endif
-      }
-      break;
-    case 14: /* ipReasmReqds */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipreasmreqds;
-      }
-      break;
-    case 15: /* ipReasmOKs */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipreasmoks;
-      }
-      break;
-    case 16: /* ipReasmFails */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipreasmfails;
-      }
-      break;
-    case 17: /* ipFragOKs */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipfragoks;
-      }
-      break;
-    case 18: /* ipFragFails */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipfragfails;
-      }
-      break;
-    case 19: /* ipFragCreates */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = ipfragcreates;
-      }
-      break;
-    case 23: /* ipRoutingDiscards */
-      /** @todo can lwIP discard routes at all?? hardwire this to 0?? */
-      {
-        u32_t *uint_ptr = value;
-        *uint_ptr = iproutingdiscards;
-      }
-      break;
-  };
-}
-
-/**
- * Test ip object value before setting.
- *
- * @param od is the object definition
- * @param len return value space (in bytes)
- * @param value points to (varbind) space to copy value from.
- *
- * @note we allow set if the value matches the hardwired value,
- *   otherwise return badvalue.
- */
-static u8_t
-ip_set_test(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id, set_ok;
-  s32_t *sint_ptr = value;
-
-  if (len) {}
-  set_ok = 0;
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 1: /* ipForwarding */
-#if IP_FORWARD
-      /* forwarding */
-      if (*sint_ptr == 1)
-#else
-      /* not-forwarding */
-      if (*sint_ptr == 2)
-#endif
-      {
-        set_ok = 1;
-      }
-      break;
-    case 2: /* ipDefaultTTL */
-      if (*sint_ptr == IP_DEFAULT_TTL)
-      {
-        set_ok = 1;
-      }
-      break;
-  };
-  return set_ok;
-}
-
-static void
-ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (4) */
-  ident_len += 4;
-  ident -= 4;
-
-  if (ident_len == 5)
-  {
-    u8_t id;
-
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    switch (id)
-    {
-      case 1: /* ipAdEntAddr */
-      case 3: /* ipAdEntNetMask */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
-        od->v_len = 4;
-        break;
-      case 2: /* ipAdEntIfIndex */
-      case 4: /* ipAdEntBcastAddr */
-      case 5: /* ipAdEntReasmMaxSize */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    }
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id;
-  u16_t ifidx;
-  struct ip_addr ip;
-  struct netif *netif = netif_list;
-
-  if (len) {}
-  snmp_oidtoip(&od->id_inst_ptr[1], &ip);
-  ip.addr = htonl(ip.addr);
-  ifidx = 0;
-  while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr))
-  {
-    netif = netif->next;
-    ifidx++;
-  }
-
-  if (netif != NULL)
-  {
-    id = od->id_inst_ptr[0];
-    switch (id)
-    {
-      case 1: /* ipAdEntAddr */
-        {
-          struct ip_addr *dst = value;
-          *dst = netif->ip_addr;
-        }
-        break;
-      case 2: /* ipAdEntIfIndex */
-        {
-          s32_t *sint_ptr = value;
-          *sint_ptr = ifidx + 1;
-        }
-        break;
-      case 3: /* ipAdEntNetMask */
-        {
-          struct ip_addr *dst = value;
-          *dst = netif->netmask;
-        }
-        break;
-      case 4: /* ipAdEntBcastAddr */
-        {
-          s32_t *sint_ptr = value;
-
-          /* lwIP oddity, there's no broadcast
-            address in the netif we can rely on */
-          *sint_ptr = ip_addr_broadcast.addr & 1;
-        }
-        break;
-      case 5: /* ipAdEntReasmMaxSize */
-        {
-          s32_t *sint_ptr = value;
-#if IP_REASSEMBLY
-          *sint_ptr = (IP_HLEN + IP_REASS_BUFSIZE);
-#else
-          /** @todo returning MTU would be a bad thing and
-             returning a wild guess like '576' isn't good either */
-          *sint_ptr = 0;
-#endif
-        }
-        break;
-    }
-  }
-}
-
-/**
- * @note
- * lwIP IP routing is currently using the network addresses in netif_list.
- * if no suitable network IP is found in netif_list, the default_netif is used.
- */
-static void
-ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  u8_t id;
-
-  /* return to object name, adding index depth (4) */
-  ident_len += 4;
-  ident -= 4;
-
-  if (ident_len == 5)
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    switch (id)
-    {
-      case 1: /* ipRouteDest */
-      case 7: /* ipRouteNextHop */
-      case 11: /* ipRouteMask */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
-        od->v_len = 4;
-        break;
-      case 2: /* ipRouteIfIndex */
-      case 3: /* ipRouteMetric1 */
-      case 4: /* ipRouteMetric2 */
-      case 5: /* ipRouteMetric3 */
-      case 6: /* ipRouteMetric4 */
-      case 8: /* ipRouteType */
-      case 10: /* ipRouteAge */
-      case 12: /* ipRouteMetric5 */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 9: /* ipRouteProto */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 13: /* ipRouteInfo */
-        /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
-        od->v_len = iprouteinfo.len * sizeof(s32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    }
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  struct netif *netif;
-  struct ip_addr dest;
-  s32_t *ident;
-  u8_t id;
-
-  ident = od->id_inst_ptr;
-  snmp_oidtoip(&ident[1], &dest);
-  dest.addr = htonl(dest.addr);
-
-  if (dest.addr == 0)
-  {
-    /* ip_route() uses default netif for default route */
-    netif = netif_default;
-  }
-  else
-  {
-    /* not using ip_route(), need exact match! */
-    netif = netif_list;
-    while ((netif != NULL) &&
-            !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) )
-    {
-      netif = netif->next;
-    }
-  }
-  if (netif != NULL)
-  {
-    id = ident[0];
-    switch (id)
-    {
-      case 1: /* ipRouteDest */
-        {
-          struct ip_addr *dst = value;
-
-          if (dest.addr == 0)
-          {
-            /* default rte has 0.0.0.0 dest */
-            dst->addr = 0;
-          }
-          else
-          {
-            /* netifs have netaddress dest */
-            dst->addr = netif->ip_addr.addr & netif->netmask.addr;
-          }
-        }
-        break;
-      case 2: /* ipRouteIfIndex */
-        {
-          s32_t *sint_ptr = value;
-
-          snmp_netiftoifindex(netif, sint_ptr);
-        }
-        break;
-      case 3: /* ipRouteMetric1 */
-        {
-          s32_t *sint_ptr = value;
-
-          if (dest.addr == 0)
-          {
-            /* default rte has metric 1 */
-            *sint_ptr = 1;
-          }
-          else
-          {
-            /* other rtes have metric 0 */
-            *sint_ptr = 0;
-          }
-        }
-        break;
-      case 4: /* ipRouteMetric2 */
-      case 5: /* ipRouteMetric3 */
-      case 6: /* ipRouteMetric4 */
-      case 12: /* ipRouteMetric5 */
-        {
-          s32_t *sint_ptr = value;
-          /* not used */
-          *sint_ptr = -1;
-        }
-        break;
-      case 7: /* ipRouteNextHop */
-        {
-          struct ip_addr *dst = value;
-
-          if (dest.addr == 0)
-          {
-            /* default rte: gateway */
-            *dst = netif->gw;
-          }
-          else
-          {
-            /* other rtes: netif ip_addr  */
-            *dst = netif->ip_addr;
-          }
-        }
-        break;
-      case 8: /* ipRouteType */
-        {
-          s32_t *sint_ptr = value;
-
-          if (dest.addr == 0)
-          {
-            /* default rte is indirect */
-            *sint_ptr = 4;
-          }
-          else
-          {
-            /* other rtes are direct */
-            *sint_ptr = 3;
-          }
-        }
-        break;
-      case 9: /* ipRouteProto */
-        {
-          s32_t *sint_ptr = value;
-          /* locally defined routes */
-          *sint_ptr = 2;
-        }
-        break;
-      case 10: /* ipRouteAge */
-        {
-          s32_t *sint_ptr = value;
-          /** @todo (sysuptime - timestamp last change) / 100
-              @see snmp_insert_iprteidx_tree() */
-          *sint_ptr = 0;
-        }
-        break;
-      case 11: /* ipRouteMask */
-        {
-          struct ip_addr *dst = value;
-
-          if (dest.addr == 0)
-          {
-            /* default rte use 0.0.0.0 mask */
-            dst->addr = 0;
-          }
-          else
-          {
-            /* other rtes use netmask */
-            *dst = netif->netmask;
-          }
-        }
-        break;
-      case 13: /* ipRouteInfo */
-        objectidncpy((s32_t*)value,(s32_t*)iprouteinfo.id,len / sizeof(s32_t));
-        break;
-    }
-  }
-}
-
-static void
-ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (5) */
-  ident_len += 5;
-  ident -= 5;
-
-  if (ident_len == 6)
-  {
-    u8_t id;
-
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    switch (id)
-    {
-      case 1: /* ipNetToMediaIfIndex */
-      case 4: /* ipNetToMediaType */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 2: /* ipNetToMediaPhysAddress */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
-        od->v_len = sizeof(struct eth_addr);
-        break;
-      case 3: /* ipNetToMediaNetAddress */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
-        od->v_len = 4;
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    }
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id;
-  struct eth_addr* ethaddr_ret;
-  struct ip_addr* ipaddr_ret;
-  struct ip_addr ip;
-  struct netif *netif;
-
-  if (len) {}
-
-  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
-  snmp_oidtoip(&od->id_inst_ptr[2], &ip);
-  ip.addr = htonl(ip.addr);
-
-  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)
-  {
-    id = od->id_inst_ptr[0];
-    switch (id)
-    {
-      case 1: /* ipNetToMediaIfIndex */
-        {
-          s32_t *sint_ptr = value;
-          *sint_ptr = od->id_inst_ptr[1];
-        }
-        break;
-      case 2: /* ipNetToMediaPhysAddress */
-        {
-          struct eth_addr *dst = value;
-
-          *dst = *ethaddr_ret;
-        }
-        break;
-      case 3: /* ipNetToMediaNetAddress */
-        {
-          struct ip_addr *dst = value;
-
-          *dst = *ipaddr_ret;
-        }
-        break;
-      case 4: /* ipNetToMediaType */
-        {
-          s32_t *sint_ptr = value;
-          /* dynamic (?) */
-          *sint_ptr = 3;
-        }
-        break;
-    }
-  }
-}
-
-static void
-icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (1) */
-  ident_len += 1;
-  ident -= 1;
-  if ((ident_len == 2) &&
-      (ident[0] > 0) && (ident[0] < 27))
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    od->instance = MIB_OBJECT_SCALAR;
-    od->access = MIB_OBJECT_READ_ONLY;
-    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
-    od->v_len = sizeof(u32_t);
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-icmp_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u32_t *uint_ptr = value;
-  u8_t id;
-
-  if (len){}
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 1: /* icmpInMsgs */
-      *uint_ptr = icmpinmsgs;
-      break;
-    case 2: /* icmpInErrors */
-      *uint_ptr = icmpinerrors;
-      break;
-    case 3: /* icmpInDestUnreachs */
-      *uint_ptr = icmpindestunreachs;
-      break;
-    case 4: /* icmpInTimeExcds */
-      *uint_ptr = icmpintimeexcds;
-      break;
-    case 5: /* icmpInParmProbs */
-      *uint_ptr = icmpinparmprobs;
-      break;
-    case 6: /* icmpInSrcQuenchs */
-      *uint_ptr = icmpinsrcquenchs;
-      break;
-    case 7: /* icmpInRedirects */
-      *uint_ptr = icmpinredirects;
-      break;
-    case 8: /* icmpInEchos */
-      *uint_ptr = icmpinechos;
-      break;
-    case 9: /* icmpInEchoReps */
-      *uint_ptr = icmpinechoreps;
-      break;
-    case 10: /* icmpInTimestamps */
-      *uint_ptr = icmpintimestamps;
-      break;
-    case 11: /* icmpInTimestampReps */
-      *uint_ptr = icmpintimestampreps;
-      break;
-    case 12: /* icmpInAddrMasks */
-      *uint_ptr = icmpinaddrmasks;
-      break;
-    case 13: /* icmpInAddrMaskReps */
-      *uint_ptr = icmpinaddrmaskreps;
-      break;
-    case 14: /* icmpOutMsgs */
-      *uint_ptr = icmpoutmsgs;
-      break;
-    case 15: /* icmpOutErrors */
-      *uint_ptr = icmpouterrors;
-      break;
-    case 16: /* icmpOutDestUnreachs */
-      *uint_ptr = icmpoutdestunreachs;
-      break;
-    case 17: /* icmpOutTimeExcds */
-      *uint_ptr = icmpouttimeexcds;
-      break;
-    case 18: /* icmpOutParmProbs */
-      *uint_ptr = icmpoutparmprobs;
-      break;
-    case 19: /* icmpOutSrcQuenchs */
-      *uint_ptr = icmpoutsrcquenchs;
-      break;
-    case 20: /* icmpOutRedirects */
-      *uint_ptr = icmpoutredirects;
-      break;
-    case 21: /* icmpOutEchos */
-      *uint_ptr = icmpoutechos;
-      break;
-    case 22: /* icmpOutEchoReps */
-      *uint_ptr = icmpoutechoreps;
-      break;
-    case 23: /* icmpOutTimestamps */
-      *uint_ptr = icmpouttimestamps;
-      break;
-    case 24: /* icmpOutTimestampReps */
-      *uint_ptr = icmpouttimestampreps;
-      break;
-    case 25: /* icmpOutAddrMasks */
-      *uint_ptr = icmpoutaddrmasks;
-      break;
-    case 26: /* icmpOutAddrMaskReps */
-      *uint_ptr = icmpoutaddrmaskreps;
-      break;
-  }
-}
-
-#if LWIP_TCP
-/** @todo tcp grp */
-static void
-tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  u8_t id;
-
-  /* return to object name, adding index depth (1) */
-  ident_len += 1;
-  ident -= 1;
-  if (ident_len == 2)
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));
-
-    switch (id)
-    {
-      case 1: /* tcpRtoAlgorithm */
-      case 2: /* tcpRtoMin */
-      case 3: /* tcpRtoMax */
-      case 4: /* tcpMaxConn */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 5: /* tcpActiveOpens */
-      case 6: /* tcpPassiveOpens */
-      case 7: /* tcpAttemptFails */
-      case 8: /* tcpEstabResets */
-      case 10: /* tcpInSegs */
-      case 11: /* tcpOutSegs */
-      case 12: /* tcpRetransSegs */
-      case 14: /* tcpInErrs */
-      case 15: /* tcpOutRsts */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
-        od->v_len = sizeof(u32_t);
-        break;
-      case 9: /* tcpCurrEstab */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);
-        od->v_len = sizeof(u32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    };
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-tcp_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u32_t *uint_ptr = value;
-  s32_t *sint_ptr = value;
-  u8_t id;
-
-  if (len){}
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 1: /* tcpRtoAlgorithm, vanj(4) */
-      *sint_ptr = 4;
-      break;
-    case 2: /* tcpRtoMin */
-      /* @todo not the actual value, a guess,
-          needs to be calculated */
-      *sint_ptr = 1000;
-      break;
-    case 3: /* tcpRtoMax */
-      /* @todo not the actual value, a guess,
-         needs to be calculated */
-      *sint_ptr = 60000;
-      break;
-    case 4: /* tcpMaxConn */
-      *sint_ptr = MEMP_NUM_TCP_PCB;
-      break;
-    case 5: /* tcpActiveOpens */
-      *uint_ptr = tcpactiveopens;
-      break;
-    case 6: /* tcpPassiveOpens */
-      *uint_ptr = tcppassiveopens;
-      break;
-    case 7: /* tcpAttemptFails */
-      *uint_ptr = tcpattemptfails;
-      break;
-    case 8: /* tcpEstabResets */
-      *uint_ptr = tcpestabresets;
-      break;
-    case 9: /* tcpCurrEstab */
-      {
-        u16_t tcpcurrestab = 0;
-        struct tcp_pcb *pcb = tcp_active_pcbs;
-        while (pcb != NULL)
-        {
-          if ((pcb->state == ESTABLISHED) ||
-              (pcb->state == CLOSE_WAIT))
-          {
-            tcpcurrestab++;
-          }
-          pcb = pcb->next;
-        }
-        *uint_ptr = tcpcurrestab;
-      }
-      break;
-    case 10: /* tcpInSegs */
-      *uint_ptr = tcpinsegs;
-      break;
-    case 11: /* tcpOutSegs */
-      *uint_ptr = tcpoutsegs;
-      break;
-    case 12: /* tcpRetransSegs */
-      *uint_ptr = tcpretranssegs;
-      break;
-    case 14: /* tcpInErrs */
-      *uint_ptr = tcpinerrs;
-      break;
-    case 15: /* tcpOutRsts */
-      *uint_ptr = tcpoutrsts;
-      break;
-  }
-}
-
-static void
-tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (10) */
-  ident_len += 10;
-  ident -= 10;
-
-  if (ident_len == 11)
-  {
-    u8_t id;
-
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));
-
-    switch (id)
-    {
-      case 1: /* tcpConnState */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      case 2: /* tcpConnLocalAddress */
-      case 4: /* tcpConnRemAddress */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
-        od->v_len = 4;
-        break;
-      case 3: /* tcpConnLocalPort */
-      case 5: /* tcpConnRemPort */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    };
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  struct ip_addr lip, rip;
-  u16_t lport, rport;
-  s32_t *ident;
-
-  ident = od->id_inst_ptr;
-  snmp_oidtoip(&ident[1], &lip);
-  lip.addr = htonl(lip.addr);
-  lport = ident[5];
-  snmp_oidtoip(&ident[6], &rip);
-  rip.addr = htonl(rip.addr);
-  rport = ident[10];
-
-  /** @todo find matching PCB */
-}
-#endif
-
-static void
-udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (1) */
-  ident_len += 1;
-  ident -= 1;
-  if ((ident_len == 2) &&
-      (ident[0] > 0) && (ident[0] < 6))
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    od->instance = MIB_OBJECT_SCALAR;
-    od->access = MIB_OBJECT_READ_ONLY;
-    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
-    od->v_len = sizeof(u32_t);
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-udp_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u32_t *uint_ptr = value;
-  u8_t id;
-
-  if (len){}
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-    case 1: /* udpInDatagrams */
-      *uint_ptr = udpindatagrams;
-      break;
-    case 2: /* udpNoPorts */
-      *uint_ptr = udpnoports;
-      break;
-    case 3: /* udpInErrors */
-      *uint_ptr = udpinerrors;
-      break;
-    case 4: /* udpOutDatagrams */
-      *uint_ptr = udpoutdatagrams;
-      break;
-  }
-}
-
-static void
-udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (5) */
-  ident_len += 5;
-  ident -= 5;
-
-  if (ident_len == 6)
-  {
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    switch (ident[0])
-    {
-      case 1: /* udpLocalAddress */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
-        od->v_len = 4;
-        break;
-      case 2: /* udpLocalPort */
-        od->instance = MIB_OBJECT_TAB;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    }
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-udpentry_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id;
-  struct udp_pcb *pcb;
-  struct ip_addr ip;
-  u16_t port;
-
-  if (len){}
-  snmp_oidtoip(&od->id_inst_ptr[1], &ip);
-  ip.addr = htonl(ip.addr);
-  port = od->id_inst_ptr[5];
-
-  pcb = udp_pcbs;
-  while ((pcb != NULL) &&
-         !((pcb->local_ip.addr == ip.addr) &&
-           (pcb->local_port == port)))
-  {
-    pcb = pcb->next;
-  }
-
-  if (pcb != NULL)
-  {
-    id = od->id_inst_ptr[0];
-    switch (id)
-    {
-      case 1: /* udpLocalAddress */
-        {
-          struct ip_addr *dst = value;
-          *dst = pcb->local_ip;
-        }
-        break;
-      case 2: /* udpLocalPort */
-        {
-          s32_t *sint_ptr = value;
-          *sint_ptr = pcb->local_port;
-        }
-        break;
-    }
-  }
-}
-
-static void
-snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
-{
-  /* return to object name, adding index depth (1) */
-  ident_len += 1;
-  ident -= 1;
-  if (ident_len == 2)
-  {
-    u8_t id;
-
-    od->id_inst_len = ident_len;
-    od->id_inst_ptr = ident;
-
-    id = ident[0];
-    switch (id)
-    {
-      case 1: /* snmpInPkts */
-      case 2: /* snmpOutPkts */
-      case 3: /* snmpInBadVersions */
-      case 4: /* snmpInBadCommunityNames */
-      case 5: /* snmpInBadCommunityUses */
-      case 6: /* snmpInASNParseErrs */
-      case 8: /* snmpInTooBigs */
-      case 9: /* snmpInNoSuchNames */
-      case 10: /* snmpInBadValues */
-      case 11: /* snmpInReadOnlys */
-      case 12: /* snmpInGenErrs */
-      case 13: /* snmpInTotalReqVars */
-      case 14: /* snmpInTotalSetVars */
-      case 15: /* snmpInGetRequests */
-      case 16: /* snmpInGetNexts */
-      case 17: /* snmpInSetRequests */
-      case 18: /* snmpInGetResponses */
-      case 19: /* snmpInTraps */
-      case 20: /* snmpOutTooBigs */
-      case 21: /* snmpOutNoSuchNames */
-      case 22: /* snmpOutBadValues */
-      case 24: /* snmpOutGenErrs */
-      case 25: /* snmpOutGetRequests */
-      case 26: /* snmpOutGetNexts */
-      case 27: /* snmpOutSetRequests */
-      case 28: /* snmpOutGetResponses */
-      case 29: /* snmpOutTraps */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_ONLY;
-        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
-        od->v_len = sizeof(u32_t);
-        break;
-      case 30: /* snmpEnableAuthenTraps */
-        od->instance = MIB_OBJECT_SCALAR;
-        od->access = MIB_OBJECT_READ_WRITE;
-        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
-        od->v_len = sizeof(s32_t);
-        break;
-      default:
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n"));
-        od->instance = MIB_OBJECT_NONE;
-        break;
-    };
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n"));
-    od->instance = MIB_OBJECT_NONE;
-  }
-}
-
-static void
-snmp_get_value(struct obj_def *od, u16_t len, void *value)
-{
-  u32_t *uint_ptr = value;
-  u8_t id;
-
-  if (len){}
-  id = od->id_inst_ptr[0];
-  switch (id)
-  {
-      case 1: /* snmpInPkts */
-        *uint_ptr = snmpinpkts;
-        break;
-      case 2: /* snmpOutPkts */
-        *uint_ptr = snmpoutpkts;
-        break;
-      case 3: /* snmpInBadVersions */
-        *uint_ptr = snmpinbadversions;
-        break;
-      case 4: /* snmpInBadCommunityNames */
-        *uint_ptr = snmpinbadcommunitynames;
-        break;
-      case 5: /* snmpInBadCommunityUses */
-        *uint_ptr = snmpinbadcommunityuses;
-        break;
-      case 6: /* snmpInASNParseErrs */
-        *uint_ptr = snmpinasnparseerrs;
-        break;
-      case 8: /* snmpInTooBigs */
-        *uint_ptr = snmpintoobigs;
-        break;
-      case 9: /* snmpInNoSuchNames */
-        *uint_ptr = snmpinnosuchnames;
-        break;
-      case 10: /* snmpInBadValues */
-        *uint_ptr = snmpinbadvalues;
-        break;
-      case 11: /* snmpInReadOnlys */
-        *uint_ptr = snmpinreadonlys;
-        break;
-      case 12: /* snmpInGenErrs */
-        *uint_ptr = snmpingenerrs;
-        break;
-      case 13: /* snmpInTotalReqVars */
-        *uint_ptr = snmpintotalreqvars;
-        break;
-      case 14: /* snmpInTotalSetVars */
-        *uint_ptr = snmpintotalsetvars;
-        break;
-      case 15: /* snmpInGetRequests */
-        *uint_ptr = snmpingetrequests;
-        break;
-      case 16: /* snmpInGetNexts */
-        *uint_ptr = snmpingetnexts;
-        break;
-      case 17: /* snmpInSetRequests */
-        *uint_ptr = snmpinsetrequests;
-        break;
-      case 18: /* snmpInGetResponses */
-        *uint_ptr = snmpingetresponses;
-        break;
-      case 19: /* snmpInTraps */
-        *uint_ptr = snmpintraps;
-        break;
-      case 20: /* snmpOutTooBigs */
-        *uint_ptr = snmpouttoobigs;
-        break;
-      case 21: /* snmpOutNoSuchNames */
-        *uint_ptr = snmpoutnosuchnames;
-        break;
-      case 22: /* snmpOutBadValues */
-        *uint_ptr = snmpoutbadvalues;
-        break;
-      case 24: /* snmpOutGenErrs */
-        *uint_ptr = snmpoutgenerrs;
-        break;
-      case 25: /* snmpOutGetRequests */
-        *uint_ptr = snmpoutgetrequests;
-        break;
-      case 26: /* snmpOutGetNexts */
-        *uint_ptr = snmpoutgetnexts;
-        break;
-      case 27: /* snmpOutSetRequests */
-        *uint_ptr = snmpoutsetrequests;
-        break;
-      case 28: /* snmpOutGetResponses */
-        *uint_ptr = snmpoutgetresponses;
-        break;
-      case 29: /* snmpOutTraps */
-        *uint_ptr = snmpouttraps;
-        break;
-      case 30: /* snmpEnableAuthenTraps */
-        *uint_ptr = *snmpenableauthentraps_ptr;
-        break;
-  };
-}
-
-/**
- * Test snmp object value before setting.
- *
- * @param od is the object definition
- * @param len return value space (in bytes)
- * @param value points to (varbind) space to copy value from.
- */
-static u8_t
-snmp_set_test(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id, set_ok;
-
-  if (len) {}
-  set_ok = 0;
-  id = od->id_inst_ptr[0];
-  if (id == 30)
-  {
-    /* snmpEnableAuthenTraps */
-    s32_t *sint_ptr = value;
-
-    if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default)
-    {
-      /* we should have writable non-volatile mem here */
-      if ((*sint_ptr == 1) || (*sint_ptr == 2))
-      {
-        set_ok = 1;
-      }
-    }
-    else
-    {
-      /* const or hardwired value */
-      if (*sint_ptr == snmpenableauthentraps_default)
-      {
-        set_ok = 1;
-      }
-    }
-  }
-  return set_ok;
-}
-
-static void
-snmp_set_value(struct obj_def *od, u16_t len, void *value)
-{
-  u8_t id;
-
-  if (len) {}
-  id = od->id_inst_ptr[0];
-  if (id == 30)
-  {
-    /* snmpEnableAuthenTraps */
-    s32_t *sint_ptr = value;
-    *snmpenableauthentraps_ptr = *sint_ptr;
-  }
-}
-
-#endif /* LWIP_SNMP */
+/**

+ * @file

+ * Management Information Base II (RFC1213) objects and functions.

+ *

+ * @note the object identifiers for this MIB-2 and private MIB tree

+ * must be kept in sorted ascending order. This to ensure correct getnext operation.

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * 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: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "arch/cc.h"

+#include "lwip/opt.h"

+

+#if LWIP_SNMP

+#include "lwip/snmp.h"

+#include "lwip/netif.h"

+#include "netif/etharp.h"

+#include "lwip/ip.h"

+#include "lwip/ip_frag.h"

+#include "lwip/tcp.h"

+#include "lwip/udp.h"

+#include "lwip/snmp_asn1.h"

+#include "lwip/snmp_structs.h"

+

+/**

+ * IANA assigned enterprise ID for lwIP is 26381

+ * @see http://www.iana.org/assignments/enterprise-numbers

+ *

+ * @note this enterprise ID is assigned to the lwIP project,

+ * all object identifiers living under this ID are assigned

+ * by the lwIP maintainers (contact Christiaan Simons)!

+ * @note don't change this define, use snmp_set_sysobjid()

+ *

+ * If you need to create your own private MIB you'll need

+ * to apply for your own enterprise ID with IANA:

+ * http://www.iana.org/numbers.html

+ */

+#define SNMP_ENTERPRISE_ID 26381

+#define SNMP_SYSOBJID_LEN 7

+#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID}

+

+#ifndef SNMP_SYSSERVICES

+#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2))

+#endif

+

+static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void system_get_value(struct obj_def *od, u16_t len, void *value);

+static u8_t system_set_test(struct obj_def *od, u16_t len, void *value);

+static void system_set_value(struct obj_def *od, u16_t len, void *value);

+static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void interfaces_get_value(struct obj_def *od, u16_t len, void *value);

+static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ifentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void atentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ip_get_value(struct obj_def *od, u16_t len, void *value);

+static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value);

+static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void icmp_get_value(struct obj_def *od, u16_t len, void *value);

+#if LWIP_TCP

+static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void tcp_get_value(struct obj_def *od, u16_t len, void *value);

+static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value);

+#endif

+static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void udp_get_value(struct obj_def *od, u16_t len, void *value);

+static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void udpentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void snmp_get_value(struct obj_def *od, u16_t len, void *value);

+static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value);

+static void snmp_set_value(struct obj_def *od, u16_t len, void *value);

+

+

+/* snmp .1.3.6.1.2.1.11 */

+const mib_scalar_node snmp_scalar = {

+  &snmp_get_object_def,

+  &snmp_get_value,

+  &snmp_set_test,

+  &snmp_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t snmp_ids[28] = {

+  1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16,

+  17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30

+};

+struct mib_node* const snmp_nodes[28] = {

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar

+};

+const struct mib_array_node snmp = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  28,

+  snmp_ids,

+  snmp_nodes

+};

+

+/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */

+/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */

+/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */

+

+/* udp .1.3.6.1.2.1.7 */

+/** index root node for udpTable */

+struct mib_list_rootnode udp_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t udpentry_ids[2] = { 1, 2 };

+struct mib_node* const udpentry_nodes[2] = {

+  (struct mib_node* const)&udp_root, (struct mib_node* const)&udp_root,

+};

+const struct mib_array_node udpentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  2,

+  udpentry_ids,

+  udpentry_nodes

+};

+

+s32_t udptable_id = 1;

+struct mib_node* udptable_node = (struct mib_node* const)&udpentry;

+struct mib_ram_array_node udptable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &udptable_id,

+  &udptable_node

+};

+

+const mib_scalar_node udp_scalar = {

+  &udp_get_object_def,

+  &udp_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 };

+struct mib_node* const udp_nodes[5] = {

+  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,

+  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,

+  (struct mib_node* const)&udptable

+};

+const struct mib_array_node udp = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  5,

+  udp_ids,

+  udp_nodes

+};

+

+/* tcp .1.3.6.1.2.1.6 */

+#if LWIP_TCP

+/* only if the TCP protocol is available may implement this group */

+/** index root node for tcpConnTable */

+struct mib_list_rootnode tcpconntree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 };

+struct mib_node* const tcpconnentry_nodes[5] = {

+  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,

+  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,

+  (struct mib_node* const)&tcpconntree_root

+};

+const struct mib_array_node tcpconnentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  5,

+  tcpconnentry_ids,

+  tcpconnentry_nodes

+};

+

+s32_t tcpconntable_id = 1;

+struct mib_node* tcpconntable_node = (struct mib_node* const)&tcpconnentry;

+struct mib_ram_array_node tcpconntable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+/** @todo update maxlength when inserting / deleting from table

+   0 when table is empty, 1 when more than one entry */

+  0,

+  &tcpconntable_id,

+  &tcpconntable_node

+};

+

+const mib_scalar_node tcp_scalar = {

+  &tcp_get_object_def,

+  &tcp_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };

+struct mib_node* const tcp_nodes[15] = {

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcpconntable, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar

+};

+const struct mib_array_node tcp = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  15,

+  tcp_ids,

+  tcp_nodes

+};

+#endif

+

+/* icmp .1.3.6.1.2.1.5 */

+const mib_scalar_node icmp_scalar = {

+  &icmp_get_object_def,

+  &icmp_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };

+struct mib_node* const icmp_nodes[26] = {

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar

+};

+const struct mib_array_node icmp = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  26,

+  icmp_ids,

+  icmp_nodes

+};

+

+/** index root node for ipNetToMediaTable */

+struct mib_list_rootnode ipntomtree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 };

+struct mib_node* const ipntomentry_nodes[4] = {

+  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root,

+  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root

+};

+const struct mib_array_node ipntomentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  4,

+  ipntomentry_ids,

+  ipntomentry_nodes

+};

+

+s32_t ipntomtable_id = 1;

+struct mib_node* ipntomtable_node = (struct mib_node* const)&ipntomentry;

+struct mib_ram_array_node ipntomtable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &ipntomtable_id,

+  &ipntomtable_node

+};

+

+/** index root node for ipRouteTable */

+struct mib_list_rootnode iprtetree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };

+struct mib_node* const iprteentry_nodes[13] = {

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root

+};

+const struct mib_array_node iprteentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  13,

+  iprteentry_ids,

+  iprteentry_nodes

+};

+

+s32_t iprtetable_id = 1;

+struct mib_node* iprtetable_node = (struct mib_node* const)&iprteentry;

+struct mib_ram_array_node iprtetable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &iprtetable_id,

+  &iprtetable_node

+};

+

+/** index root node for ipAddrTable */

+struct mib_list_rootnode ipaddrtree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 };

+struct mib_node* const ipaddrentry_nodes[5] = {

+  (struct mib_node* const)&ipaddrtree_root,

+  (struct mib_node* const)&ipaddrtree_root,

+  (struct mib_node* const)&ipaddrtree_root,

+  (struct mib_node* const)&ipaddrtree_root,

+  (struct mib_node* const)&ipaddrtree_root

+};

+const struct mib_array_node ipaddrentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  5,

+  ipaddrentry_ids,

+  ipaddrentry_nodes

+};

+

+s32_t ipaddrtable_id = 1;

+struct mib_node* ipaddrtable_node = (struct mib_node* const)&ipaddrentry;

+struct mib_ram_array_node ipaddrtable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &ipaddrtable_id,

+  &ipaddrtable_node

+};

+

+/* ip .1.3.6.1.2.1.4 */

+const mib_scalar_node ip_scalar = {

+  &ip_get_object_def,

+  &ip_get_value,

+  &ip_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };

+struct mib_node* const ip_nodes[23] = {

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ipaddrtable,

+  (struct mib_node* const)&iprtetable, (struct mib_node* const)&ipntomtable,

+  (struct mib_node* const)&ip_scalar

+};

+const struct mib_array_node ip = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  23,

+  ip_ids,

+  ip_nodes

+};

+

+/** index root node for atTable */

+struct mib_list_rootnode arptree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t atentry_ids[3] = { 1, 2, 3 };

+struct mib_node* const atentry_nodes[3] = {

+  (struct mib_node* const)&arptree_root,

+  (struct mib_node* const)&arptree_root,

+  (struct mib_node* const)&arptree_root

+};

+const struct mib_array_node atentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  3,

+  atentry_ids,

+  atentry_nodes

+};

+

+const s32_t attable_id = 1;

+struct mib_node* const attable_node = (struct mib_node* const)&atentry;

+const struct mib_array_node attable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  1,

+  &attable_id,

+  &attable_node

+};

+

+/* at .1.3.6.1.2.1.3 */

+s32_t at_id = 1;

+struct mib_node* at_node = (struct mib_node* const)&attable;

+struct mib_ram_array_node at = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &at_id,

+  &at_node

+};

+

+/** index root node for ifTable */

+struct mib_list_rootnode iflist_root = {

+  &ifentry_get_object_def,

+  &ifentry_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 };

+struct mib_node* const ifentry_nodes[22] = {

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root

+};

+const struct mib_array_node ifentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  22,

+  ifentry_ids,

+  ifentry_nodes

+};

+

+s32_t iftable_id = 1;

+struct mib_node* iftable_node = (struct mib_node* const)&ifentry;

+struct mib_ram_array_node iftable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &iftable_id,

+  &iftable_node

+};

+

+/* interfaces .1.3.6.1.2.1.2 */

+const mib_scalar_node interfaces_scalar = {

+  &interfaces_get_object_def,

+  &interfaces_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t interfaces_ids[2] = { 1, 2 };

+struct mib_node* const interfaces_nodes[2] = {

+  (struct mib_node* const)&interfaces_scalar, (struct mib_node* const)&iftable

+};

+const struct mib_array_node interfaces = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  2,

+  interfaces_ids,

+  interfaces_nodes

+};

+

+

+/*             0 1 2 3 4 5 6 */

+/* system .1.3.6.1.2.1.1 */

+const mib_scalar_node sys_tem_scalar = {

+  &system_get_object_def,

+  &system_get_value,

+  &system_set_test,

+  &system_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 };

+struct mib_node* const sys_tem_nodes[7] = {

+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,

+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,

+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,

+  (struct mib_node* const)&sys_tem_scalar

+};

+/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */

+const struct mib_array_node sys_tem = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  7,

+  sys_tem_ids,

+  sys_tem_nodes

+};

+

+/* mib-2 .1.3.6.1.2.1 */

+#if LWIP_TCP

+#define MIB2_GROUPS 8

+#else

+#define MIB2_GROUPS 7

+#endif

+const s32_t mib2_ids[MIB2_GROUPS] =

+{

+  1,

+  2,

+  3,

+  4,

+  5,

+#if LWIP_TCP

+  6,

+#endif

+  7,

+  11

+};

+struct mib_node* const mib2_nodes[MIB2_GROUPS] = {

+  (struct mib_node* const)&sys_tem,

+  (struct mib_node* const)&interfaces,

+  (struct mib_node* const)&at,

+  (struct mib_node* const)&ip,

+  (struct mib_node* const)&icmp,

+#if LWIP_TCP

+  (struct mib_node* const)&tcp,

+#endif

+  (struct mib_node* const)&udp,

+  (struct mib_node* const)&snmp

+};

+

+const struct mib_array_node mib2 = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  MIB2_GROUPS,

+  mib2_ids,

+  mib2_nodes

+};

+

+/* mgmt .1.3.6.1.2 */

+const s32_t mgmt_ids[1] = { 1 };

+struct mib_node* const mgmt_nodes[1] = { (struct mib_node* const)&mib2 };

+const struct mib_array_node mgmt = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  1,

+  mgmt_ids,

+  mgmt_nodes

+};

+

+/* internet .1.3.6.1 */

+#if SNMP_PRIVATE_MIB

+s32_t internet_ids[2] = { 2, 4 };

+struct mib_node* const internet_nodes[2] = { (struct mib_node* const)&mgmt, (struct mib_node* const)&private };

+const struct mib_array_node internet = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  2,

+  internet_ids,

+  internet_nodes

+};

+#else

+const s32_t internet_ids[1] = { 2 };

+struct mib_node* const internet_nodes[1] = { (struct mib_node* const)&mgmt };

+const struct mib_array_node internet = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  1,

+  internet_ids,

+  internet_nodes

+};

+#endif

+

+/** mib-2.system.sysObjectID  */

+static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID};

+/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */

+static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}};

+/** mib-2.system.sysServices */

+static const s32_t sysservices = SNMP_SYSSERVICES;

+

+/** mib-2.system.sysDescr */

+static const u8_t sysdescr_len_default = 4;

+static const u8_t sysdescr_default[] = "lwIP";

+static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default;

+static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0];

+/** mib-2.system.sysContact */

+static const u8_t syscontact_len_default = 0;

+static const u8_t syscontact_default[] = "";

+static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default;

+static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0];

+/** mib-2.system.sysName */

+static const u8_t sysname_len_default = 8;

+static const u8_t sysname_default[] = "FQDN-unk";

+static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default;

+static u8_t* sysname_ptr = (u8_t*)&sysname_default[0];

+/** mib-2.system.sysLocation */

+static const u8_t syslocation_len_default = 0;

+static const u8_t syslocation_default[] = "";

+static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default;

+static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0];

+/** mib-2.snmp.snmpEnableAuthenTraps */

+static const u8_t snmpenableauthentraps_default = 2; /* disabled */

+static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default;

+

+/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */

+static const struct snmp_obj_id ifspecific = {2, {0, 0}};

+/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */

+static const struct snmp_obj_id iprouteinfo = {2, {0, 0}};

+

+

+

+/* mib-2.system counter(s) */

+static u32_t sysuptime = 0;

+

+/* mib-2.ip counter(s) */

+static u32_t ipinreceives = 0,

+             ipinhdrerrors = 0,

+             ipinaddrerrors = 0,

+             ipforwdatagrams = 0,

+             ipinunknownprotos = 0,

+             ipindiscards = 0,

+             ipindelivers = 0,

+             ipoutrequests = 0,

+             ipoutdiscards = 0,

+             ipoutnoroutes = 0,

+             ipreasmreqds = 0,

+             ipreasmoks = 0,

+             ipreasmfails = 0,

+             ipfragoks = 0,

+             ipfragfails = 0,

+             ipfragcreates = 0,

+             iproutingdiscards = 0;

+/* mib-2.icmp counter(s) */

+static u32_t icmpinmsgs = 0,

+             icmpinerrors = 0,

+             icmpindestunreachs = 0,

+             icmpintimeexcds = 0,

+             icmpinparmprobs = 0,

+             icmpinsrcquenchs = 0,

+             icmpinredirects = 0,

+             icmpinechos = 0,

+             icmpinechoreps = 0,

+             icmpintimestamps = 0,

+             icmpintimestampreps = 0,

+             icmpinaddrmasks = 0,

+             icmpinaddrmaskreps = 0,

+             icmpoutmsgs = 0,

+             icmpouterrors = 0,

+             icmpoutdestunreachs = 0,

+             icmpouttimeexcds = 0,

+             icmpoutparmprobs = 0,

+             icmpoutsrcquenchs = 0,

+             icmpoutredirects = 0,

+             icmpoutechos = 0,

+             icmpoutechoreps = 0,

+             icmpouttimestamps = 0,

+             icmpouttimestampreps = 0,

+             icmpoutaddrmasks = 0,

+             icmpoutaddrmaskreps = 0;

+/* mib-2.tcp counter(s) */

+static u32_t tcpactiveopens = 0,

+             tcppassiveopens = 0,

+             tcpattemptfails = 0,

+             tcpestabresets = 0,

+             tcpinsegs = 0,

+             tcpoutsegs = 0,

+             tcpretranssegs = 0,

+             tcpinerrs = 0,

+             tcpoutrsts = 0;

+/* mib-2.udp counter(s) */

+static u32_t udpindatagrams = 0,

+             udpnoports = 0,

+             udpinerrors = 0,

+             udpoutdatagrams = 0;

+/* mib-2.snmp counter(s) */

+static u32_t snmpinpkts = 0,

+             snmpoutpkts = 0,

+             snmpinbadversions = 0,

+             snmpinbadcommunitynames = 0,

+             snmpinbadcommunityuses = 0,

+             snmpinasnparseerrs = 0,

+             snmpintoobigs = 0,

+             snmpinnosuchnames = 0,

+             snmpinbadvalues = 0,

+             snmpinreadonlys = 0,

+             snmpingenerrs = 0,

+             snmpintotalreqvars = 0,

+             snmpintotalsetvars = 0,

+             snmpingetrequests = 0,

+             snmpingetnexts = 0,

+             snmpinsetrequests = 0,

+             snmpingetresponses = 0,

+             snmpintraps = 0,

+             snmpouttoobigs = 0,

+             snmpoutnosuchnames = 0,

+             snmpoutbadvalues = 0,

+             snmpoutgenerrs = 0,

+             snmpoutgetrequests = 0,

+             snmpoutgetnexts = 0,

+             snmpoutsetrequests = 0,

+             snmpoutgetresponses = 0,

+             snmpouttraps = 0;

+

+

+

+/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */

+/**

+ * Copy octet string.

+ *

+ * @param dst points to destination

+ * @param src points to source

+ * @param n number of octets to copy.

+ */

+void ocstrncpy(u8_t *dst, u8_t *src, u8_t n)

+{

+  while (n > 0)

+  {

+    n--;

+    *dst++ = *src++;

+  }

+}

+

+/**

+ * Copy object identifier (s32_t) array.

+ *

+ * @param dst points to destination

+ * @param src points to source

+ * @param n number of sub identifiers to copy.

+ */

+void objectidncpy(s32_t *dst, s32_t *src, u8_t n)

+{

+  while(n > 0)

+  {

+    n--;

+    *dst++ = *src++;

+  }

+}

+

+/**

+ * Initializes sysDescr pointers.

+ *

+ * @param str if non-NULL then copy str pointer

+ * @param strlen points to string length, excluding zero terminator

+ */

+void snmp_set_sysdesr(u8_t *str, u8_t *strlen)

+{

+  if (str != NULL)

+  {

+    sysdescr_ptr = str;

+    sysdescr_len_ptr = strlen;

+  }

+}

+

+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid)

+{

+  *oid = &sysobjid;

+}

+

+/**

+ * Initializes sysObjectID value.

+ *

+ * @param oid points to stuct snmp_obj_id to copy

+ */

+void snmp_set_sysobjid(struct snmp_obj_id *oid)

+{

+  sysobjid = *oid;

+}

+

+/**

+ * Must be called at regular 10 msec interval from a timer interrupt

+ * or signal handler depending on your runtime environment.

+ */

+void snmp_inc_sysuptime(void)

+{

+  sysuptime++;

+}

+

+void snmp_get_sysuptime(u32_t *value)

+{

+  *value = sysuptime;

+}

+

+/**

+ * Initializes sysContact pointers,

+ * e.g. ptrs to non-volatile memory external to lwIP.

+ *

+ * @param str if non-NULL then copy str pointer

+ * @param strlen points to string length, excluding zero terminator

+ */

+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen)

+{

+  if (ocstr != NULL)

+  {

+    syscontact_ptr = ocstr;

+    syscontact_len_ptr = ocstrlen;

+  }

+}

+

+/**

+ * Initializes sysName pointers,

+ * e.g. ptrs to non-volatile memory external to lwIP.

+ *

+ * @param str if non-NULL then copy str pointer

+ * @param strlen points to string length, excluding zero terminator

+ */

+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen)

+{

+  if (ocstr != NULL)

+  {

+    sysname_ptr = ocstr;

+    sysname_len_ptr = ocstrlen;

+  }

+}

+

+/**

+ * Initializes sysLocation pointers,

+ * e.g. ptrs to non-volatile memory external to lwIP.

+ *

+ * @param str if non-NULL then copy str pointer

+ * @param strlen points to string length, excluding zero terminator

+ */

+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen)

+{

+  if (ocstr != NULL)

+  {

+    syslocation_ptr = ocstr;

+    syslocation_len_ptr = ocstrlen;

+  }

+}

+

+

+void snmp_add_ifinoctets(struct netif *ni, u32_t value)

+{

+  ni->ifinoctets += value;

+}

+

+void snmp_inc_ifinucastpkts(struct netif *ni)

+{

+  (ni->ifinucastpkts)++;

+}

+

+void snmp_inc_ifinnucastpkts(struct netif *ni)

+{

+  (ni->ifinnucastpkts)++;

+}

+

+void snmp_inc_ifindiscards(struct netif *ni)

+{

+  (ni->ifindiscards)++;

+}

+

+void snmp_add_ifoutoctets(struct netif *ni, u32_t value)

+{

+  ni->ifoutoctets += value;

+}

+

+void snmp_inc_ifoutucastpkts(struct netif *ni)

+{

+  (ni->ifoutucastpkts)++;

+}

+

+void snmp_inc_ifoutnucastpkts(struct netif *ni)

+{

+  (ni->ifoutnucastpkts)++;

+}

+

+void snmp_inc_ifoutdiscards(struct netif *ni)

+{

+  (ni->ifoutdiscards)++;

+}

+

+void snmp_inc_iflist(void)

+{

+  struct mib_list_node *if_node = NULL;

+

+  snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node);

+  /* enable getnext traversal on filled table */

+  iftable.maxlength = 1;

+}

+

+void snmp_dec_iflist(void)

+{

+  snmp_mib_node_delete(&iflist_root, iflist_root.tail);

+  /* disable getnext traversal on empty table */

+  if(iflist_root.count == 0) iftable.maxlength = 0;

+}

+

+/**

+ * Inserts ARP table indexes (.xIfIndex.xNetAddress)

+ * into arp table index trees (both atTable and ipNetToMediaTable).

+ */

+void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip)

+{

+  struct mib_list_rootnode *at_rn;

+  struct mib_list_node *at_node;

+  struct ip_addr hip;

+  s32_t arpidx[5];

+  u8_t level, tree;

+

+  LWIP_ASSERT("ni != NULL", ni != NULL);

+  snmp_netiftoifindex(ni, &arpidx[0]);

+  hip.addr = ntohl(ip->addr);

+  snmp_iptooid(&hip, &arpidx[1]);

+

+  for (tree = 0; tree < 2; tree++)

+  {

+    if (tree == 0)

+    {

+      at_rn = &arptree_root;

+    }

+    else

+    {

+      at_rn = &ipntomtree_root;

+    }

+    for (level = 0; level < 5; level++)

+    {

+      at_node = NULL;

+      snmp_mib_node_insert(at_rn, arpidx[level], &at_node);

+      if ((level != 4) && (at_node != NULL))

+      {

+        if (at_node->nptr == NULL)

+        {

+          at_rn = snmp_mib_lrn_alloc();

+          at_node->nptr = (struct mib_node*)at_rn;

+          if (at_rn != NULL)

+          {

+            if (level == 3)

+            {

+              if (tree == 0)

+              {

+                at_rn->get_object_def = atentry_get_object_def;

+                at_rn->get_value = atentry_get_value;

+              }

+              else

+              {

+                at_rn->get_object_def = ip_ntomentry_get_object_def;

+                at_rn->get_value = ip_ntomentry_get_value;

+              }

+              at_rn->set_test = noleafs_set_test;

+              at_rn->set_value = noleafs_set_value;

+            }

+          }

+          else

+          {

+            /* at_rn == NULL, malloc failure */

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full"));

+            break;

+          }

+        }

+        else

+        {

+          at_rn = (struct mib_list_rootnode*)at_node->nptr;

+        }

+      }

+    }

+  }

+  /* enable getnext traversal on filled tables */

+  at.maxlength = 1;

+  ipntomtable.maxlength = 1;

+}

+

+/**

+ * Removes ARP table indexes (.xIfIndex.xNetAddress)

+ * from arp table index trees.

+ */

+void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip)

+{

+  struct mib_list_rootnode *at_rn, *next, *del_rn[5];

+  struct mib_list_node *at_n, *del_n[5];

+  struct ip_addr hip;

+  s32_t arpidx[5];

+  u8_t fc, tree, level, del_cnt;

+

+  snmp_netiftoifindex(ni, &arpidx[0]);

+  hip.addr = ntohl(ip->addr);

+  snmp_iptooid(&hip, &arpidx[1]);

+

+  for (tree = 0; tree < 2; tree++)

+  {

+    /* mark nodes for deletion */

+    if (tree == 0)

+    {

+      at_rn = &arptree_root;

+    }

+    else

+    {

+      at_rn = &ipntomtree_root;

+    }

+    level = 0;

+    del_cnt = 0;

+    while ((level < 5) && (at_rn != NULL))

+    {

+      fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n);

+      if (fc == 0)

+      {

+        /* arpidx[level] does not exist */

+        del_cnt = 0;

+        at_rn = NULL;

+      }

+      else if (fc == 1)

+      {

+        del_rn[del_cnt] = at_rn;

+        del_n[del_cnt] = at_n;

+        del_cnt++;

+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);

+      }

+      else if (fc == 2)

+      {

+        /* reset delete (2 or more childs) */

+        del_cnt = 0;

+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);

+      }

+      level++;

+    }

+    /* delete marked index nodes */

+    while (del_cnt > 0)

+    {

+      del_cnt--;

+

+      at_rn = del_rn[del_cnt];

+      at_n = del_n[del_cnt];

+

+      next = snmp_mib_node_delete(at_rn, at_n);

+      if (next != NULL)

+      {

+        LWIP_ASSERT("next_count == 0",next->count == 0);

+        snmp_mib_lrn_free(next);

+      }

+    }

+  }

+  /* disable getnext traversal on empty tables */

+  if(arptree_root.count == 0) at.maxlength = 0;

+  if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0;

+}

+

+void snmp_inc_ipinreceives(void)

+{

+  ipinreceives++;

+}

+

+void snmp_inc_ipinhdrerrors(void)

+{

+  ipinhdrerrors++;

+}

+

+void snmp_inc_ipinaddrerrors(void)

+{

+  ipinaddrerrors++;

+}

+

+void snmp_inc_ipforwdatagrams(void)

+{

+  ipforwdatagrams++;

+}

+

+void snmp_inc_ipinunknownprotos(void)

+{

+  ipinunknownprotos++;

+}

+

+void snmp_inc_ipindiscards(void)

+{

+  ipindiscards++;

+}

+

+void snmp_inc_ipindelivers(void)

+{

+  ipindelivers++;

+}

+

+void snmp_inc_ipoutrequests(void)

+{

+  ipoutrequests++;

+}

+

+void snmp_inc_ipoutdiscards(void)

+{

+  ipoutdiscards++;

+}

+

+void snmp_inc_ipoutnoroutes(void)

+{

+  ipoutnoroutes++;

+}

+

+void snmp_inc_ipreasmreqds(void)

+{

+  ipreasmreqds++;

+}

+

+void snmp_inc_ipreasmoks(void)

+{

+  ipreasmoks++;

+}

+

+void snmp_inc_ipreasmfails(void)

+{

+  ipreasmfails++;

+}

+

+void snmp_inc_ipfragoks(void)

+{

+  ipfragoks++;

+}

+

+void snmp_inc_ipfragfails(void)

+{

+  ipfragfails++;

+}

+

+void snmp_inc_ipfragcreates(void)

+{

+  ipfragcreates++;

+}

+

+void snmp_inc_iproutingdiscards(void)

+{

+  iproutingdiscards++;

+}

+

+/**

+ * Inserts ipAddrTable indexes (.ipAdEntAddr)

+ * into index tree.

+ */

+void snmp_insert_ipaddridx_tree(struct netif *ni)

+{

+  struct mib_list_rootnode *ipa_rn;

+  struct mib_list_node *ipa_node;

+  struct ip_addr ip;

+  s32_t ipaddridx[4];

+  u8_t level;

+

+  LWIP_ASSERT("ni != NULL", ni != NULL);

+  ip.addr = ntohl(ni->ip_addr.addr);

+  snmp_iptooid(&ip, &ipaddridx[0]);

+

+  level = 0;

+  ipa_rn = &ipaddrtree_root;

+  while (level < 4)

+  {

+    ipa_node = NULL;

+    snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node);

+    if ((level != 3) && (ipa_node != NULL))

+    {

+      if (ipa_node->nptr == NULL)

+      {

+        ipa_rn = snmp_mib_lrn_alloc();

+        ipa_node->nptr = (struct mib_node*)ipa_rn;

+        if (ipa_rn != NULL)

+        {

+          if (level == 2)

+          {

+            ipa_rn->get_object_def = ip_addrentry_get_object_def;

+            ipa_rn->get_value = ip_addrentry_get_value;

+            ipa_rn->set_test = noleafs_set_test;

+            ipa_rn->set_value = noleafs_set_value;

+          }

+        }

+        else

+        {

+          /* ipa_rn == NULL, malloc failure */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full"));

+          break;

+        }

+      }

+      else

+      {

+        ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr;

+      }

+    }

+    level++;

+  }

+  /* enable getnext traversal on filled table */

+  ipaddrtable.maxlength = 1;

+}

+

+/**

+ * Removes ipAddrTable indexes (.ipAdEntAddr)

+ * from index tree.

+ */

+void snmp_delete_ipaddridx_tree(struct netif *ni)

+{

+  struct mib_list_rootnode *ipa_rn, *next, *del_rn[4];

+  struct mib_list_node *ipa_n, *del_n[4];

+  struct ip_addr ip;

+  s32_t ipaddridx[4];

+  u8_t fc, level, del_cnt;

+

+  LWIP_ASSERT("ni != NULL", ni != NULL);

+  ip.addr = ntohl(ni->ip_addr.addr);

+  snmp_iptooid(&ip, &ipaddridx[0]);

+

+  /* mark nodes for deletion */

+  level = 0;

+  del_cnt = 0;

+  ipa_rn = &ipaddrtree_root;

+  while ((level < 4) && (ipa_rn != NULL))

+  {

+    fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n);

+    if (fc == 0)

+    {

+      /* ipaddridx[level] does not exist */

+      del_cnt = 0;

+      ipa_rn = NULL;

+    }

+    else if (fc == 1)

+    {

+      del_rn[del_cnt] = ipa_rn;

+      del_n[del_cnt] = ipa_n;

+      del_cnt++;

+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);

+    }

+    else if (fc == 2)

+    {

+      /* reset delete (2 or more childs) */

+      del_cnt = 0;

+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);

+    }

+    level++;

+  }

+  /* delete marked index nodes */

+  while (del_cnt > 0)

+  {

+    del_cnt--;

+

+    ipa_rn = del_rn[del_cnt];

+    ipa_n = del_n[del_cnt];

+

+    next = snmp_mib_node_delete(ipa_rn, ipa_n);

+    if (next != NULL)

+    {

+      LWIP_ASSERT("next_count == 0",next->count == 0);

+      snmp_mib_lrn_free(next);

+    }

+  }

+  /* disable getnext traversal on empty table */

+  if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0;

+}

+

+/**

+ * Inserts ipRouteTable indexes (.ipRouteDest)

+ * into index tree.

+ *

+ * @param dflt non-zero for the default rte, zero for network rte

+ * @param netif points to network interface for this rte

+ *

+ * @todo record sysuptime for _this_ route when it is installed

+ *   (needed for ipRouteAge) in the netif.

+ */

+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni)

+{

+  u8_t insert = 0;

+  struct ip_addr dst;

+

+  if (dflt != 0)

+  {

+    /* the default route 0.0.0.0 */

+    dst.addr = 0;

+    insert = 1;

+  }

+  else

+  {

+    /* route to the network address */

+    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);

+    /* exclude 0.0.0.0 network (reserved for default rte) */

+    if (dst.addr != 0) insert = 1;

+  }

+  if (insert)

+  {

+    struct mib_list_rootnode *iprte_rn;

+    struct mib_list_node *iprte_node;

+    s32_t iprteidx[4];

+    u8_t level;

+

+    snmp_iptooid(&dst, &iprteidx[0]);

+    level = 0;

+    iprte_rn = &iprtetree_root;

+    while (level < 4)

+    {

+      iprte_node = NULL;

+      snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node);

+      if ((level != 3) && (iprte_node != NULL))

+      {

+        if (iprte_node->nptr == NULL)

+        {

+          iprte_rn = snmp_mib_lrn_alloc();

+          iprte_node->nptr = (struct mib_node*)iprte_rn;

+          if (iprte_rn != NULL)

+          {

+            if (level == 2)

+            {

+              iprte_rn->get_object_def = ip_rteentry_get_object_def;

+              iprte_rn->get_value = ip_rteentry_get_value;

+              iprte_rn->set_test = noleafs_set_test;

+              iprte_rn->set_value = noleafs_set_value;

+            }

+          }

+          else

+          {

+            /* iprte_rn == NULL, malloc failure */

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full"));

+            break;

+          }

+        }

+        else

+        {

+          iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr;

+        }

+      }

+      level++;

+    }

+  }

+  /* enable getnext traversal on filled table */

+  iprtetable.maxlength = 1;

+}

+

+/**

+ * Removes ipRouteTable indexes (.ipRouteDest)

+ * from index tree.

+ *

+ * @param dflt non-zero for the default rte, zero for network rte

+ * @param netif points to network interface for this rte or NULL

+ *   for default route to be removed.

+ */

+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni)

+{

+  u8_t delete = 0;

+  struct ip_addr dst;

+

+  if (dflt != 0)

+  {

+    /* the default route 0.0.0.0 */

+    dst.addr = 0;

+    delete = 1;

+  }

+  else

+  {

+    /* route to the network address */

+    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);

+    /* exclude 0.0.0.0 network (reserved for default rte) */

+    if (dst.addr != 0) delete = 1;

+  }

+  if (delete)

+  {

+    struct mib_list_rootnode *iprte_rn, *next, *del_rn[4];

+    struct mib_list_node *iprte_n, *del_n[4];

+    s32_t iprteidx[4];

+    u8_t fc, level, del_cnt;

+

+    snmp_iptooid(&dst, &iprteidx[0]);

+    /* mark nodes for deletion */

+    level = 0;

+    del_cnt = 0;

+    iprte_rn = &iprtetree_root;

+    while ((level < 4) && (iprte_rn != NULL))

+    {

+      fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n);

+      if (fc == 0)

+      {

+        /* iprteidx[level] does not exist */

+        del_cnt = 0;

+        iprte_rn = NULL;

+      }

+      else if (fc == 1)

+      {

+        del_rn[del_cnt] = iprte_rn;

+        del_n[del_cnt] = iprte_n;

+        del_cnt++;

+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);

+      }

+      else if (fc == 2)

+      {

+        /* reset delete (2 or more childs) */

+        del_cnt = 0;

+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);

+      }

+      level++;

+    }

+    /* delete marked index nodes */

+    while (del_cnt > 0)

+    {

+      del_cnt--;

+

+      iprte_rn = del_rn[del_cnt];

+      iprte_n = del_n[del_cnt];

+

+      next = snmp_mib_node_delete(iprte_rn, iprte_n);

+      if (next != NULL)

+      {

+        LWIP_ASSERT("next_count == 0",next->count == 0);

+        snmp_mib_lrn_free(next);

+      }

+    }

+  }

+  /* disable getnext traversal on empty table */

+  if (iprtetree_root.count == 0) iprtetable.maxlength = 0;

+}

+

+

+void snmp_inc_icmpinmsgs(void)

+{

+  icmpinmsgs++;

+}

+

+void snmp_inc_icmpinerrors(void)

+{

+  icmpinerrors++;

+}

+

+void snmp_inc_icmpindestunreachs(void)

+{

+  icmpindestunreachs++;

+}

+

+void snmp_inc_icmpintimeexcds(void)

+{

+  icmpintimeexcds++;

+}

+

+void snmp_inc_icmpinparmprobs(void)

+{

+  icmpinparmprobs++;

+}

+

+void snmp_inc_icmpinsrcquenchs(void)

+{

+  icmpinsrcquenchs++;

+}

+

+void snmp_inc_icmpinredirects(void)

+{

+  icmpinredirects++;

+}

+

+void snmp_inc_icmpinechos(void)

+{

+  icmpinechos++;

+}

+

+void snmp_inc_icmpinechoreps(void)

+{

+  icmpinechoreps++;

+}

+

+void snmp_inc_icmpintimestamps(void)

+{

+  icmpintimestamps++;

+}

+

+void snmp_inc_icmpintimestampreps(void)

+{

+  icmpintimestampreps++;

+}

+

+void snmp_inc_icmpinaddrmasks(void)

+{

+  icmpinaddrmasks++;

+}

+

+void snmp_inc_icmpinaddrmaskreps(void)

+{

+  icmpinaddrmaskreps++;

+}

+

+void snmp_inc_icmpoutmsgs(void)

+{

+  icmpoutmsgs++;

+}

+

+void snmp_inc_icmpouterrors(void)

+{

+  icmpouterrors++;

+}

+

+void snmp_inc_icmpoutdestunreachs(void)

+{

+  icmpoutdestunreachs++;

+}

+

+void snmp_inc_icmpouttimeexcds(void)

+{

+  icmpouttimeexcds++;

+}

+

+void snmp_inc_icmpoutparmprobs(void)

+{

+  icmpoutparmprobs++;

+}

+

+void snmp_inc_icmpoutsrcquenchs(void)

+{

+  icmpoutsrcquenchs++;

+}

+

+void snmp_inc_icmpoutredirects(void)

+{

+  icmpoutredirects++;

+}

+

+void snmp_inc_icmpoutechos(void)

+{

+  icmpoutechos++;

+}

+

+void snmp_inc_icmpoutechoreps(void)

+{

+  icmpoutechoreps++;

+}

+

+void snmp_inc_icmpouttimestamps(void)

+{

+  icmpouttimestamps++;

+}

+

+void snmp_inc_icmpouttimestampreps(void)

+{

+  icmpouttimestampreps++;

+}

+

+void snmp_inc_icmpoutaddrmasks(void)

+{

+  icmpoutaddrmasks++;

+}

+

+void snmp_inc_icmpoutaddrmaskreps(void)

+{

+  icmpoutaddrmaskreps++;

+}

+

+void snmp_inc_tcpactiveopens(void)

+{

+  tcpactiveopens++;

+}

+

+void snmp_inc_tcppassiveopens(void)

+{

+  tcppassiveopens++;

+}

+

+void snmp_inc_tcpattemptfails(void)

+{

+  tcpattemptfails++;

+}

+

+void snmp_inc_tcpestabresets(void)

+{

+  tcpestabresets++;

+}

+

+void snmp_inc_tcpinsegs(void)

+{

+  tcpinsegs++;

+}

+

+void snmp_inc_tcpoutsegs(void)

+{

+  tcpoutsegs++;

+}

+

+void snmp_inc_tcpretranssegs(void)

+{

+  tcpretranssegs++;

+}

+

+void snmp_inc_tcpinerrs(void)

+{

+  tcpinerrs++;

+}

+

+void snmp_inc_tcpoutrsts(void)

+{

+  tcpoutrsts++;

+}

+

+void snmp_inc_udpindatagrams(void)

+{

+  udpindatagrams++;

+}

+

+void snmp_inc_udpnoports(void)

+{

+  udpnoports++;

+}

+

+void snmp_inc_udpinerrors(void)

+{

+  udpinerrors++;

+}

+

+void snmp_inc_udpoutdatagrams(void)

+{

+  udpoutdatagrams++;

+}

+

+/**

+ * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort)

+ * into index tree.

+ */

+void snmp_insert_udpidx_tree(struct udp_pcb *pcb)

+{

+  struct mib_list_rootnode *udp_rn;

+  struct mib_list_node *udp_node;

+  struct ip_addr ip;

+  s32_t udpidx[5];

+  u8_t level;

+

+  LWIP_ASSERT("pcb != NULL", pcb != NULL);

+  ip.addr = ntohl(pcb->local_ip.addr);

+  snmp_iptooid(&ip, &udpidx[0]);

+  udpidx[4] = pcb->local_port;

+

+  udp_rn = &udp_root;

+  for (level = 0; level < 5; level++)

+  {

+    udp_node = NULL;

+    snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node);

+    if ((level != 4) && (udp_node != NULL))

+    {

+      if (udp_node->nptr == NULL)

+      {

+        udp_rn = snmp_mib_lrn_alloc();

+        udp_node->nptr = (struct mib_node*)udp_rn;

+        if (udp_rn != NULL)

+        {

+          if (level == 3)

+          {

+            udp_rn->get_object_def = udpentry_get_object_def;

+            udp_rn->get_value = udpentry_get_value;

+            udp_rn->set_test = noleafs_set_test;

+            udp_rn->set_value = noleafs_set_value;

+          }

+        }

+        else

+        {

+          /* udp_rn == NULL, malloc failure */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full"));

+          break;

+        }

+      }

+      else

+      {

+        udp_rn = (struct mib_list_rootnode*)udp_node->nptr;

+      }

+    }

+  }

+  udptable.maxlength = 1;

+}

+

+/**

+ * Removes udpTable indexes (.udpLocalAddress.udpLocalPort)

+ * from index tree.

+ */

+void snmp_delete_udpidx_tree(struct udp_pcb *pcb)

+{

+  struct mib_list_rootnode *udp_rn, *next, *del_rn[5];

+  struct mib_list_node *udp_n, *del_n[5];

+  struct ip_addr ip;

+  s32_t udpidx[5];

+  u8_t bindings, fc, level, del_cnt;

+

+  LWIP_ASSERT("pcb != NULL", pcb != NULL);

+  ip.addr = ntohl(pcb->local_ip.addr);

+  snmp_iptooid(&ip, &udpidx[0]);

+  udpidx[4] = pcb->local_port;

+

+  /* count PCBs for a given binding

+     (e.g. when reusing ports or for temp output PCBs) */

+  bindings = 0;

+  pcb = udp_pcbs;

+  while ((pcb != NULL))

+  {

+    if ((pcb->local_ip.addr == ip.addr) &&

+        (pcb->local_port == udpidx[4]))

+    {

+      bindings++;

+    }

+    pcb = pcb->next;

+  }

+  if (bindings == 1)

+  {

+    /* selectively remove */

+    /* mark nodes for deletion */

+    level = 0;

+    del_cnt = 0;

+    udp_rn = &udp_root;

+    while ((level < 5) && (udp_rn != NULL))

+    {

+      fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n);

+      if (fc == 0)

+      {

+        /* udpidx[level] does not exist */

+        del_cnt = 0;

+        udp_rn = NULL;

+      }

+      else if (fc == 1)

+      {

+        del_rn[del_cnt] = udp_rn;

+        del_n[del_cnt] = udp_n;

+        del_cnt++;

+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);

+      }

+      else if (fc == 2)

+      {

+        /* reset delete (2 or more childs) */

+        del_cnt = 0;

+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);

+      }

+      level++;

+    }

+    /* delete marked index nodes */

+    while (del_cnt > 0)

+    {

+      del_cnt--;

+

+      udp_rn = del_rn[del_cnt];

+      udp_n = del_n[del_cnt];

+

+      next = snmp_mib_node_delete(udp_rn, udp_n);

+      if (next != NULL)

+      {

+        LWIP_ASSERT("next_count == 0",next->count == 0);

+        snmp_mib_lrn_free(next);

+      }

+    }

+  }

+  /* disable getnext traversal on empty table */

+  if (udp_root.count == 0) udptable.maxlength = 0;

+}

+

+

+void snmp_inc_snmpinpkts(void)

+{

+  snmpinpkts++;

+}

+

+void snmp_inc_snmpoutpkts(void)

+{

+  snmpoutpkts++;

+}

+

+void snmp_inc_snmpinbadversions(void)

+{

+  snmpinbadversions++;

+}

+

+void snmp_inc_snmpinbadcommunitynames(void)

+{

+  snmpinbadcommunitynames++;

+}

+

+void snmp_inc_snmpinbadcommunityuses(void)

+{

+  snmpinbadcommunityuses++;

+}

+

+void snmp_inc_snmpinasnparseerrs(void)

+{

+  snmpinasnparseerrs++;

+}

+

+void snmp_inc_snmpintoobigs(void)

+{

+  snmpintoobigs++;

+}

+

+void snmp_inc_snmpinnosuchnames(void)

+{

+  snmpinnosuchnames++;

+}

+

+void snmp_inc_snmpinbadvalues(void)

+{

+  snmpinbadvalues++;

+}

+

+void snmp_inc_snmpinreadonlys(void)

+{

+  snmpinreadonlys++;

+}

+

+void snmp_inc_snmpingenerrs(void)

+{

+  snmpingenerrs++;

+}

+

+void snmp_add_snmpintotalreqvars(u8_t value)

+{

+  snmpintotalreqvars += value;

+}

+

+void snmp_add_snmpintotalsetvars(u8_t value)

+{

+  snmpintotalsetvars += value;

+}

+

+void snmp_inc_snmpingetrequests(void)

+{

+  snmpingetrequests++;

+}

+

+void snmp_inc_snmpingetnexts(void)

+{

+  snmpingetnexts++;

+}

+

+void snmp_inc_snmpinsetrequests(void)

+{

+  snmpinsetrequests++;

+}

+

+void snmp_inc_snmpingetresponses(void)

+{

+  snmpingetresponses++;

+}

+

+void snmp_inc_snmpintraps(void)

+{

+  snmpintraps++;

+}

+

+void snmp_inc_snmpouttoobigs(void)

+{

+  snmpouttoobigs++;

+}

+

+void snmp_inc_snmpoutnosuchnames(void)

+{

+  snmpoutnosuchnames++;

+}

+

+void snmp_inc_snmpoutbadvalues(void)

+{

+  snmpoutbadvalues++;

+}

+

+void snmp_inc_snmpoutgenerrs(void)

+{

+  snmpoutgenerrs++;

+}

+

+void snmp_inc_snmpoutgetrequests(void)

+{

+  snmpoutgetrequests++;

+}

+

+void snmp_inc_snmpoutgetnexts(void)

+{

+  snmpoutgetnexts++;

+}

+

+void snmp_inc_snmpoutsetrequests(void)

+{

+  snmpoutsetrequests++;

+}

+

+void snmp_inc_snmpoutgetresponses(void)

+{

+  snmpoutgetresponses++;

+}

+

+void snmp_inc_snmpouttraps(void)

+{

+  snmpouttraps++;

+}

+

+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid)

+{

+  *oid = &snmpgrp_id;

+}

+

+void snmp_set_snmpenableauthentraps(u8_t *value)

+{

+  if (value != NULL)

+  {

+    snmpenableauthentraps_ptr = value;

+  }

+}

+

+void snmp_get_snmpenableauthentraps(u8_t *value)

+{

+  *value = *snmpenableauthentraps_ptr;

+}

+

+void

+noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  if (ident_len){}

+  if (ident){}

+  od->instance = MIB_OBJECT_NONE;

+}

+

+void

+noleafs_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  if (od){}

+  if (len){}

+  if (value){}

+}

+

+u8_t

+noleafs_set_test(struct obj_def *od, u16_t len, void *value)

+{

+  if (od){}

+  if (len){}

+  if (value){}

+  /* can't set */

+  return 0;

+}

+

+void

+noleafs_set_value(struct obj_def *od, u16_t len, void *value)

+{

+  if (od){}

+  if (len){}

+  if (value){}

+}

+

+

+/**

+ * Returns systems object definitions.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.0 (object id trailer)

+ * @param od points to object definition.

+ */

+static void

+system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id));

+    switch (id)

+    {

+      case 1: /* sysDescr */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = *sysdescr_len_ptr;

+        break;

+      case 2: /* sysObjectID */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);

+        od->v_len = sysobjid.len * sizeof(s32_t);

+        break;

+      case 3: /* sysUpTime */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 4: /* sysContact */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = *syscontact_len_ptr;

+        break;

+      case 5: /* sysName */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = *sysname_len_ptr;

+        break;

+      case 6: /* sysLocation */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = *syslocation_len_ptr;

+        break;

+      case 7: /* sysServices */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+/**

+ * Returns system object value.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.0 (object id trailer)

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value into.

+ */

+static void

+system_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* sysDescr */

+      ocstrncpy(value,sysdescr_ptr,len);

+      break;

+    case 2: /* sysObjectID */

+      objectidncpy((s32_t*)value,(s32_t*)sysobjid.id,len / sizeof(s32_t));

+      break;

+    case 3: /* sysUpTime */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = sysuptime;

+      }

+      break;

+    case 4: /* sysContact */

+      ocstrncpy(value,syscontact_ptr,len);

+      break;

+    case 5: /* sysName */

+      ocstrncpy(value,sysname_ptr,len);

+      break;

+    case 6: /* sysLocation */

+      ocstrncpy(value,syslocation_ptr,len);

+      break;

+    case 7: /* sysServices */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = sysservices;

+      }

+      break;

+  };

+}

+

+static u8_t

+system_set_test(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id, set_ok;

+

+  if (value) {}

+  set_ok = 0;

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 4: /* sysContact */

+      if ((syscontact_ptr != syscontact_default) &&

+          (len <= 255))

+      {

+        set_ok = 1;

+      }

+      break;

+    case 5: /* sysName */

+      if ((sysname_ptr != sysname_default) &&

+          (len <= 255))

+      {

+        set_ok = 1;

+      }

+      break;

+    case 6: /* sysLocation */

+      if ((syslocation_ptr != syslocation_default) &&

+          (len <= 255))

+      {

+        set_ok = 1;

+      }

+      break;

+  };

+  return set_ok;

+}

+

+static void

+system_set_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 4: /* sysContact */

+      ocstrncpy(syscontact_ptr,value,len);

+      *syscontact_len_ptr = len;

+      break;

+    case 5: /* sysName */

+      ocstrncpy(sysname_ptr,value,len);

+      *sysname_len_ptr = len;

+      break;

+    case 6: /* sysLocation */

+      ocstrncpy(syslocation_ptr,value,len);

+      *syslocation_len_ptr = len;

+      break;

+  };

+}

+

+/**

+ * Returns interfaces.ifnumber object definition.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.index

+ * @param od points to object definition.

+ */

+static void

+interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    od->instance = MIB_OBJECT_SCALAR;

+    od->access = MIB_OBJECT_READ_ONLY;

+    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+    od->v_len = sizeof(s32_t);

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+/**

+ * Returns interfaces.ifnumber object value.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.0 (object id trailer)

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value into.

+ */

+static void

+interfaces_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  if (len){}

+  if (od->id_inst_ptr[0] == 1)

+  {

+    s32_t *sint_ptr = value;

+    *sint_ptr = iflist_root.count;

+  }

+}

+

+/**

+ * Returns ifentry object definitions.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.index

+ * @param od points to object definition.

+ */

+static void

+ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id));

+    switch (id)

+    {

+      case 1: /* ifIndex */

+      case 3: /* ifType */

+      case 4: /* ifMtu */

+      case 8: /* ifOperStatus */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 2: /* ifDescr */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        /** @todo this should be some sort of sizeof(struct netif.name) */

+        od->v_len = 2;

+        break;

+      case 5: /* ifSpeed */

+      case 21: /* ifOutQLen */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 6: /* ifPhysAddress */

+        {

+          struct netif *netif;

+

+          snmp_ifindextonetif(ident[1], &netif);

+          od->instance = MIB_OBJECT_TAB;

+          od->access = MIB_OBJECT_READ_ONLY;

+          od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+          od->v_len = netif->hwaddr_len;

+        }

+        break;

+      case 7: /* ifAdminStatus */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 9: /* ifLastChange */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 10: /* ifInOctets */

+      case 11: /* ifInUcastPkts */

+      case 12: /* ifInNUcastPkts */

+      case 13: /* ifInDiscarts */

+      case 14: /* ifInErrors */

+      case 15: /* ifInUnkownProtos */

+      case 16: /* ifOutOctets */

+      case 17: /* ifOutUcastPkts */

+      case 18: /* ifOutNUcastPkts */

+      case 19: /* ifOutDiscarts */

+      case 20: /* ifOutErrors */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 22: /* ifSpecific */

+        /** @note returning zeroDotZero (0.0) no media specific MIB support */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);

+        od->v_len = ifspecific.len * sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+/**

+ * Returns ifentry object value.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.0 (object id trailer)

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value into.

+ */

+static void

+ifentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  struct netif *netif;

+  u8_t id;

+

+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* ifIndex */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = od->id_inst_ptr[1];

+      }

+      break;

+    case 2: /* ifDescr */

+      ocstrncpy(value,(u8_t*)netif->name,len);

+      break;

+    case 3: /* ifType */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = netif->link_type;

+      }

+      break;

+    case 4: /* ifMtu */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = netif->mtu;

+      }

+      break;

+    case 5: /* ifSpeed */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->link_speed;

+      }

+      break;

+    case 6: /* ifPhysAddress */

+      ocstrncpy(value,netif->hwaddr,len);

+      break;

+    case 7: /* ifAdminStatus */

+    case 8: /* ifOperStatus */

+      {

+        s32_t *sint_ptr = value;

+        if (netif_is_up(netif))

+        {

+          *sint_ptr = 1;

+        }

+        else

+        {

+          *sint_ptr = 2;

+        }

+      }

+      break;

+    case 9: /* ifLastChange */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ts;

+      }

+      break;

+    case 10: /* ifInOctets */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifinoctets;

+      }

+      break;

+    case 11: /* ifInUcastPkts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifinucastpkts;

+      }

+      break;

+    case 12: /* ifInNUcastPkts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifinnucastpkts;

+      }

+      break;

+    case 13: /* ifInDiscarts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifindiscards;

+      }

+      break;

+    case 14: /* ifInErrors */

+    case 15: /* ifInUnkownProtos */

+      /** @todo add these counters! */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = 0;

+      }

+      break;

+    case 16: /* ifOutOctets */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifoutoctets;

+      }

+      break;

+    case 17: /* ifOutUcastPkts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifoutucastpkts;

+      }

+      break;

+    case 18: /* ifOutNUcastPkts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifoutnucastpkts;

+      }

+      break;

+    case 19: /* ifOutDiscarts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifoutdiscards;

+      }

+      break;

+    case 20: /* ifOutErrors */

+       /** @todo add this counter! */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = 0;

+      }

+      break;

+    case 21: /* ifOutQLen */

+      /** @todo figure out if this must be 0 (no queue) or 1? */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = 0;

+      }

+      break;

+    case 22: /* ifSpecific */

+      objectidncpy((s32_t*)value,(s32_t*)ifspecific.id,len / sizeof(s32_t));

+      break;

+  };

+}

+

+/**

+ * Returns atentry object definitions.

+ *

+ * @param ident_len the address length (6)

+ * @param ident points to objectname.atifindex.atnetaddress

+ * @param od points to object definition.

+ */

+static void

+atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (5) */

+  ident_len += 5;

+  ident -= 5;

+

+  if (ident_len == 6)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    switch (ident[0])

+    {

+      case 1: /* atIfIndex */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 2: /* atPhysAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = sizeof(struct eth_addr);

+        break;

+      case 3: /* atNetAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+atentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+  struct eth_addr* ethaddr_ret;

+  struct ip_addr* ipaddr_ret;

+  struct ip_addr ip;

+  struct netif *netif;

+

+  if (len) {}

+

+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);

+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);

+  ip.addr = htonl(ip.addr);

+

+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)

+  {

+    id = od->id_inst_ptr[0];

+    switch (id)

+    {

+      case 1: /* atIfIndex */

+        {

+          s32_t *sint_ptr = value;

+          *sint_ptr = od->id_inst_ptr[1];

+        }

+        break;

+      case 2: /* atPhysAddress */

+        {

+          struct eth_addr *dst = value;

+

+          *dst = *ethaddr_ret;

+        }

+        break;

+      case 3: /* atNetAddress */

+        {

+          struct ip_addr *dst = value;

+

+          *dst = *ipaddr_ret;

+        }

+        break;

+    }

+  }

+}

+

+static void

+ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id));

+    switch (id)

+    {

+      case 1: /* ipForwarding */

+      case 2: /* ipDefaultTTL */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 3: /* ipInReceives */

+      case 4: /* ipInHdrErrors */

+      case 5: /* ipInAddrErrors */

+      case 6: /* ipForwDatagrams */

+      case 7: /* ipInUnknownProtos */

+      case 8: /* ipInDiscards */

+      case 9: /* ipInDelivers */

+      case 10: /* ipOutRequests */

+      case 11: /* ipOutDiscards */

+      case 12: /* ipOutNoRoutes */

+      case 14: /* ipReasmReqds */

+      case 15: /* ipReasmOKs */

+      case 16: /* ipReasmFails */

+      case 17: /* ipFragOKs */

+      case 18: /* ipFragFails */

+      case 19: /* ipFragCreates */

+      case 23: /* ipRoutingDiscards */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 13: /* ipReasmTimeout */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+ip_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+

+  if (len) {}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* ipForwarding */

+      {

+        s32_t *sint_ptr = value;

+#if IP_FORWARD

+        /* forwarding */

+        *sint_ptr = 1;

+#else

+        /* not-forwarding */

+        *sint_ptr = 2;

+#endif

+      }

+      break;

+    case 2: /* ipDefaultTTL */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = IP_DEFAULT_TTL;

+      }

+      break;

+    case 3: /* ipInReceives */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipinreceives;

+      }

+      break;

+    case 4: /* ipInHdrErrors */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipinhdrerrors;

+      }

+      break;

+    case 5: /* ipInAddrErrors */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipinaddrerrors;

+      }

+      break;

+    case 6: /* ipForwDatagrams */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipforwdatagrams;

+      }

+      break;

+    case 7: /* ipInUnknownProtos */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipinunknownprotos;

+      }

+      break;

+    case 8: /* ipInDiscards */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipindiscards;

+      }

+      break;

+    case 9: /* ipInDelivers */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipindelivers;

+      }

+      break;

+    case 10: /* ipOutRequests */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipoutrequests;

+      }

+      break;

+    case 11: /* ipOutDiscards */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipoutdiscards;

+      }

+      break;

+    case 12: /* ipOutNoRoutes */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipoutnoroutes;

+      }

+      break;

+    case 13: /* ipReasmTimeout */

+      {

+        s32_t *sint_ptr = value;

+#if IP_REASSEMBLY

+        *sint_ptr = IP_REASS_MAXAGE;

+#else

+        *sint_ptr = 0;

+#endif

+      }

+      break;

+    case 14: /* ipReasmReqds */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipreasmreqds;

+      }

+      break;

+    case 15: /* ipReasmOKs */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipreasmoks;

+      }

+      break;

+    case 16: /* ipReasmFails */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipreasmfails;

+      }

+      break;

+    case 17: /* ipFragOKs */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipfragoks;

+      }

+      break;

+    case 18: /* ipFragFails */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipfragfails;

+      }

+      break;

+    case 19: /* ipFragCreates */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipfragcreates;

+      }

+      break;

+    case 23: /* ipRoutingDiscards */

+      /** @todo can lwIP discard routes at all?? hardwire this to 0?? */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = iproutingdiscards;

+      }

+      break;

+  };

+}

+

+/**

+ * Test ip object value before setting.

+ *

+ * @param od is the object definition

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value from.

+ *

+ * @note we allow set if the value matches the hardwired value,

+ *   otherwise return badvalue.

+ */

+static u8_t

+ip_set_test(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id, set_ok;

+  s32_t *sint_ptr = value;

+

+  if (len) {}

+  set_ok = 0;

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* ipForwarding */

+#if IP_FORWARD

+      /* forwarding */

+      if (*sint_ptr == 1)

+#else

+      /* not-forwarding */

+      if (*sint_ptr == 2)

+#endif

+      {

+        set_ok = 1;

+      }

+      break;

+    case 2: /* ipDefaultTTL */

+      if (*sint_ptr == IP_DEFAULT_TTL)

+      {

+        set_ok = 1;

+      }

+      break;

+  };

+  return set_ok;

+}

+

+static void

+ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (4) */

+  ident_len += 4;

+  ident -= 4;

+

+  if (ident_len == 5)

+  {

+    u8_t id;

+

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* ipAdEntAddr */

+      case 3: /* ipAdEntNetMask */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      case 2: /* ipAdEntIfIndex */

+      case 4: /* ipAdEntBcastAddr */

+      case 5: /* ipAdEntReasmMaxSize */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+  u16_t ifidx;

+  struct ip_addr ip;

+  struct netif *netif = netif_list;

+

+  if (len) {}

+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);

+  ip.addr = htonl(ip.addr);

+  ifidx = 0;

+  while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr))

+  {

+    netif = netif->next;

+    ifidx++;

+  }

+

+  if (netif != NULL)

+  {

+    id = od->id_inst_ptr[0];

+    switch (id)

+    {

+      case 1: /* ipAdEntAddr */

+        {

+          struct ip_addr *dst = value;

+          *dst = netif->ip_addr;

+        }

+        break;

+      case 2: /* ipAdEntIfIndex */

+        {

+          s32_t *sint_ptr = value;

+          *sint_ptr = ifidx + 1;

+        }

+        break;

+      case 3: /* ipAdEntNetMask */

+        {

+          struct ip_addr *dst = value;

+          *dst = netif->netmask;

+        }

+        break;

+      case 4: /* ipAdEntBcastAddr */

+        {

+          s32_t *sint_ptr = value;

+

+          /* lwIP oddity, there's no broadcast

+            address in the netif we can rely on */

+          *sint_ptr = ip_addr_broadcast.addr & 1;

+        }

+        break;

+      case 5: /* ipAdEntReasmMaxSize */

+        {

+          s32_t *sint_ptr = value;

+#if IP_REASSEMBLY

+          *sint_ptr = (IP_HLEN + IP_REASS_BUFSIZE);

+#else

+          /** @todo returning MTU would be a bad thing and

+             returning a wild guess like '576' isn't good either */

+          *sint_ptr = 0;

+#endif

+        }

+        break;

+    }

+  }

+}

+

+/**

+ * @note

+ * lwIP IP routing is currently using the network addresses in netif_list.

+ * if no suitable network IP is found in netif_list, the default_netif is used.

+ */

+static void

+ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (4) */

+  ident_len += 4;

+  ident -= 4;

+

+  if (ident_len == 5)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* ipRouteDest */

+      case 7: /* ipRouteNextHop */

+      case 11: /* ipRouteMask */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      case 2: /* ipRouteIfIndex */

+      case 3: /* ipRouteMetric1 */

+      case 4: /* ipRouteMetric2 */

+      case 5: /* ipRouteMetric3 */

+      case 6: /* ipRouteMetric4 */

+      case 8: /* ipRouteType */

+      case 10: /* ipRouteAge */

+      case 12: /* ipRouteMetric5 */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 9: /* ipRouteProto */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 13: /* ipRouteInfo */

+        /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);

+        od->v_len = iprouteinfo.len * sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  struct netif *netif;

+  struct ip_addr dest;

+  s32_t *ident;

+  u8_t id;

+

+  ident = od->id_inst_ptr;

+  snmp_oidtoip(&ident[1], &dest);

+  dest.addr = htonl(dest.addr);

+

+  if (dest.addr == 0)

+  {

+    /* ip_route() uses default netif for default route */

+    netif = netif_default;

+  }

+  else

+  {

+    /* not using ip_route(), need exact match! */

+    netif = netif_list;

+    while ((netif != NULL) &&

+            !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) )

+    {

+      netif = netif->next;

+    }

+  }

+  if (netif != NULL)

+  {

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* ipRouteDest */

+        {

+          struct ip_addr *dst = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte has 0.0.0.0 dest */

+            dst->addr = 0;

+          }

+          else

+          {

+            /* netifs have netaddress dest */

+            dst->addr = netif->ip_addr.addr & netif->netmask.addr;

+          }

+        }

+        break;

+      case 2: /* ipRouteIfIndex */

+        {

+          s32_t *sint_ptr = value;

+

+          snmp_netiftoifindex(netif, sint_ptr);

+        }

+        break;

+      case 3: /* ipRouteMetric1 */

+        {

+          s32_t *sint_ptr = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte has metric 1 */

+            *sint_ptr = 1;

+          }

+          else

+          {

+            /* other rtes have metric 0 */

+            *sint_ptr = 0;

+          }

+        }

+        break;

+      case 4: /* ipRouteMetric2 */

+      case 5: /* ipRouteMetric3 */

+      case 6: /* ipRouteMetric4 */

+      case 12: /* ipRouteMetric5 */

+        {

+          s32_t *sint_ptr = value;

+          /* not used */

+          *sint_ptr = -1;

+        }

+        break;

+      case 7: /* ipRouteNextHop */

+        {

+          struct ip_addr *dst = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte: gateway */

+            *dst = netif->gw;

+          }

+          else

+          {

+            /* other rtes: netif ip_addr  */

+            *dst = netif->ip_addr;

+          }

+        }

+        break;

+      case 8: /* ipRouteType */

+        {

+          s32_t *sint_ptr = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte is indirect */

+            *sint_ptr = 4;

+          }

+          else

+          {

+            /* other rtes are direct */

+            *sint_ptr = 3;

+          }

+        }

+        break;

+      case 9: /* ipRouteProto */

+        {

+          s32_t *sint_ptr = value;

+          /* locally defined routes */

+          *sint_ptr = 2;

+        }

+        break;

+      case 10: /* ipRouteAge */

+        {

+          s32_t *sint_ptr = value;

+          /** @todo (sysuptime - timestamp last change) / 100

+              @see snmp_insert_iprteidx_tree() */

+          *sint_ptr = 0;

+        }

+        break;

+      case 11: /* ipRouteMask */

+        {

+          struct ip_addr *dst = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte use 0.0.0.0 mask */

+            dst->addr = 0;

+          }

+          else

+          {

+            /* other rtes use netmask */

+            *dst = netif->netmask;

+          }

+        }

+        break;

+      case 13: /* ipRouteInfo */

+        objectidncpy((s32_t*)value,(s32_t*)iprouteinfo.id,len / sizeof(s32_t));

+        break;

+    }

+  }

+}

+

+static void

+ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (5) */

+  ident_len += 5;

+  ident -= 5;

+

+  if (ident_len == 6)

+  {

+    u8_t id;

+

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* ipNetToMediaIfIndex */

+      case 4: /* ipNetToMediaType */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 2: /* ipNetToMediaPhysAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = sizeof(struct eth_addr);

+        break;

+      case 3: /* ipNetToMediaNetAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+  struct eth_addr* ethaddr_ret;

+  struct ip_addr* ipaddr_ret;

+  struct ip_addr ip;

+  struct netif *netif;

+

+  if (len) {}

+

+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);

+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);

+  ip.addr = htonl(ip.addr);

+

+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)

+  {

+    id = od->id_inst_ptr[0];

+    switch (id)

+    {

+      case 1: /* ipNetToMediaIfIndex */

+        {

+          s32_t *sint_ptr = value;

+          *sint_ptr = od->id_inst_ptr[1];

+        }

+        break;

+      case 2: /* ipNetToMediaPhysAddress */

+        {

+          struct eth_addr *dst = value;

+

+          *dst = *ethaddr_ret;

+        }

+        break;

+      case 3: /* ipNetToMediaNetAddress */

+        {

+          struct ip_addr *dst = value;

+

+          *dst = *ipaddr_ret;

+        }

+        break;

+      case 4: /* ipNetToMediaType */

+        {

+          s32_t *sint_ptr = value;

+          /* dynamic (?) */

+          *sint_ptr = 3;

+        }

+        break;

+    }

+  }

+}

+

+static void

+icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if ((ident_len == 2) &&

+      (ident[0] > 0) && (ident[0] < 27))

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    od->instance = MIB_OBJECT_SCALAR;

+    od->access = MIB_OBJECT_READ_ONLY;

+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+    od->v_len = sizeof(u32_t);

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+icmp_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u32_t *uint_ptr = value;

+  u8_t id;

+

+  if (len){}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* icmpInMsgs */

+      *uint_ptr = icmpinmsgs;

+      break;

+    case 2: /* icmpInErrors */

+      *uint_ptr = icmpinerrors;

+      break;

+    case 3: /* icmpInDestUnreachs */

+      *uint_ptr = icmpindestunreachs;

+      break;

+    case 4: /* icmpInTimeExcds */

+      *uint_ptr = icmpintimeexcds;

+      break;

+    case 5: /* icmpInParmProbs */

+      *uint_ptr = icmpinparmprobs;

+      break;

+    case 6: /* icmpInSrcQuenchs */

+      *uint_ptr = icmpinsrcquenchs;

+      break;

+    case 7: /* icmpInRedirects */

+      *uint_ptr = icmpinredirects;

+      break;

+    case 8: /* icmpInEchos */

+      *uint_ptr = icmpinechos;

+      break;

+    case 9: /* icmpInEchoReps */

+      *uint_ptr = icmpinechoreps;

+      break;

+    case 10: /* icmpInTimestamps */

+      *uint_ptr = icmpintimestamps;

+      break;

+    case 11: /* icmpInTimestampReps */

+      *uint_ptr = icmpintimestampreps;

+      break;

+    case 12: /* icmpInAddrMasks */

+      *uint_ptr = icmpinaddrmasks;

+      break;

+    case 13: /* icmpInAddrMaskReps */

+      *uint_ptr = icmpinaddrmaskreps;

+      break;

+    case 14: /* icmpOutMsgs */

+      *uint_ptr = icmpoutmsgs;

+      break;

+    case 15: /* icmpOutErrors */

+      *uint_ptr = icmpouterrors;

+      break;

+    case 16: /* icmpOutDestUnreachs */

+      *uint_ptr = icmpoutdestunreachs;

+      break;

+    case 17: /* icmpOutTimeExcds */

+      *uint_ptr = icmpouttimeexcds;

+      break;

+    case 18: /* icmpOutParmProbs */

+      *uint_ptr = icmpoutparmprobs;

+      break;

+    case 19: /* icmpOutSrcQuenchs */

+      *uint_ptr = icmpoutsrcquenchs;

+      break;

+    case 20: /* icmpOutRedirects */

+      *uint_ptr = icmpoutredirects;

+      break;

+    case 21: /* icmpOutEchos */

+      *uint_ptr = icmpoutechos;

+      break;

+    case 22: /* icmpOutEchoReps */

+      *uint_ptr = icmpoutechoreps;

+      break;

+    case 23: /* icmpOutTimestamps */

+      *uint_ptr = icmpouttimestamps;

+      break;

+    case 24: /* icmpOutTimestampReps */

+      *uint_ptr = icmpouttimestampreps;

+      break;

+    case 25: /* icmpOutAddrMasks */

+      *uint_ptr = icmpoutaddrmasks;

+      break;

+    case 26: /* icmpOutAddrMaskReps */

+      *uint_ptr = icmpoutaddrmaskreps;

+      break;

+  }

+}

+

+#if LWIP_TCP

+/** @todo tcp grp */

+static void

+tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));

+

+    switch (id)

+    {

+      case 1: /* tcpRtoAlgorithm */

+      case 2: /* tcpRtoMin */

+      case 3: /* tcpRtoMax */

+      case 4: /* tcpMaxConn */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 5: /* tcpActiveOpens */

+      case 6: /* tcpPassiveOpens */

+      case 7: /* tcpAttemptFails */

+      case 8: /* tcpEstabResets */

+      case 10: /* tcpInSegs */

+      case 11: /* tcpOutSegs */

+      case 12: /* tcpRetransSegs */

+      case 14: /* tcpInErrs */

+      case 15: /* tcpOutRsts */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 9: /* tcpCurrEstab */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);

+        od->v_len = sizeof(u32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+tcp_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u32_t *uint_ptr = value;

+  s32_t *sint_ptr = value;

+  u8_t id;

+

+  if (len){}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* tcpRtoAlgorithm, vanj(4) */

+      *sint_ptr = 4;

+      break;

+    case 2: /* tcpRtoMin */

+      /* @todo not the actual value, a guess,

+          needs to be calculated */

+      *sint_ptr = 1000;

+      break;

+    case 3: /* tcpRtoMax */

+      /* @todo not the actual value, a guess,

+         needs to be calculated */

+      *sint_ptr = 60000;

+      break;

+    case 4: /* tcpMaxConn */

+      *sint_ptr = MEMP_NUM_TCP_PCB;

+      break;

+    case 5: /* tcpActiveOpens */

+      *uint_ptr = tcpactiveopens;

+      break;

+    case 6: /* tcpPassiveOpens */

+      *uint_ptr = tcppassiveopens;

+      break;

+    case 7: /* tcpAttemptFails */

+      *uint_ptr = tcpattemptfails;

+      break;

+    case 8: /* tcpEstabResets */

+      *uint_ptr = tcpestabresets;

+      break;

+    case 9: /* tcpCurrEstab */

+      {

+        u16_t tcpcurrestab = 0;

+        struct tcp_pcb *pcb = tcp_active_pcbs;

+        while (pcb != NULL)

+        {

+          if ((pcb->state == ESTABLISHED) ||

+              (pcb->state == CLOSE_WAIT))

+          {

+            tcpcurrestab++;

+          }

+          pcb = pcb->next;

+        }

+        *uint_ptr = tcpcurrestab;

+      }

+      break;

+    case 10: /* tcpInSegs */

+      *uint_ptr = tcpinsegs;

+      break;

+    case 11: /* tcpOutSegs */

+      *uint_ptr = tcpoutsegs;

+      break;

+    case 12: /* tcpRetransSegs */

+      *uint_ptr = tcpretranssegs;

+      break;

+    case 14: /* tcpInErrs */

+      *uint_ptr = tcpinerrs;

+      break;

+    case 15: /* tcpOutRsts */

+      *uint_ptr = tcpoutrsts;

+      break;

+  }

+}

+

+static void

+tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (10) */

+  ident_len += 10;

+  ident -= 10;

+

+  if (ident_len == 11)

+  {

+    u8_t id;

+

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));

+

+    switch (id)

+    {

+      case 1: /* tcpConnState */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 2: /* tcpConnLocalAddress */

+      case 4: /* tcpConnRemAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      case 3: /* tcpConnLocalPort */

+      case 5: /* tcpConnRemPort */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  struct ip_addr lip, rip;

+  u16_t lport, rport;

+  s32_t *ident;

+

+  ident = od->id_inst_ptr;

+  snmp_oidtoip(&ident[1], &lip);

+  lip.addr = htonl(lip.addr);

+  lport = ident[5];

+  snmp_oidtoip(&ident[6], &rip);

+  rip.addr = htonl(rip.addr);

+  rport = ident[10];

+

+  /** @todo find matching PCB */

+}

+#endif

+

+static void

+udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if ((ident_len == 2) &&

+      (ident[0] > 0) && (ident[0] < 6))

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    od->instance = MIB_OBJECT_SCALAR;

+    od->access = MIB_OBJECT_READ_ONLY;

+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+    od->v_len = sizeof(u32_t);

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+udp_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u32_t *uint_ptr = value;

+  u8_t id;

+

+  if (len){}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* udpInDatagrams */

+      *uint_ptr = udpindatagrams;

+      break;

+    case 2: /* udpNoPorts */

+      *uint_ptr = udpnoports;

+      break;

+    case 3: /* udpInErrors */

+      *uint_ptr = udpinerrors;

+      break;

+    case 4: /* udpOutDatagrams */

+      *uint_ptr = udpoutdatagrams;

+      break;

+  }

+}

+

+static void

+udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (5) */

+  ident_len += 5;

+  ident -= 5;

+

+  if (ident_len == 6)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    switch (ident[0])

+    {

+      case 1: /* udpLocalAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      case 2: /* udpLocalPort */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+udpentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+  struct udp_pcb *pcb;

+  struct ip_addr ip;

+  u16_t port;

+

+  if (len){}

+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);

+  ip.addr = htonl(ip.addr);

+  port = od->id_inst_ptr[5];

+

+  pcb = udp_pcbs;

+  while ((pcb != NULL) &&

+         !((pcb->local_ip.addr == ip.addr) &&

+           (pcb->local_port == port)))

+  {

+    pcb = pcb->next;

+  }

+

+  if (pcb != NULL)

+  {

+    id = od->id_inst_ptr[0];

+    switch (id)

+    {

+      case 1: /* udpLocalAddress */

+        {

+          struct ip_addr *dst = value;

+          *dst = pcb->local_ip;

+        }

+        break;

+      case 2: /* udpLocalPort */

+        {

+          s32_t *sint_ptr = value;

+          *sint_ptr = pcb->local_port;

+        }

+        break;

+    }

+  }

+}

+

+static void

+snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    u8_t id;

+

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* snmpInPkts */

+      case 2: /* snmpOutPkts */

+      case 3: /* snmpInBadVersions */

+      case 4: /* snmpInBadCommunityNames */

+      case 5: /* snmpInBadCommunityUses */

+      case 6: /* snmpInASNParseErrs */

+      case 8: /* snmpInTooBigs */

+      case 9: /* snmpInNoSuchNames */

+      case 10: /* snmpInBadValues */

+      case 11: /* snmpInReadOnlys */

+      case 12: /* snmpInGenErrs */

+      case 13: /* snmpInTotalReqVars */

+      case 14: /* snmpInTotalSetVars */

+      case 15: /* snmpInGetRequests */

+      case 16: /* snmpInGetNexts */

+      case 17: /* snmpInSetRequests */

+      case 18: /* snmpInGetResponses */

+      case 19: /* snmpInTraps */

+      case 20: /* snmpOutTooBigs */

+      case 21: /* snmpOutNoSuchNames */

+      case 22: /* snmpOutBadValues */

+      case 24: /* snmpOutGenErrs */

+      case 25: /* snmpOutGetRequests */

+      case 26: /* snmpOutGetNexts */

+      case 27: /* snmpOutSetRequests */

+      case 28: /* snmpOutGetResponses */

+      case 29: /* snmpOutTraps */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 30: /* snmpEnableAuthenTraps */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+snmp_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u32_t *uint_ptr = value;

+  u8_t id;

+

+  if (len){}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+      case 1: /* snmpInPkts */

+        *uint_ptr = snmpinpkts;

+        break;

+      case 2: /* snmpOutPkts */

+        *uint_ptr = snmpoutpkts;

+        break;

+      case 3: /* snmpInBadVersions */

+        *uint_ptr = snmpinbadversions;

+        break;

+      case 4: /* snmpInBadCommunityNames */

+        *uint_ptr = snmpinbadcommunitynames;

+        break;

+      case 5: /* snmpInBadCommunityUses */

+        *uint_ptr = snmpinbadcommunityuses;

+        break;

+      case 6: /* snmpInASNParseErrs */

+        *uint_ptr = snmpinasnparseerrs;

+        break;

+      case 8: /* snmpInTooBigs */

+        *uint_ptr = snmpintoobigs;

+        break;

+      case 9: /* snmpInNoSuchNames */

+        *uint_ptr = snmpinnosuchnames;

+        break;

+      case 10: /* snmpInBadValues */

+        *uint_ptr = snmpinbadvalues;

+        break;

+      case 11: /* snmpInReadOnlys */

+        *uint_ptr = snmpinreadonlys;

+        break;

+      case 12: /* snmpInGenErrs */

+        *uint_ptr = snmpingenerrs;

+        break;

+      case 13: /* snmpInTotalReqVars */

+        *uint_ptr = snmpintotalreqvars;

+        break;

+      case 14: /* snmpInTotalSetVars */

+        *uint_ptr = snmpintotalsetvars;

+        break;

+      case 15: /* snmpInGetRequests */

+        *uint_ptr = snmpingetrequests;

+        break;

+      case 16: /* snmpInGetNexts */

+        *uint_ptr = snmpingetnexts;

+        break;

+      case 17: /* snmpInSetRequests */

+        *uint_ptr = snmpinsetrequests;

+        break;

+      case 18: /* snmpInGetResponses */

+        *uint_ptr = snmpingetresponses;

+        break;

+      case 19: /* snmpInTraps */

+        *uint_ptr = snmpintraps;

+        break;

+      case 20: /* snmpOutTooBigs */

+        *uint_ptr = snmpouttoobigs;

+        break;

+      case 21: /* snmpOutNoSuchNames */

+        *uint_ptr = snmpoutnosuchnames;

+        break;

+      case 22: /* snmpOutBadValues */

+        *uint_ptr = snmpoutbadvalues;

+        break;

+      case 24: /* snmpOutGenErrs */

+        *uint_ptr = snmpoutgenerrs;

+        break;

+      case 25: /* snmpOutGetRequests */

+        *uint_ptr = snmpoutgetrequests;

+        break;

+      case 26: /* snmpOutGetNexts */

+        *uint_ptr = snmpoutgetnexts;

+        break;

+      case 27: /* snmpOutSetRequests */

+        *uint_ptr = snmpoutsetrequests;

+        break;

+      case 28: /* snmpOutGetResponses */

+        *uint_ptr = snmpoutgetresponses;

+        break;

+      case 29: /* snmpOutTraps */

+        *uint_ptr = snmpouttraps;

+        break;

+      case 30: /* snmpEnableAuthenTraps */

+        *uint_ptr = *snmpenableauthentraps_ptr;

+        break;

+  };

+}

+

+/**

+ * Test snmp object value before setting.

+ *

+ * @param od is the object definition

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value from.

+ */

+static u8_t

+snmp_set_test(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id, set_ok;

+

+  if (len) {}

+  set_ok = 0;

+  id = od->id_inst_ptr[0];

+  if (id == 30)

+  {

+    /* snmpEnableAuthenTraps */

+    s32_t *sint_ptr = value;

+

+    if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default)

+    {

+      /* we should have writable non-volatile mem here */

+      if ((*sint_ptr == 1) || (*sint_ptr == 2))

+      {

+        set_ok = 1;

+      }

+    }

+    else

+    {

+      /* const or hardwired value */

+      if (*sint_ptr == snmpenableauthentraps_default)

+      {

+        set_ok = 1;

+      }

+    }

+  }

+  return set_ok;

+}

+

+static void

+snmp_set_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+

+  if (len) {}

+  id = od->id_inst_ptr[0];

+  if (id == 30)

+  {

+    /* snmpEnableAuthenTraps */

+    s32_t *sint_ptr = value;

+    *snmpenableauthentraps_ptr = *sint_ptr;

+  }

+}

+

+#endif /* LWIP_SNMP */

diff --git a/Demo/Common/ethernet/lwIP/core/snmp/mib_structs.c b/Demo/Common/ethernet/lwIP/core/snmp/mib_structs.c
index e68636a..1fad588 100644
--- a/Demo/Common/ethernet/lwIP/core/snmp/mib_structs.c
+++ b/Demo/Common/ethernet/lwIP/core/snmp/mib_structs.c
@@ -1,1185 +1,1185 @@
-/**
- * @file
- * MIB tree access/construction functions.
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * 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: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_SNMP
-#include "lwip/snmp_structs.h"
-#include "lwip/mem.h"
-
-
-
-/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */
-const s32_t prefix[4] = {1, 3, 6, 1};
-
-#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)
-/** node stack entry (old news?) */
-struct nse
-{
-  /** right child */
-  struct mib_node* r_ptr;
-  /** right child identifier */
-  s32_t r_id;
-  /** right child next level */
-  u8_t r_nl;
-};
-static u8_t node_stack_cnt = 0;
-static struct nse node_stack[NODE_STACK_SIZE];
-
-/**
- * Pushes nse struct onto stack.
- */
-static void
-push_node(struct nse* node)
-{
-  LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);
-  LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id));
-  if (node_stack_cnt < NODE_STACK_SIZE)
-  {
-    node_stack[node_stack_cnt] = *node;
-    node_stack_cnt++;
-  }
-}
-
-/**
- * Pops nse struct from stack.
- */
-static void
-pop_node(struct nse* node)
-{
-  if (node_stack_cnt > 0)
-  {
-    node_stack_cnt--;
-    *node = node_stack[node_stack_cnt];
-  }
-  LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id));
-}
-
-/**
- * Conversion from ifIndex to lwIP netif
- * @param ifindex is a s32_t object sub-identifier
- * @param netif points to returned netif struct pointer
- */
-void
-snmp_ifindextonetif(s32_t ifindex, struct netif **netif)
-{
-  struct netif *nif = netif_list;
-  u16_t i, ifidx;
-
-  ifidx = ifindex - 1;
-  i = 0;
-  while ((nif != NULL) && (i < ifidx))
-  {
-    nif = nif->next;
-    i++;
-  }
-  *netif = nif;
-}
-
-/**
- * Conversion from lwIP netif to ifIndex
- * @param netif points to a netif struct
- * @param ifindex points to s32_t object sub-identifier
- */
-void
-snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
-{
-  struct netif *nif = netif_list;
-  u16_t i;
-
-  i = 0;
-  while (nif != netif)
-  {
-    nif = nif->next;
-    i++;
-  }
-  *ifidx = i+1;
-}
-
-/**
- * Conversion from oid to lwIP ip_addr
- * @param ident points to s32_t ident[4] input
- * @param ip points to output struct
- */
-void
-snmp_oidtoip(s32_t *ident, struct ip_addr *ip)
-{
-  u32_t ipa;
-
-  ipa = ident[0];
-  ipa <<= 8;
-  ipa |= ident[1];
-  ipa <<= 8;
-  ipa |= ident[2];
-  ipa <<= 8;
-  ipa |= ident[3];
-  ip->addr = ipa;
-}
-
-/**
- * Conversion from lwIP ip_addr to oid
- * @param ip points to input struct
- * @param ident points to s32_t ident[4] output
- */
-void
-snmp_iptooid(struct ip_addr *ip, s32_t *ident)
-{
-  u32_t ipa;
-
-  ipa = ip->addr;
-  ident[0] = (ipa >> 24) & 0xff;
-  ident[1] = (ipa >> 16) & 0xff;
-  ident[2] = (ipa >> 8) & 0xff;
-  ident[3] = ipa & 0xff;
-}
-
-struct mib_list_node *
-snmp_mib_ln_alloc(s32_t id)
-{
-  struct mib_list_node *ln;
-
-  ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node));
-  if (ln != NULL)
-  {
-    ln->prev = NULL;
-    ln->next = NULL;
-    ln->objid = id;
-    ln->nptr = NULL;
-  }
-  return ln;
-}
-
-void
-snmp_mib_ln_free(struct mib_list_node *ln)
-{
-  mem_free(ln);
-}
-
-struct mib_list_rootnode *
-snmp_mib_lrn_alloc(void)
-{
-  struct mib_list_rootnode *lrn;
-
-  lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode));
-  if (lrn != NULL)
-  {
-    lrn->get_object_def = noleafs_get_object_def;
-    lrn->get_value = noleafs_get_value;
-    lrn->set_test = noleafs_set_test;
-    lrn->set_value = noleafs_set_value;
-    lrn->node_type = MIB_NODE_LR;
-    lrn->maxlength = 0;
-    lrn->head = NULL;
-    lrn->tail = NULL;
-    lrn->count = 0;
-  }
-  return lrn;
-}
-
-void
-snmp_mib_lrn_free(struct mib_list_rootnode *lrn)
-{
-  mem_free(lrn);
-}
-
-/**
- * Inserts node in idx list in a sorted
- * (ascending order) fashion and
- * allocates the node if needed.
- *
- * @param rn points to the root node
- * @param objid is the object sub identifier
- * @param insn points to a pointer to the inserted node
- *   used for constructing the tree.
- * @return -1 if failed, 1 if inserted, 2 if present.
- */
-s8_t
-snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)
-{
-  struct mib_list_node *nn;
-  s8_t insert;
-
-  LWIP_ASSERT("rn != NULL",rn != NULL);
-
-  /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */
-  insert = 0;
-  if (rn->head == NULL)
-  {
-    /* empty list, add first node */
-    LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));
-    nn = snmp_mib_ln_alloc(objid);
-    if (nn != NULL)
-    {
-      rn->head = nn;
-      rn->tail = nn;
-      *insn = nn;
-      insert = 1;
-    }
-    else
-    {
-      insert = -1;
-    }
-  }
-  else
-  {
-    struct mib_list_node *n;
-    /* at least one node is present */
-    n = rn->head;
-    while ((n != NULL) && (insert == 0))
-    {
-      if (n->objid == objid)
-      {
-        /* node is already there */
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));
-        *insn = n;
-        insert = 2;
-      }
-      else if (n->objid < objid)
-      {
-        if (n->next == NULL)
-        {
-          /* alloc and insert at the tail */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));
-          nn = snmp_mib_ln_alloc(objid);
-          if (nn != NULL)
-          {
-            nn->next = NULL;
-            nn->prev = n;
-            n->next = nn;
-            rn->tail = nn;
-            *insn = nn;
-            insert = 1;
-          }
-          else
-          {
-            /* insertion failure */
-            insert = -1;
-          }
-        }
-        else
-        {
-          /* there's more to explore: traverse list */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));
-          n = n->next;
-        }
-      }
-      else
-      {
-        /* n->objid > objid */
-        /* alloc and insert between n->prev and n */
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));
-        nn = snmp_mib_ln_alloc(objid);
-        if (nn != NULL)
-        {
-          if (n->prev == NULL)
-          {
-            /* insert at the head */
-            nn->next = n;
-            nn->prev = NULL;
-            rn->head = nn;
-            n->prev = nn;
-          }
-          else
-          {
-            /* insert in the middle */
-            nn->next = n;
-            nn->prev = n->prev;
-            n->prev->next = nn;
-            n->prev = nn;
-          }
-          *insn = nn;
-          insert = 1;
-        }
-        else
-        {
-          /* insertion failure */
-          insert = -1;
-        }
-      }
-    }
-  }
-  if (insert == 1)
-  {
-    rn->count += 1;
-  }
-  LWIP_ASSERT("insert != 0",insert != 0);
-  return insert;
-}
-
-/**
- * Finds node in idx list and returns deletion mark.
- *
- * @param rn points to the root node
- * @param objid  is the object sub identifier
- * @param fn returns pointer to found node
- * @return 0 if not found, 1 if deletable,
- *   2 can't delete (2 or more children), 3 not a list_node
- */
-s8_t
-snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)
-{
-  s8_t fc;
-  struct mib_list_node *n;
-
-  LWIP_ASSERT("rn != NULL",rn != NULL);
-  n = rn->head;
-  while ((n != NULL) && (n->objid != objid))
-  {
-    n = n->next;
-  }
-  if (n == NULL)
-  {
-    fc = 0;
-  }
-  else if (n->nptr == NULL)
-  {
-    /* leaf, can delete node */
-    fc = 1;
-  }
-  else
-  {
-    struct mib_list_rootnode *rn;
-
-    if (n->nptr->node_type == MIB_NODE_LR)
-    {
-      rn = (struct mib_list_rootnode *)n->nptr;
-      if (rn->count > 1)
-      {
-        /* can't delete node */
-        fc = 2;
-      }
-      else
-      {
-        /* count <= 1, can delete node */
-        fc = 1;
-      }
-    }
-    else
-    {
-      /* other node type */
-      fc = 3;
-    }
-  }
-  *fn = n;
-  return fc;
-}
-
-/**
- * Removes node from idx list
- * if it has a single child left.
- *
- * @param rn points to the root node
- * @param n points to the node to delete
- * @return the nptr to be freed by caller
- */
-struct mib_list_rootnode *
-snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)
-{
-  struct mib_list_rootnode *next;
-
-  LWIP_ASSERT("rn != NULL",rn != NULL);
-  LWIP_ASSERT("n != NULL",n != NULL);
-
-  /* caller must remove this sub-tree */
-  next = (struct mib_list_rootnode*)(n->nptr);
-  rn->count -= 1;
-
-  if (n == rn->head)
-  {
-    rn->head = n->next;
-    if (n->next != NULL)
-    {
-      /* not last node, new list begin */
-      n->next->prev = NULL;
-    }
-  }
-  else if (n == rn->tail)
-  {
-    rn->tail = n->prev;
-    if (n->prev != NULL)
-    {
-      /* not last node, new list end */
-      n->prev->next = NULL;
-    }
-  }
-  else
-  {
-    /* node must be in the middle */
-    n->prev->next = n->next;
-    n->next->prev = n->prev;
-  }
-  LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));
-  snmp_mib_ln_free(n);
-  if (rn->count == 0)
-  {
-    rn->head = NULL;
-    rn->tail = NULL;
-  }
-  return next;
-}
-
-
-
-/**
- * Searches tree for the supplied (scalar?) object identifier.
- *
- * @param node points to the root of the tree ('.internet')
- * @param ident_len the length of the supplied object identifier
- * @param ident points to the array of sub identifiers
- * @param np points to the found object instance (rerurn)
- * @return pointer to the requested parent (!) node if success, NULL otherwise
- */
-struct mib_node *
-snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)
-{
-  u8_t node_type, ext_level;
-
-  ext_level = 0;
-  LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident));
-  while (node != NULL)
-  {
-    node_type = node->node_type;
-    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
-    {
-      struct mib_array_node *an;
-      u16_t i;
-
-      if (ident_len > 0)
-      {
-        /* array node (internal ROM or RAM, fixed length) */
-        an = (struct mib_array_node *)node;
-        i = 0;
-        while ((i < an->maxlength) && (an->objid[i] != *ident))
-        {
-          i++;
-        }
-        if (i < an->maxlength)
-        {
-          /* found it, if available proceed to child, otherwise inspect leaf */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));
-          if (an->nptr[i] == NULL)
-          {
-            /* a scalar leaf OR table,
-               inspect remaining instance number / table index */
-            np->ident_len = ident_len;
-            np->ident = ident;
-            return (struct mib_node*)an;
-          }
-          else
-          {
-            /* follow next child pointer */
-            ident++;
-            ident_len--;
-            node = an->nptr[i];
-          }
-        }
-        else
-        {
-          /* search failed, identifier mismatch (nosuchname) */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));
-          return NULL;
-        }
-      }
-      else
-      {
-        /* search failed, short object identifier (nosuchname) */
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));
-        return NULL;
-      }
-    }
-    else if(node_type == MIB_NODE_LR)
-    {
-      struct mib_list_rootnode *lrn;
-      struct mib_list_node *ln;
-
-      if (ident_len > 0)
-      {
-        /* list root node (internal 'RAM', variable length) */
-        lrn = (struct mib_list_rootnode *)node;
-        ln = lrn->head;
-        /* iterate over list, head to tail */
-        while ((ln != NULL) && (ln->objid != *ident))
-        {
-          ln = ln->next;
-        }
-        if (ln != NULL)
-        {
-          /* found it, proceed to child */;
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
-          if (ln->nptr == NULL)
-          {
-            np->ident_len = ident_len;
-            np->ident = ident;
-            return (struct mib_node*)lrn;
-          }
-          else
-          {
-            /* follow next child pointer */
-            ident_len--;
-            ident++;
-            node = ln->nptr;
-          }
-        }
-        else
-        {
-          /* search failed */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));
-          return NULL;
-        }
-      }
-      else
-      {
-        /* search failed, short object identifier (nosuchname) */
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));
-        return NULL;
-      }
-    }
-    else if(node_type == MIB_NODE_EX)
-    {
-      struct mib_external_node *en;
-      u16_t i, len;
-
-      if (ident_len > 0)
-      {
-        /* external node (addressing and access via functions) */
-        en = (struct mib_external_node *)node;
-
-        i = 0;
-        len = en->level_length(en->addr_inf,ext_level);
-        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0))
-        {
-          i++;
-        }
-        if (i < len)
-        {
-          s32_t debug_id;
-
-          en->get_objid(en->addr_inf,ext_level,i,&debug_id);
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));
-          if ((ext_level + 1) == en->tree_levels)
-          {
-            np->ident_len = ident_len;
-            np->ident = ident;
-            return (struct mib_node*)en;
-          }
-          else
-          {
-            /* found it, proceed to child */
-            ident_len--;
-            ident++;
-            ext_level++;
-          }
-        }
-        else
-        {
-          /* search failed */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));
-          return NULL;
-        }
-      }
-      else
-      {
-        /* search failed, short object identifier (nosuchname) */
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));
-        return NULL;
-      }
-    }
-    else if (node_type == MIB_NODE_SC)
-    {
-      mib_scalar_node *sn;
-
-      sn = (mib_scalar_node *)node;
-      if ((ident_len == 1) && (*ident == 0))
-      {
-        np->ident_len = ident_len;
-        np->ident = ident;
-        return (struct mib_node*)sn;
-      }
-      else
-      {
-        /* search failed, short object identifier (nosuchname) */
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));
-        return NULL;
-      }
-    }
-    else
-    {
-      /* unknown node_type */
-      LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));
-      return NULL;
-    }
-  }
-  /* done, found nothing */
-  LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node));
-  return NULL;
-}
-
-/**
- * Test table for presence of at least one table entry.
- */
-static u8_t
-empty_table(struct mib_node *node)
-{
-  u8_t node_type;
-  u8_t empty = 0;
-
-  if (node != NULL)
-  {
-    node_type = node->node_type;
-    if (node_type == MIB_NODE_LR)
-    {
-      struct mib_list_rootnode *lrn;
-      lrn = (struct mib_list_rootnode *)node;
-      if ((lrn->count == 0) || (lrn->head == NULL))
-      {
-        empty = 1;
-      }
-    }
-    else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
-    {
-      struct mib_array_node *an;
-      an = (struct mib_array_node *)node;
-      if ((an->maxlength == 0) || (an->nptr == NULL))
-      {
-        empty = 1;
-      }
-    }
-    else if (node_type == MIB_NODE_EX)
-    {
-      struct mib_external_node *en;
-      en = (struct mib_external_node *)node;
-      if (en->tree_levels == 0)
-      {
-        empty = 1;
-      }
-    }
-  }
-  return empty;
-}
-
-/**
- * Tree expansion.
- */
-struct mib_node *
-snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
-{
-  u8_t node_type, ext_level, climb_tree;
-
-  ext_level = 0;
-  /* reset node stack */
-  node_stack_cnt = 0;
-  while (node != NULL)
-  {
-    climb_tree = 0;
-    node_type = node->node_type;
-    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
-    {
-      struct mib_array_node *an;
-      u16_t i;
-
-      /* array node (internal ROM or RAM, fixed length) */
-      an = (struct mib_array_node *)node;
-      if (ident_len > 0)
-      {
-        i = 0;
-        while ((i < an->maxlength) && (an->objid[i] < *ident))
-        {
-          i++;
-        }
-        if (i < an->maxlength)
-        {
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));
-          /* add identifier to oidret */
-          oidret->id[oidret->len] = an->objid[i];
-          (oidret->len)++;
-
-          if (an->nptr[i] == NULL)
-          {
-            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
-            /* leaf node (e.g. in a fixed size table) */
-            if (an->objid[i] > *ident)
-            {
-              return (struct mib_node*)an;
-            }
-            else if ((i + 1) < an->maxlength)
-            {
-              /* an->objid[i] == *ident */
-              (oidret->len)--;
-              oidret->id[oidret->len] = an->objid[i + 1];
-              (oidret->len)++;
-              return (struct mib_node*)an;
-            }
-            else
-            {
-              /* (i + 1) == an->maxlength */
-              (oidret->len)--;
-              climb_tree = 1;
-            }
-          }
-          else
-          {
-            u8_t j;
-            struct nse cur_node;
-
-            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
-            /* non-leaf, store right child ptr and id */
-            j = i + 1;
-            while ((j < an->maxlength) && (empty_table(an->nptr[j])))
-            {
-              j++;
-            }
-            if (j < an->maxlength)
-            {
-              cur_node.r_ptr = an->nptr[j];
-              cur_node.r_id = an->objid[j];
-              cur_node.r_nl = 0;
-            }
-            else
-            {
-              cur_node.r_ptr = NULL;
-            }
-            push_node(&cur_node);
-            if (an->objid[i] == *ident)
-            {
-              ident_len--;
-              ident++;
-            }
-            else
-            {
-              /* an->objid[i] < *ident */
-              ident_len = 0;
-            }
-            /* follow next child pointer */
-            node = an->nptr[i];
-          }
-        }
-        else
-        {
-          /* i == an->maxlength */
-          climb_tree = 1;
-        }
-      }
-      else
-      {
-        u8_t j;
-        /* ident_len == 0, complete with leftmost '.thing' */
-        j = 0;
-        while ((j < an->maxlength) && empty_table(an->nptr[j]))
-        {
-          j++;
-        }
-        if (j < an->maxlength)
-        {
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j]));
-          oidret->id[oidret->len] = an->objid[j];
-          (oidret->len)++;
-          if (an->nptr[j] == NULL)
-          {
-            /* leaf node */
-            return (struct mib_node*)an;
-          }
-          else
-          {
-            /* no leaf, continue */
-            node = an->nptr[j];
-          }
-        }
-        else
-        {
-          /* j == an->maxlength */
-          climb_tree = 1;
-        }
-      }
-    }
-    else if(node_type == MIB_NODE_LR)
-    {
-      struct mib_list_rootnode *lrn;
-      struct mib_list_node *ln;
-
-      /* list root node (internal 'RAM', variable length) */
-      lrn = (struct mib_list_rootnode *)node;
-      if (ident_len > 0)
-      {
-        ln = lrn->head;
-        /* iterate over list, head to tail */
-        while ((ln != NULL) && (ln->objid < *ident))
-        {
-          ln = ln->next;
-        }
-        if (ln != NULL)
-        {
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
-          oidret->id[oidret->len] = ln->objid;
-          (oidret->len)++;
-          if (ln->nptr == NULL)
-          {
-            /* leaf node */
-            if (ln->objid > *ident)
-            {
-              return (struct mib_node*)lrn;
-            }
-            else if (ln->next != NULL)
-            {
-              /* ln->objid == *ident */
-              (oidret->len)--;
-              oidret->id[oidret->len] = ln->next->objid;
-              (oidret->len)++;
-              return (struct mib_node*)lrn;
-            }
-            else
-            {
-              /* ln->next == NULL */
-              (oidret->len)--;
-              climb_tree = 1;
-            }
-          }
-          else
-          {
-            struct mib_list_node *jn;
-            struct nse cur_node;
-
-            /* non-leaf, store right child ptr and id */
-            jn = ln->next;
-            while ((jn != NULL) && empty_table(jn->nptr))
-            {
-              jn = jn->next;
-            }
-            if (jn != NULL)
-            {
-              cur_node.r_ptr = jn->nptr;
-              cur_node.r_id = jn->objid;
-              cur_node.r_nl = 0;
-            }
-            else
-            {
-              cur_node.r_ptr = NULL;
-            }
-            push_node(&cur_node);
-            if (ln->objid == *ident)
-            {
-              ident_len--;
-              ident++;
-            }
-            else
-            {
-              /* ln->objid < *ident */
-              ident_len = 0;
-            }
-            /* follow next child pointer */
-            node = ln->nptr;
-          }
-
-        }
-        else
-        {
-          /* ln == NULL */
-          climb_tree = 1;
-        }
-      }
-      else
-      {
-        struct mib_list_node *jn;
-        /* ident_len == 0, complete with leftmost '.thing' */
-        jn = lrn->head;
-        while ((jn != NULL) && empty_table(jn->nptr))
-        {
-          jn = jn->next;
-        }
-        if (jn != NULL)
-        {
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));
-          oidret->id[oidret->len] = jn->objid;
-          (oidret->len)++;
-          if (jn->nptr == NULL)
-          {
-            /* leaf node */
-            LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));
-            return (struct mib_node*)lrn;
-          }
-          else
-          {
-            /* no leaf, continue */
-            node = jn->nptr;
-          }
-        }
-        else
-        {
-          /* jn == NULL */
-          climb_tree = 1;
-        }
-      }
-    }
-    else if(node_type == MIB_NODE_EX)
-    {
-      struct mib_external_node *en;
-      s32_t ex_id;
-
-      /* external node (addressing and access via functions) */
-      en = (struct mib_external_node *)node;
-      if (ident_len > 0)
-      {
-        u16_t i, len;
-
-        i = 0;
-        len = en->level_length(en->addr_inf,ext_level);
-        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0))
-        {
-          i++;
-        }
-        if (i < len)
-        {
-          /* add identifier to oidret */
-          en->get_objid(en->addr_inf,ext_level,i,&ex_id);
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));
-          oidret->id[oidret->len] = ex_id;
-          (oidret->len)++;
-
-          if ((ext_level + 1) == en->tree_levels)
-          {
-            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
-            /* leaf node */
-            if (ex_id > *ident)
-            {
-              return (struct mib_node*)en;
-            }
-            else if ((i + 1) < len)
-            {
-              /* ex_id == *ident */
-              en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);
-              (oidret->len)--;
-              oidret->id[oidret->len] = ex_id;
-              (oidret->len)++;
-              return (struct mib_node*)en;
-            }
-            else
-            {
-              /* (i + 1) == len */
-              (oidret->len)--;
-              climb_tree = 1;
-            }
-          }
-          else
-          {
-            u8_t j;
-            struct nse cur_node;
-
-            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
-            /* non-leaf, store right child ptr and id */
-            j = i + 1;
-            if (j < len)
-            {
-              /* right node is the current external node */
-              cur_node.r_ptr = node;
-              en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);
-              cur_node.r_nl = ext_level + 1;
-            }
-            else
-            {
-              cur_node.r_ptr = NULL;
-            }
-            push_node(&cur_node);
-            if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0)
-            {
-              ident_len--;
-              ident++;
-            }
-            else
-            {
-              /* external id < *ident */
-              ident_len = 0;
-            }
-            /* proceed to child */
-            ext_level++;
-          }
-        }
-        else
-        {
-          /* i == len (en->level_len()) */
-          climb_tree = 1;
-        }
-      }
-      else
-      {
-        /* ident_len == 0, complete with leftmost '.thing' */
-        en->get_objid(en->addr_inf,ext_level,0,&ex_id);
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));
-        oidret->id[oidret->len] = ex_id;
-        (oidret->len)++;
-        if ((ext_level + 1) == en->tree_levels)
-        {
-          /* leaf node */
-          LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));
-          return (struct mib_node*)en;
-        }
-        else
-        {
-          /* no leaf, proceed to child */
-          ext_level++;
-        }
-      }
-    }
-    else if(node_type == MIB_NODE_SC)
-    {
-      mib_scalar_node *sn;
-
-      /* scalar node  */
-      sn = (mib_scalar_node *)node;
-      if (ident_len > 0)
-      {
-        /* at .0 */
-        climb_tree = 1;
-      }
-      else
-      {
-        /* ident_len == 0, complete object identifier */
-        oidret->id[oidret->len] = 0;
-        (oidret->len)++;
-        /* leaf node */
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));
-        return (struct mib_node*)sn;
-      }
-    }
-    else
-    {
-      /* unknown/unhandled node_type */
-      LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));
-      return NULL;
-    }
-
-    if (climb_tree)
-    {
-      struct nse child;
-
-      /* find right child ptr */
-      child.r_ptr = NULL;
-      child.r_id = 0;
-      child.r_nl = 0;
-      while ((node_stack_cnt > 0) && (child.r_ptr == NULL))
-      {
-        pop_node(&child);
-        /* trim returned oid */
-        (oidret->len)--;
-      }
-      if (child.r_ptr != NULL)
-      {
-        /* incoming ident is useless beyond this point */
-        ident_len = 0;
-        oidret->id[oidret->len] = child.r_id;
-        oidret->len++;
-        node = child.r_ptr;
-        ext_level = child.r_nl;
-      }
-      else
-      {
-        /* tree ends here ... */
-        LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));
-        return NULL;
-      }
-    }
-  }
-  /* done, found nothing */
-  LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node));
-  return NULL;
-}
-
-/**
- * Test object identifier for the iso.org.dod.internet prefix.
- *
- * @param ident_len the length of the supplied object identifier
- * @param ident points to the array of sub identifiers
- * @return 1 if it matches, 0 otherwise
- */
-u8_t
-snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)
-{
-  if ((ident_len > 3) &&
-      (ident[0] == 1) && (ident[1] == 3) &&
-      (ident[2] == 6) && (ident[3] == 1))
-  {
-    return 1;
-  }
-  else
-  {
-    return 0;
-  }
-}
-
-/**
- * Expands object identifier to the iso.org.dod.internet
- * prefix for use in getnext operation.
- *
- * @param ident_len the length of the supplied object identifier
- * @param ident points to the array of sub identifiers
- * @param oidret points to returned expanded object identifier
- * @return 1 if it matches, 0 otherwise
- *
- * @note ident_len 0 is allowed, expanding to the first known object id!!
- */
-u8_t
-snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
-{
-  const s32_t *prefix_ptr;
-  s32_t *ret_ptr;
-  u8_t i;
-
-  i = 0;
-  prefix_ptr = &prefix[0];
-  ret_ptr = &oidret->id[0];
-  ident_len = ((ident_len < 4)?ident_len:4);
-  while ((i < ident_len) && ((*ident) <= (*prefix_ptr)))
-  {
-    *ret_ptr++ = *prefix_ptr++;
-    ident++;
-    i++;
-  }
-  if (i == ident_len)
-  {
-    /* match, complete missing bits */
-    while (i < 4)
-    {
-      *ret_ptr++ = *prefix_ptr++;
-      i++;
-    }
-    oidret->len = i;
-    return 1;
-  }
-  else
-  {
-    /* i != ident_len */
-    return 0;
-  }
-}
-
-#endif /* LWIP_SNMP */
-
+/**

+ * @file

+ * MIB tree access/construction functions.

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * 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: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP

+#include "lwip/snmp_structs.h"

+#include "lwip/mem.h"

+

+

+

+/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */

+const s32_t prefix[4] = {1, 3, 6, 1};

+

+#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)

+/** node stack entry (old news?) */

+struct nse

+{

+  /** right child */

+  struct mib_node* r_ptr;

+  /** right child identifier */

+  s32_t r_id;

+  /** right child next level */

+  u8_t r_nl;

+};

+static u8_t node_stack_cnt = 0;

+static struct nse node_stack[NODE_STACK_SIZE];

+

+/**

+ * Pushes nse struct onto stack.

+ */

+static void

+push_node(struct nse* node)

+{

+  LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id));

+  if (node_stack_cnt < NODE_STACK_SIZE)

+  {

+    node_stack[node_stack_cnt] = *node;

+    node_stack_cnt++;

+  }

+}

+

+/**

+ * Pops nse struct from stack.

+ */

+static void

+pop_node(struct nse* node)

+{

+  if (node_stack_cnt > 0)

+  {

+    node_stack_cnt--;

+    *node = node_stack[node_stack_cnt];

+  }

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id));

+}

+

+/**

+ * Conversion from ifIndex to lwIP netif

+ * @param ifindex is a s32_t object sub-identifier

+ * @param netif points to returned netif struct pointer

+ */

+void

+snmp_ifindextonetif(s32_t ifindex, struct netif **netif)

+{

+  struct netif *nif = netif_list;

+  u16_t i, ifidx;

+

+  ifidx = ifindex - 1;

+  i = 0;

+  while ((nif != NULL) && (i < ifidx))

+  {

+    nif = nif->next;

+    i++;

+  }

+  *netif = nif;

+}

+

+/**

+ * Conversion from lwIP netif to ifIndex

+ * @param netif points to a netif struct

+ * @param ifindex points to s32_t object sub-identifier

+ */

+void

+snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)

+{

+  struct netif *nif = netif_list;

+  u16_t i;

+

+  i = 0;

+  while (nif != netif)

+  {

+    nif = nif->next;

+    i++;

+  }

+  *ifidx = i+1;

+}

+

+/**

+ * Conversion from oid to lwIP ip_addr

+ * @param ident points to s32_t ident[4] input

+ * @param ip points to output struct

+ */

+void

+snmp_oidtoip(s32_t *ident, struct ip_addr *ip)

+{

+  u32_t ipa;

+

+  ipa = ident[0];

+  ipa <<= 8;

+  ipa |= ident[1];

+  ipa <<= 8;

+  ipa |= ident[2];

+  ipa <<= 8;

+  ipa |= ident[3];

+  ip->addr = ipa;

+}

+

+/**

+ * Conversion from lwIP ip_addr to oid

+ * @param ip points to input struct

+ * @param ident points to s32_t ident[4] output

+ */

+void

+snmp_iptooid(struct ip_addr *ip, s32_t *ident)

+{

+  u32_t ipa;

+

+  ipa = ip->addr;

+  ident[0] = (ipa >> 24) & 0xff;

+  ident[1] = (ipa >> 16) & 0xff;

+  ident[2] = (ipa >> 8) & 0xff;

+  ident[3] = ipa & 0xff;

+}

+

+struct mib_list_node *

+snmp_mib_ln_alloc(s32_t id)

+{

+  struct mib_list_node *ln;

+

+  ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node));

+  if (ln != NULL)

+  {

+    ln->prev = NULL;

+    ln->next = NULL;

+    ln->objid = id;

+    ln->nptr = NULL;

+  }

+  return ln;

+}

+

+void

+snmp_mib_ln_free(struct mib_list_node *ln)

+{

+  mem_free(ln);

+}

+

+struct mib_list_rootnode *

+snmp_mib_lrn_alloc(void)

+{

+  struct mib_list_rootnode *lrn;

+

+  lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode));

+  if (lrn != NULL)

+  {

+    lrn->get_object_def = noleafs_get_object_def;

+    lrn->get_value = noleafs_get_value;

+    lrn->set_test = noleafs_set_test;

+    lrn->set_value = noleafs_set_value;

+    lrn->node_type = MIB_NODE_LR;

+    lrn->maxlength = 0;

+    lrn->head = NULL;

+    lrn->tail = NULL;

+    lrn->count = 0;

+  }

+  return lrn;

+}

+

+void

+snmp_mib_lrn_free(struct mib_list_rootnode *lrn)

+{

+  mem_free(lrn);

+}

+

+/**

+ * Inserts node in idx list in a sorted

+ * (ascending order) fashion and

+ * allocates the node if needed.

+ *

+ * @param rn points to the root node

+ * @param objid is the object sub identifier

+ * @param insn points to a pointer to the inserted node

+ *   used for constructing the tree.

+ * @return -1 if failed, 1 if inserted, 2 if present.

+ */

+s8_t

+snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)

+{

+  struct mib_list_node *nn;

+  s8_t insert;

+

+  LWIP_ASSERT("rn != NULL",rn != NULL);

+

+  /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */

+  insert = 0;

+  if (rn->head == NULL)

+  {

+    /* empty list, add first node */

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));

+    nn = snmp_mib_ln_alloc(objid);

+    if (nn != NULL)

+    {

+      rn->head = nn;

+      rn->tail = nn;

+      *insn = nn;

+      insert = 1;

+    }

+    else

+    {

+      insert = -1;

+    }

+  }

+  else

+  {

+    struct mib_list_node *n;

+    /* at least one node is present */

+    n = rn->head;

+    while ((n != NULL) && (insert == 0))

+    {

+      if (n->objid == objid)

+      {

+        /* node is already there */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));

+        *insn = n;

+        insert = 2;

+      }

+      else if (n->objid < objid)

+      {

+        if (n->next == NULL)

+        {

+          /* alloc and insert at the tail */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));

+          nn = snmp_mib_ln_alloc(objid);

+          if (nn != NULL)

+          {

+            nn->next = NULL;

+            nn->prev = n;

+            n->next = nn;

+            rn->tail = nn;

+            *insn = nn;

+            insert = 1;

+          }

+          else

+          {

+            /* insertion failure */

+            insert = -1;

+          }

+        }

+        else

+        {

+          /* there's more to explore: traverse list */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));

+          n = n->next;

+        }

+      }

+      else

+      {

+        /* n->objid > objid */

+        /* alloc and insert between n->prev and n */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));

+        nn = snmp_mib_ln_alloc(objid);

+        if (nn != NULL)

+        {

+          if (n->prev == NULL)

+          {

+            /* insert at the head */

+            nn->next = n;

+            nn->prev = NULL;

+            rn->head = nn;

+            n->prev = nn;

+          }

+          else

+          {

+            /* insert in the middle */

+            nn->next = n;

+            nn->prev = n->prev;

+            n->prev->next = nn;

+            n->prev = nn;

+          }

+          *insn = nn;

+          insert = 1;

+        }

+        else

+        {

+          /* insertion failure */

+          insert = -1;

+        }

+      }

+    }

+  }

+  if (insert == 1)

+  {

+    rn->count += 1;

+  }

+  LWIP_ASSERT("insert != 0",insert != 0);

+  return insert;

+}

+

+/**

+ * Finds node in idx list and returns deletion mark.

+ *

+ * @param rn points to the root node

+ * @param objid  is the object sub identifier

+ * @param fn returns pointer to found node

+ * @return 0 if not found, 1 if deletable,

+ *   2 can't delete (2 or more children), 3 not a list_node

+ */

+s8_t

+snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)

+{

+  s8_t fc;

+  struct mib_list_node *n;

+

+  LWIP_ASSERT("rn != NULL",rn != NULL);

+  n = rn->head;

+  while ((n != NULL) && (n->objid != objid))

+  {

+    n = n->next;

+  }

+  if (n == NULL)

+  {

+    fc = 0;

+  }

+  else if (n->nptr == NULL)

+  {

+    /* leaf, can delete node */

+    fc = 1;

+  }

+  else

+  {

+    struct mib_list_rootnode *rn;

+

+    if (n->nptr->node_type == MIB_NODE_LR)

+    {

+      rn = (struct mib_list_rootnode *)n->nptr;

+      if (rn->count > 1)

+      {

+        /* can't delete node */

+        fc = 2;

+      }

+      else

+      {

+        /* count <= 1, can delete node */

+        fc = 1;

+      }

+    }

+    else

+    {

+      /* other node type */

+      fc = 3;

+    }

+  }

+  *fn = n;

+  return fc;

+}

+

+/**

+ * Removes node from idx list

+ * if it has a single child left.

+ *

+ * @param rn points to the root node

+ * @param n points to the node to delete

+ * @return the nptr to be freed by caller

+ */

+struct mib_list_rootnode *

+snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)

+{

+  struct mib_list_rootnode *next;

+

+  LWIP_ASSERT("rn != NULL",rn != NULL);

+  LWIP_ASSERT("n != NULL",n != NULL);

+

+  /* caller must remove this sub-tree */

+  next = (struct mib_list_rootnode*)(n->nptr);

+  rn->count -= 1;

+

+  if (n == rn->head)

+  {

+    rn->head = n->next;

+    if (n->next != NULL)

+    {

+      /* not last node, new list begin */

+      n->next->prev = NULL;

+    }

+  }

+  else if (n == rn->tail)

+  {

+    rn->tail = n->prev;

+    if (n->prev != NULL)

+    {

+      /* not last node, new list end */

+      n->prev->next = NULL;

+    }

+  }

+  else

+  {

+    /* node must be in the middle */

+    n->prev->next = n->next;

+    n->next->prev = n->prev;

+  }

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));

+  snmp_mib_ln_free(n);

+  if (rn->count == 0)

+  {

+    rn->head = NULL;

+    rn->tail = NULL;

+  }

+  return next;

+}

+

+

+

+/**

+ * Searches tree for the supplied (scalar?) object identifier.

+ *

+ * @param node points to the root of the tree ('.internet')

+ * @param ident_len the length of the supplied object identifier

+ * @param ident points to the array of sub identifiers

+ * @param np points to the found object instance (rerurn)

+ * @return pointer to the requested parent (!) node if success, NULL otherwise

+ */

+struct mib_node *

+snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)

+{

+  u8_t node_type, ext_level;

+

+  ext_level = 0;

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident));

+  while (node != NULL)

+  {

+    node_type = node->node_type;

+    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))

+    {

+      struct mib_array_node *an;

+      u16_t i;

+

+      if (ident_len > 0)

+      {

+        /* array node (internal ROM or RAM, fixed length) */

+        an = (struct mib_array_node *)node;

+        i = 0;

+        while ((i < an->maxlength) && (an->objid[i] != *ident))

+        {

+          i++;

+        }

+        if (i < an->maxlength)

+        {

+          /* found it, if available proceed to child, otherwise inspect leaf */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));

+          if (an->nptr[i] == NULL)

+          {

+            /* a scalar leaf OR table,

+               inspect remaining instance number / table index */

+            np->ident_len = ident_len;

+            np->ident = ident;

+            return (struct mib_node*)an;

+          }

+          else

+          {

+            /* follow next child pointer */

+            ident++;

+            ident_len--;

+            node = an->nptr[i];

+          }

+        }

+        else

+        {

+          /* search failed, identifier mismatch (nosuchname) */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));

+          return NULL;

+        }

+      }

+      else

+      {

+        /* search failed, short object identifier (nosuchname) */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));

+        return NULL;

+      }

+    }

+    else if(node_type == MIB_NODE_LR)

+    {

+      struct mib_list_rootnode *lrn;

+      struct mib_list_node *ln;

+

+      if (ident_len > 0)

+      {

+        /* list root node (internal 'RAM', variable length) */

+        lrn = (struct mib_list_rootnode *)node;

+        ln = lrn->head;

+        /* iterate over list, head to tail */

+        while ((ln != NULL) && (ln->objid != *ident))

+        {

+          ln = ln->next;

+        }

+        if (ln != NULL)

+        {

+          /* found it, proceed to child */;

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));

+          if (ln->nptr == NULL)

+          {

+            np->ident_len = ident_len;

+            np->ident = ident;

+            return (struct mib_node*)lrn;

+          }

+          else

+          {

+            /* follow next child pointer */

+            ident_len--;

+            ident++;

+            node = ln->nptr;

+          }

+        }

+        else

+        {

+          /* search failed */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));

+          return NULL;

+        }

+      }

+      else

+      {

+        /* search failed, short object identifier (nosuchname) */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));

+        return NULL;

+      }

+    }

+    else if(node_type == MIB_NODE_EX)

+    {

+      struct mib_external_node *en;

+      u16_t i, len;

+

+      if (ident_len > 0)

+      {

+        /* external node (addressing and access via functions) */

+        en = (struct mib_external_node *)node;

+

+        i = 0;

+        len = en->level_length(en->addr_inf,ext_level);

+        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0))

+        {

+          i++;

+        }

+        if (i < len)

+        {

+          s32_t debug_id;

+

+          en->get_objid(en->addr_inf,ext_level,i,&debug_id);

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));

+          if ((ext_level + 1) == en->tree_levels)

+          {

+            np->ident_len = ident_len;

+            np->ident = ident;

+            return (struct mib_node*)en;

+          }

+          else

+          {

+            /* found it, proceed to child */

+            ident_len--;

+            ident++;

+            ext_level++;

+          }

+        }

+        else

+        {

+          /* search failed */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));

+          return NULL;

+        }

+      }

+      else

+      {

+        /* search failed, short object identifier (nosuchname) */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));

+        return NULL;

+      }

+    }

+    else if (node_type == MIB_NODE_SC)

+    {

+      mib_scalar_node *sn;

+

+      sn = (mib_scalar_node *)node;

+      if ((ident_len == 1) && (*ident == 0))

+      {

+        np->ident_len = ident_len;

+        np->ident = ident;

+        return (struct mib_node*)sn;

+      }

+      else

+      {

+        /* search failed, short object identifier (nosuchname) */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));

+        return NULL;

+      }

+    }

+    else

+    {

+      /* unknown node_type */

+      LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));

+      return NULL;

+    }

+  }

+  /* done, found nothing */

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node));

+  return NULL;

+}

+

+/**

+ * Test table for presence of at least one table entry.

+ */

+static u8_t

+empty_table(struct mib_node *node)

+{

+  u8_t node_type;

+  u8_t empty = 0;

+

+  if (node != NULL)

+  {

+    node_type = node->node_type;

+    if (node_type == MIB_NODE_LR)

+    {

+      struct mib_list_rootnode *lrn;

+      lrn = (struct mib_list_rootnode *)node;

+      if ((lrn->count == 0) || (lrn->head == NULL))

+      {

+        empty = 1;

+      }

+    }

+    else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))

+    {

+      struct mib_array_node *an;

+      an = (struct mib_array_node *)node;

+      if ((an->maxlength == 0) || (an->nptr == NULL))

+      {

+        empty = 1;

+      }

+    }

+    else if (node_type == MIB_NODE_EX)

+    {

+      struct mib_external_node *en;

+      en = (struct mib_external_node *)node;

+      if (en->tree_levels == 0)

+      {

+        empty = 1;

+      }

+    }

+  }

+  return empty;

+}

+

+/**

+ * Tree expansion.

+ */

+struct mib_node *

+snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)

+{

+  u8_t node_type, ext_level, climb_tree;

+

+  ext_level = 0;

+  /* reset node stack */

+  node_stack_cnt = 0;

+  while (node != NULL)

+  {

+    climb_tree = 0;

+    node_type = node->node_type;

+    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))

+    {

+      struct mib_array_node *an;

+      u16_t i;

+

+      /* array node (internal ROM or RAM, fixed length) */

+      an = (struct mib_array_node *)node;

+      if (ident_len > 0)

+      {

+        i = 0;

+        while ((i < an->maxlength) && (an->objid[i] < *ident))

+        {

+          i++;

+        }

+        if (i < an->maxlength)

+        {

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));

+          /* add identifier to oidret */

+          oidret->id[oidret->len] = an->objid[i];

+          (oidret->len)++;

+

+          if (an->nptr[i] == NULL)

+          {

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));

+            /* leaf node (e.g. in a fixed size table) */

+            if (an->objid[i] > *ident)

+            {

+              return (struct mib_node*)an;

+            }

+            else if ((i + 1) < an->maxlength)

+            {

+              /* an->objid[i] == *ident */

+              (oidret->len)--;

+              oidret->id[oidret->len] = an->objid[i + 1];

+              (oidret->len)++;

+              return (struct mib_node*)an;

+            }

+            else

+            {

+              /* (i + 1) == an->maxlength */

+              (oidret->len)--;

+              climb_tree = 1;

+            }

+          }

+          else

+          {

+            u8_t j;

+            struct nse cur_node;

+

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));

+            /* non-leaf, store right child ptr and id */

+            j = i + 1;

+            while ((j < an->maxlength) && (empty_table(an->nptr[j])))

+            {

+              j++;

+            }

+            if (j < an->maxlength)

+            {

+              cur_node.r_ptr = an->nptr[j];

+              cur_node.r_id = an->objid[j];

+              cur_node.r_nl = 0;

+            }

+            else

+            {

+              cur_node.r_ptr = NULL;

+            }

+            push_node(&cur_node);

+            if (an->objid[i] == *ident)

+            {

+              ident_len--;

+              ident++;

+            }

+            else

+            {

+              /* an->objid[i] < *ident */

+              ident_len = 0;

+            }

+            /* follow next child pointer */

+            node = an->nptr[i];

+          }

+        }

+        else

+        {

+          /* i == an->maxlength */

+          climb_tree = 1;

+        }

+      }

+      else

+      {

+        u8_t j;

+        /* ident_len == 0, complete with leftmost '.thing' */

+        j = 0;

+        while ((j < an->maxlength) && empty_table(an->nptr[j]))

+        {

+          j++;

+        }

+        if (j < an->maxlength)

+        {

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j]));

+          oidret->id[oidret->len] = an->objid[j];

+          (oidret->len)++;

+          if (an->nptr[j] == NULL)

+          {

+            /* leaf node */

+            return (struct mib_node*)an;

+          }

+          else

+          {

+            /* no leaf, continue */

+            node = an->nptr[j];

+          }

+        }

+        else

+        {

+          /* j == an->maxlength */

+          climb_tree = 1;

+        }

+      }

+    }

+    else if(node_type == MIB_NODE_LR)

+    {

+      struct mib_list_rootnode *lrn;

+      struct mib_list_node *ln;

+

+      /* list root node (internal 'RAM', variable length) */

+      lrn = (struct mib_list_rootnode *)node;

+      if (ident_len > 0)

+      {

+        ln = lrn->head;

+        /* iterate over list, head to tail */

+        while ((ln != NULL) && (ln->objid < *ident))

+        {

+          ln = ln->next;

+        }

+        if (ln != NULL)

+        {

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));

+          oidret->id[oidret->len] = ln->objid;

+          (oidret->len)++;

+          if (ln->nptr == NULL)

+          {

+            /* leaf node */

+            if (ln->objid > *ident)

+            {

+              return (struct mib_node*)lrn;

+            }

+            else if (ln->next != NULL)

+            {

+              /* ln->objid == *ident */

+              (oidret->len)--;

+              oidret->id[oidret->len] = ln->next->objid;

+              (oidret->len)++;

+              return (struct mib_node*)lrn;

+            }

+            else

+            {

+              /* ln->next == NULL */

+              (oidret->len)--;

+              climb_tree = 1;

+            }

+          }

+          else

+          {

+            struct mib_list_node *jn;

+            struct nse cur_node;

+

+            /* non-leaf, store right child ptr and id */

+            jn = ln->next;

+            while ((jn != NULL) && empty_table(jn->nptr))

+            {

+              jn = jn->next;

+            }

+            if (jn != NULL)

+            {

+              cur_node.r_ptr = jn->nptr;

+              cur_node.r_id = jn->objid;

+              cur_node.r_nl = 0;

+            }

+            else

+            {

+              cur_node.r_ptr = NULL;

+            }

+            push_node(&cur_node);

+            if (ln->objid == *ident)

+            {

+              ident_len--;

+              ident++;

+            }

+            else

+            {

+              /* ln->objid < *ident */

+              ident_len = 0;

+            }

+            /* follow next child pointer */

+            node = ln->nptr;

+          }

+

+        }

+        else

+        {

+          /* ln == NULL */

+          climb_tree = 1;

+        }

+      }

+      else

+      {

+        struct mib_list_node *jn;

+        /* ident_len == 0, complete with leftmost '.thing' */

+        jn = lrn->head;

+        while ((jn != NULL) && empty_table(jn->nptr))

+        {

+          jn = jn->next;

+        }

+        if (jn != NULL)

+        {

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));

+          oidret->id[oidret->len] = jn->objid;

+          (oidret->len)++;

+          if (jn->nptr == NULL)

+          {

+            /* leaf node */

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));

+            return (struct mib_node*)lrn;

+          }

+          else

+          {

+            /* no leaf, continue */

+            node = jn->nptr;

+          }

+        }

+        else

+        {

+          /* jn == NULL */

+          climb_tree = 1;

+        }

+      }

+    }

+    else if(node_type == MIB_NODE_EX)

+    {

+      struct mib_external_node *en;

+      s32_t ex_id;

+

+      /* external node (addressing and access via functions) */

+      en = (struct mib_external_node *)node;

+      if (ident_len > 0)

+      {

+        u16_t i, len;

+

+        i = 0;

+        len = en->level_length(en->addr_inf,ext_level);

+        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0))

+        {

+          i++;

+        }

+        if (i < len)

+        {

+          /* add identifier to oidret */

+          en->get_objid(en->addr_inf,ext_level,i,&ex_id);

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));

+          oidret->id[oidret->len] = ex_id;

+          (oidret->len)++;

+

+          if ((ext_level + 1) == en->tree_levels)

+          {

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));

+            /* leaf node */

+            if (ex_id > *ident)

+            {

+              return (struct mib_node*)en;

+            }

+            else if ((i + 1) < len)

+            {

+              /* ex_id == *ident */

+              en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);

+              (oidret->len)--;

+              oidret->id[oidret->len] = ex_id;

+              (oidret->len)++;

+              return (struct mib_node*)en;

+            }

+            else

+            {

+              /* (i + 1) == len */

+              (oidret->len)--;

+              climb_tree = 1;

+            }

+          }

+          else

+          {

+            u8_t j;

+            struct nse cur_node;

+

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));

+            /* non-leaf, store right child ptr and id */

+            j = i + 1;

+            if (j < len)

+            {

+              /* right node is the current external node */

+              cur_node.r_ptr = node;

+              en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);

+              cur_node.r_nl = ext_level + 1;

+            }

+            else

+            {

+              cur_node.r_ptr = NULL;

+            }

+            push_node(&cur_node);

+            if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0)

+            {

+              ident_len--;

+              ident++;

+            }

+            else

+            {

+              /* external id < *ident */

+              ident_len = 0;

+            }

+            /* proceed to child */

+            ext_level++;

+          }

+        }

+        else

+        {

+          /* i == len (en->level_len()) */

+          climb_tree = 1;

+        }

+      }

+      else

+      {

+        /* ident_len == 0, complete with leftmost '.thing' */

+        en->get_objid(en->addr_inf,ext_level,0,&ex_id);

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));

+        oidret->id[oidret->len] = ex_id;

+        (oidret->len)++;

+        if ((ext_level + 1) == en->tree_levels)

+        {

+          /* leaf node */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));

+          return (struct mib_node*)en;

+        }

+        else

+        {

+          /* no leaf, proceed to child */

+          ext_level++;

+        }

+      }

+    }

+    else if(node_type == MIB_NODE_SC)

+    {

+      mib_scalar_node *sn;

+

+      /* scalar node  */

+      sn = (mib_scalar_node *)node;

+      if (ident_len > 0)

+      {

+        /* at .0 */

+        climb_tree = 1;

+      }

+      else

+      {

+        /* ident_len == 0, complete object identifier */

+        oidret->id[oidret->len] = 0;

+        (oidret->len)++;

+        /* leaf node */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));

+        return (struct mib_node*)sn;

+      }

+    }

+    else

+    {

+      /* unknown/unhandled node_type */

+      LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));

+      return NULL;

+    }

+

+    if (climb_tree)

+    {

+      struct nse child;

+

+      /* find right child ptr */

+      child.r_ptr = NULL;

+      child.r_id = 0;

+      child.r_nl = 0;

+      while ((node_stack_cnt > 0) && (child.r_ptr == NULL))

+      {

+        pop_node(&child);

+        /* trim returned oid */

+        (oidret->len)--;

+      }

+      if (child.r_ptr != NULL)

+      {

+        /* incoming ident is useless beyond this point */

+        ident_len = 0;

+        oidret->id[oidret->len] = child.r_id;

+        oidret->len++;

+        node = child.r_ptr;

+        ext_level = child.r_nl;

+      }

+      else

+      {

+        /* tree ends here ... */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));

+        return NULL;

+      }

+    }

+  }

+  /* done, found nothing */

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node));

+  return NULL;

+}

+

+/**

+ * Test object identifier for the iso.org.dod.internet prefix.

+ *

+ * @param ident_len the length of the supplied object identifier

+ * @param ident points to the array of sub identifiers

+ * @return 1 if it matches, 0 otherwise

+ */

+u8_t

+snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)

+{

+  if ((ident_len > 3) &&

+      (ident[0] == 1) && (ident[1] == 3) &&

+      (ident[2] == 6) && (ident[3] == 1))

+  {

+    return 1;

+  }

+  else

+  {

+    return 0;

+  }

+}

+

+/**

+ * Expands object identifier to the iso.org.dod.internet

+ * prefix for use in getnext operation.

+ *

+ * @param ident_len the length of the supplied object identifier

+ * @param ident points to the array of sub identifiers

+ * @param oidret points to returned expanded object identifier

+ * @return 1 if it matches, 0 otherwise

+ *

+ * @note ident_len 0 is allowed, expanding to the first known object id!!

+ */

+u8_t

+snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)

+{

+  const s32_t *prefix_ptr;

+  s32_t *ret_ptr;

+  u8_t i;

+

+  i = 0;

+  prefix_ptr = &prefix[0];

+  ret_ptr = &oidret->id[0];

+  ident_len = ((ident_len < 4)?ident_len:4);

+  while ((i < ident_len) && ((*ident) <= (*prefix_ptr)))

+  {

+    *ret_ptr++ = *prefix_ptr++;

+    ident++;

+    i++;

+  }

+  if (i == ident_len)

+  {

+    /* match, complete missing bits */

+    while (i < 4)

+    {

+      *ret_ptr++ = *prefix_ptr++;

+      i++;

+    }

+    oidret->len = i;

+    return 1;

+  }

+  else

+  {

+    /* i != ident_len */

+    return 0;

+  }

+}

+

+#endif /* LWIP_SNMP */

+

diff --git a/Demo/Common/ethernet/lwIP/core/snmp/msg_in.c b/Demo/Common/ethernet/lwIP/core/snmp/msg_in.c
index d071850..1999d13 100644
--- a/Demo/Common/ethernet/lwIP/core/snmp/msg_in.c
+++ b/Demo/Common/ethernet/lwIP/core/snmp/msg_in.c
@@ -1,1458 +1,1458 @@
-/**
- * @file
- * SNMP input message processing (RFC1157).
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * 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: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_SNMP
-#include <string.h>
-#include "arch/cc.h"
-#include "lwip/ip_addr.h"
-#include "lwip/mem.h"
-#include "lwip/udp.h"
-#include "lwip/stats.h"
-
-#include "lwip/snmp.h"
-#include "lwip/snmp_asn1.h"
-#include "lwip/snmp_msg.h"
-#include "lwip/snmp_structs.h"
-
-
-/* public (non-static) constants */
-/** SNMP v1 == 0 */
-const s32_t snmp_version = 0;
-/** default SNMP community string */
-const char snmp_publiccommunity[7] = "public";
-
-/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */
-#if (SNMP_CONCURRENT_REQUESTS == 0)
-#error "need at least one snmp_msg_pstat"
-#endif
-struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
-/* UDP Protocol Control Block */
-struct udp_pcb *snmp1_pcb = NULL;
-
-static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
-static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
-static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
-
-
-/**
- * Starts SNMP Agent.
- * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
- */
-void
-snmp_init(void)
-{
-  struct snmp_msg_pstat *msg_ps;
-  u8_t i;
-
-  snmp1_pcb = udp_new();
-  if (snmp1_pcb != NULL)
-  {
-    udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);
-    udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
-  }
-  msg_ps = &msg_input_list[0];
-  for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)
-  {
-    msg_ps->state = SNMP_MSG_EMPTY;
-    msg_ps->error_index = 0;
-    msg_ps->error_status = SNMP_ES_NOERROR;
-    msg_ps++;
-  }
-  trap_msg.pcb = snmp1_pcb;
-  /* The coldstart trap will only be output
-     if our outgoing interface is up & configured  */
-  snmp_coldstart_trap();
-}
-
-static void
-snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
-{
-  snmp_varbind_list_free(&msg_ps->outvb);
-  msg_ps->outvb = msg_ps->invb;
-  msg_ps->invb.head = NULL;
-  msg_ps->invb.tail = NULL;
-  msg_ps->invb.count = 0;
-  msg_ps->error_status = error;
-  msg_ps->error_index = 1 + msg_ps->vb_idx;
-  snmp_send_response(msg_ps);
-  snmp_varbind_list_free(&msg_ps->outvb);
-  msg_ps->state = SNMP_MSG_EMPTY;
-}
-
-static void
-snmp_ok_response(struct snmp_msg_pstat *msg_ps)
-{
-  err_t err_ret;
-
-  err_ret = snmp_send_response(msg_ps);
-  if (err_ret == ERR_MEM)
-  {
-    /* serious memory problem, can't return tooBig */
-#if LWIP_STATS
-    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event pbufs.used = %"U16_F"\n",lwip_stats.pbuf.used));
-#endif
-  }
-  else
-  {
-    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));
-  }
-  /* free varbinds (if available) */
-  snmp_varbind_list_free(&msg_ps->invb);
-  snmp_varbind_list_free(&msg_ps->outvb);
-  msg_ps->state = SNMP_MSG_EMPTY;
-}
-
-/**
- * Service an internal or external event for SNMP GET.
- *
- * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
- * @param msg_ps points to the assosicated message process state
- */
-static void
-snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
-{
-  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
-
-  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
-  {
-    struct mib_external_node *en;
-    struct snmp_name_ptr np;
-
-    /* get_object_def() answer*/
-    en = msg_ps->ext_mib_node;
-    np = msg_ps->ext_name_ptr;
-
-    /* translate answer into a known lifeform */
-    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
-    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
-    {
-      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
-      en->get_value_q(request_id, &msg_ps->ext_object_def);
-    }
-    else
-    {
-      en->get_object_def_pc(request_id, np.ident_len, np.ident);
-      /* search failed, object id points to unknown object (nosuchname) */
-      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
-    }
-  }
-  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
-  {
-    struct mib_external_node *en;
-    struct snmp_varbind *vb;
-
-    /* get_value() answer */
-    en = msg_ps->ext_mib_node;
-
-    /* allocate output varbind */
-    vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
-    LWIP_ASSERT("vb != NULL",vb != NULL);
-    if (vb != NULL)
-    {
-      vb->next = NULL;
-      vb->prev = NULL;
-
-      /* move name from invb to outvb */
-      vb->ident = msg_ps->vb_ptr->ident;
-      vb->ident_len = msg_ps->vb_ptr->ident_len;
-      /* ensure this memory is refereced once only */
-      msg_ps->vb_ptr->ident = NULL;
-      msg_ps->vb_ptr->ident_len = 0;
-
-      vb->value_type = msg_ps->ext_object_def.asn_type;
-      vb->value_len =  msg_ps->ext_object_def.v_len;
-      if (vb->value_len > 0)
-      {
-        vb->value = mem_malloc(vb->value_len);
-        LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
-        if (vb->value != NULL)
-        {
-          en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
-          snmp_varbind_tail_add(&msg_ps->outvb, vb);
-          /* search again (if vb_idx < msg_ps->invb.count) */
-          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-          msg_ps->vb_idx += 1;
-        }
-        else
-        {
-          en->get_value_pc(request_id, &msg_ps->ext_object_def);
-          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
-          msg_ps->vb_ptr->ident = vb->ident;
-          msg_ps->vb_ptr->ident_len = vb->ident_len;
-          mem_free(vb);
-          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
-        }
-      }
-      else
-      {
-        /* vb->value_len == 0, empty value (e.g. empty string) */
-        en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
-        vb->value = NULL;
-        snmp_varbind_tail_add(&msg_ps->outvb, vb);
-        /* search again (if vb_idx < msg_ps->invb.count) */
-        msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-        msg_ps->vb_idx += 1;
-      }
-    }
-    else
-    {
-      en->get_value_pc(request_id, &msg_ps->ext_object_def);
-      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));
-      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
-    }
-  }
-
-  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
-         (msg_ps->vb_idx < msg_ps->invb.count))
-  {
-    struct mib_node *mn;
-    struct snmp_name_ptr np;
-
-    if (msg_ps->vb_idx == 0)
-    {
-      msg_ps->vb_ptr = msg_ps->invb.head;
-    }
-    else
-    {
-      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
-    }
-    /** test object identifier for .iso.org.dod.internet prefix */
-    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
-    {
-      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
-                             msg_ps->vb_ptr->ident + 4, &np);
-    }
-    else
-    {
-      mn = NULL;
-    }
-    if (mn != NULL)
-    {
-      if (mn->node_type == MIB_NODE_EX)
-      {
-        /* external object */
-        struct mib_external_node *en = (struct mib_external_node*)mn;
-
-        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
-        /* save en && args in msg_ps!! */
-        msg_ps->ext_mib_node = en;
-        msg_ps->ext_name_ptr = np;
-
-        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
-      }
-      else
-      {
-        /* internal object */
-        struct obj_def object_def;
-
-        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
-        mn->get_object_def(np.ident_len, np.ident, &object_def);
-        if (object_def.instance != MIB_OBJECT_NONE)
-        {
-          mn = mn;
-        }
-        else
-        {
-          /* search failed, object id points to unknown object (nosuchname) */
-          mn =  NULL;
-        }
-        if (mn != NULL)
-        {
-          struct snmp_varbind *vb;
-
-          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
-          /* allocate output varbind */
-          vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
-          LWIP_ASSERT("vb != NULL",vb != NULL);
-          if (vb != NULL)
-          {
-            vb->next = NULL;
-            vb->prev = NULL;
-
-            /* move name from invb to outvb */
-            vb->ident = msg_ps->vb_ptr->ident;
-            vb->ident_len = msg_ps->vb_ptr->ident_len;
-            /* ensure this memory is refereced once only */
-            msg_ps->vb_ptr->ident = NULL;
-            msg_ps->vb_ptr->ident_len = 0;
-
-            vb->value_type = object_def.asn_type;
-            vb->value_len = object_def.v_len;
-            if (vb->value_len > 0)
-            {
-              vb->value = mem_malloc(vb->value_len);
-              LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
-              if (vb->value != NULL)
-              {
-                mn->get_value(&object_def, vb->value_len, vb->value);
-                snmp_varbind_tail_add(&msg_ps->outvb, vb);
-                msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-                msg_ps->vb_idx += 1;
-              }
-              else
-              {
-                LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
-                msg_ps->vb_ptr->ident = vb->ident;
-                msg_ps->vb_ptr->ident_len = vb->ident_len;
-                mem_free(vb);
-                snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
-              }
-            }
-            else
-            {
-              /* vb->value_len == 0, empty value (e.g. empty string) */
-              vb->value = NULL;
-              snmp_varbind_tail_add(&msg_ps->outvb, vb);
-              msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-              msg_ps->vb_idx += 1;
-            }
-          }
-          else
-          {
-            LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));
-            snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
-          }
-        }
-      }
-    }
-    if (mn == NULL)
-    {
-      /* mn == NULL, noSuchName */
-      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
-    }
-  }
-  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
-      (msg_ps->vb_idx == msg_ps->invb.count))
-  {
-    snmp_ok_response(msg_ps);
-  }
-}
-
-/**
- * Service an internal or external event for SNMP GETNEXT.
- *
- * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
- * @param msg_ps points to the assosicated message process state
- */
-static void
-snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
-{
-  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
-
-  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
-  {
-    struct mib_external_node *en;
-
-    /* get_object_def() answer*/
-    en = msg_ps->ext_mib_node;
-
-    /* translate answer into a known lifeform */
-    en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);
-    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
-    {
-      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
-      en->get_value_q(request_id, &msg_ps->ext_object_def);
-    }
-    else
-    {
-      en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);
-      /* search failed, object id points to unknown object (nosuchname) */
-      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
-    }
-  }
-  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
-  {
-    struct mib_external_node *en;
-    struct snmp_varbind *vb;
-
-    /* get_value() answer */
-    en = msg_ps->ext_mib_node;
-
-    vb = snmp_varbind_alloc(&msg_ps->ext_oid,
-                            msg_ps->ext_object_def.asn_type,
-                            msg_ps->ext_object_def.v_len);
-    if (vb != NULL)
-    {
-      en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
-      snmp_varbind_tail_add(&msg_ps->outvb, vb);
-      msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-      msg_ps->vb_idx += 1;
-    }
-    else
-    {
-      en->get_value_pc(request_id, &msg_ps->ext_object_def);
-      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
-      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
-    }
-  }
-
-  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
-         (msg_ps->vb_idx < msg_ps->invb.count))
-  {
-    struct mib_node *mn;
-    struct snmp_obj_id oid;
-
-    if (msg_ps->vb_idx == 0)
-    {
-      msg_ps->vb_ptr = msg_ps->invb.head;
-    }
-    else
-    {
-      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
-    }
-    if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))
-    {
-      if (msg_ps->vb_ptr->ident_len > 3)
-      {
-        /* can offset ident_len and ident */
-        mn = snmp_expand_tree((struct mib_node*)&internet,
-                              msg_ps->vb_ptr->ident_len - 4,
-                              msg_ps->vb_ptr->ident + 4, &oid);
-      }
-      else
-      {
-        /* can't offset ident_len -4, ident + 4 */
-        mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);
-      }
-    }
-    else
-    {
-      mn = NULL;
-    }
-    if (mn != NULL)
-    {
-      if (mn->node_type == MIB_NODE_EX)
-      {
-        /* external object */
-        struct mib_external_node *en = (struct mib_external_node*)mn;
-
-        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
-        /* save en && args in msg_ps!! */
-        msg_ps->ext_mib_node = en;
-        msg_ps->ext_oid = oid;
-
-        en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);
-      }
-      else
-      {
-        /* internal object */
-        struct obj_def object_def;
-        struct snmp_varbind *vb;
-
-        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
-        mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
-
-        vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);
-        if (vb != NULL)
-        {
-          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
-          mn->get_value(&object_def, object_def.v_len, vb->value);
-          snmp_varbind_tail_add(&msg_ps->outvb, vb);
-          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-          msg_ps->vb_idx += 1;
-        }
-        else
-        {
-          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));
-          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
-        }
-      }
-    }
-    if (mn == NULL)
-    {
-      /* mn == NULL, noSuchName */
-      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
-    }
-  }
-  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
-      (msg_ps->vb_idx == msg_ps->invb.count))
-  {
-    snmp_ok_response(msg_ps);
-  }
-}
-
-/**
- * Service an internal or external event for SNMP SET.
- *
- * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
- * @param msg_ps points to the assosicated message process state
- */
-static void
-snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
-{
-  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
-
-  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
-  {
-    struct mib_external_node *en;
-    struct snmp_name_ptr np;
-
-    /* get_object_def() answer*/
-    en = msg_ps->ext_mib_node;
-    np = msg_ps->ext_name_ptr;
-
-    /* translate answer into a known lifeform */
-    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
-    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
-    {
-      msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;
-      en->set_test_q(request_id, &msg_ps->ext_object_def);
-    }
-    else
-    {
-      en->get_object_def_pc(request_id, np.ident_len, np.ident);
-      /* search failed, object id points to unknown object (nosuchname) */
-      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
-    }
-  }
-  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)
-  {
-    struct mib_external_node *en;
-    struct snmp_name_ptr np;
-
-    /* set_test() answer*/
-    en = msg_ps->ext_mib_node;
-    np = msg_ps->ext_name_ptr;
-
-    if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
-    {
-       if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
-           (en->set_test_a(request_id,&msg_ps->ext_object_def,
-                           msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
-      {
-        msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-        msg_ps->vb_idx += 1;
-      }
-      else
-      {
-        en->set_test_pc(request_id,&msg_ps->ext_object_def);
-        /* bad value */
-        snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
-      }
-    }
-    else
-    {
-      en->set_test_pc(request_id,&msg_ps->ext_object_def);
-      /* object not available for set */
-      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
-    }
-  }
-  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
-  {
-    struct mib_external_node *en;
-    struct snmp_name_ptr np;
-
-    /* get_object_def() answer*/
-    en = msg_ps->ext_mib_node;
-    np = msg_ps->ext_name_ptr;
-
-    /* translate answer into a known lifeform */
-    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
-    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
-    {
-      msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;
-      en->set_value_q(request_id, &msg_ps->ext_object_def,
-                      msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
-    }
-    else
-    {
-      en->get_object_def_pc(request_id, np.ident_len, np.ident);
-      /* set_value failed, object has disappeared for some odd reason?? */
-      snmp_error_response(msg_ps,SNMP_ES_GENERROR);
-    }
-  }
-  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
-  {
-    struct mib_external_node *en;
-
-    /** set_value_a() @todo: use reply value?? */
-    en = msg_ps->ext_mib_node;
-    en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
-
-    /** @todo use set_value_pc() if toobig */
-    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
-    msg_ps->vb_idx += 1;
-  }
-
-  /* test all values before setting */
-  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
-         (msg_ps->vb_idx < msg_ps->invb.count))
-  {
-    struct mib_node *mn;
-    struct snmp_name_ptr np;
-
-    if (msg_ps->vb_idx == 0)
-    {
-      msg_ps->vb_ptr = msg_ps->invb.head;
-    }
-    else
-    {
-      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
-    }
-    /** test object identifier for .iso.org.dod.internet prefix */
-    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
-    {
-      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
-                             msg_ps->vb_ptr->ident + 4, &np);
-    }
-    else
-    {
-      mn = NULL;
-    }
-    if (mn != NULL)
-    {
-      if (mn->node_type == MIB_NODE_EX)
-      {
-        /* external object */
-        struct mib_external_node *en = (struct mib_external_node*)mn;
-
-        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
-        /* save en && args in msg_ps!! */
-        msg_ps->ext_mib_node = en;
-        msg_ps->ext_name_ptr = np;
-
-        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
-      }
-      else
-      {
-        /* internal object */
-        struct obj_def object_def;
-
-        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
-        mn->get_object_def(np.ident_len, np.ident, &object_def);
-        if (object_def.instance != MIB_OBJECT_NONE)
-        {
-          mn = mn;
-        }
-        else
-        {
-          /* search failed, object id points to unknown object (nosuchname) */
-          mn = NULL;
-        }
-        if (mn != NULL)
-        {
-          msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
-
-          if (object_def.access == MIB_OBJECT_READ_WRITE)
-          {
-            if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
-                (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
-            {
-              msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-              msg_ps->vb_idx += 1;
-            }
-            else
-            {
-              /* bad value */
-              snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
-            }
-          }
-          else
-          {
-            /* object not available for set */
-            snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
-          }
-        }
-      }
-    }
-    if (mn == NULL)
-    {
-      /* mn == NULL, noSuchName */
-      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
-    }
-  }
-
-  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
-      (msg_ps->vb_idx == msg_ps->invb.count))
-  {
-    msg_ps->vb_idx = 0;
-    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
-  }
-
-  /* set all values "atomically" (be as "atomic" as possible) */
-  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
-         (msg_ps->vb_idx < msg_ps->invb.count))
-  {
-    struct mib_node *mn;
-    struct snmp_name_ptr np;
-
-    if (msg_ps->vb_idx == 0)
-    {
-      msg_ps->vb_ptr = msg_ps->invb.head;
-    }
-    else
-    {
-      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
-    }
-    /* skip iso prefix test, was done previously while settesting() */
-    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
-                           msg_ps->vb_ptr->ident + 4, &np);
-    /* check if object is still available
-       (e.g. external hot-plug thingy present?) */
-    if (mn != NULL)
-    {
-      if (mn->node_type == MIB_NODE_EX)
-      {
-        /* external object */
-        struct mib_external_node *en = (struct mib_external_node*)mn;
-
-        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
-        /* save en && args in msg_ps!! */
-        msg_ps->ext_mib_node = en;
-        msg_ps->ext_name_ptr = np;
-
-        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
-      }
-      else
-      {
-        /* internal object */
-        struct obj_def object_def;
-
-        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
-        mn->get_object_def(np.ident_len, np.ident, &object_def);
-        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
-        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
-        msg_ps->vb_idx += 1;
-      }
-    }
-  }
-  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
-      (msg_ps->vb_idx == msg_ps->invb.count))
-  {
-    /* simply echo the input if we can set it
-       @todo do we need to return the actual value?
-       e.g. if value is silently modified or behaves sticky? */
-    msg_ps->outvb = msg_ps->invb;
-    msg_ps->invb.head = NULL;
-    msg_ps->invb.tail = NULL;
-    msg_ps->invb.count = 0;
-    snmp_ok_response(msg_ps);
-  }
-}
-
-
-/**
- * Handle one internal or external event.
- * Called for one async event. (recv external/private answer)
- *
- * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
- */
-void
-snmp_msg_event(u8_t request_id)
-{
-  struct snmp_msg_pstat *msg_ps;
-
-  if (request_id < SNMP_CONCURRENT_REQUESTS)
-  {
-    msg_ps = &msg_input_list[request_id];
-    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
-    {
-      snmp_msg_getnext_event(request_id, msg_ps);
-    }
-    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
-    {
-      snmp_msg_get_event(request_id, msg_ps);
-    }
-    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
-    {
-      snmp_msg_set_event(request_id, msg_ps);
-    }
-  }
-}
-
-
-/* lwIP UDP receive callback function */
-static void
-snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
-{
-  struct udp_hdr *udphdr;
-
-  /* suppress unused argument warning */
-  if (arg);
-  /* peek in the UDP header (goto IP payload) */
-  pbuf_header(p, UDP_HLEN);
-  udphdr = p->payload;
-
-  /* check if datagram is really directed at us (including broadcast requests) */
-  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == 161))
-  {
-    struct snmp_msg_pstat *msg_ps;
-    u8_t req_idx;
-
-    /* traverse input message process list, look for SNMP_MSG_EMPTY */
-    msg_ps = &msg_input_list[0];
-    req_idx = 0;
-    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
-    {
-      req_idx++;
-      msg_ps++;
-    }
-    if (req_idx != SNMP_CONCURRENT_REQUESTS)
-    {
-      err_t err_ret;
-      u16_t payload_len;
-      u16_t payload_ofs;
-      u16_t varbind_ofs = 0;
-
-      /* accepting request */
-      snmp_inc_snmpinpkts();
-      /* record used 'protocol control block' */
-      msg_ps->pcb = pcb;
-      /* source address (network order) */
-      msg_ps->sip = *addr;
-      /* source port (host order (lwIP oddity)) */
-      msg_ps->sp = port;
-      /* read UDP payload length from UDP header */
-      payload_len = ntohs(udphdr->len) - UDP_HLEN;
-
-      /* adjust to UDP payload */
-      payload_ofs = UDP_HLEN;
-
-      /* check total length, version, community, pdu type */
-      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
-      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
-           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
-           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
-          ((msg_ps->error_status == SNMP_ES_NOERROR) &&
-           (msg_ps->error_index == 0)) )
-      {
-        /* Only accept requests and requests without error (be robust) */
-        err_ret = err_ret;
-      }
-      else
-      {
-        /* Reject response and trap headers or error requests as input! */
-        err_ret = ERR_ARG;
-      }
-      if (err_ret == ERR_OK)
-      {
-        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
-
-        /* Builds a list of variable bindings. Copy the varbinds from the pbuf
-          chain to glue them when these are divided over two or more pbuf's. */
-        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
-        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
-        {
-          /* we've decoded the incoming message, release input msg now */
-          pbuf_free(p);
-
-          msg_ps->error_status = SNMP_ES_NOERROR;
-          msg_ps->error_index = 0;
-          /* find object for each variable binding */
-          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-          /* first variable binding from list to inspect */
-          msg_ps->vb_idx = 0;
-
-          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
-
-          /* handle input event and as much objects as possible in one go */
-          snmp_msg_event(req_idx);
-        }
-        else
-        {
-          /* varbind-list decode failed, or varbind list empty.
-             drop request silently, do not return error!
-             (errors are only returned for a specific varbind failure) */
-          pbuf_free(p);
-          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
-        }
-      }
-      else
-      {
-        /* header check failed
-           drop request silently, do not return error! */
-        pbuf_free(p);
-        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
-      }
-    }
-    else
-    {
-      /* exceeding number of concurrent requests */
-      pbuf_free(p);
-    }
-  }
-  else
-  {
-    /* datagram not for us */
-    pbuf_free(p);
-  }
-}
-
-/**
- * Checks and decodes incoming SNMP message header, logs header errors.
- *
- * @param p points to pbuf chain of SNMP message (UDP payload)
- * @param ofs points to first octet of SNMP message
- * @param pdu_len the length of the UDP payload
- * @param ofs_ret returns the ofset of the variable bindings
- * @param m_stat points to the current message request state return
- * @return
- * - ERR_OK SNMP header is sane and accepted
- * - ERR_ARG SNMP header is either malformed or rejected
- */
-static err_t
-snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
-{
-  err_t derr;
-  u16_t len, ofs_base;
-  u8_t  len_octets;
-  u8_t  type;
-  s32_t version;
-
-  ofs_base = ofs;
-  snmp_asn1_dec_type(p, ofs, &type);
-  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-  if ((derr != ERR_OK) ||
-      (pdu_len != (1 + len_octets + len)) ||
-      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
-  {
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  ofs += (1 + len_octets);
-  snmp_asn1_dec_type(p, ofs, &type);
-  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
-  {
-    /* can't decode or no integer (version) */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
-  if (derr != ERR_OK)
-  {
-    /* can't decode */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  if (version != 0)
-  {
-    /* not version 1 */
-    snmp_inc_snmpinbadversions();
-    return ERR_ARG;
-  }
-  ofs += (1 + len_octets + len);
-  snmp_asn1_dec_type(p, ofs, &type);
-  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
-  {
-    /* can't decode or no octet string (community) */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
-  if (derr != ERR_OK)
-  {
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  /* add zero terminator */
-  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
-  m_stat->community[len] = 0;
-  m_stat->com_strlen = len;
-  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
-  {
-    /** @todo: move this if we need to check more names */
-    snmp_inc_snmpinbadcommunitynames();
-    snmp_authfail_trap();
-    return ERR_ARG;
-  }
-  ofs += (1 + len_octets + len);
-  snmp_asn1_dec_type(p, ofs, &type);
-  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-  if (derr != ERR_OK)
-  {
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  switch(type)
-  {
-    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
-      /* GetRequest PDU */
-      snmp_inc_snmpingetrequests();
-      derr = ERR_OK;
-      break;
-    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
-      /* GetNextRequest PDU */
-      snmp_inc_snmpingetnexts();
-      derr = ERR_OK;
-      break;
-    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
-      /* GetResponse PDU */
-      snmp_inc_snmpingetresponses();
-      derr = ERR_ARG;
-      break;
-    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
-      /* SetRequest PDU */
-      snmp_inc_snmpinsetrequests();
-      derr = ERR_OK;
-      break;
-    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
-      /* Trap PDU */
-      snmp_inc_snmpintraps();
-      derr = ERR_ARG;
-      break;
-    default:
-      snmp_inc_snmpinasnparseerrs();
-      derr = ERR_ARG;
-      break;
-  }
-  if (derr != ERR_OK)
-  {
-    /* unsupported input PDU for this agent (no parse error) */
-    return ERR_ARG;
-  }
-  m_stat->rt = type & 0x1F;
-  ofs += (1 + len_octets);
-  if (len != (pdu_len - (ofs - ofs_base)))
-  {
-    /* decoded PDU length does not equal actual payload length */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  snmp_asn1_dec_type(p, ofs, &type);
-  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
-  {
-    /* can't decode or no integer (request ID) */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
-  if (derr != ERR_OK)
-  {
-    /* can't decode */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  ofs += (1 + len_octets + len);
-  snmp_asn1_dec_type(p, ofs, &type);
-  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
-  {
-    /* can't decode or no integer (error-status) */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  /* must be noError (0) for incoming requests.
-     log errors for mib-2 completeness and for debug purposes */
-  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
-  if (derr != ERR_OK)
-  {
-    /* can't decode */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  switch (m_stat->error_status)
-  {
-    case SNMP_ES_TOOBIG:
-      snmp_inc_snmpintoobigs();
-      break;
-    case SNMP_ES_NOSUCHNAME:
-      snmp_inc_snmpinnosuchnames();
-      break;
-    case SNMP_ES_BADVALUE:
-      snmp_inc_snmpinbadvalues();
-      break;
-    case SNMP_ES_READONLY:
-      snmp_inc_snmpinreadonlys();
-      break;
-    case SNMP_ES_GENERROR:
-      snmp_inc_snmpingenerrs();
-      break;
-  }
-  ofs += (1 + len_octets + len);
-  snmp_asn1_dec_type(p, ofs, &type);
-  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
-  {
-    /* can't decode or no integer (error-index) */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  /* must be 0 for incoming requests.
-     decode anyway to catch bad integers (and dirty tricks) */
-  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
-  if (derr != ERR_OK)
-  {
-    /* can't decode */
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  ofs += (1 + len_octets + len);
-  *ofs_ret = ofs;
-  return ERR_OK;
-}
-
-static err_t
-snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
-{
-  err_t derr;
-  u16_t len, vb_len;
-  u8_t  len_octets;
-  u8_t type;
-
-  /* variable binding list */
-  snmp_asn1_dec_type(p, ofs, &type);
-  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
-  if ((derr != ERR_OK) ||
-      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
-  {
-    snmp_inc_snmpinasnparseerrs();
-    return ERR_ARG;
-  }
-  ofs += (1 + len_octets);
-
-  /* start with empty list */
-  m_stat->invb.count = 0;
-  m_stat->invb.head = NULL;
-  m_stat->invb.tail = NULL;
-
-  while (vb_len > 0)
-  {
-    struct snmp_obj_id oid, oid_value;
-    struct snmp_varbind *vb;
-
-    snmp_asn1_dec_type(p, ofs, &type);
-    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-    if ((derr != ERR_OK) ||
-        (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
-        (len <= 0) || (len > vb_len))
-    {
-      snmp_inc_snmpinasnparseerrs();
-      /* free varbinds (if available) */
-      snmp_varbind_list_free(&m_stat->invb);
-      return ERR_ARG;
-    }
-    ofs += (1 + len_octets);
-    vb_len -= (1 + len_octets);
-
-    snmp_asn1_dec_type(p, ofs, &type);
-    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-    if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
-    {
-      /* can't decode object name length */
-      snmp_inc_snmpinasnparseerrs();
-      /* free varbinds (if available) */
-      snmp_varbind_list_free(&m_stat->invb);
-      return ERR_ARG;
-    }
-    derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
-    if (derr != ERR_OK)
-    {
-      /* can't decode object name */
-      snmp_inc_snmpinasnparseerrs();
-      /* free varbinds (if available) */
-      snmp_varbind_list_free(&m_stat->invb);
-      return ERR_ARG;
-    }
-    ofs += (1 + len_octets + len);
-    vb_len -= (1 + len_octets + len);
-
-    snmp_asn1_dec_type(p, ofs, &type);
-    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
-    if (derr != ERR_OK)
-    {
-      /* can't decode object value length */
-      snmp_inc_snmpinasnparseerrs();
-      /* free varbinds (if available) */
-      snmp_varbind_list_free(&m_stat->invb);
-      return ERR_ARG;
-    }
-
-    switch (type)
-    {
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
-        vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
-        if (vb != NULL)
-        {
-          s32_t *vptr = vb->value;
-
-          derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
-          snmp_varbind_tail_add(&m_stat->invb, vb);
-        }
-        else
-        {
-          derr = ERR_ARG;
-        }
-        break;
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
-        vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
-        if (vb != NULL)
-        {
-          u32_t *vptr = vb->value;
-
-          derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
-          snmp_varbind_tail_add(&m_stat->invb, vb);
-        }
-        else
-        {
-          derr = ERR_ARG;
-        }
-        break;
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
-        vb = snmp_varbind_alloc(&oid, type, len);
-        if (vb != NULL)
-        {
-          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
-          snmp_varbind_tail_add(&m_stat->invb, vb);
-        }
-        else
-        {
-          derr = ERR_ARG;
-        }
-        break;
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
-        vb = snmp_varbind_alloc(&oid, type, 0);
-        if (vb != NULL)
-        {
-          snmp_varbind_tail_add(&m_stat->invb, vb);
-          derr = ERR_OK;
-        }
-        else
-        {
-          derr = ERR_ARG;
-        }
-        break;
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
-        derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
-        if (derr == ERR_OK)
-        {
-          vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
-          if (vb != NULL)
-          {
-            u8_t i = oid_value.len;
-            s32_t *vptr = vb->value;
-
-            while(i > 0)
-            {
-              i--;
-              vptr[i] = oid_value.id[i];
-            }
-            snmp_varbind_tail_add(&m_stat->invb, vb);
-            derr = ERR_OK;
-          }
-          else
-          {
-            derr = ERR_ARG;
-          }
-        }
-        break;
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
-        if (len == 4)
-        {
-          /* must be exactly 4 octets! */
-          vb = snmp_varbind_alloc(&oid, type, 4);
-          if (vb != NULL)
-          {
-            derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
-            snmp_varbind_tail_add(&m_stat->invb, vb);
-          }
-          else
-          {
-            derr = ERR_ARG;
-          }
-        }
-        else
-        {
-          derr = ERR_ARG;
-        }
-        break;
-      default:
-        derr = ERR_ARG;
-        break;
-    }
-    if (derr != ERR_OK)
-    {
-      snmp_inc_snmpinasnparseerrs();
-      /* free varbinds (if available) */
-      snmp_varbind_list_free(&m_stat->invb);
-      return ERR_ARG;
-    }
-    ofs += (1 + len_octets + len);
-    vb_len -= (1 + len_octets + len);
-  }
-
-  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
-  {
-    snmp_add_snmpintotalsetvars(m_stat->invb.count);
-  }
-  else
-  {
-    snmp_add_snmpintotalreqvars(m_stat->invb.count);
-  }
-
-  *ofs_ret = ofs;
-  return ERR_OK;
-}
-
-struct snmp_varbind*
-snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
-{
-  struct snmp_varbind *vb;
-
-  vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
-  LWIP_ASSERT("vb != NULL",vb != NULL);
-  if (vb != NULL)
-  {
-    u8_t i;
-
-    vb->next = NULL;
-    vb->prev = NULL;
-    i = oid->len;
-    vb->ident_len = i;
-    if (i > 0)
-    {
-      /* allocate array of s32_t for our object identifier */
-      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);
-      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
-      if (vb->ident == NULL)
-      {
-        mem_free(vb);
-        return NULL;
-      }
-      while(i > 0)
-      {
-        i--;
-        vb->ident[i] = oid->id[i];
-      }
-    }
-    else
-    {
-      /* i == 0, pass zero length object identifier */
-      vb->ident = NULL;
-    }
-    vb->value_type = type;
-    vb->value_len = len;
-    if (len > 0)
-    {
-      /* allocate raw bytes for our object value */
-      vb->value = mem_malloc(len);
-      LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
-      if (vb->value == NULL)
-      {
-        if (vb->ident != NULL)
-        {
-          mem_free(vb->ident);
-        }
-        mem_free(vb);
-        return NULL;
-      }
-    }
-    else
-    {
-      /* ASN1_NUL type, or zero length ASN1_OC_STR */
-      vb->value = NULL;
-    }
-  }
-  return vb;
-}
-
-void
-snmp_varbind_free(struct snmp_varbind *vb)
-{
-  if (vb->value != NULL )
-  {
-    mem_free(vb->value);
-  }
-  if (vb->ident != NULL )
-  {
-    mem_free(vb->ident);
-  }
-  mem_free(vb);
-}
-
-void
-snmp_varbind_list_free(struct snmp_varbind_root *root)
-{
-  struct snmp_varbind *vb, *prev;
-
-  vb = root->tail;
-  while ( vb != NULL )
-  {
-    prev = vb->prev;
-    snmp_varbind_free(vb);
-    vb = prev;
-  }
-  root->count = 0;
-  root->head = NULL;
-  root->tail = NULL;
-}
-
-void
-snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
-{
-  if (root->count == 0)
-  {
-    /* add first varbind to list */
-    root->head = vb;
-    root->tail = vb;
-  }
-  else
-  {
-    /* add nth varbind to list tail */
-    root->tail->next = vb;
-    vb->prev = root->tail;
-    root->tail = vb;
-  }
-  root->count += 1;
-}
-
-struct snmp_varbind*
-snmp_varbind_tail_remove(struct snmp_varbind_root *root)
-{
-  struct snmp_varbind* vb;
-
-  if (root->count > 0)
-  {
-    /* remove tail varbind */
-    vb = root->tail;
-    root->tail = vb->prev;
-    vb->prev->next = NULL;
-    root->count -= 1;
-  }
-  else
-  {
-    /* nothing to remove */
-    vb = NULL;
-  }
-  return vb;
-}
-
-#endif /* LWIP_SNMP */
+/**

+ * @file

+ * SNMP input message processing (RFC1157).

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * 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: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP

+#include <string.h>

+#include "arch/cc.h"

+#include "lwip/ip_addr.h"

+#include "lwip/mem.h"

+#include "lwip/udp.h"

+#include "lwip/stats.h"

+

+#include "lwip/snmp.h"

+#include "lwip/snmp_asn1.h"

+#include "lwip/snmp_msg.h"

+#include "lwip/snmp_structs.h"

+

+

+/* public (non-static) constants */

+/** SNMP v1 == 0 */

+const s32_t snmp_version = 0;

+/** default SNMP community string */

+const char snmp_publiccommunity[7] = "public";

+

+/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */

+#if (SNMP_CONCURRENT_REQUESTS == 0)

+#error "need at least one snmp_msg_pstat"

+#endif

+struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];

+/* UDP Protocol Control Block */

+struct udp_pcb *snmp1_pcb = NULL;

+

+static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);

+static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);

+static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);

+

+

+/**

+ * Starts SNMP Agent.

+ * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.

+ */

+void

+snmp_init(void)

+{

+  struct snmp_msg_pstat *msg_ps;

+  u8_t i;

+

+  snmp1_pcb = udp_new();

+  if (snmp1_pcb != NULL)

+  {

+    udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);

+    udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);

+  }

+  msg_ps = &msg_input_list[0];

+  for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)

+  {

+    msg_ps->state = SNMP_MSG_EMPTY;

+    msg_ps->error_index = 0;

+    msg_ps->error_status = SNMP_ES_NOERROR;

+    msg_ps++;

+  }

+  trap_msg.pcb = snmp1_pcb;

+  /* The coldstart trap will only be output

+     if our outgoing interface is up & configured  */

+  snmp_coldstart_trap();

+}

+

+static void

+snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)

+{

+  snmp_varbind_list_free(&msg_ps->outvb);

+  msg_ps->outvb = msg_ps->invb;

+  msg_ps->invb.head = NULL;

+  msg_ps->invb.tail = NULL;

+  msg_ps->invb.count = 0;

+  msg_ps->error_status = error;

+  msg_ps->error_index = 1 + msg_ps->vb_idx;

+  snmp_send_response(msg_ps);

+  snmp_varbind_list_free(&msg_ps->outvb);

+  msg_ps->state = SNMP_MSG_EMPTY;

+}

+

+static void

+snmp_ok_response(struct snmp_msg_pstat *msg_ps)

+{

+  err_t err_ret;

+

+  err_ret = snmp_send_response(msg_ps);

+  if (err_ret == ERR_MEM)

+  {

+    /* serious memory problem, can't return tooBig */

+#if LWIP_STATS

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event pbufs.used = %"U16_F"\n",lwip_stats.pbuf.used));

+#endif

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));

+  }

+  /* free varbinds (if available) */

+  snmp_varbind_list_free(&msg_ps->invb);

+  snmp_varbind_list_free(&msg_ps->outvb);

+  msg_ps->state = SNMP_MSG_EMPTY;

+}

+

+/**

+ * Service an internal or external event for SNMP GET.

+ *

+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)

+ * @param msg_ps points to the assosicated message process state

+ */

+static void

+snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)

+{

+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));

+

+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)

+  {

+    struct mib_external_node *en;

+    struct snmp_name_ptr np;

+

+    /* get_object_def() answer*/

+    en = msg_ps->ext_mib_node;

+    np = msg_ps->ext_name_ptr;

+

+    /* translate answer into a known lifeform */

+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);

+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)

+    {

+      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;

+      en->get_value_q(request_id, &msg_ps->ext_object_def);

+    }

+    else

+    {

+      en->get_object_def_pc(request_id, np.ident_len, np.ident);

+      /* search failed, object id points to unknown object (nosuchname) */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)

+  {

+    struct mib_external_node *en;

+    struct snmp_varbind *vb;

+

+    /* get_value() answer */

+    en = msg_ps->ext_mib_node;

+

+    /* allocate output varbind */

+    vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));

+    LWIP_ASSERT("vb != NULL",vb != NULL);

+    if (vb != NULL)

+    {

+      vb->next = NULL;

+      vb->prev = NULL;

+

+      /* move name from invb to outvb */

+      vb->ident = msg_ps->vb_ptr->ident;

+      vb->ident_len = msg_ps->vb_ptr->ident_len;

+      /* ensure this memory is refereced once only */

+      msg_ps->vb_ptr->ident = NULL;

+      msg_ps->vb_ptr->ident_len = 0;

+

+      vb->value_type = msg_ps->ext_object_def.asn_type;

+      vb->value_len =  msg_ps->ext_object_def.v_len;

+      if (vb->value_len > 0)

+      {

+        vb->value = mem_malloc(vb->value_len);

+        LWIP_ASSERT("vb->value != NULL",vb->value != NULL);

+        if (vb->value != NULL)

+        {

+          en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);

+          snmp_varbind_tail_add(&msg_ps->outvb, vb);

+          /* search again (if vb_idx < msg_ps->invb.count) */

+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+          msg_ps->vb_idx += 1;

+        }

+        else

+        {

+          en->get_value_pc(request_id, &msg_ps->ext_object_def);

+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));

+          msg_ps->vb_ptr->ident = vb->ident;

+          msg_ps->vb_ptr->ident_len = vb->ident_len;

+          mem_free(vb);

+          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+        }

+      }

+      else

+      {

+        /* vb->value_len == 0, empty value (e.g. empty string) */

+        en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);

+        vb->value = NULL;

+        snmp_varbind_tail_add(&msg_ps->outvb, vb);

+        /* search again (if vb_idx < msg_ps->invb.count) */

+        msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+        msg_ps->vb_idx += 1;

+      }

+    }

+    else

+    {

+      en->get_value_pc(request_id, &msg_ps->ext_object_def);

+      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));

+      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+    }

+  }

+

+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+         (msg_ps->vb_idx < msg_ps->invb.count))

+  {

+    struct mib_node *mn;

+    struct snmp_name_ptr np;

+

+    if (msg_ps->vb_idx == 0)

+    {

+      msg_ps->vb_ptr = msg_ps->invb.head;

+    }

+    else

+    {

+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;

+    }

+    /** test object identifier for .iso.org.dod.internet prefix */

+    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))

+    {

+      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,

+                             msg_ps->vb_ptr->ident + 4, &np);

+    }

+    else

+    {

+      mn = NULL;

+    }

+    if (mn != NULL)

+    {

+      if (mn->node_type == MIB_NODE_EX)

+      {

+        /* external object */

+        struct mib_external_node *en = (struct mib_external_node*)mn;

+

+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;

+        /* save en && args in msg_ps!! */

+        msg_ps->ext_mib_node = en;

+        msg_ps->ext_name_ptr = np;

+

+        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);

+      }

+      else

+      {

+        /* internal object */

+        struct obj_def object_def;

+

+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;

+        mn->get_object_def(np.ident_len, np.ident, &object_def);

+        if (object_def.instance != MIB_OBJECT_NONE)

+        {

+          mn = mn;

+        }

+        else

+        {

+          /* search failed, object id points to unknown object (nosuchname) */

+          mn =  NULL;

+        }

+        if (mn != NULL)

+        {

+          struct snmp_varbind *vb;

+

+          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;

+          /* allocate output varbind */

+          vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));

+          LWIP_ASSERT("vb != NULL",vb != NULL);

+          if (vb != NULL)

+          {

+            vb->next = NULL;

+            vb->prev = NULL;

+

+            /* move name from invb to outvb */

+            vb->ident = msg_ps->vb_ptr->ident;

+            vb->ident_len = msg_ps->vb_ptr->ident_len;

+            /* ensure this memory is refereced once only */

+            msg_ps->vb_ptr->ident = NULL;

+            msg_ps->vb_ptr->ident_len = 0;

+

+            vb->value_type = object_def.asn_type;

+            vb->value_len = object_def.v_len;

+            if (vb->value_len > 0)

+            {

+              vb->value = mem_malloc(vb->value_len);

+              LWIP_ASSERT("vb->value != NULL",vb->value != NULL);

+              if (vb->value != NULL)

+              {

+                mn->get_value(&object_def, vb->value_len, vb->value);

+                snmp_varbind_tail_add(&msg_ps->outvb, vb);

+                msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+                msg_ps->vb_idx += 1;

+              }

+              else

+              {

+                LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));

+                msg_ps->vb_ptr->ident = vb->ident;

+                msg_ps->vb_ptr->ident_len = vb->ident_len;

+                mem_free(vb);

+                snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+              }

+            }

+            else

+            {

+              /* vb->value_len == 0, empty value (e.g. empty string) */

+              vb->value = NULL;

+              snmp_varbind_tail_add(&msg_ps->outvb, vb);

+              msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+              msg_ps->vb_idx += 1;

+            }

+          }

+          else

+          {

+            LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));

+            snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+          }

+        }

+      }

+    }

+    if (mn == NULL)

+    {

+      /* mn == NULL, noSuchName */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+      (msg_ps->vb_idx == msg_ps->invb.count))

+  {

+    snmp_ok_response(msg_ps);

+  }

+}

+

+/**

+ * Service an internal or external event for SNMP GETNEXT.

+ *

+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)

+ * @param msg_ps points to the assosicated message process state

+ */

+static void

+snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)

+{

+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));

+

+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)

+  {

+    struct mib_external_node *en;

+

+    /* get_object_def() answer*/

+    en = msg_ps->ext_mib_node;

+

+    /* translate answer into a known lifeform */

+    en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);

+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)

+    {

+      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;

+      en->get_value_q(request_id, &msg_ps->ext_object_def);

+    }

+    else

+    {

+      en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);

+      /* search failed, object id points to unknown object (nosuchname) */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)

+  {

+    struct mib_external_node *en;

+    struct snmp_varbind *vb;

+

+    /* get_value() answer */

+    en = msg_ps->ext_mib_node;

+

+    vb = snmp_varbind_alloc(&msg_ps->ext_oid,

+                            msg_ps->ext_object_def.asn_type,

+                            msg_ps->ext_object_def.v_len);

+    if (vb != NULL)

+    {

+      en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);

+      snmp_varbind_tail_add(&msg_ps->outvb, vb);

+      msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+      msg_ps->vb_idx += 1;

+    }

+    else

+    {

+      en->get_value_pc(request_id, &msg_ps->ext_object_def);

+      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));

+      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+    }

+  }

+

+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+         (msg_ps->vb_idx < msg_ps->invb.count))

+  {

+    struct mib_node *mn;

+    struct snmp_obj_id oid;

+

+    if (msg_ps->vb_idx == 0)

+    {

+      msg_ps->vb_ptr = msg_ps->invb.head;

+    }

+    else

+    {

+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;

+    }

+    if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))

+    {

+      if (msg_ps->vb_ptr->ident_len > 3)

+      {

+        /* can offset ident_len and ident */

+        mn = snmp_expand_tree((struct mib_node*)&internet,

+                              msg_ps->vb_ptr->ident_len - 4,

+                              msg_ps->vb_ptr->ident + 4, &oid);

+      }

+      else

+      {

+        /* can't offset ident_len -4, ident + 4 */

+        mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);

+      }

+    }

+    else

+    {

+      mn = NULL;

+    }

+    if (mn != NULL)

+    {

+      if (mn->node_type == MIB_NODE_EX)

+      {

+        /* external object */

+        struct mib_external_node *en = (struct mib_external_node*)mn;

+

+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;

+        /* save en && args in msg_ps!! */

+        msg_ps->ext_mib_node = en;

+        msg_ps->ext_oid = oid;

+

+        en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);

+      }

+      else

+      {

+        /* internal object */

+        struct obj_def object_def;

+        struct snmp_varbind *vb;

+

+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;

+        mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);

+

+        vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);

+        if (vb != NULL)

+        {

+          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;

+          mn->get_value(&object_def, object_def.v_len, vb->value);

+          snmp_varbind_tail_add(&msg_ps->outvb, vb);

+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+          msg_ps->vb_idx += 1;

+        }

+        else

+        {

+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));

+          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+        }

+      }

+    }

+    if (mn == NULL)

+    {

+      /* mn == NULL, noSuchName */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+      (msg_ps->vb_idx == msg_ps->invb.count))

+  {

+    snmp_ok_response(msg_ps);

+  }

+}

+

+/**

+ * Service an internal or external event for SNMP SET.

+ *

+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)

+ * @param msg_ps points to the assosicated message process state

+ */

+static void

+snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)

+{

+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));

+

+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)

+  {

+    struct mib_external_node *en;

+    struct snmp_name_ptr np;

+

+    /* get_object_def() answer*/

+    en = msg_ps->ext_mib_node;

+    np = msg_ps->ext_name_ptr;

+

+    /* translate answer into a known lifeform */

+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);

+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)

+    {

+      msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;

+      en->set_test_q(request_id, &msg_ps->ext_object_def);

+    }

+    else

+    {

+      en->get_object_def_pc(request_id, np.ident_len, np.ident);

+      /* search failed, object id points to unknown object (nosuchname) */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)

+  {

+    struct mib_external_node *en;

+    struct snmp_name_ptr np;

+

+    /* set_test() answer*/

+    en = msg_ps->ext_mib_node;

+    np = msg_ps->ext_name_ptr;

+

+    if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)

+    {

+       if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&

+           (en->set_test_a(request_id,&msg_ps->ext_object_def,

+                           msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))

+      {

+        msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+        msg_ps->vb_idx += 1;

+      }

+      else

+      {

+        en->set_test_pc(request_id,&msg_ps->ext_object_def);

+        /* bad value */

+        snmp_error_response(msg_ps,SNMP_ES_BADVALUE);

+      }

+    }

+    else

+    {

+      en->set_test_pc(request_id,&msg_ps->ext_object_def);

+      /* object not available for set */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)

+  {

+    struct mib_external_node *en;

+    struct snmp_name_ptr np;

+

+    /* get_object_def() answer*/

+    en = msg_ps->ext_mib_node;

+    np = msg_ps->ext_name_ptr;

+

+    /* translate answer into a known lifeform */

+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);

+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)

+    {

+      msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;

+      en->set_value_q(request_id, &msg_ps->ext_object_def,

+                      msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);

+    }

+    else

+    {

+      en->get_object_def_pc(request_id, np.ident_len, np.ident);

+      /* set_value failed, object has disappeared for some odd reason?? */

+      snmp_error_response(msg_ps,SNMP_ES_GENERROR);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)

+  {

+    struct mib_external_node *en;

+

+    /** set_value_a() @todo: use reply value?? */

+    en = msg_ps->ext_mib_node;

+    en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);

+

+    /** @todo use set_value_pc() if toobig */

+    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;

+    msg_ps->vb_idx += 1;

+  }

+

+  /* test all values before setting */

+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+         (msg_ps->vb_idx < msg_ps->invb.count))

+  {

+    struct mib_node *mn;

+    struct snmp_name_ptr np;

+

+    if (msg_ps->vb_idx == 0)

+    {

+      msg_ps->vb_ptr = msg_ps->invb.head;

+    }

+    else

+    {

+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;

+    }

+    /** test object identifier for .iso.org.dod.internet prefix */

+    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))

+    {

+      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,

+                             msg_ps->vb_ptr->ident + 4, &np);

+    }

+    else

+    {

+      mn = NULL;

+    }

+    if (mn != NULL)

+    {

+      if (mn->node_type == MIB_NODE_EX)

+      {

+        /* external object */

+        struct mib_external_node *en = (struct mib_external_node*)mn;

+

+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;

+        /* save en && args in msg_ps!! */

+        msg_ps->ext_mib_node = en;

+        msg_ps->ext_name_ptr = np;

+

+        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);

+      }

+      else

+      {

+        /* internal object */

+        struct obj_def object_def;

+

+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;

+        mn->get_object_def(np.ident_len, np.ident, &object_def);

+        if (object_def.instance != MIB_OBJECT_NONE)

+        {

+          mn = mn;

+        }

+        else

+        {

+          /* search failed, object id points to unknown object (nosuchname) */

+          mn = NULL;

+        }

+        if (mn != NULL)

+        {

+          msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;

+

+          if (object_def.access == MIB_OBJECT_READ_WRITE)

+          {

+            if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&

+                (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))

+            {

+              msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+              msg_ps->vb_idx += 1;

+            }

+            else

+            {

+              /* bad value */

+              snmp_error_response(msg_ps,SNMP_ES_BADVALUE);

+            }

+          }

+          else

+          {

+            /* object not available for set */

+            snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+          }

+        }

+      }

+    }

+    if (mn == NULL)

+    {

+      /* mn == NULL, noSuchName */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+

+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+      (msg_ps->vb_idx == msg_ps->invb.count))

+  {

+    msg_ps->vb_idx = 0;

+    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;

+  }

+

+  /* set all values "atomically" (be as "atomic" as possible) */

+  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&

+         (msg_ps->vb_idx < msg_ps->invb.count))

+  {

+    struct mib_node *mn;

+    struct snmp_name_ptr np;

+

+    if (msg_ps->vb_idx == 0)

+    {

+      msg_ps->vb_ptr = msg_ps->invb.head;

+    }

+    else

+    {

+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;

+    }

+    /* skip iso prefix test, was done previously while settesting() */

+    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,

+                           msg_ps->vb_ptr->ident + 4, &np);

+    /* check if object is still available

+       (e.g. external hot-plug thingy present?) */

+    if (mn != NULL)

+    {

+      if (mn->node_type == MIB_NODE_EX)

+      {

+        /* external object */

+        struct mib_external_node *en = (struct mib_external_node*)mn;

+

+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;

+        /* save en && args in msg_ps!! */

+        msg_ps->ext_mib_node = en;

+        msg_ps->ext_name_ptr = np;

+

+        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);

+      }

+      else

+      {

+        /* internal object */

+        struct obj_def object_def;

+

+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;

+        mn->get_object_def(np.ident_len, np.ident, &object_def);

+        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;

+        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);

+        msg_ps->vb_idx += 1;

+      }

+    }

+  }

+  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&

+      (msg_ps->vb_idx == msg_ps->invb.count))

+  {

+    /* simply echo the input if we can set it

+       @todo do we need to return the actual value?

+       e.g. if value is silently modified or behaves sticky? */

+    msg_ps->outvb = msg_ps->invb;

+    msg_ps->invb.head = NULL;

+    msg_ps->invb.tail = NULL;

+    msg_ps->invb.count = 0;

+    snmp_ok_response(msg_ps);

+  }

+}

+

+

+/**

+ * Handle one internal or external event.

+ * Called for one async event. (recv external/private answer)

+ *

+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)

+ */

+void

+snmp_msg_event(u8_t request_id)

+{

+  struct snmp_msg_pstat *msg_ps;

+

+  if (request_id < SNMP_CONCURRENT_REQUESTS)

+  {

+    msg_ps = &msg_input_list[request_id];

+    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)

+    {

+      snmp_msg_getnext_event(request_id, msg_ps);

+    }

+    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)

+    {

+      snmp_msg_get_event(request_id, msg_ps);

+    }

+    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)

+    {

+      snmp_msg_set_event(request_id, msg_ps);

+    }

+  }

+}

+

+

+/* lwIP UDP receive callback function */

+static void

+snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)

+{

+  struct udp_hdr *udphdr;

+

+  /* suppress unused argument warning */

+  if (arg);

+  /* peek in the UDP header (goto IP payload) */

+  pbuf_header(p, UDP_HLEN);

+  udphdr = p->payload;

+

+  /* check if datagram is really directed at us (including broadcast requests) */

+  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == 161))

+  {

+    struct snmp_msg_pstat *msg_ps;

+    u8_t req_idx;

+

+    /* traverse input message process list, look for SNMP_MSG_EMPTY */

+    msg_ps = &msg_input_list[0];

+    req_idx = 0;

+    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))

+    {

+      req_idx++;

+      msg_ps++;

+    }

+    if (req_idx != SNMP_CONCURRENT_REQUESTS)

+    {

+      err_t err_ret;

+      u16_t payload_len;

+      u16_t payload_ofs;

+      u16_t varbind_ofs = 0;

+

+      /* accepting request */

+      snmp_inc_snmpinpkts();

+      /* record used 'protocol control block' */

+      msg_ps->pcb = pcb;

+      /* source address (network order) */

+      msg_ps->sip = *addr;

+      /* source port (host order (lwIP oddity)) */

+      msg_ps->sp = port;

+      /* read UDP payload length from UDP header */

+      payload_len = ntohs(udphdr->len) - UDP_HLEN;

+

+      /* adjust to UDP payload */

+      payload_ofs = UDP_HLEN;

+

+      /* check total length, version, community, pdu type */

+      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);

+      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||

+           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||

+           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&

+          ((msg_ps->error_status == SNMP_ES_NOERROR) &&

+           (msg_ps->error_index == 0)) )

+      {

+        /* Only accept requests and requests without error (be robust) */

+        err_ret = err_ret;

+      }

+      else

+      {

+        /* Reject response and trap headers or error requests as input! */

+        err_ret = ERR_ARG;

+      }

+      if (err_ret == ERR_OK)

+      {

+        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));

+

+        /* Builds a list of variable bindings. Copy the varbinds from the pbuf

+          chain to glue them when these are divided over two or more pbuf's. */

+        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);

+        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))

+        {

+          /* we've decoded the incoming message, release input msg now */

+          pbuf_free(p);

+

+          msg_ps->error_status = SNMP_ES_NOERROR;

+          msg_ps->error_index = 0;

+          /* find object for each variable binding */

+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+          /* first variable binding from list to inspect */

+          msg_ps->vb_idx = 0;

+

+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));

+

+          /* handle input event and as much objects as possible in one go */

+          snmp_msg_event(req_idx);

+        }

+        else

+        {

+          /* varbind-list decode failed, or varbind list empty.

+             drop request silently, do not return error!

+             (errors are only returned for a specific varbind failure) */

+          pbuf_free(p);

+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));

+        }

+      }

+      else

+      {

+        /* header check failed

+           drop request silently, do not return error! */

+        pbuf_free(p);

+        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));

+      }

+    }

+    else

+    {

+      /* exceeding number of concurrent requests */

+      pbuf_free(p);

+    }

+  }

+  else

+  {

+    /* datagram not for us */

+    pbuf_free(p);

+  }

+}

+

+/**

+ * Checks and decodes incoming SNMP message header, logs header errors.

+ *

+ * @param p points to pbuf chain of SNMP message (UDP payload)

+ * @param ofs points to first octet of SNMP message

+ * @param pdu_len the length of the UDP payload

+ * @param ofs_ret returns the ofset of the variable bindings

+ * @param m_stat points to the current message request state return

+ * @return

+ * - ERR_OK SNMP header is sane and accepted

+ * - ERR_ARG SNMP header is either malformed or rejected

+ */

+static err_t

+snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)

+{

+  err_t derr;

+  u16_t len, ofs_base;

+  u8_t  len_octets;

+  u8_t  type;

+  s32_t version;

+

+  ofs_base = ofs;

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) ||

+      (pdu_len != (1 + len_octets + len)) ||

+      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))

+  {

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))

+  {

+    /* can't decode or no integer (version) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);

+  if (derr != ERR_OK)

+  {

+    /* can't decode */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  if (version != 0)

+  {

+    /* not version 1 */

+    snmp_inc_snmpinbadversions();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets + len);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))

+  {

+    /* can't decode or no octet string (community) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);

+  if (derr != ERR_OK)

+  {

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  /* add zero terminator */

+  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));

+  m_stat->community[len] = 0;

+  m_stat->com_strlen = len;

+  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)

+  {

+    /** @todo: move this if we need to check more names */

+    snmp_inc_snmpinbadcommunitynames();

+    snmp_authfail_trap();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets + len);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if (derr != ERR_OK)

+  {

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  switch(type)

+  {

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):

+      /* GetRequest PDU */

+      snmp_inc_snmpingetrequests();

+      derr = ERR_OK;

+      break;

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):

+      /* GetNextRequest PDU */

+      snmp_inc_snmpingetnexts();

+      derr = ERR_OK;

+      break;

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):

+      /* GetResponse PDU */

+      snmp_inc_snmpingetresponses();

+      derr = ERR_ARG;

+      break;

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):

+      /* SetRequest PDU */

+      snmp_inc_snmpinsetrequests();

+      derr = ERR_OK;

+      break;

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):

+      /* Trap PDU */

+      snmp_inc_snmpintraps();

+      derr = ERR_ARG;

+      break;

+    default:

+      snmp_inc_snmpinasnparseerrs();

+      derr = ERR_ARG;

+      break;

+  }

+  if (derr != ERR_OK)

+  {

+    /* unsupported input PDU for this agent (no parse error) */

+    return ERR_ARG;

+  }

+  m_stat->rt = type & 0x1F;

+  ofs += (1 + len_octets);

+  if (len != (pdu_len - (ofs - ofs_base)))

+  {

+    /* decoded PDU length does not equal actual payload length */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))

+  {

+    /* can't decode or no integer (request ID) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);

+  if (derr != ERR_OK)

+  {

+    /* can't decode */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets + len);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))

+  {

+    /* can't decode or no integer (error-status) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  /* must be noError (0) for incoming requests.

+     log errors for mib-2 completeness and for debug purposes */

+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);

+  if (derr != ERR_OK)

+  {

+    /* can't decode */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  switch (m_stat->error_status)

+  {

+    case SNMP_ES_TOOBIG:

+      snmp_inc_snmpintoobigs();

+      break;

+    case SNMP_ES_NOSUCHNAME:

+      snmp_inc_snmpinnosuchnames();

+      break;

+    case SNMP_ES_BADVALUE:

+      snmp_inc_snmpinbadvalues();

+      break;

+    case SNMP_ES_READONLY:

+      snmp_inc_snmpinreadonlys();

+      break;

+    case SNMP_ES_GENERROR:

+      snmp_inc_snmpingenerrs();

+      break;

+  }

+  ofs += (1 + len_octets + len);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))

+  {

+    /* can't decode or no integer (error-index) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  /* must be 0 for incoming requests.

+     decode anyway to catch bad integers (and dirty tricks) */

+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);

+  if (derr != ERR_OK)

+  {

+    /* can't decode */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets + len);

+  *ofs_ret = ofs;

+  return ERR_OK;

+}

+

+static err_t

+snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)

+{

+  err_t derr;

+  u16_t len, vb_len;

+  u8_t  len_octets;

+  u8_t type;

+

+  /* variable binding list */

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);

+  if ((derr != ERR_OK) ||

+      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))

+  {

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets);

+

+  /* start with empty list */

+  m_stat->invb.count = 0;

+  m_stat->invb.head = NULL;

+  m_stat->invb.tail = NULL;

+

+  while (vb_len > 0)

+  {

+    struct snmp_obj_id oid, oid_value;

+    struct snmp_varbind *vb;

+

+    snmp_asn1_dec_type(p, ofs, &type);

+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+    if ((derr != ERR_OK) ||

+        (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||

+        (len <= 0) || (len > vb_len))

+    {

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+    ofs += (1 + len_octets);

+    vb_len -= (1 + len_octets);

+

+    snmp_asn1_dec_type(p, ofs, &type);

+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+    if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))

+    {

+      /* can't decode object name length */

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+    derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);

+    if (derr != ERR_OK)

+    {

+      /* can't decode object name */

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+    ofs += (1 + len_octets + len);

+    vb_len -= (1 + len_octets + len);

+

+    snmp_asn1_dec_type(p, ofs, &type);

+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+    if (derr != ERR_OK)

+    {

+      /* can't decode object value length */

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+

+    switch (type)

+    {

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):

+        vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));

+        if (vb != NULL)

+        {

+          s32_t *vptr = vb->value;

+

+          derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);

+          snmp_varbind_tail_add(&m_stat->invb, vb);

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):

+        vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));

+        if (vb != NULL)

+        {

+          u32_t *vptr = vb->value;

+

+          derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);

+          snmp_varbind_tail_add(&m_stat->invb, vb);

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):

+        vb = snmp_varbind_alloc(&oid, type, len);

+        if (vb != NULL)

+        {

+          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);

+          snmp_varbind_tail_add(&m_stat->invb, vb);

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):

+        vb = snmp_varbind_alloc(&oid, type, 0);

+        if (vb != NULL)

+        {

+          snmp_varbind_tail_add(&m_stat->invb, vb);

+          derr = ERR_OK;

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):

+        derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);

+        if (derr == ERR_OK)

+        {

+          vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));

+          if (vb != NULL)

+          {

+            u8_t i = oid_value.len;

+            s32_t *vptr = vb->value;

+

+            while(i > 0)

+            {

+              i--;

+              vptr[i] = oid_value.id[i];

+            }

+            snmp_varbind_tail_add(&m_stat->invb, vb);

+            derr = ERR_OK;

+          }

+          else

+          {

+            derr = ERR_ARG;

+          }

+        }

+        break;

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):

+        if (len == 4)

+        {

+          /* must be exactly 4 octets! */

+          vb = snmp_varbind_alloc(&oid, type, 4);

+          if (vb != NULL)

+          {

+            derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);

+            snmp_varbind_tail_add(&m_stat->invb, vb);

+          }

+          else

+          {

+            derr = ERR_ARG;

+          }

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      default:

+        derr = ERR_ARG;

+        break;

+    }

+    if (derr != ERR_OK)

+    {

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+    ofs += (1 + len_octets + len);

+    vb_len -= (1 + len_octets + len);

+  }

+

+  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)

+  {

+    snmp_add_snmpintotalsetvars(m_stat->invb.count);

+  }

+  else

+  {

+    snmp_add_snmpintotalreqvars(m_stat->invb.count);

+  }

+

+  *ofs_ret = ofs;

+  return ERR_OK;

+}

+

+struct snmp_varbind*

+snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)

+{

+  struct snmp_varbind *vb;

+

+  vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));

+  LWIP_ASSERT("vb != NULL",vb != NULL);

+  if (vb != NULL)

+  {

+    u8_t i;

+

+    vb->next = NULL;

+    vb->prev = NULL;

+    i = oid->len;

+    vb->ident_len = i;

+    if (i > 0)

+    {

+      /* allocate array of s32_t for our object identifier */

+      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);

+      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);

+      if (vb->ident == NULL)

+      {

+        mem_free(vb);

+        return NULL;

+      }

+      while(i > 0)

+      {

+        i--;

+        vb->ident[i] = oid->id[i];

+      }

+    }

+    else

+    {

+      /* i == 0, pass zero length object identifier */

+      vb->ident = NULL;

+    }

+    vb->value_type = type;

+    vb->value_len = len;

+    if (len > 0)

+    {

+      /* allocate raw bytes for our object value */

+      vb->value = mem_malloc(len);

+      LWIP_ASSERT("vb->value != NULL",vb->value != NULL);

+      if (vb->value == NULL)

+      {

+        if (vb->ident != NULL)

+        {

+          mem_free(vb->ident);

+        }

+        mem_free(vb);

+        return NULL;

+      }

+    }

+    else

+    {

+      /* ASN1_NUL type, or zero length ASN1_OC_STR */

+      vb->value = NULL;

+    }

+  }

+  return vb;

+}

+

+void

+snmp_varbind_free(struct snmp_varbind *vb)

+{

+  if (vb->value != NULL )

+  {

+    mem_free(vb->value);

+  }

+  if (vb->ident != NULL )

+  {

+    mem_free(vb->ident);

+  }

+  mem_free(vb);

+}

+

+void

+snmp_varbind_list_free(struct snmp_varbind_root *root)

+{

+  struct snmp_varbind *vb, *prev;

+

+  vb = root->tail;

+  while ( vb != NULL )

+  {

+    prev = vb->prev;

+    snmp_varbind_free(vb);

+    vb = prev;

+  }

+  root->count = 0;

+  root->head = NULL;

+  root->tail = NULL;

+}

+

+void

+snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)

+{

+  if (root->count == 0)

+  {

+    /* add first varbind to list */

+    root->head = vb;

+    root->tail = vb;

+  }

+  else

+  {

+    /* add nth varbind to list tail */

+    root->tail->next = vb;

+    vb->prev = root->tail;

+    root->tail = vb;

+  }

+  root->count += 1;

+}

+

+struct snmp_varbind*

+snmp_varbind_tail_remove(struct snmp_varbind_root *root)

+{

+  struct snmp_varbind* vb;

+

+  if (root->count > 0)

+  {

+    /* remove tail varbind */

+    vb = root->tail;

+    root->tail = vb->prev;

+    vb->prev->next = NULL;

+    root->count -= 1;

+  }

+  else

+  {

+    /* nothing to remove */

+    vb = NULL;

+  }

+  return vb;

+}

+

+#endif /* LWIP_SNMP */

diff --git a/Demo/Common/ethernet/lwIP/core/snmp/msg_out.c b/Demo/Common/ethernet/lwIP/core/snmp/msg_out.c
index c8961c9..0da70de 100644
--- a/Demo/Common/ethernet/lwIP/core/snmp/msg_out.c
+++ b/Demo/Common/ethernet/lwIP/core/snmp/msg_out.c
@@ -1,687 +1,687 @@
-/**
- * @file
- * SNMP output message processing (RFC1157).
- *
- * Output responses and traps are build in two passes:
- *
- * Pass 0: iterate over the output message backwards to determine encoding lengths
- * Pass 1: the actual forward encoding of internal form into ASN1
- *
- * The single-pass encoding method described by Comer & Stevens
- * requires extra buffer space and copying for reversal of the packet.
- * The buffer requirement can be prohibitively large for big payloads
- * (>= 484) therefore we use the two encoding passes.
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * 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: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_SNMP
-#include "arch/cc.h"
-#include "lwip/udp.h"
-#include "lwip/netif.h"
-
-#include "lwip/snmp.h"
-#include "lwip/snmp_asn1.h"
-#include "lwip/snmp_msg.h"
-
-struct snmp_trap_dst
-{
-  /* destination IP address in network order */
-  struct ip_addr dip;
-  /* set to 0 when disabled, >0 when enabled */
-  u8_t enable;
-};
-#if (SNMP_TRAP_DESTINATIONS == 0)
-#error "need at least one trap destination"
-#endif
-struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
-
-/** TRAP message structure */
-struct snmp_msg_trap trap_msg;
-
-static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);
-static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);
-static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);
-
-static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);
-static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);
-static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);
-
-/**
- * Sets enable switch for this trap destination.
- * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
- * @param enable switch if 0 destination is disabled >0 enabled.
- */
-void
-snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
-{
-  if (dst_idx < SNMP_TRAP_DESTINATIONS)
-  {
-    trap_dst[dst_idx].enable = enable;
-  }
-}
-
-/**
- * Sets IPv4 address for this trap destination.
- * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
- * @param dst IPv4 address in host order.
- */
-void
-snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst)
-{
-  if (dst_idx < SNMP_TRAP_DESTINATIONS)
-  {
-    trap_dst[dst_idx].dip.addr = htonl(dst->addr);
-  }
-}
-
-/**
- * Sends a 'getresponse' message to the request originator.
- *
- * @param m_stat points to the current message request state source
- * @return ERR_OK when success, ERR_MEM if we're out of memory
- *
- * @note the caller is responsible for filling in outvb in the m_stat
- * and provide error-status and index (except for tooBig errors) ...
- */
-err_t
-snmp_send_response(struct snmp_msg_pstat *m_stat)
-{
-  struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};
-  struct pbuf *p;
-  u16_t tot_len;
-  err_t err;
-
-  /* pass 0, calculate length fields */
-  tot_len = snmp_varbind_list_sum(&m_stat->outvb);
-  tot_len = snmp_resp_header_sum(m_stat, tot_len);
-
-  /* try allocating pbuf(s) for complete response */
-  p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
-  if (p == NULL)
-  {
-    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));
-
-    /* can't construct reply, return error-status tooBig */
-    m_stat->error_status = SNMP_ES_TOOBIG;
-    m_stat->error_index = 0;
-    /* pass 0, recalculate lengths, for empty varbind-list */
-    tot_len = snmp_varbind_list_sum(&emptyvb);
-    tot_len = snmp_resp_header_sum(m_stat, tot_len);
-    /* retry allocation once for header and empty varbind-list */
-    p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
-  }
-  if (p != NULL)
-  {
-    /* first pbuf alloc try or retry alloc success */
-    u16_t ofs;
-
-    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));
-
-    /* pass 1, size error, encode packet ino the pbuf(s) */
-    ofs = snmp_resp_header_enc(m_stat, p);
-    if (m_stat->error_status == SNMP_ES_TOOBIG)
-    {
-      snmp_varbind_list_enc(&emptyvb, p, ofs);
-    }
-    else
-    {
-      snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
-    }
-
-    switch (m_stat->error_status)
-    {
-      case SNMP_ES_TOOBIG:
-        snmp_inc_snmpouttoobigs();
-        break;
-      case SNMP_ES_NOSUCHNAME:
-        snmp_inc_snmpoutnosuchnames();
-        break;
-      case SNMP_ES_BADVALUE:
-        snmp_inc_snmpoutbadvalues();
-        break;
-      case SNMP_ES_GENERROR:
-        snmp_inc_snmpoutgenerrs();
-        break;
-    }
-    snmp_inc_snmpoutgetresponses();
-    snmp_inc_snmpoutpkts();
-
-    /** @todo do we need separate rx and tx pcbs for threaded case? */
-    /** connect to the originating source */
-    udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);
-    err = udp_send(m_stat->pcb, p);
-    if (err == ERR_MEM)
-    {
-      /** @todo release some memory, retry and return tooBig? tooMuchHassle? */
-      err = ERR_MEM;
-    }
-    else
-    {
-      err = ERR_OK;
-    }
-    /** disassociate remote address and port with this pcb */
-    udp_disconnect(m_stat->pcb);
-
-    pbuf_free(p);
-    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));
-    return err;
-  }
-  else
-  {
-    /* first pbuf alloc try or retry alloc failed
-       very low on memory, couldn't return tooBig */
-    return ERR_MEM;
-  }
-}
-
-
-/**
- * Sends an generic or enterprise specific trap message.
- *
- * @param generic_trap is the trap code
- * @param eoid points to enterprise object identifier
- * @param specific_trap used for enterprise traps when generic_trap == 6
- * @return ERR_OK when success, ERR_MEM if we're out of memory
- *
- * @note the caller is responsible for filling in outvb in the trap_msg
- * @note the use of the enterpise identifier field
- * is per RFC1215.
- * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
- * and .iso.org.dod.internet.private.enterprises.yourenterprise
- * (sysObjectID) for specific traps.
- */
-err_t
-snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
-{
-  struct snmp_trap_dst *td;
-  struct netif *dst_if;
-  struct ip_addr dst_ip;
-  struct pbuf *p;
-  u16_t i,tot_len;
-
-  for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
-  {
-    if ((td->enable != 0) && (td->dip.addr != 0))
-    {
-      /* network order trap destination */
-      trap_msg.dip.addr = td->dip.addr;
-      /* lookup current source address for this dst */
-      dst_if = ip_route(&td->dip);
-      dst_ip.addr = ntohl(dst_if->ip_addr.addr);
-      trap_msg.sip_raw[0] = dst_ip.addr >> 24;
-      trap_msg.sip_raw[1] = dst_ip.addr >> 16;
-      trap_msg.sip_raw[2] = dst_ip.addr >> 8;
-      trap_msg.sip_raw[3] = dst_ip.addr;
-      trap_msg.gen_trap = generic_trap;
-      trap_msg.spc_trap = specific_trap;
-      if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
-      {
-        /* enterprise-Specific trap */
-        trap_msg.enterprise = eoid;
-      }
-      else
-      {
-        /* generic (MIB-II) trap */
-        snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
-      }
-      snmp_get_sysuptime(&trap_msg.ts);
-
-      /* pass 0, calculate length fields */
-      tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
-      tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
-
-      /* allocate pbuf(s) */
-      p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
-      if (p != NULL)
-      {
-        u16_t ofs;
-
-        /* pass 1, encode packet ino the pbuf(s) */
-        ofs = snmp_trap_header_enc(&trap_msg, p);
-        snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
-
-        snmp_inc_snmpouttraps();
-        snmp_inc_snmpoutpkts();
-
-        /** connect to the TRAP destination */
-        udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);
-        udp_send(trap_msg.pcb, p);
-        /** disassociate remote address and port with this pcb */
-        udp_disconnect(trap_msg.pcb);
-
-        pbuf_free(p);
-      }
-      else
-      {
-        return ERR_MEM;
-      }
-    }
-  }
-  return ERR_OK;
-}
-
-void
-snmp_coldstart_trap(void)
-{
-  trap_msg.outvb.head = NULL;
-  trap_msg.outvb.tail = NULL;
-  trap_msg.outvb.count = 0;
-  snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);
-}
-
-void
-snmp_authfail_trap(void)
-{
-  u8_t enable;
-  snmp_get_snmpenableauthentraps(&enable);
-  if (enable == 1)
-  {
-    trap_msg.outvb.head = NULL;
-    trap_msg.outvb.tail = NULL;
-    trap_msg.outvb.count = 0;
-    snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);
-  }
-}
-
-/**
- * Sums response header field lengths from tail to head and
- * returns resp_header_lengths for second encoding pass.
- *
- * @param vb_len varbind-list length
- * @param rhl points to returned header lengths
- * @return the required lenght for encoding the response header
- */
-static u16_t
-snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)
-{
-  u16_t tot_len;
-  struct snmp_resp_header_lengths *rhl;
-
-  rhl = &m_stat->rhl;
-  tot_len = vb_len;
-  snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);
-  snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);
-  tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;
-
-  snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);
-  snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);
-  tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;
-
-  snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);
-  snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);
-  tot_len += 1 + rhl->ridlenlen + rhl->ridlen;
-
-  rhl->pdulen = tot_len;
-  snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);
-  tot_len += 1 + rhl->pdulenlen;
-
-  rhl->comlen = m_stat->com_strlen;
-  snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);
-  tot_len += 1 + rhl->comlenlen + rhl->comlen;
-
-  snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);
-  snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);
-  tot_len += 1 + rhl->verlen + rhl->verlenlen;
-
-  rhl->seqlen = tot_len;
-  snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);
-  tot_len += 1 + rhl->seqlenlen;
-
-  return tot_len;
-}
-
-/**
- * Sums trap header field lengths from tail to head and
- * returns trap_header_lengths for second encoding pass.
- *
- * @param vb_len varbind-list length
- * @param thl points to returned header lengths
- * @return the required lenght for encoding the trap header
- */
-static u16_t
-snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)
-{
-  u16_t tot_len;
-  struct snmp_trap_header_lengths *thl;
-
-  thl = &m_trap->thl;
-  tot_len = vb_len;
-
-  snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);
-  snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);
-  tot_len += 1 + thl->tslen + thl->tslenlen;
-
-  snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);
-  snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);
-  tot_len += 1 + thl->strplen + thl->strplenlen;
-
-  snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);
-  snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);
-  tot_len += 1 + thl->gtrplen + thl->gtrplenlen;
-
-  thl->aaddrlen = 4;
-  snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);
-  tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;
-
-  snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);
-  snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);
-  tot_len += 1 + thl->eidlen + thl->eidlenlen;
-
-  thl->pdulen = tot_len;
-  snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);
-  tot_len += 1 + thl->pdulenlen;
-
-  thl->comlen = sizeof(snmp_publiccommunity) - 1;
-  snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);
-  tot_len += 1 + thl->comlenlen + thl->comlen;
-
-  snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);
-  snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);
-  tot_len += 1 + thl->verlen + thl->verlenlen;
-
-  thl->seqlen = tot_len;
-  snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);
-  tot_len += 1 + thl->seqlenlen;
-
-  return tot_len;
-}
-
-/**
- * Sums varbind lengths from tail to head and
- * annotates lengths in varbind for second encoding pass.
- *
- * @param root points to the root of the variable binding list
- * @return the required lenght for encoding the variable bindings
- */
-static u16_t
-snmp_varbind_list_sum(struct snmp_varbind_root *root)
-{
-  struct snmp_varbind *vb;
-  u32_t *uint_ptr;
-  s32_t *sint_ptr;
-  u16_t tot_len;
-
-  tot_len = 0;
-  vb = root->tail;
-  while ( vb != NULL )
-  {
-    /* encoded value lenght depends on type */
-    switch (vb->value_type)
-    {
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
-        sint_ptr = vb->value;
-        snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);
-        break;
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
-        uint_ptr = vb->value;
-        snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);
-        break;
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
-        vb->vlen = vb->value_len;
-        break;
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
-        sint_ptr = vb->value;
-        snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);
-        break;
-      default:
-        /* unsupported type */
-        vb->vlen = 0;
-        break;
-    };
-    /* encoding length of value length field */
-    snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);
-    snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);
-    snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);
-
-    vb->seqlen = 1 + vb->vlenlen + vb->vlen;
-    vb->seqlen += 1 + vb->olenlen + vb->olen;
-    snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);
-
-    /* varbind seq */
-    tot_len += 1 + vb->seqlenlen + vb->seqlen;
-
-    vb = vb->prev;
-  }
-
-  /* varbind-list seq */
-  root->seqlen = tot_len;
-  snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);
-  tot_len += 1 + root->seqlenlen;
-
-  return tot_len;
-}
-
-/**
- * Encodes response header from head to tail.
- */
-static u16_t
-snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)
-{
-  u16_t ofs;
-
-  ofs = 0;
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);
-  ofs += m_stat->rhl.seqlenlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);
-  ofs += m_stat->rhl.verlenlen;
-  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);
-  ofs += m_stat->rhl.verlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);
-  ofs += m_stat->rhl.comlenlen;
-  snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);
-  ofs += m_stat->rhl.comlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);
-  ofs += m_stat->rhl.pdulenlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);
-  ofs += m_stat->rhl.ridlenlen;
-  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);
-  ofs += m_stat->rhl.ridlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);
-  ofs += m_stat->rhl.errstatlenlen;
-  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);
-  ofs += m_stat->rhl.errstatlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);
-  ofs += m_stat->rhl.erridxlenlen;
-  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);
-  ofs += m_stat->rhl.erridxlen;
-
-  return ofs;
-}
-
-/**
- * Encodes trap header from head to tail.
- */
-static u16_t
-snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)
-{
-  u16_t ofs;
-
-  ofs = 0;
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);
-  ofs += m_trap->thl.seqlenlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);
-  ofs += m_trap->thl.verlenlen;
-  snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);
-  ofs += m_trap->thl.verlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);
-  ofs += m_trap->thl.comlenlen;
-  snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);
-  ofs += m_trap->thl.comlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);
-  ofs += m_trap->thl.pdulenlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);
-  ofs += m_trap->thl.eidlenlen;
-  snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);
-  ofs += m_trap->thl.eidlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);
-  ofs += m_trap->thl.aaddrlenlen;
-  snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);
-  ofs += m_trap->thl.aaddrlen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);
-  ofs += m_trap->thl.gtrplenlen;
-  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);
-  ofs += m_trap->thl.gtrplen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);
-  ofs += m_trap->thl.strplenlen;
-  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);
-  ofs += m_trap->thl.strplen;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);
-  ofs += m_trap->thl.tslenlen;
-  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);
-  ofs += m_trap->thl.tslen;
-
-  return ofs;
-}
-
-/**
- * Encodes varbind list from head to tail.
- */
-static u16_t
-snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)
-{
-  struct snmp_varbind *vb;
-  s32_t *sint_ptr;
-  u32_t *uint_ptr;
-  u8_t *raw_ptr;
-
-  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
-  ofs += 1;
-  snmp_asn1_enc_length(p, ofs, root->seqlen);
-  ofs += root->seqlenlen;
-
-  vb = root->head;
-  while ( vb != NULL )
-  {
-    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
-    ofs += 1;
-    snmp_asn1_enc_length(p, ofs, vb->seqlen);
-    ofs += vb->seqlenlen;
-
-    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
-    ofs += 1;
-    snmp_asn1_enc_length(p, ofs, vb->olen);
-    ofs += vb->olenlen;
-    snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);
-    ofs += vb->olen;
-
-    snmp_asn1_enc_type(p, ofs, vb->value_type);
-    ofs += 1;
-    snmp_asn1_enc_length(p, ofs, vb->vlen);
-    ofs += vb->vlenlen;
-
-    switch (vb->value_type)
-    {
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
-        sint_ptr = vb->value;
-        snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);
-        break;
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
-        uint_ptr = vb->value;
-        snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);
-        break;
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
-      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
-        raw_ptr = vb->value;
-        snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);
-        break;
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
-        break;
-      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
-        sint_ptr = vb->value;
-        snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);
-        break;
-      default:
-        /* unsupported type */
-        break;
-    };
-    ofs += vb->vlen;
-    vb = vb->next;
-  }
-  return ofs;
-}
-
-#endif /* LWIP_SNMP */
+/**

+ * @file

+ * SNMP output message processing (RFC1157).

+ *

+ * Output responses and traps are build in two passes:

+ *

+ * Pass 0: iterate over the output message backwards to determine encoding lengths

+ * Pass 1: the actual forward encoding of internal form into ASN1

+ *

+ * The single-pass encoding method described by Comer & Stevens

+ * requires extra buffer space and copying for reversal of the packet.

+ * The buffer requirement can be prohibitively large for big payloads

+ * (>= 484) therefore we use the two encoding passes.

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * 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: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP

+#include "arch/cc.h"

+#include "lwip/udp.h"

+#include "lwip/netif.h"

+

+#include "lwip/snmp.h"

+#include "lwip/snmp_asn1.h"

+#include "lwip/snmp_msg.h"

+

+struct snmp_trap_dst

+{

+  /* destination IP address in network order */

+  struct ip_addr dip;

+  /* set to 0 when disabled, >0 when enabled */

+  u8_t enable;

+};

+#if (SNMP_TRAP_DESTINATIONS == 0)

+#error "need at least one trap destination"

+#endif

+struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];

+

+/** TRAP message structure */

+struct snmp_msg_trap trap_msg;

+

+static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);

+static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);

+static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);

+

+static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);

+static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);

+static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);

+

+/**

+ * Sets enable switch for this trap destination.

+ * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1

+ * @param enable switch if 0 destination is disabled >0 enabled.

+ */

+void

+snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)

+{

+  if (dst_idx < SNMP_TRAP_DESTINATIONS)

+  {

+    trap_dst[dst_idx].enable = enable;

+  }

+}

+

+/**

+ * Sets IPv4 address for this trap destination.

+ * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1

+ * @param dst IPv4 address in host order.

+ */

+void

+snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst)

+{

+  if (dst_idx < SNMP_TRAP_DESTINATIONS)

+  {

+    trap_dst[dst_idx].dip.addr = htonl(dst->addr);

+  }

+}

+

+/**

+ * Sends a 'getresponse' message to the request originator.

+ *

+ * @param m_stat points to the current message request state source

+ * @return ERR_OK when success, ERR_MEM if we're out of memory

+ *

+ * @note the caller is responsible for filling in outvb in the m_stat

+ * and provide error-status and index (except for tooBig errors) ...

+ */

+err_t

+snmp_send_response(struct snmp_msg_pstat *m_stat)

+{

+  struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};

+  struct pbuf *p;

+  u16_t tot_len;

+  err_t err;

+

+  /* pass 0, calculate length fields */

+  tot_len = snmp_varbind_list_sum(&m_stat->outvb);

+  tot_len = snmp_resp_header_sum(m_stat, tot_len);

+

+  /* try allocating pbuf(s) for complete response */

+  p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);

+  if (p == NULL)

+  {

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));

+

+    /* can't construct reply, return error-status tooBig */

+    m_stat->error_status = SNMP_ES_TOOBIG;

+    m_stat->error_index = 0;

+    /* pass 0, recalculate lengths, for empty varbind-list */

+    tot_len = snmp_varbind_list_sum(&emptyvb);

+    tot_len = snmp_resp_header_sum(m_stat, tot_len);

+    /* retry allocation once for header and empty varbind-list */

+    p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);

+  }

+  if (p != NULL)

+  {

+    /* first pbuf alloc try or retry alloc success */

+    u16_t ofs;

+

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));

+

+    /* pass 1, size error, encode packet ino the pbuf(s) */

+    ofs = snmp_resp_header_enc(m_stat, p);

+    if (m_stat->error_status == SNMP_ES_TOOBIG)

+    {

+      snmp_varbind_list_enc(&emptyvb, p, ofs);

+    }

+    else

+    {

+      snmp_varbind_list_enc(&m_stat->outvb, p, ofs);

+    }

+

+    switch (m_stat->error_status)

+    {

+      case SNMP_ES_TOOBIG:

+        snmp_inc_snmpouttoobigs();

+        break;

+      case SNMP_ES_NOSUCHNAME:

+        snmp_inc_snmpoutnosuchnames();

+        break;

+      case SNMP_ES_BADVALUE:

+        snmp_inc_snmpoutbadvalues();

+        break;

+      case SNMP_ES_GENERROR:

+        snmp_inc_snmpoutgenerrs();

+        break;

+    }

+    snmp_inc_snmpoutgetresponses();

+    snmp_inc_snmpoutpkts();

+

+    /** @todo do we need separate rx and tx pcbs for threaded case? */

+    /** connect to the originating source */

+    udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);

+    err = udp_send(m_stat->pcb, p);

+    if (err == ERR_MEM)

+    {

+      /** @todo release some memory, retry and return tooBig? tooMuchHassle? */

+      err = ERR_MEM;

+    }

+    else

+    {

+      err = ERR_OK;

+    }

+    /** disassociate remote address and port with this pcb */

+    udp_disconnect(m_stat->pcb);

+

+    pbuf_free(p);

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));

+    return err;

+  }

+  else

+  {

+    /* first pbuf alloc try or retry alloc failed

+       very low on memory, couldn't return tooBig */

+    return ERR_MEM;

+  }

+}

+

+

+/**

+ * Sends an generic or enterprise specific trap message.

+ *

+ * @param generic_trap is the trap code

+ * @param eoid points to enterprise object identifier

+ * @param specific_trap used for enterprise traps when generic_trap == 6

+ * @return ERR_OK when success, ERR_MEM if we're out of memory

+ *

+ * @note the caller is responsible for filling in outvb in the trap_msg

+ * @note the use of the enterpise identifier field

+ * is per RFC1215.

+ * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps

+ * and .iso.org.dod.internet.private.enterprises.yourenterprise

+ * (sysObjectID) for specific traps.

+ */

+err_t

+snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)

+{

+  struct snmp_trap_dst *td;

+  struct netif *dst_if;

+  struct ip_addr dst_ip;

+  struct pbuf *p;

+  u16_t i,tot_len;

+

+  for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)

+  {

+    if ((td->enable != 0) && (td->dip.addr != 0))

+    {

+      /* network order trap destination */

+      trap_msg.dip.addr = td->dip.addr;

+      /* lookup current source address for this dst */

+      dst_if = ip_route(&td->dip);

+      dst_ip.addr = ntohl(dst_if->ip_addr.addr);

+      trap_msg.sip_raw[0] = dst_ip.addr >> 24;

+      trap_msg.sip_raw[1] = dst_ip.addr >> 16;

+      trap_msg.sip_raw[2] = dst_ip.addr >> 8;

+      trap_msg.sip_raw[3] = dst_ip.addr;

+      trap_msg.gen_trap = generic_trap;

+      trap_msg.spc_trap = specific_trap;

+      if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)

+      {

+        /* enterprise-Specific trap */

+        trap_msg.enterprise = eoid;

+      }

+      else

+      {

+        /* generic (MIB-II) trap */

+        snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);

+      }

+      snmp_get_sysuptime(&trap_msg.ts);

+

+      /* pass 0, calculate length fields */

+      tot_len = snmp_varbind_list_sum(&trap_msg.outvb);

+      tot_len = snmp_trap_header_sum(&trap_msg, tot_len);

+

+      /* allocate pbuf(s) */

+      p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);

+      if (p != NULL)

+      {

+        u16_t ofs;

+

+        /* pass 1, encode packet ino the pbuf(s) */

+        ofs = snmp_trap_header_enc(&trap_msg, p);

+        snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);

+

+        snmp_inc_snmpouttraps();

+        snmp_inc_snmpoutpkts();

+

+        /** connect to the TRAP destination */

+        udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);

+        udp_send(trap_msg.pcb, p);

+        /** disassociate remote address and port with this pcb */

+        udp_disconnect(trap_msg.pcb);

+

+        pbuf_free(p);

+      }

+      else

+      {

+        return ERR_MEM;

+      }

+    }

+  }

+  return ERR_OK;

+}

+

+void

+snmp_coldstart_trap(void)

+{

+  trap_msg.outvb.head = NULL;

+  trap_msg.outvb.tail = NULL;

+  trap_msg.outvb.count = 0;

+  snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);

+}

+

+void

+snmp_authfail_trap(void)

+{

+  u8_t enable;

+  snmp_get_snmpenableauthentraps(&enable);

+  if (enable == 1)

+  {

+    trap_msg.outvb.head = NULL;

+    trap_msg.outvb.tail = NULL;

+    trap_msg.outvb.count = 0;

+    snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);

+  }

+}

+

+/**

+ * Sums response header field lengths from tail to head and

+ * returns resp_header_lengths for second encoding pass.

+ *

+ * @param vb_len varbind-list length

+ * @param rhl points to returned header lengths

+ * @return the required lenght for encoding the response header

+ */

+static u16_t

+snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)

+{

+  u16_t tot_len;

+  struct snmp_resp_header_lengths *rhl;

+

+  rhl = &m_stat->rhl;

+  tot_len = vb_len;

+  snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);

+  snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);

+  tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;

+

+  snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);

+  snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);

+  tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;

+

+  snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);

+  snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);

+  tot_len += 1 + rhl->ridlenlen + rhl->ridlen;

+

+  rhl->pdulen = tot_len;

+  snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);

+  tot_len += 1 + rhl->pdulenlen;

+

+  rhl->comlen = m_stat->com_strlen;

+  snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);

+  tot_len += 1 + rhl->comlenlen + rhl->comlen;

+

+  snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);

+  snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);

+  tot_len += 1 + rhl->verlen + rhl->verlenlen;

+

+  rhl->seqlen = tot_len;

+  snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);

+  tot_len += 1 + rhl->seqlenlen;

+

+  return tot_len;

+}

+

+/**

+ * Sums trap header field lengths from tail to head and

+ * returns trap_header_lengths for second encoding pass.

+ *

+ * @param vb_len varbind-list length

+ * @param thl points to returned header lengths

+ * @return the required lenght for encoding the trap header

+ */

+static u16_t

+snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)

+{

+  u16_t tot_len;

+  struct snmp_trap_header_lengths *thl;

+

+  thl = &m_trap->thl;

+  tot_len = vb_len;

+

+  snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);

+  snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);

+  tot_len += 1 + thl->tslen + thl->tslenlen;

+

+  snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);

+  snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);

+  tot_len += 1 + thl->strplen + thl->strplenlen;

+

+  snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);

+  snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);

+  tot_len += 1 + thl->gtrplen + thl->gtrplenlen;

+

+  thl->aaddrlen = 4;

+  snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);

+  tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;

+

+  snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);

+  snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);

+  tot_len += 1 + thl->eidlen + thl->eidlenlen;

+

+  thl->pdulen = tot_len;

+  snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);

+  tot_len += 1 + thl->pdulenlen;

+

+  thl->comlen = sizeof(snmp_publiccommunity) - 1;

+  snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);

+  tot_len += 1 + thl->comlenlen + thl->comlen;

+

+  snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);

+  snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);

+  tot_len += 1 + thl->verlen + thl->verlenlen;

+

+  thl->seqlen = tot_len;

+  snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);

+  tot_len += 1 + thl->seqlenlen;

+

+  return tot_len;

+}

+

+/**

+ * Sums varbind lengths from tail to head and

+ * annotates lengths in varbind for second encoding pass.

+ *

+ * @param root points to the root of the variable binding list

+ * @return the required lenght for encoding the variable bindings

+ */

+static u16_t

+snmp_varbind_list_sum(struct snmp_varbind_root *root)

+{

+  struct snmp_varbind *vb;

+  u32_t *uint_ptr;

+  s32_t *sint_ptr;

+  u16_t tot_len;

+

+  tot_len = 0;

+  vb = root->tail;

+  while ( vb != NULL )

+  {

+    /* encoded value lenght depends on type */

+    switch (vb->value_type)

+    {

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):

+        sint_ptr = vb->value;

+        snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);

+        break;

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):

+        uint_ptr = vb->value;

+        snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):

+        vb->vlen = vb->value_len;

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):

+        sint_ptr = vb->value;

+        snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);

+        break;

+      default:

+        /* unsupported type */

+        vb->vlen = 0;

+        break;

+    };

+    /* encoding length of value length field */

+    snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);

+    snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);

+    snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);

+

+    vb->seqlen = 1 + vb->vlenlen + vb->vlen;

+    vb->seqlen += 1 + vb->olenlen + vb->olen;

+    snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);

+

+    /* varbind seq */

+    tot_len += 1 + vb->seqlenlen + vb->seqlen;

+

+    vb = vb->prev;

+  }

+

+  /* varbind-list seq */

+  root->seqlen = tot_len;

+  snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);

+  tot_len += 1 + root->seqlenlen;

+

+  return tot_len;

+}

+

+/**

+ * Encodes response header from head to tail.

+ */

+static u16_t

+snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)

+{

+  u16_t ofs;

+

+  ofs = 0;

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);

+  ofs += m_stat->rhl.seqlenlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);

+  ofs += m_stat->rhl.verlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);

+  ofs += m_stat->rhl.verlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);

+  ofs += m_stat->rhl.comlenlen;

+  snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);

+  ofs += m_stat->rhl.comlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);

+  ofs += m_stat->rhl.pdulenlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);

+  ofs += m_stat->rhl.ridlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);

+  ofs += m_stat->rhl.ridlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);

+  ofs += m_stat->rhl.errstatlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);

+  ofs += m_stat->rhl.errstatlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);

+  ofs += m_stat->rhl.erridxlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);

+  ofs += m_stat->rhl.erridxlen;

+

+  return ofs;

+}

+

+/**

+ * Encodes trap header from head to tail.

+ */

+static u16_t

+snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)

+{

+  u16_t ofs;

+

+  ofs = 0;

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);

+  ofs += m_trap->thl.seqlenlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);

+  ofs += m_trap->thl.verlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);

+  ofs += m_trap->thl.verlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);

+  ofs += m_trap->thl.comlenlen;

+  snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);

+  ofs += m_trap->thl.comlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);

+  ofs += m_trap->thl.pdulenlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);

+  ofs += m_trap->thl.eidlenlen;

+  snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);

+  ofs += m_trap->thl.eidlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);

+  ofs += m_trap->thl.aaddrlenlen;

+  snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);

+  ofs += m_trap->thl.aaddrlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);

+  ofs += m_trap->thl.gtrplenlen;

+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);

+  ofs += m_trap->thl.gtrplen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);

+  ofs += m_trap->thl.strplenlen;

+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);

+  ofs += m_trap->thl.strplen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);

+  ofs += m_trap->thl.tslenlen;

+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);

+  ofs += m_trap->thl.tslen;

+

+  return ofs;

+}

+

+/**

+ * Encodes varbind list from head to tail.

+ */

+static u16_t

+snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)

+{

+  struct snmp_varbind *vb;

+  s32_t *sint_ptr;

+  u32_t *uint_ptr;

+  u8_t *raw_ptr;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, root->seqlen);

+  ofs += root->seqlenlen;

+

+  vb = root->head;

+  while ( vb != NULL )

+  {

+    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));

+    ofs += 1;

+    snmp_asn1_enc_length(p, ofs, vb->seqlen);

+    ofs += vb->seqlenlen;

+

+    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));

+    ofs += 1;

+    snmp_asn1_enc_length(p, ofs, vb->olen);

+    ofs += vb->olenlen;

+    snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);

+    ofs += vb->olen;

+

+    snmp_asn1_enc_type(p, ofs, vb->value_type);

+    ofs += 1;

+    snmp_asn1_enc_length(p, ofs, vb->vlen);

+    ofs += vb->vlenlen;

+

+    switch (vb->value_type)

+    {

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):

+        sint_ptr = vb->value;

+        snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);

+        break;

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):

+        uint_ptr = vb->value;

+        snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):

+        raw_ptr = vb->value;

+        snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):

+        sint_ptr = vb->value;

+        snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);

+        break;

+      default:

+        /* unsupported type */

+        break;

+    };

+    ofs += vb->vlen;

+    vb = vb->next;

+  }

+  return ofs;

+}

+

+#endif /* LWIP_SNMP */

diff --git a/Demo/Common/ethernet/lwIP/core/stats.c b/Demo/Common/ethernet/lwIP/core/stats.c
index d5b3740..e3cf4a3 100644
--- a/Demo/Common/ethernet/lwIP/core/stats.c
+++ b/Demo/Common/ethernet/lwIP/core/stats.c
@@ -1,115 +1,115 @@
-/*
- * 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 <string.h>
-
-#include "lwip/opt.h"
-
-#include "lwip/def.h"
-
-#include "lwip/stats.h"
-#include "lwip/mem.h"
-
-
-#if LWIP_STATS
-struct stats_ lwip_stats;
-
-void
-stats_init(void)
-{
-  memset(&lwip_stats, 0, sizeof(struct stats_));
-}
-#if LWIP_STATS_DISPLAY
-void
-stats_display_proto(struct stats_proto *proto, char *name)
-{
-  LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
-  LWIP_PLATFORM_DIAG(("xmit: %"S16_F"\n\t", proto->xmit)); 
-  LWIP_PLATFORM_DIAG(("rexmit: %"S16_F"\n\t", proto->rexmit)); 
-  LWIP_PLATFORM_DIAG(("recv: %"S16_F"\n\t", proto->recv)); 
-  LWIP_PLATFORM_DIAG(("fw: %"S16_F"\n\t", proto->fw)); 
-  LWIP_PLATFORM_DIAG(("drop: %"S16_F"\n\t", proto->drop)); 
-  LWIP_PLATFORM_DIAG(("chkerr: %"S16_F"\n\t", proto->chkerr)); 
-  LWIP_PLATFORM_DIAG(("lenerr: %"S16_F"\n\t", proto->lenerr)); 
-  LWIP_PLATFORM_DIAG(("memerr: %"S16_F"\n\t", proto->memerr)); 
-  LWIP_PLATFORM_DIAG(("rterr: %"S16_F"\n\t", proto->rterr)); 
-  LWIP_PLATFORM_DIAG(("proterr: %"S16_F"\n\t", proto->proterr)); 
-  LWIP_PLATFORM_DIAG(("opterr: %"S16_F"\n\t", proto->opterr)); 
-  LWIP_PLATFORM_DIAG(("err: %"S16_F"\n\t", proto->err)); 
-  LWIP_PLATFORM_DIAG(("cachehit: %"S16_F"\n", proto->cachehit)); 
-}
-
-void
-stats_display_pbuf(struct stats_pbuf *pbuf)
-{
-  LWIP_PLATFORM_DIAG(("\nPBUF\n\t"));
-  LWIP_PLATFORM_DIAG(("avail: %"S16_F"\n\t", pbuf->avail)); 
-  LWIP_PLATFORM_DIAG(("used: %"S16_F"\n\t", pbuf->used)); 
-  LWIP_PLATFORM_DIAG(("max: %"S16_F"\n\t", pbuf->max)); 
-  LWIP_PLATFORM_DIAG(("err: %"S16_F"\n\t", pbuf->err)); 
-  LWIP_PLATFORM_DIAG(("alloc_locked: %"S16_F"\n\t", pbuf->alloc_locked)); 
-  LWIP_PLATFORM_DIAG(("refresh_locked: %"S16_F"\n", pbuf->refresh_locked)); 
-}
-
-void
-stats_display_mem(struct stats_mem *mem, char *name)
-{
-  LWIP_PLATFORM_DIAG(("\n MEM %s\n\t", name));
-  LWIP_PLATFORM_DIAG(("avail: %"MEM_SIZE_F"\n\t", mem->avail)); 
-  LWIP_PLATFORM_DIAG(("used: %"MEM_SIZE_F"\n\t", mem->used)); 
-  LWIP_PLATFORM_DIAG(("max: %"MEM_SIZE_F"\n\t", mem->max)); 
-  LWIP_PLATFORM_DIAG(("err: %"MEM_SIZE_F"\n", mem->err));
-  
-}
-
-void
-stats_display(void)
-{
-  s16_t i;
-  char * memp_names[] = {"PBUF", "RAW_PCB", "UDP_PCB", "TCP_PCB", "TCP_PCB_LISTEN",
-        "TCP_SEG", "NETBUF", "NETCONN", "API_MSG", "TCP_MSG", "TIMEOUT"};
-  stats_display_proto(&lwip_stats.link, "LINK");
-  stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");
-  stats_display_proto(&lwip_stats.ip, "IP");
-  stats_display_proto(&lwip_stats.icmp, "ICMP");
-  stats_display_proto(&lwip_stats.udp, "UDP");
-  stats_display_proto(&lwip_stats.tcp, "TCP");
-  stats_display_pbuf(&lwip_stats.pbuf);
-  stats_display_mem(&lwip_stats.mem, "HEAP");
-  for (i = 0; i < MEMP_MAX; i++) {
-    stats_display_mem(&lwip_stats.memp[i], memp_names[i]);
-  }
-  
-}
-#endif /* LWIP_STATS_DISPLAY */
-#endif /* LWIP_STATS */
-
+/*

+ * 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 <string.h>

+

+#include "lwip/opt.h"

+

+#include "lwip/def.h"

+

+#include "lwip/stats.h"

+#include "lwip/mem.h"

+

+

+#if LWIP_STATS

+struct stats_ lwip_stats;

+

+void

+stats_init(void)

+{

+  memset(&lwip_stats, 0, sizeof(struct stats_));

+}

+#if LWIP_STATS_DISPLAY

+void

+stats_display_proto(struct stats_proto *proto, char *name)

+{

+  LWIP_PLATFORM_DIAG(("\n%s\n\t", name));

+  LWIP_PLATFORM_DIAG(("xmit: %"S16_F"\n\t", proto->xmit)); 

+  LWIP_PLATFORM_DIAG(("rexmit: %"S16_F"\n\t", proto->rexmit)); 

+  LWIP_PLATFORM_DIAG(("recv: %"S16_F"\n\t", proto->recv)); 

+  LWIP_PLATFORM_DIAG(("fw: %"S16_F"\n\t", proto->fw)); 

+  LWIP_PLATFORM_DIAG(("drop: %"S16_F"\n\t", proto->drop)); 

+  LWIP_PLATFORM_DIAG(("chkerr: %"S16_F"\n\t", proto->chkerr)); 

+  LWIP_PLATFORM_DIAG(("lenerr: %"S16_F"\n\t", proto->lenerr)); 

+  LWIP_PLATFORM_DIAG(("memerr: %"S16_F"\n\t", proto->memerr)); 

+  LWIP_PLATFORM_DIAG(("rterr: %"S16_F"\n\t", proto->rterr)); 

+  LWIP_PLATFORM_DIAG(("proterr: %"S16_F"\n\t", proto->proterr)); 

+  LWIP_PLATFORM_DIAG(("opterr: %"S16_F"\n\t", proto->opterr)); 

+  LWIP_PLATFORM_DIAG(("err: %"S16_F"\n\t", proto->err)); 

+  LWIP_PLATFORM_DIAG(("cachehit: %"S16_F"\n", proto->cachehit)); 

+}

+

+void

+stats_display_pbuf(struct stats_pbuf *pbuf)

+{

+  LWIP_PLATFORM_DIAG(("\nPBUF\n\t"));

+  LWIP_PLATFORM_DIAG(("avail: %"S16_F"\n\t", pbuf->avail)); 

+  LWIP_PLATFORM_DIAG(("used: %"S16_F"\n\t", pbuf->used)); 

+  LWIP_PLATFORM_DIAG(("max: %"S16_F"\n\t", pbuf->max)); 

+  LWIP_PLATFORM_DIAG(("err: %"S16_F"\n\t", pbuf->err)); 

+  LWIP_PLATFORM_DIAG(("alloc_locked: %"S16_F"\n\t", pbuf->alloc_locked)); 

+  LWIP_PLATFORM_DIAG(("refresh_locked: %"S16_F"\n", pbuf->refresh_locked)); 

+}

+

+void

+stats_display_mem(struct stats_mem *mem, char *name)

+{

+  LWIP_PLATFORM_DIAG(("\n MEM %s\n\t", name));

+  LWIP_PLATFORM_DIAG(("avail: %"MEM_SIZE_F"\n\t", mem->avail)); 

+  LWIP_PLATFORM_DIAG(("used: %"MEM_SIZE_F"\n\t", mem->used)); 

+  LWIP_PLATFORM_DIAG(("max: %"MEM_SIZE_F"\n\t", mem->max)); 

+  LWIP_PLATFORM_DIAG(("err: %"MEM_SIZE_F"\n", mem->err));

+  

+}

+

+void

+stats_display(void)

+{

+  s16_t i;

+  char * memp_names[] = {"PBUF", "RAW_PCB", "UDP_PCB", "TCP_PCB", "TCP_PCB_LISTEN",

+        "TCP_SEG", "NETBUF", "NETCONN", "API_MSG", "TCP_MSG", "TIMEOUT"};

+  stats_display_proto(&lwip_stats.link, "LINK");

+  stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");

+  stats_display_proto(&lwip_stats.ip, "IP");

+  stats_display_proto(&lwip_stats.icmp, "ICMP");

+  stats_display_proto(&lwip_stats.udp, "UDP");

+  stats_display_proto(&lwip_stats.tcp, "TCP");

+  stats_display_pbuf(&lwip_stats.pbuf);

+  stats_display_mem(&lwip_stats.mem, "HEAP");

+  for (i = 0; i < MEMP_MAX; i++) {

+    stats_display_mem(&lwip_stats.memp[i], memp_names[i]);

+  }

+  

+}

+#endif /* LWIP_STATS_DISPLAY */

+#endif /* LWIP_STATS */

+

diff --git a/Demo/Common/ethernet/lwIP/core/sys.c b/Demo/Common/ethernet/lwIP/core/sys.c
index b7bfbf9..2ecb880 100644
--- a/Demo/Common/ethernet/lwIP/core/sys.c
+++ b/Demo/Common/ethernet/lwIP/core/sys.c
@@ -1,294 +1,294 @@
-/*
- * 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/sys.h"
-#include "lwip/opt.h"
-#include "lwip/def.h"
-#include "lwip/memp.h"
-
-#if (NO_SYS == 0)
-
-struct sswt_cb
-{
-    s16_t timeflag;
-    sys_sem_t *psem;
-};
-
-
-
-void
-sys_mbox_fetch(sys_mbox_t mbox, void **msg)
-{
-  u32_t time;
-  struct sys_timeouts *timeouts;
-  struct sys_timeo *tmptimeout;
-  sys_timeout_handler h;
-  void *arg;
-
-
- again:
-  timeouts = sys_arch_timeouts();
-
-  if (!timeouts || !timeouts->next) {
-    sys_arch_mbox_fetch(mbox, msg, 0);
-  } else {
-    if (timeouts->next->time > 0) {
-      time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
-    } else {
-      time = SYS_ARCH_TIMEOUT;
-    }
-
-    if (time == SYS_ARCH_TIMEOUT) {
-      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
-   could be fetched. We should now call the timeout handler and
-   deallocate the memory allocated for the timeout. */
-      tmptimeout = timeouts->next;
-      timeouts->next = tmptimeout->next;
-      h = tmptimeout->h;
-      arg = tmptimeout->arg;
-      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
-      if (h != NULL) {
-        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void *)h, (void *)arg));
-      	h(arg);
-      }
-
-      /* We try again to fetch a message from the mbox. */
-      goto again;
-    } else {
-      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
-   occured. The time variable is set to the number of
-   milliseconds we waited for the message. */
-      if (time <= timeouts->next->time) {
-  timeouts->next->time -= time;
-      } else {
-  timeouts->next->time = 0;
-      }
-    }
-
-  }
-}
-
-void
-sys_sem_wait(sys_sem_t sem)
-{
-  u32_t time;
-  struct sys_timeouts *timeouts;
-  struct sys_timeo *tmptimeout;
-  sys_timeout_handler h;
-  void *arg;
-
-  /*  while (sys_arch_sem_wait(sem, 1000) == 0);
-      return;*/
-
- again:
-
-  timeouts = sys_arch_timeouts();
-
-  if (!timeouts || !timeouts->next) {
-    sys_arch_sem_wait(sem, 0);
-  } else {
-    if (timeouts->next->time > 0) {
-      time = sys_arch_sem_wait(sem, timeouts->next->time);
-    } else {
-      time = SYS_ARCH_TIMEOUT;
-    }
-
-    if (time == SYS_ARCH_TIMEOUT) {
-      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
-   could be fetched. We should now call the timeout handler and
-   deallocate the memory allocated for the timeout. */
-      tmptimeout = timeouts->next;
-      timeouts->next = tmptimeout->next;
-      h = tmptimeout->h;
-      arg = tmptimeout->arg;
-      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
-      if (h != NULL) {
-        LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void *)h, (void *)arg));
-        h(arg);
-      }
-
-
-      /* We try again to fetch a message from the mbox. */
-      goto again;
-    } else {
-      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
-   occured. The time variable is set to the number of
-   milliseconds we waited for the message. */
-      if (time <= timeouts->next->time) {
-  timeouts->next->time -= time;
-      } else {
-  timeouts->next->time = 0;
-      }
-    }
-
-  }
-}
-
-void
-sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
-{
-  struct sys_timeouts *timeouts;
-  struct sys_timeo *timeout, *t;
-
-  timeout = memp_malloc(MEMP_SYS_TIMEOUT);
-  if (timeout == NULL) {
-    return;
-  }
-  timeout->next = NULL;
-  timeout->h = h;
-  timeout->arg = arg;
-  timeout->time = msecs;
-
-  timeouts = sys_arch_timeouts();
-
-  LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
-    (void *)timeout, msecs, (void *)h, (void *)arg));
-
-  LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
-
-  if (timeouts->next == NULL) {
-    timeouts->next = timeout;
-    return;
-  }
-
-  if (timeouts->next->time > msecs) {
-    timeouts->next->time -= msecs;
-    timeout->next = timeouts->next;
-    timeouts->next = timeout;
-  } else {
-    for(t = timeouts->next; t != NULL; t = t->next) {
-      timeout->time -= t->time;
-      if (t->next == NULL || t->next->time > timeout->time) {
-        if (t->next != NULL) {
-          t->next->time -= timeout->time;
-        }
-        timeout->next = t->next;
-        t->next = timeout;
-        break;
-      }
-    }
-  }
-
-}
-
-/* Go through timeout list (for this task only) and remove the first matching entry,
-   even though the timeout has not triggered yet.
-*/
-
-void
-sys_untimeout(sys_timeout_handler h, void *arg)
-{
-    struct sys_timeouts *timeouts;
-    struct sys_timeo *prev_t, *t;
-
-    timeouts = sys_arch_timeouts();
-
-    if (timeouts->next == NULL)
-        return;
-
-    for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next)
-    {
-        if ((t->h == h) && (t->arg == arg))
-        {
-            /* We have a match */
-            /* Unlink from previous in list */
-            if (prev_t == NULL)
-                timeouts->next = t->next;
-            else
-                prev_t->next = t->next;
-            /* If not the last one, add time of this one back to next */
-            if (t->next != NULL)
-                t->next->time += t->time;
-            memp_free(MEMP_SYS_TIMEOUT, t);
-            return;
-        }
-    }
-    return;
-}
-
-
-
-
-
-static void
-sswt_handler(void *arg)
-{
-    struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
-
-    /* Timeout. Set flag to TRUE and signal semaphore */
-    sswt_cb->timeflag = 1;
-    sys_sem_signal(*(sswt_cb->psem));
-}
-
-/* Wait for a semaphore with timeout (specified in ms) */
-/* timeout = 0: wait forever */
-/* Returns 0 on timeout. 1 otherwise */
-
-int
-sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
-{
-    struct sswt_cb sswt_cb;
-
-    sswt_cb.psem = &sem;
-    sswt_cb.timeflag = 0;
-
-    /* If timeout is zero, then just wait forever */
-    if (timeout > 0)
-        /* Create a timer and pass it the address of our flag */
-        sys_timeout(timeout, sswt_handler, &sswt_cb);
-    sys_sem_wait(sem);
-    /* Was it a timeout? */
-    if (sswt_cb.timeflag)
-    {
-        /* timeout */
-        return 0;
-    } else {
-        /* Not a timeout. Remove timeout entry */
-        sys_untimeout(sswt_handler, &sswt_cb);
-        return 1;
-    }
-
-}
-
-
-void
-sys_msleep(u32_t ms)
-{
-  sys_sem_t delaysem = sys_sem_new(0);
-
-  sys_sem_wait_timeout(delaysem, ms);
-
-  sys_sem_free(delaysem);
-}
-
-
-#endif /* NO_SYS */
+/*

+ * 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/sys.h"

+#include "lwip/opt.h"

+#include "lwip/def.h"

+#include "lwip/memp.h"

+

+#if (NO_SYS == 0)

+

+struct sswt_cb

+{

+    s16_t timeflag;

+    sys_sem_t *psem;

+};

+

+

+

+void

+sys_mbox_fetch(sys_mbox_t mbox, void **msg)

+{

+  u32_t time;

+  struct sys_timeouts *timeouts;

+  struct sys_timeo *tmptimeout;

+  sys_timeout_handler h;

+  void *arg;

+

+

+ again:

+  timeouts = sys_arch_timeouts();

+

+  if (!timeouts || !timeouts->next) {

+    sys_arch_mbox_fetch(mbox, msg, 0);

+  } else {

+    if (timeouts->next->time > 0) {

+      time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);

+    } else {

+      time = SYS_ARCH_TIMEOUT;

+    }

+

+    if (time == SYS_ARCH_TIMEOUT) {

+      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message

+   could be fetched. We should now call the timeout handler and

+   deallocate the memory allocated for the timeout. */

+      tmptimeout = timeouts->next;

+      timeouts->next = tmptimeout->next;

+      h = tmptimeout->h;

+      arg = tmptimeout->arg;

+      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);

+      if (h != NULL) {

+        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void *)h, (void *)arg));

+      	h(arg);

+      }

+

+      /* We try again to fetch a message from the mbox. */

+      goto again;

+    } else {

+      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout

+   occured. The time variable is set to the number of

+   milliseconds we waited for the message. */

+      if (time <= timeouts->next->time) {

+  timeouts->next->time -= time;

+      } else {

+  timeouts->next->time = 0;

+      }

+    }

+

+  }

+}

+

+void

+sys_sem_wait(sys_sem_t sem)

+{

+  u32_t time;

+  struct sys_timeouts *timeouts;

+  struct sys_timeo *tmptimeout;

+  sys_timeout_handler h;

+  void *arg;

+

+  /*  while (sys_arch_sem_wait(sem, 1000) == 0);

+      return;*/

+

+ again:

+

+  timeouts = sys_arch_timeouts();

+

+  if (!timeouts || !timeouts->next) {

+    sys_arch_sem_wait(sem, 0);

+  } else {

+    if (timeouts->next->time > 0) {

+      time = sys_arch_sem_wait(sem, timeouts->next->time);

+    } else {

+      time = SYS_ARCH_TIMEOUT;

+    }

+

+    if (time == SYS_ARCH_TIMEOUT) {

+      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message

+   could be fetched. We should now call the timeout handler and

+   deallocate the memory allocated for the timeout. */

+      tmptimeout = timeouts->next;

+      timeouts->next = tmptimeout->next;

+      h = tmptimeout->h;

+      arg = tmptimeout->arg;

+      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);

+      if (h != NULL) {

+        LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void *)h, (void *)arg));

+        h(arg);

+      }

+

+

+      /* We try again to fetch a message from the mbox. */

+      goto again;

+    } else {

+      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout

+   occured. The time variable is set to the number of

+   milliseconds we waited for the message. */

+      if (time <= timeouts->next->time) {

+  timeouts->next->time -= time;

+      } else {

+  timeouts->next->time = 0;

+      }

+    }

+

+  }

+}

+

+void

+sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)

+{

+  struct sys_timeouts *timeouts;

+  struct sys_timeo *timeout, *t;

+

+  timeout = memp_malloc(MEMP_SYS_TIMEOUT);

+  if (timeout == NULL) {

+    return;

+  }

+  timeout->next = NULL;

+  timeout->h = h;

+  timeout->arg = arg;

+  timeout->time = msecs;

+

+  timeouts = sys_arch_timeouts();

+

+  LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",

+    (void *)timeout, msecs, (void *)h, (void *)arg));

+

+  LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);

+

+  if (timeouts->next == NULL) {

+    timeouts->next = timeout;

+    return;

+  }

+

+  if (timeouts->next->time > msecs) {

+    timeouts->next->time -= msecs;

+    timeout->next = timeouts->next;

+    timeouts->next = timeout;

+  } else {

+    for(t = timeouts->next; t != NULL; t = t->next) {

+      timeout->time -= t->time;

+      if (t->next == NULL || t->next->time > timeout->time) {

+        if (t->next != NULL) {

+          t->next->time -= timeout->time;

+        }

+        timeout->next = t->next;

+        t->next = timeout;

+        break;

+      }

+    }

+  }

+

+}

+

+/* Go through timeout list (for this task only) and remove the first matching entry,

+   even though the timeout has not triggered yet.

+*/

+

+void

+sys_untimeout(sys_timeout_handler h, void *arg)

+{

+    struct sys_timeouts *timeouts;

+    struct sys_timeo *prev_t, *t;

+

+    timeouts = sys_arch_timeouts();

+

+    if (timeouts->next == NULL)

+        return;

+

+    for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next)

+    {

+        if ((t->h == h) && (t->arg == arg))

+        {

+            /* We have a match */

+            /* Unlink from previous in list */

+            if (prev_t == NULL)

+                timeouts->next = t->next;

+            else

+                prev_t->next = t->next;

+            /* If not the last one, add time of this one back to next */

+            if (t->next != NULL)

+                t->next->time += t->time;

+            memp_free(MEMP_SYS_TIMEOUT, t);

+            return;

+        }

+    }

+    return;

+}

+

+

+

+

+

+static void

+sswt_handler(void *arg)

+{

+    struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;

+

+    /* Timeout. Set flag to TRUE and signal semaphore */

+    sswt_cb->timeflag = 1;

+    sys_sem_signal(*(sswt_cb->psem));

+}

+

+/* Wait for a semaphore with timeout (specified in ms) */

+/* timeout = 0: wait forever */

+/* Returns 0 on timeout. 1 otherwise */

+

+int

+sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)

+{

+    struct sswt_cb sswt_cb;

+

+    sswt_cb.psem = &sem;

+    sswt_cb.timeflag = 0;

+

+    /* If timeout is zero, then just wait forever */

+    if (timeout > 0)

+        /* Create a timer and pass it the address of our flag */

+        sys_timeout(timeout, sswt_handler, &sswt_cb);

+    sys_sem_wait(sem);

+    /* Was it a timeout? */

+    if (sswt_cb.timeflag)

+    {

+        /* timeout */

+        return 0;

+    } else {

+        /* Not a timeout. Remove timeout entry */

+        sys_untimeout(sswt_handler, &sswt_cb);

+        return 1;

+    }

+

+}

+

+

+void

+sys_msleep(u32_t ms)

+{

+  sys_sem_t delaysem = sys_sem_new(0);

+

+  sys_sem_wait_timeout(delaysem, ms);

+

+  sys_sem_free(delaysem);

+}

+

+

+#endif /* NO_SYS */

diff --git a/Demo/Common/ethernet/lwIP/core/tcp.c b/Demo/Common/ethernet/lwIP/core/tcp.c
index 89dfd24..5b69ee7 100644
--- a/Demo/Common/ethernet/lwIP/core/tcp.c
+++ b/Demo/Common/ethernet/lwIP/core/tcp.c
@@ -1,1182 +1,1182 @@
-/**
- * @file
- *
- * Transmission Control Protocol for IP
- *
- * This file contains common functions for the TCP implementation, such as functinos
- * for manipulating the data structures and the TCP timer functions. TCP functions
- * related to input and output is found in tcp_in.c and tcp_out.c respectively.
- *
- */
-
-/*
- * 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 <string.h>
-
-#include "lwip/opt.h"
-#include "lwip/def.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/snmp.h"
-
-#include "lwip/tcp.h"
-#if LWIP_TCP
-
-/* Incremented every coarse grained timer shot (typically every 500 ms). */
-u32_t tcp_ticks;
-const u8_t tcp_backoff[13] =
-    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
-
-/* The TCP PCB lists. */
-
-/** List of all TCP PCBs in LISTEN state */
-union tcp_listen_pcbs_t tcp_listen_pcbs;
-/** List of all TCP PCBs that are in a state in which
- * they accept or send data. */
-struct tcp_pcb *tcp_active_pcbs;  
-/** List of all TCP PCBs in TIME-WAIT state */
-struct tcp_pcb *tcp_tw_pcbs;
-
-struct tcp_pcb *tcp_tmp_pcb;
-
-static u8_t tcp_timer;
-static u16_t tcp_new_port(void);
-
-/**
- * Initializes the TCP layer.
- */
-void
-tcp_init(void)
-{
-  /* Clear globals. */
-  tcp_listen_pcbs.listen_pcbs = NULL;
-  tcp_active_pcbs = NULL;
-  tcp_tw_pcbs = NULL;
-  tcp_tmp_pcb = NULL;
-  
-  /* initialize timer */
-  tcp_ticks = 0;
-  tcp_timer = 0;
-  
-}
-
-/**
- * Called periodically to dispatch TCP timers.
- *
- */
-void
-tcp_tmr(void)
-{
-  /* Call tcp_fasttmr() every 250 ms */
-  tcp_fasttmr();
-
-  if (++tcp_timer & 1) {
-    /* Call tcp_tmr() every 500 ms, i.e., every other timer
-       tcp_tmr() is called. */
-    tcp_slowtmr();
-  }
-}
-
-/**
- * Closes the connection held by the PCB.
- *
- */
-err_t
-tcp_close(struct tcp_pcb *pcb)
-{
-  err_t err;
-
-#if TCP_DEBUG
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
-  tcp_debug_print_state(pcb->state);
-#endif /* TCP_DEBUG */
-
-  switch (pcb->state) {
-  case CLOSED:
-    /* Closing a pcb in the CLOSED state might seem erroneous,
-     * however, it is in this state once allocated and as yet unused
-     * and the user needs some way to free it should the need arise.
-     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
-     * or for a pcb that has been used and then entered the CLOSED state 
-     * is erroneous, but this should never happen as the pcb has in those cases
-     * been freed, and so any remaining handles are bogus. */
-    err = ERR_OK;
-    memp_free(MEMP_TCP_PCB, pcb);
-    pcb = NULL;
-    break;
-  case LISTEN:
-    err = ERR_OK;
-    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);
-    memp_free(MEMP_TCP_PCB_LISTEN, pcb);
-    pcb = NULL;
-    break;
-  case SYN_SENT:
-    err = ERR_OK;
-    tcp_pcb_remove(&tcp_active_pcbs, pcb);
-    memp_free(MEMP_TCP_PCB, pcb);
-    pcb = NULL;
-    snmp_inc_tcpattemptfails();
-    break;
-  case SYN_RCVD:
-    err = tcp_send_ctrl(pcb, TCP_FIN);
-    if (err == ERR_OK) {
-      snmp_inc_tcpattemptfails();
-      pcb->state = FIN_WAIT_1;
-    }
-    break;
-  case ESTABLISHED:
-    err = tcp_send_ctrl(pcb, TCP_FIN);
-    if (err == ERR_OK) {
-      snmp_inc_tcpestabresets();
-      pcb->state = FIN_WAIT_1;
-    }
-    break;
-  case CLOSE_WAIT:
-    err = tcp_send_ctrl(pcb, TCP_FIN);
-    if (err == ERR_OK) {
-      snmp_inc_tcpestabresets();
-      pcb->state = LAST_ACK;
-    }
-    break;
-  default:
-    /* Has already been closed, do nothing. */
-    err = ERR_OK;
-    pcb = NULL;
-    break;
-  }
-
-  if (pcb != NULL && err == ERR_OK) {
-    err = tcp_output(pcb);
-  }
-  return err;
-}
-
-/**
- * Aborts a connection by sending a RST to the remote host and deletes
- * the local protocol control block. This is done when a connection is
- * killed because of shortage of memory.
- *
- */
-void
-tcp_abort(struct tcp_pcb *pcb)
-{
-  u32_t seqno, ackno;
-  u16_t remote_port, local_port;
-  struct ip_addr remote_ip, local_ip;
-#if LWIP_CALLBACK_API  
-  void (* errf)(void *arg, err_t err);
-#endif /* LWIP_CALLBACK_API */
-  void *errf_arg;
-
-  
-  /* Figure out on which TCP PCB list we are, and remove us. If we
-     are in an active state, call the receive function associated with
-     the PCB with a NULL argument, and send an RST to the remote end. */
-  if (pcb->state == TIME_WAIT) {
-    tcp_pcb_remove(&tcp_tw_pcbs, pcb);
-    memp_free(MEMP_TCP_PCB, pcb);
-  } else {
-    seqno = pcb->snd_nxt;
-    ackno = pcb->rcv_nxt;
-    ip_addr_set(&local_ip, &(pcb->local_ip));
-    ip_addr_set(&remote_ip, &(pcb->remote_ip));
-    local_port = pcb->local_port;
-    remote_port = pcb->remote_port;
-#if LWIP_CALLBACK_API
-    errf = pcb->errf;
-#endif /* LWIP_CALLBACK_API */
-    errf_arg = pcb->callback_arg;
-    tcp_pcb_remove(&tcp_active_pcbs, pcb);
-    if (pcb->unacked != NULL) {
-      tcp_segs_free(pcb->unacked);
-    }
-    if (pcb->unsent != NULL) {
-      tcp_segs_free(pcb->unsent);
-    }
-#if TCP_QUEUE_OOSEQ    
-    if (pcb->ooseq != NULL) {
-      tcp_segs_free(pcb->ooseq);
-    }
-#endif /* TCP_QUEUE_OOSEQ */
-    memp_free(MEMP_TCP_PCB, pcb);
-    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
-    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));
-    tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
-  }
-}
-
-/**
- * Binds the connection to a local portnumber and IP address. If the
- * IP address is not given (i.e., ipaddr == NULL), the IP address of
- * the outgoing network interface is used instead.
- *
- */
-
-err_t
-tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
-{
-  struct tcp_pcb *cpcb;
-
-  if (port == 0) {
-    port = tcp_new_port();
-  }
-  /* Check if the address already is in use. */
-  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;
-      cpcb != NULL; cpcb = cpcb->next) {
-    if (cpcb->local_port == port) {
-      if (ip_addr_isany(&(cpcb->local_ip)) ||
-        ip_addr_isany(ipaddr) ||
-        ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
-          return ERR_USE;
-      }
-    }
-  }
-  for(cpcb = tcp_active_pcbs;
-      cpcb != NULL; cpcb = cpcb->next) {
-    if (cpcb->local_port == port) {
-      if (ip_addr_isany(&(cpcb->local_ip)) ||
-   ip_addr_isany(ipaddr) ||
-   ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
-  return ERR_USE;
-      }
-    }
-  }
-
-  if (!ip_addr_isany(ipaddr)) {
-    pcb->local_ip = *ipaddr;
-  }
-  pcb->local_port = port;
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));
-  return ERR_OK;
-}
-#if LWIP_CALLBACK_API
-static err_t
-tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
-{
-  (void)arg;
-  (void)pcb;
-  (void)err;
-
-  return ERR_ABRT;
-}
-#endif /* LWIP_CALLBACK_API */
-
-/**
- * Set the state of the connection to be LISTEN, which means that it
- * is able to accept incoming connections. The protocol control block
- * is reallocated in order to consume less memory. Setting the
- * connection to LISTEN is an irreversible process.
- *
- */
-struct tcp_pcb *
-tcp_listen(struct tcp_pcb *pcb)
-{
-  struct tcp_pcb_listen *lpcb;
-
-  /* already listening? */
-  if (pcb->state == LISTEN) {
-    return pcb;
-  }
-  lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);
-  if (lpcb == NULL) {
-    return NULL;
-  }
-  lpcb->callback_arg = pcb->callback_arg;
-  lpcb->local_port = pcb->local_port;
-  lpcb->state = LISTEN;
-  lpcb->so_options = pcb->so_options;
-  lpcb->so_options |= SOF_ACCEPTCONN;
-  lpcb->ttl = pcb->ttl;
-  lpcb->tos = pcb->tos;
-  ip_addr_set(&lpcb->local_ip, &pcb->local_ip);
-  memp_free(MEMP_TCP_PCB, pcb);
-#if LWIP_CALLBACK_API
-  lpcb->accept = tcp_accept_null;
-#endif /* LWIP_CALLBACK_API */
-  TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);
-  return (struct tcp_pcb *)lpcb;
-}
-
-/**
- * This function should be called by the application when it has
- * processed the data. The purpose is to advertise a larger window
- * when the data has been processed.
- *
- */
-void
-tcp_recved(struct tcp_pcb *pcb, u16_t len)
-{
-  if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {
-    pcb->rcv_wnd = TCP_WND;
-  } else {
-    pcb->rcv_wnd += len;
-  }
-  if (!(pcb->flags & TF_ACK_DELAY) &&
-     !(pcb->flags & TF_ACK_NOW)) {
-    /*
-     * We send an ACK here (if one is not already pending, hence
-     * the above tests) as tcp_recved() implies that the application
-     * has processed some data, and so we can open the receiver's
-     * window to allow more to be transmitted.  This could result in
-     * two ACKs being sent for each received packet in some limited cases
-     * (where the application is only receiving data, and is slow to
-     * process it) but it is necessary to guarantee that the sender can
-     * continue to transmit.
-     */
-    tcp_ack(pcb);
-  } 
-  else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {
-    /* If we can send a window update such that there is a full
-     * segment available in the window, do so now.  This is sort of
-     * nagle-like in its goals, and tries to hit a compromise between
-     * sending acks each time the window is updated, and only sending
-     * window updates when a timer expires.  The "threshold" used
-     * above (currently TCP_WND/2) can be tuned to be more or less
-     * aggressive  */
-    tcp_ack_now(pcb);
-  }
-
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
-         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
-}
-
-/**
- * A nastly hack featuring 'goto' statements that allocates a
- * new TCP local port.
- */
-static u16_t
-tcp_new_port(void)
-{
-  struct tcp_pcb *pcb;
-#ifndef TCP_LOCAL_PORT_RANGE_START
-#define TCP_LOCAL_PORT_RANGE_START 4096
-#define TCP_LOCAL_PORT_RANGE_END   0x7fff
-#endif
-  static u16_t port = TCP_LOCAL_PORT_RANGE_START;
-  
- again:
-  if (++port > TCP_LOCAL_PORT_RANGE_END) {
-    port = TCP_LOCAL_PORT_RANGE_START;
-  }
-  
-  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-    if (pcb->local_port == port) {
-      goto again;
-    }
-  }
-  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
-    if (pcb->local_port == port) {
-      goto again;
-    }
-  }
-  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
-    if (pcb->local_port == port) {
-      goto again;
-    }
-  }
-  return port;
-}
-
-/**
- * Connects to another host. The function given as the "connected"
- * argument will be called when the connection has been established.
- *
- */
-err_t
-tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
-      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
-{
-  u32_t optdata;
-  err_t ret;
-  u32_t iss;
-
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
-  if (ipaddr != NULL) {
-    pcb->remote_ip = *ipaddr;
-  } else {
-    return ERR_VAL;
-  }
-  pcb->remote_port = port;
-  if (pcb->local_port == 0) {
-    pcb->local_port = tcp_new_port();
-  }
-  iss = tcp_next_iss();
-  pcb->rcv_nxt = 0;
-  pcb->snd_nxt = iss;
-  pcb->lastack = iss - 1;
-  pcb->snd_lbb = iss - 1;
-  pcb->rcv_wnd = TCP_WND;
-  pcb->snd_wnd = TCP_WND;
-  pcb->mss = TCP_MSS;
-  pcb->cwnd = 1;
-  pcb->ssthresh = pcb->mss * 10;
-  pcb->state = SYN_SENT;
-#if LWIP_CALLBACK_API  
-  pcb->connected = connected;
-#endif /* LWIP_CALLBACK_API */  
-  TCP_REG(&tcp_active_pcbs, pcb);
-
-  snmp_inc_tcpactiveopens();
-  
-  /* Build an MSS option */
-  optdata = htonl(((u32_t)2 << 24) | 
-      ((u32_t)4 << 16) | 
-      (((u32_t)pcb->mss / 256) << 8) |
-      (pcb->mss & 255));
-
-  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);
-  if (ret == ERR_OK) { 
-    tcp_output(pcb);
-  }
-  return ret;
-} 
-
-/**
- * Called every 500 ms and implements the retransmission timer and the timer that
- * removes PCBs that have been in TIME-WAIT for enough time. It also increments
- * various timers such as the inactivity timer in each PCB.
- */
-void
-tcp_slowtmr(void)
-{
-  struct tcp_pcb *pcb, *pcb2, *prev;
-  u32_t eff_wnd;
-  u8_t pcb_remove;      /* flag if a PCB should be removed */
-  err_t err;
-
-  err = ERR_OK;
-
-  ++tcp_ticks;
-
-  /* Steps through all of the active PCBs. */
-  prev = NULL;
-  pcb = tcp_active_pcbs;
-  if (pcb == NULL) {
-    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
-  }
-  while (pcb != NULL) {
-    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
-    LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
-    LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
-    LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
-
-    pcb_remove = 0;
-
-    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
-      ++pcb_remove;
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
-    }
-    else if (pcb->nrtx == TCP_MAXRTX) {
-      ++pcb_remove;
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
-    } else {
-      ++pcb->rtime;
-      if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
-
-        /* Time for a retransmission. */
-        LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"U16_F" pcb->rto %"U16_F"\n",
-          pcb->rtime, pcb->rto));
-
-        /* Double retransmission time-out unless we are trying to
-         * connect to somebody (i.e., we are in SYN_SENT). */
-        if (pcb->state != SYN_SENT) {
-          pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
-        }
-        /* Reduce congestion window and ssthresh. */
-        eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
-        pcb->ssthresh = eff_wnd >> 1;
-        if (pcb->ssthresh < pcb->mss) {
-          pcb->ssthresh = pcb->mss * 2;
-        }
-        pcb->cwnd = pcb->mss;
-        LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh %"U16_F"\n",
-                                pcb->cwnd, pcb->ssthresh));
- 
-        /* The following needs to be called AFTER cwnd is set to one mss - STJ */
-        tcp_rexmit_rto(pcb);
-     }
-    }
-    /* Check if this PCB has stayed too long in FIN-WAIT-2 */
-    if (pcb->state == FIN_WAIT_2) {
-      if ((u32_t)(tcp_ticks - pcb->tmr) >
-        TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
-        ++pcb_remove;
-        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
-      }
-    }
-
-   /* Check if KEEPALIVE should be sent */
-   if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {
-      if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)  {
-         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
-                                 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
-                                 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
-
-         tcp_abort(pcb);
-      }
-      else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) {
-         tcp_keepalive(pcb);
-         pcb->keep_cnt++;
-      }
-   }
-
-    /* If this PCB has queued out of sequence data, but has been
-       inactive for too long, will drop the data (it will eventually
-       be retransmitted). */
-#if TCP_QUEUE_OOSEQ    
-    if (pcb->ooseq != NULL &&
-       (u32_t)tcp_ticks - pcb->tmr >=
-       pcb->rto * TCP_OOSEQ_TIMEOUT) {
-      tcp_segs_free(pcb->ooseq);
-      pcb->ooseq = NULL;
-      LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
-    }
-#endif /* TCP_QUEUE_OOSEQ */
-
-    /* Check if this PCB has stayed too long in SYN-RCVD */
-    if (pcb->state == SYN_RCVD) {
-      if ((u32_t)(tcp_ticks - pcb->tmr) >
-        TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {
-        ++pcb_remove;
-        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
-      }
-    }
-
-    /* Check if this PCB has stayed too long in LAST-ACK */
-    if (pcb->state == LAST_ACK) {
-      if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
-        ++pcb_remove;
-        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));
-      }
-    }
-
-    /* If the PCB should be removed, do it. */
-    if (pcb_remove) {
-      tcp_pcb_purge(pcb);      
-      /* Remove PCB from tcp_active_pcbs list. */
-      if (prev != NULL) {
-  LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
-        prev->next = pcb->next;
-      } else {
-        /* This PCB was the first. */
-        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
-        tcp_active_pcbs = pcb->next;
-      }
-
-      TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
-
-      pcb2 = pcb->next;
-      memp_free(MEMP_TCP_PCB, pcb);
-      pcb = pcb2;
-    } else {
-
-      /* We check if we should poll the connection. */
-      ++pcb->polltmr;
-      if (pcb->polltmr >= pcb->pollinterval) {
-        pcb->polltmr = 0;
-        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
-        TCP_EVENT_POLL(pcb, err);
-        if (err == ERR_OK) {
-          tcp_output(pcb);
-        }
-      }
-      
-      prev = pcb;
-      pcb = pcb->next;
-    }
-  }
-
-  
-  /* Steps through all of the TIME-WAIT PCBs. */
-  prev = NULL;    
-  pcb = tcp_tw_pcbs;
-  while (pcb != NULL) {
-    LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
-    pcb_remove = 0;
-
-    /* Check if this PCB has stayed long enough in TIME-WAIT */
-    if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
-      ++pcb_remove;
-    }
-    
-
-
-    /* If the PCB should be removed, do it. */
-    if (pcb_remove) {
-      tcp_pcb_purge(pcb);      
-      /* Remove PCB from tcp_tw_pcbs list. */
-      if (prev != NULL) {
-  LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
-        prev->next = pcb->next;
-      } else {
-        /* This PCB was the first. */
-        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
-        tcp_tw_pcbs = pcb->next;
-      }
-      pcb2 = pcb->next;
-      memp_free(MEMP_TCP_PCB, pcb);
-      pcb = pcb2;
-    } else {
-      prev = pcb;
-      pcb = pcb->next;
-    }
-  }
-}
-
-/**
- * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.
- */
-void
-tcp_fasttmr(void)
-{
-  struct tcp_pcb *pcb;
-
-  /* send delayed ACKs */  
-  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-    if (pcb->flags & TF_ACK_DELAY) {
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
-      tcp_ack_now(pcb);
-      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
-    }
-  }
-}
-
-/**
- * Deallocates a list of TCP segments (tcp_seg structures).
- *
- */
-u8_t
-tcp_segs_free(struct tcp_seg *seg)
-{
-  u8_t count = 0;
-  struct tcp_seg *next;
-  while (seg != NULL) {
-    next = seg->next;
-    count += tcp_seg_free(seg);
-    seg = next;
-  }
-  return count;
-}
-
-/**
- * Frees a TCP segment.
- *
- */
-u8_t
-tcp_seg_free(struct tcp_seg *seg)
-{
-  u8_t count = 0;
-  
-  if (seg != NULL) {
-    if (seg->p != NULL) {
-      count = pbuf_free(seg->p);
-#if TCP_DEBUG
-      seg->p = NULL;
-#endif /* TCP_DEBUG */
-    }
-    memp_free(MEMP_TCP_SEG, seg);
-  }
-  return count;
-}
-
-/**
- * Sets the priority of a connection.
- *
- */
-void
-tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
-{
-  pcb->prio = prio;
-}
-#if TCP_QUEUE_OOSEQ
-
-/**
- * Returns a copy of the given TCP segment.
- *
- */ 
-struct tcp_seg *
-tcp_seg_copy(struct tcp_seg *seg)
-{
-  struct tcp_seg *cseg;
-
-  cseg = memp_malloc(MEMP_TCP_SEG);
-  if (cseg == NULL) {
-    return NULL;
-  }
-  memcpy((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); 
-  pbuf_ref(cseg->p);
-  return cseg;
-}
-#endif
-
-#if LWIP_CALLBACK_API
-static err_t
-tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
-{
-  arg = arg;
-  if (p != NULL) {
-    pbuf_free(p);
-  } else if (err == ERR_OK) {
-    return tcp_close(pcb);
-  }
-  return ERR_OK;
-}
-#endif /* LWIP_CALLBACK_API */
-
-static void
-tcp_kill_prio(u8_t prio)
-{
-  struct tcp_pcb *pcb, *inactive;
-  u32_t inactivity;
-  u8_t mprio;
-
-
-  mprio = TCP_PRIO_MAX;
-  
-  /* We kill the oldest active connection that has lower priority than
-     prio. */
-  inactivity = 0;
-  inactive = NULL;
-  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-    if (pcb->prio <= prio &&
-       pcb->prio <= mprio &&
-       (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
-      inactivity = tcp_ticks - pcb->tmr;
-      inactive = pcb;
-      mprio = pcb->prio;
-    }
-  }
-  if (inactive != NULL) {
-    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
-           (void *)inactive, inactivity));
-    tcp_abort(inactive);
-  }      
-}
-
-
-static void
-tcp_kill_timewait(void)
-{
-  struct tcp_pcb *pcb, *inactive;
-  u32_t inactivity;
-
-  inactivity = 0;
-  inactive = NULL;
-  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
-    if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
-      inactivity = tcp_ticks - pcb->tmr;
-      inactive = pcb;
-    }
-  }
-  if (inactive != NULL) {
-    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
-           (void *)inactive, inactivity));
-    tcp_abort(inactive);
-  }      
-}
-
-
-
-struct tcp_pcb *
-tcp_alloc(u8_t prio)
-{
-  struct tcp_pcb *pcb;
-  u32_t iss;
-  
-  pcb = memp_malloc(MEMP_TCP_PCB);
-  if (pcb == NULL) {
-    /* Try killing oldest connection in TIME-WAIT. */
-    LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));
-    tcp_kill_timewait();
-    pcb = memp_malloc(MEMP_TCP_PCB);
-    if (pcb == NULL) {
-      tcp_kill_prio(prio);    
-      pcb = memp_malloc(MEMP_TCP_PCB);
-    }
-  }
-  if (pcb != NULL) {
-    memset(pcb, 0, sizeof(struct tcp_pcb));
-    pcb->prio = TCP_PRIO_NORMAL;
-    pcb->snd_buf = TCP_SND_BUF;
-    pcb->snd_queuelen = 0;
-    pcb->rcv_wnd = TCP_WND;
-    pcb->tos = 0;
-    pcb->ttl = TCP_TTL;
-    pcb->mss = TCP_MSS;
-    pcb->rto = 3000 / TCP_SLOW_INTERVAL;
-    pcb->sa = 0;
-    pcb->sv = 3000 / TCP_SLOW_INTERVAL;
-    pcb->rtime = 0;
-    pcb->cwnd = 1;
-    iss = tcp_next_iss();
-    pcb->snd_wl2 = iss;
-    pcb->snd_nxt = iss;
-    pcb->snd_max = iss;
-    pcb->lastack = iss;
-    pcb->snd_lbb = iss;   
-    pcb->tmr = tcp_ticks;
-
-    pcb->polltmr = 0;
-
-#if LWIP_CALLBACK_API
-    pcb->recv = tcp_recv_null;
-#endif /* LWIP_CALLBACK_API */  
-    
-    /* Init KEEPALIVE timer */
-    pcb->keepalive = TCP_KEEPDEFAULT;
-    pcb->keep_cnt = 0;
-  }
-  return pcb;
-}
-
-/**
- * Creates a new TCP protocol control block but doesn't place it on
- * any of the TCP PCB lists.
- *
- * @internal: Maybe there should be a idle TCP PCB list where these
- * PCBs are put on. We can then implement port reservation using
- * tcp_bind(). Currently, we lack this (BSD socket type of) feature.
- */
-
-struct tcp_pcb *
-tcp_new(void)
-{
-  return tcp_alloc(TCP_PRIO_NORMAL);
-}
-
-/*
- * tcp_arg():
- *
- * Used to specify the argument that should be passed callback
- * functions.
- *
- */ 
-
-void
-tcp_arg(struct tcp_pcb *pcb, void *arg)
-{  
-  pcb->callback_arg = arg;
-}
-#if LWIP_CALLBACK_API
-
-/**
- * Used to specify the function that should be called when a TCP
- * connection receives data.
- *
- */ 
-void
-tcp_recv(struct tcp_pcb *pcb,
-   err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
-{
-  pcb->recv = recv;
-}
-
-/**
- * Used to specify the function that should be called when TCP data
- * has been successfully delivered to the remote host.
- *
- */ 
-
-void
-tcp_sent(struct tcp_pcb *pcb,
-   err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))
-{
-  pcb->sent = sent;
-}
-
-/**
- * Used to specify the function that should be called when a fatal error
- * has occured on the connection.
- *
- */ 
-void
-tcp_err(struct tcp_pcb *pcb,
-   void (* errf)(void *arg, err_t err))
-{
-  pcb->errf = errf;
-}
-
-/**
- * Used for specifying the function that should be called when a
- * LISTENing connection has been connected to another host.
- *
- */ 
-void
-tcp_accept(struct tcp_pcb *pcb,
-     err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
-{
-  ((struct tcp_pcb_listen *)pcb)->accept = accept;
-}
-#endif /* LWIP_CALLBACK_API */
-
-
-/**
- * Used to specify the function that should be called periodically
- * from TCP. The interval is specified in terms of the TCP coarse
- * timer interval, which is called twice a second.
- *
- */ 
-void
-tcp_poll(struct tcp_pcb *pcb,
-   err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
-{
-#if LWIP_CALLBACK_API
-  pcb->poll = poll;
-#endif /* LWIP_CALLBACK_API */  
-  pcb->pollinterval = interval;
-}
-
-/**
- * Purges a TCP PCB. Removes any buffered data and frees the buffer memory.
- *
- */
-void
-tcp_pcb_purge(struct tcp_pcb *pcb)
-{
-  if (pcb->state != CLOSED &&
-     pcb->state != TIME_WAIT &&
-     pcb->state != LISTEN) {
-
-    LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
-    
-    if (pcb->unsent != NULL) {    
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
-    }
-    if (pcb->unacked != NULL) {    
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
-    }
-#if TCP_QUEUE_OOSEQ /* LW */
-    if (pcb->ooseq != NULL) {    
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
-    }
-    
-    tcp_segs_free(pcb->ooseq);
-    pcb->ooseq = NULL;
-#endif /* TCP_QUEUE_OOSEQ */
-    tcp_segs_free(pcb->unsent);
-    tcp_segs_free(pcb->unacked);
-    pcb->unacked = pcb->unsent = NULL;
-  }
-}
-
-/**
- * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
- *
- */
-void
-tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
-{
-  TCP_RMV(pcblist, pcb);
-
-  tcp_pcb_purge(pcb);
-  
-  /* if there is an outstanding delayed ACKs, send it */
-  if (pcb->state != TIME_WAIT &&
-     pcb->state != LISTEN &&
-     pcb->flags & TF_ACK_DELAY) {
-    pcb->flags |= TF_ACK_NOW;
-    tcp_output(pcb);
-  }  
-  pcb->state = CLOSED;
-
-  LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
-}
-
-/**
- * Calculates a new initial sequence number for new connections.
- *
- */
-u32_t
-tcp_next_iss(void)
-{
-  static u32_t iss = 6510;
-  
-  iss += tcp_ticks;       /* XXX */
-  return iss;
-}
-
-#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
-void
-tcp_debug_print(struct tcp_hdr *tcphdr)
-{
-  LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));
-  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",
-         ntohs(tcphdr->src), ntohs(tcphdr->dest)));
-  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",
-          ntohl(tcphdr->seqno)));
-  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",
-         ntohl(tcphdr->ackno)));
-  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",
-       TCPH_HDRLEN(tcphdr),
-         TCPH_FLAGS(tcphdr) >> 5 & 1,
-         TCPH_FLAGS(tcphdr) >> 4 & 1,
-         TCPH_FLAGS(tcphdr) >> 3 & 1,
-         TCPH_FLAGS(tcphdr) >> 2 & 1,
-         TCPH_FLAGS(tcphdr) >> 1 & 1,
-         TCPH_FLAGS(tcphdr) & 1,
-         ntohs(tcphdr->wnd)));
-  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
-  LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));
-  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",
-         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
-  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
-}
-
-void
-tcp_debug_print_state(enum tcp_state s)
-{
-  LWIP_DEBUGF(TCP_DEBUG, ("State: "));
-  switch (s) {
-  case CLOSED:
-    LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));
-    break;
- case LISTEN:
-   LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));
-   break;
-  case SYN_SENT:
-    LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));
-    break;
-  case SYN_RCVD:
-    LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));
-    break;
-  case ESTABLISHED:
-    LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));
-    break;
-  case FIN_WAIT_1:
-    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));
-    break;
-  case FIN_WAIT_2:
-    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));
-    break;
-  case CLOSE_WAIT:
-    LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));
-    break;
-  case CLOSING:
-    LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));
-    break;
-  case LAST_ACK:
-    LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));
-    break;
-  case TIME_WAIT:
-    LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));
-   break;
-  }
-}
-
-void
-tcp_debug_print_flags(u8_t flags)
-{
-  if (flags & TCP_FIN) {
-    LWIP_DEBUGF(TCP_DEBUG, ("FIN "));
-  }
-  if (flags & TCP_SYN) {
-    LWIP_DEBUGF(TCP_DEBUG, ("SYN "));
-  }
-  if (flags & TCP_RST) {
-    LWIP_DEBUGF(TCP_DEBUG, ("RST "));
-  }
-  if (flags & TCP_PSH) {
-    LWIP_DEBUGF(TCP_DEBUG, ("PSH "));
-  }
-  if (flags & TCP_ACK) {
-    LWIP_DEBUGF(TCP_DEBUG, ("ACK "));
-  }
-  if (flags & TCP_URG) {
-    LWIP_DEBUGF(TCP_DEBUG, ("URG "));
-  }
-  if (flags & TCP_ECE) {
-    LWIP_DEBUGF(TCP_DEBUG, ("ECE "));
-  }
-  if (flags & TCP_CWR) {
-    LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
-  }
-}
-
-void
-tcp_debug_print_pcbs(void)
-{
-  struct tcp_pcb *pcb;
-  LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));
-  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
-                       pcb->local_port, pcb->remote_port,
-                       pcb->snd_nxt, pcb->rcv_nxt));
-    tcp_debug_print_state(pcb->state);
-  }    
-  LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
-  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
-    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
-                       pcb->local_port, pcb->remote_port,
-                       pcb->snd_nxt, pcb->rcv_nxt));
-    tcp_debug_print_state(pcb->state);
-  }    
-  LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));
-  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
-    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
-                       pcb->local_port, pcb->remote_port,
-                       pcb->snd_nxt, pcb->rcv_nxt));
-    tcp_debug_print_state(pcb->state);
-  }    
-}
-
-s16_t
-tcp_pcbs_sane(void)
-{
-  struct tcp_pcb *pcb;
-  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
-    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
-    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
-  }
-  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
-    LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
-  }
-  return 1;
-}
-#endif /* TCP_DEBUG */
-#endif /* LWIP_TCP */
-
-
-
-
-
-
-
-
-
-
+/**

+ * @file

+ *

+ * Transmission Control Protocol for IP

+ *

+ * This file contains common functions for the TCP implementation, such as functinos

+ * for manipulating the data structures and the TCP timer functions. TCP functions

+ * related to input and output is found in tcp_in.c and tcp_out.c respectively.

+ *

+ */

+

+/*

+ * 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 <string.h>

+

+#include "lwip/opt.h"

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+#include "lwip/snmp.h"

+

+#include "lwip/tcp.h"

+#if LWIP_TCP

+

+/* Incremented every coarse grained timer shot (typically every 500 ms). */

+u32_t tcp_ticks;

+const u8_t tcp_backoff[13] =

+    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};

+

+/* The TCP PCB lists. */

+

+/** List of all TCP PCBs in LISTEN state */

+union tcp_listen_pcbs_t tcp_listen_pcbs;

+/** List of all TCP PCBs that are in a state in which

+ * they accept or send data. */

+struct tcp_pcb *tcp_active_pcbs;  

+/** List of all TCP PCBs in TIME-WAIT state */

+struct tcp_pcb *tcp_tw_pcbs;

+

+struct tcp_pcb *tcp_tmp_pcb;

+

+static u8_t tcp_timer;

+static u16_t tcp_new_port(void);

+

+/**

+ * Initializes the TCP layer.

+ */

+void

+tcp_init(void)

+{

+  /* Clear globals. */

+  tcp_listen_pcbs.listen_pcbs = NULL;

+  tcp_active_pcbs = NULL;

+  tcp_tw_pcbs = NULL;

+  tcp_tmp_pcb = NULL;

+  

+  /* initialize timer */

+  tcp_ticks = 0;

+  tcp_timer = 0;

+  

+}

+

+/**

+ * Called periodically to dispatch TCP timers.

+ *

+ */

+void

+tcp_tmr(void)

+{

+  /* Call tcp_fasttmr() every 250 ms */

+  tcp_fasttmr();

+

+  if (++tcp_timer & 1) {

+    /* Call tcp_tmr() every 500 ms, i.e., every other timer

+       tcp_tmr() is called. */

+    tcp_slowtmr();

+  }

+}

+

+/**

+ * Closes the connection held by the PCB.

+ *

+ */

+err_t

+tcp_close(struct tcp_pcb *pcb)

+{

+  err_t err;

+

+#if TCP_DEBUG

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));

+  tcp_debug_print_state(pcb->state);

+#endif /* TCP_DEBUG */

+

+  switch (pcb->state) {

+  case CLOSED:

+    /* Closing a pcb in the CLOSED state might seem erroneous,

+     * however, it is in this state once allocated and as yet unused

+     * and the user needs some way to free it should the need arise.

+     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)

+     * or for a pcb that has been used and then entered the CLOSED state 

+     * is erroneous, but this should never happen as the pcb has in those cases

+     * been freed, and so any remaining handles are bogus. */

+    err = ERR_OK;

+    memp_free(MEMP_TCP_PCB, pcb);

+    pcb = NULL;

+    break;

+  case LISTEN:

+    err = ERR_OK;

+    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);

+    memp_free(MEMP_TCP_PCB_LISTEN, pcb);

+    pcb = NULL;

+    break;

+  case SYN_SENT:

+    err = ERR_OK;

+    tcp_pcb_remove(&tcp_active_pcbs, pcb);

+    memp_free(MEMP_TCP_PCB, pcb);

+    pcb = NULL;

+    snmp_inc_tcpattemptfails();

+    break;

+  case SYN_RCVD:

+    err = tcp_send_ctrl(pcb, TCP_FIN);

+    if (err == ERR_OK) {

+      snmp_inc_tcpattemptfails();

+      pcb->state = FIN_WAIT_1;

+    }

+    break;

+  case ESTABLISHED:

+    err = tcp_send_ctrl(pcb, TCP_FIN);

+    if (err == ERR_OK) {

+      snmp_inc_tcpestabresets();

+      pcb->state = FIN_WAIT_1;

+    }

+    break;

+  case CLOSE_WAIT:

+    err = tcp_send_ctrl(pcb, TCP_FIN);

+    if (err == ERR_OK) {

+      snmp_inc_tcpestabresets();

+      pcb->state = LAST_ACK;

+    }

+    break;

+  default:

+    /* Has already been closed, do nothing. */

+    err = ERR_OK;

+    pcb = NULL;

+    break;

+  }

+

+  if (pcb != NULL && err == ERR_OK) {

+    err = tcp_output(pcb);

+  }

+  return err;

+}

+

+/**

+ * Aborts a connection by sending a RST to the remote host and deletes

+ * the local protocol control block. This is done when a connection is

+ * killed because of shortage of memory.

+ *

+ */

+void

+tcp_abort(struct tcp_pcb *pcb)

+{

+  u32_t seqno, ackno;

+  u16_t remote_port, local_port;

+  struct ip_addr remote_ip, local_ip;

+#if LWIP_CALLBACK_API  

+  void (* errf)(void *arg, err_t err);

+#endif /* LWIP_CALLBACK_API */

+  void *errf_arg;

+

+  

+  /* Figure out on which TCP PCB list we are, and remove us. If we

+     are in an active state, call the receive function associated with

+     the PCB with a NULL argument, and send an RST to the remote end. */

+  if (pcb->state == TIME_WAIT) {

+    tcp_pcb_remove(&tcp_tw_pcbs, pcb);

+    memp_free(MEMP_TCP_PCB, pcb);

+  } else {

+    seqno = pcb->snd_nxt;

+    ackno = pcb->rcv_nxt;

+    ip_addr_set(&local_ip, &(pcb->local_ip));

+    ip_addr_set(&remote_ip, &(pcb->remote_ip));

+    local_port = pcb->local_port;

+    remote_port = pcb->remote_port;

+#if LWIP_CALLBACK_API

+    errf = pcb->errf;

+#endif /* LWIP_CALLBACK_API */

+    errf_arg = pcb->callback_arg;

+    tcp_pcb_remove(&tcp_active_pcbs, pcb);

+    if (pcb->unacked != NULL) {

+      tcp_segs_free(pcb->unacked);

+    }

+    if (pcb->unsent != NULL) {

+      tcp_segs_free(pcb->unsent);

+    }

+#if TCP_QUEUE_OOSEQ    

+    if (pcb->ooseq != NULL) {

+      tcp_segs_free(pcb->ooseq);

+    }

+#endif /* TCP_QUEUE_OOSEQ */

+    memp_free(MEMP_TCP_PCB, pcb);

+    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);

+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));

+    tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);

+  }

+}

+

+/**

+ * Binds the connection to a local portnumber and IP address. If the

+ * IP address is not given (i.e., ipaddr == NULL), the IP address of

+ * the outgoing network interface is used instead.

+ *

+ */

+

+err_t

+tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

+{

+  struct tcp_pcb *cpcb;

+

+  if (port == 0) {

+    port = tcp_new_port();

+  }

+  /* Check if the address already is in use. */

+  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;

+      cpcb != NULL; cpcb = cpcb->next) {

+    if (cpcb->local_port == port) {

+      if (ip_addr_isany(&(cpcb->local_ip)) ||

+        ip_addr_isany(ipaddr) ||

+        ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {

+          return ERR_USE;

+      }

+    }

+  }

+  for(cpcb = tcp_active_pcbs;

+      cpcb != NULL; cpcb = cpcb->next) {

+    if (cpcb->local_port == port) {

+      if (ip_addr_isany(&(cpcb->local_ip)) ||

+   ip_addr_isany(ipaddr) ||

+   ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {

+  return ERR_USE;

+      }

+    }

+  }

+

+  if (!ip_addr_isany(ipaddr)) {

+    pcb->local_ip = *ipaddr;

+  }

+  pcb->local_port = port;

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));

+  return ERR_OK;

+}

+#if LWIP_CALLBACK_API

+static err_t

+tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)

+{

+  (void)arg;

+  (void)pcb;

+  (void)err;

+

+  return ERR_ABRT;

+}

+#endif /* LWIP_CALLBACK_API */

+

+/**

+ * Set the state of the connection to be LISTEN, which means that it

+ * is able to accept incoming connections. The protocol control block

+ * is reallocated in order to consume less memory. Setting the

+ * connection to LISTEN is an irreversible process.

+ *

+ */

+struct tcp_pcb *

+tcp_listen(struct tcp_pcb *pcb)

+{

+  struct tcp_pcb_listen *lpcb;

+

+  /* already listening? */

+  if (pcb->state == LISTEN) {

+    return pcb;

+  }

+  lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);

+  if (lpcb == NULL) {

+    return NULL;

+  }

+  lpcb->callback_arg = pcb->callback_arg;

+  lpcb->local_port = pcb->local_port;

+  lpcb->state = LISTEN;

+  lpcb->so_options = pcb->so_options;

+  lpcb->so_options |= SOF_ACCEPTCONN;

+  lpcb->ttl = pcb->ttl;

+  lpcb->tos = pcb->tos;

+  ip_addr_set(&lpcb->local_ip, &pcb->local_ip);

+  memp_free(MEMP_TCP_PCB, pcb);

+#if LWIP_CALLBACK_API

+  lpcb->accept = tcp_accept_null;

+#endif /* LWIP_CALLBACK_API */

+  TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);

+  return (struct tcp_pcb *)lpcb;

+}

+

+/**

+ * This function should be called by the application when it has

+ * processed the data. The purpose is to advertise a larger window

+ * when the data has been processed.

+ *

+ */

+void

+tcp_recved(struct tcp_pcb *pcb, u16_t len)

+{

+  if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {

+    pcb->rcv_wnd = TCP_WND;

+  } else {

+    pcb->rcv_wnd += len;

+  }

+  if (!(pcb->flags & TF_ACK_DELAY) &&

+     !(pcb->flags & TF_ACK_NOW)) {

+    /*

+     * We send an ACK here (if one is not already pending, hence

+     * the above tests) as tcp_recved() implies that the application

+     * has processed some data, and so we can open the receiver's

+     * window to allow more to be transmitted.  This could result in

+     * two ACKs being sent for each received packet in some limited cases

+     * (where the application is only receiving data, and is slow to

+     * process it) but it is necessary to guarantee that the sender can

+     * continue to transmit.

+     */

+    tcp_ack(pcb);

+  } 

+  else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {

+    /* If we can send a window update such that there is a full

+     * segment available in the window, do so now.  This is sort of

+     * nagle-like in its goals, and tries to hit a compromise between

+     * sending acks each time the window is updated, and only sending

+     * window updates when a timer expires.  The "threshold" used

+     * above (currently TCP_WND/2) can be tuned to be more or less

+     * aggressive  */

+    tcp_ack_now(pcb);

+  }

+

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",

+         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));

+}

+

+/**

+ * A nastly hack featuring 'goto' statements that allocates a

+ * new TCP local port.

+ */

+static u16_t

+tcp_new_port(void)

+{

+  struct tcp_pcb *pcb;

+#ifndef TCP_LOCAL_PORT_RANGE_START

+#define TCP_LOCAL_PORT_RANGE_START 4096

+#define TCP_LOCAL_PORT_RANGE_END   0x7fff

+#endif

+  static u16_t port = TCP_LOCAL_PORT_RANGE_START;

+  

+ again:

+  if (++port > TCP_LOCAL_PORT_RANGE_END) {

+    port = TCP_LOCAL_PORT_RANGE_START;

+  }

+  

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->local_port == port) {

+      goto again;

+    }

+  }

+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->local_port == port) {

+      goto again;

+    }

+  }

+  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->local_port == port) {

+      goto again;

+    }

+  }

+  return port;

+}

+

+/**

+ * Connects to another host. The function given as the "connected"

+ * argument will be called when the connection has been established.

+ *

+ */

+err_t

+tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,

+      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))

+{

+  u32_t optdata;

+  err_t ret;

+  u32_t iss;

+

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));

+  if (ipaddr != NULL) {

+    pcb->remote_ip = *ipaddr;

+  } else {

+    return ERR_VAL;

+  }

+  pcb->remote_port = port;

+  if (pcb->local_port == 0) {

+    pcb->local_port = tcp_new_port();

+  }

+  iss = tcp_next_iss();

+  pcb->rcv_nxt = 0;

+  pcb->snd_nxt = iss;

+  pcb->lastack = iss - 1;

+  pcb->snd_lbb = iss - 1;

+  pcb->rcv_wnd = TCP_WND;

+  pcb->snd_wnd = TCP_WND;

+  pcb->mss = TCP_MSS;

+  pcb->cwnd = 1;

+  pcb->ssthresh = pcb->mss * 10;

+  pcb->state = SYN_SENT;

+#if LWIP_CALLBACK_API  

+  pcb->connected = connected;

+#endif /* LWIP_CALLBACK_API */  

+  TCP_REG(&tcp_active_pcbs, pcb);

+

+  snmp_inc_tcpactiveopens();

+  

+  /* Build an MSS option */

+  optdata = htonl(((u32_t)2 << 24) | 

+      ((u32_t)4 << 16) | 

+      (((u32_t)pcb->mss / 256) << 8) |

+      (pcb->mss & 255));

+

+  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);

+  if (ret == ERR_OK) { 

+    tcp_output(pcb);

+  }

+  return ret;

+} 

+

+/**

+ * Called every 500 ms and implements the retransmission timer and the timer that

+ * removes PCBs that have been in TIME-WAIT for enough time. It also increments

+ * various timers such as the inactivity timer in each PCB.

+ */

+void

+tcp_slowtmr(void)

+{

+  struct tcp_pcb *pcb, *pcb2, *prev;

+  u32_t eff_wnd;

+  u8_t pcb_remove;      /* flag if a PCB should be removed */

+  err_t err;

+

+  err = ERR_OK;

+

+  ++tcp_ticks;

+

+  /* Steps through all of the active PCBs. */

+  prev = NULL;

+  pcb = tcp_active_pcbs;

+  if (pcb == NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));

+  }

+  while (pcb != NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));

+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);

+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);

+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);

+

+    pcb_remove = 0;

+

+    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {

+      ++pcb_remove;

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));

+    }

+    else if (pcb->nrtx == TCP_MAXRTX) {

+      ++pcb_remove;

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));

+    } else {

+      ++pcb->rtime;

+      if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {

+

+        /* Time for a retransmission. */

+        LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"U16_F" pcb->rto %"U16_F"\n",

+          pcb->rtime, pcb->rto));

+

+        /* Double retransmission time-out unless we are trying to

+         * connect to somebody (i.e., we are in SYN_SENT). */

+        if (pcb->state != SYN_SENT) {

+          pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];

+        }

+        /* Reduce congestion window and ssthresh. */

+        eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);

+        pcb->ssthresh = eff_wnd >> 1;

+        if (pcb->ssthresh < pcb->mss) {

+          pcb->ssthresh = pcb->mss * 2;

+        }

+        pcb->cwnd = pcb->mss;

+        LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh %"U16_F"\n",

+                                pcb->cwnd, pcb->ssthresh));

+ 

+        /* The following needs to be called AFTER cwnd is set to one mss - STJ */

+        tcp_rexmit_rto(pcb);

+     }

+    }

+    /* Check if this PCB has stayed too long in FIN-WAIT-2 */

+    if (pcb->state == FIN_WAIT_2) {

+      if ((u32_t)(tcp_ticks - pcb->tmr) >

+        TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {

+        ++pcb_remove;

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));

+      }

+    }

+

+   /* Check if KEEPALIVE should be sent */

+   if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {

+      if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)  {

+         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",

+                                 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),

+                                 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));

+

+         tcp_abort(pcb);

+      }

+      else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) {

+         tcp_keepalive(pcb);

+         pcb->keep_cnt++;

+      }

+   }

+

+    /* If this PCB has queued out of sequence data, but has been

+       inactive for too long, will drop the data (it will eventually

+       be retransmitted). */

+#if TCP_QUEUE_OOSEQ    

+    if (pcb->ooseq != NULL &&

+       (u32_t)tcp_ticks - pcb->tmr >=

+       pcb->rto * TCP_OOSEQ_TIMEOUT) {

+      tcp_segs_free(pcb->ooseq);

+      pcb->ooseq = NULL;

+      LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));

+    }

+#endif /* TCP_QUEUE_OOSEQ */

+

+    /* Check if this PCB has stayed too long in SYN-RCVD */

+    if (pcb->state == SYN_RCVD) {

+      if ((u32_t)(tcp_ticks - pcb->tmr) >

+        TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {

+        ++pcb_remove;

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));

+      }

+    }

+

+    /* Check if this PCB has stayed too long in LAST-ACK */

+    if (pcb->state == LAST_ACK) {

+      if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {

+        ++pcb_remove;

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));

+      }

+    }

+

+    /* If the PCB should be removed, do it. */

+    if (pcb_remove) {

+      tcp_pcb_purge(pcb);      

+      /* Remove PCB from tcp_active_pcbs list. */

+      if (prev != NULL) {

+  LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);

+        prev->next = pcb->next;

+      } else {

+        /* This PCB was the first. */

+        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);

+        tcp_active_pcbs = pcb->next;

+      }

+

+      TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);

+

+      pcb2 = pcb->next;

+      memp_free(MEMP_TCP_PCB, pcb);

+      pcb = pcb2;

+    } else {

+

+      /* We check if we should poll the connection. */

+      ++pcb->polltmr;

+      if (pcb->polltmr >= pcb->pollinterval) {

+        pcb->polltmr = 0;

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));

+        TCP_EVENT_POLL(pcb, err);

+        if (err == ERR_OK) {

+          tcp_output(pcb);

+        }

+      }

+      

+      prev = pcb;

+      pcb = pcb->next;

+    }

+  }

+

+  

+  /* Steps through all of the TIME-WAIT PCBs. */

+  prev = NULL;    

+  pcb = tcp_tw_pcbs;

+  while (pcb != NULL) {

+    LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);

+    pcb_remove = 0;

+

+    /* Check if this PCB has stayed long enough in TIME-WAIT */

+    if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {

+      ++pcb_remove;

+    }

+    

+

+

+    /* If the PCB should be removed, do it. */

+    if (pcb_remove) {

+      tcp_pcb_purge(pcb);      

+      /* Remove PCB from tcp_tw_pcbs list. */

+      if (prev != NULL) {

+  LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);

+        prev->next = pcb->next;

+      } else {

+        /* This PCB was the first. */

+        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);

+        tcp_tw_pcbs = pcb->next;

+      }

+      pcb2 = pcb->next;

+      memp_free(MEMP_TCP_PCB, pcb);

+      pcb = pcb2;

+    } else {

+      prev = pcb;

+      pcb = pcb->next;

+    }

+  }

+}

+

+/**

+ * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.

+ */

+void

+tcp_fasttmr(void)

+{

+  struct tcp_pcb *pcb;

+

+  /* send delayed ACKs */  

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->flags & TF_ACK_DELAY) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));

+      tcp_ack_now(pcb);

+      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);

+    }

+  }

+}

+

+/**

+ * Deallocates a list of TCP segments (tcp_seg structures).

+ *

+ */

+u8_t

+tcp_segs_free(struct tcp_seg *seg)

+{

+  u8_t count = 0;

+  struct tcp_seg *next;

+  while (seg != NULL) {

+    next = seg->next;

+    count += tcp_seg_free(seg);

+    seg = next;

+  }

+  return count;

+}

+

+/**

+ * Frees a TCP segment.

+ *

+ */

+u8_t

+tcp_seg_free(struct tcp_seg *seg)

+{

+  u8_t count = 0;

+  

+  if (seg != NULL) {

+    if (seg->p != NULL) {

+      count = pbuf_free(seg->p);

+#if TCP_DEBUG

+      seg->p = NULL;

+#endif /* TCP_DEBUG */

+    }

+    memp_free(MEMP_TCP_SEG, seg);

+  }

+  return count;

+}

+

+/**

+ * Sets the priority of a connection.

+ *

+ */

+void

+tcp_setprio(struct tcp_pcb *pcb, u8_t prio)

+{

+  pcb->prio = prio;

+}

+#if TCP_QUEUE_OOSEQ

+

+/**

+ * Returns a copy of the given TCP segment.

+ *

+ */ 

+struct tcp_seg *

+tcp_seg_copy(struct tcp_seg *seg)

+{

+  struct tcp_seg *cseg;

+

+  cseg = memp_malloc(MEMP_TCP_SEG);

+  if (cseg == NULL) {

+    return NULL;

+  }

+  memcpy((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); 

+  pbuf_ref(cseg->p);

+  return cseg;

+}

+#endif

+

+#if LWIP_CALLBACK_API

+static err_t

+tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)

+{

+  arg = arg;

+  if (p != NULL) {

+    pbuf_free(p);

+  } else if (err == ERR_OK) {

+    return tcp_close(pcb);

+  }

+  return ERR_OK;

+}

+#endif /* LWIP_CALLBACK_API */

+

+static void

+tcp_kill_prio(u8_t prio)

+{

+  struct tcp_pcb *pcb, *inactive;

+  u32_t inactivity;

+  u8_t mprio;

+

+

+  mprio = TCP_PRIO_MAX;

+  

+  /* We kill the oldest active connection that has lower priority than

+     prio. */

+  inactivity = 0;

+  inactive = NULL;

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->prio <= prio &&

+       pcb->prio <= mprio &&

+       (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {

+      inactivity = tcp_ticks - pcb->tmr;

+      inactive = pcb;

+      mprio = pcb->prio;

+    }

+  }

+  if (inactive != NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",

+           (void *)inactive, inactivity));

+    tcp_abort(inactive);

+  }      

+}

+

+

+static void

+tcp_kill_timewait(void)

+{

+  struct tcp_pcb *pcb, *inactive;

+  u32_t inactivity;

+

+  inactivity = 0;

+  inactive = NULL;

+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+    if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {

+      inactivity = tcp_ticks - pcb->tmr;

+      inactive = pcb;

+    }

+  }

+  if (inactive != NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",

+           (void *)inactive, inactivity));

+    tcp_abort(inactive);

+  }      

+}

+

+

+

+struct tcp_pcb *

+tcp_alloc(u8_t prio)

+{

+  struct tcp_pcb *pcb;

+  u32_t iss;

+  

+  pcb = memp_malloc(MEMP_TCP_PCB);

+  if (pcb == NULL) {

+    /* Try killing oldest connection in TIME-WAIT. */

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));

+    tcp_kill_timewait();

+    pcb = memp_malloc(MEMP_TCP_PCB);

+    if (pcb == NULL) {

+      tcp_kill_prio(prio);    

+      pcb = memp_malloc(MEMP_TCP_PCB);

+    }

+  }

+  if (pcb != NULL) {

+    memset(pcb, 0, sizeof(struct tcp_pcb));

+    pcb->prio = TCP_PRIO_NORMAL;

+    pcb->snd_buf = TCP_SND_BUF;

+    pcb->snd_queuelen = 0;

+    pcb->rcv_wnd = TCP_WND;

+    pcb->tos = 0;

+    pcb->ttl = TCP_TTL;

+    pcb->mss = TCP_MSS;

+    pcb->rto = 3000 / TCP_SLOW_INTERVAL;

+    pcb->sa = 0;

+    pcb->sv = 3000 / TCP_SLOW_INTERVAL;

+    pcb->rtime = 0;

+    pcb->cwnd = 1;

+    iss = tcp_next_iss();

+    pcb->snd_wl2 = iss;

+    pcb->snd_nxt = iss;

+    pcb->snd_max = iss;

+    pcb->lastack = iss;

+    pcb->snd_lbb = iss;   

+    pcb->tmr = tcp_ticks;

+

+    pcb->polltmr = 0;

+

+#if LWIP_CALLBACK_API

+    pcb->recv = tcp_recv_null;

+#endif /* LWIP_CALLBACK_API */  

+    

+    /* Init KEEPALIVE timer */

+    pcb->keepalive = TCP_KEEPDEFAULT;

+    pcb->keep_cnt = 0;

+  }

+  return pcb;

+}

+

+/**

+ * Creates a new TCP protocol control block but doesn't place it on

+ * any of the TCP PCB lists.

+ *

+ * @internal: Maybe there should be a idle TCP PCB list where these

+ * PCBs are put on. We can then implement port reservation using

+ * tcp_bind(). Currently, we lack this (BSD socket type of) feature.

+ */

+

+struct tcp_pcb *

+tcp_new(void)

+{

+  return tcp_alloc(TCP_PRIO_NORMAL);

+}

+

+/*

+ * tcp_arg():

+ *

+ * Used to specify the argument that should be passed callback

+ * functions.

+ *

+ */ 

+

+void

+tcp_arg(struct tcp_pcb *pcb, void *arg)

+{  

+  pcb->callback_arg = arg;

+}

+#if LWIP_CALLBACK_API

+

+/**

+ * Used to specify the function that should be called when a TCP

+ * connection receives data.

+ *

+ */ 

+void

+tcp_recv(struct tcp_pcb *pcb,

+   err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))

+{

+  pcb->recv = recv;

+}

+

+/**

+ * Used to specify the function that should be called when TCP data

+ * has been successfully delivered to the remote host.

+ *

+ */ 

+

+void

+tcp_sent(struct tcp_pcb *pcb,

+   err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))

+{

+  pcb->sent = sent;

+}

+

+/**

+ * Used to specify the function that should be called when a fatal error

+ * has occured on the connection.

+ *

+ */ 

+void

+tcp_err(struct tcp_pcb *pcb,

+   void (* errf)(void *arg, err_t err))

+{

+  pcb->errf = errf;

+}

+

+/**

+ * Used for specifying the function that should be called when a

+ * LISTENing connection has been connected to another host.

+ *

+ */ 

+void

+tcp_accept(struct tcp_pcb *pcb,

+     err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))

+{

+  ((struct tcp_pcb_listen *)pcb)->accept = accept;

+}

+#endif /* LWIP_CALLBACK_API */

+

+

+/**

+ * Used to specify the function that should be called periodically

+ * from TCP. The interval is specified in terms of the TCP coarse

+ * timer interval, which is called twice a second.

+ *

+ */ 

+void

+tcp_poll(struct tcp_pcb *pcb,

+   err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)

+{

+#if LWIP_CALLBACK_API

+  pcb->poll = poll;

+#endif /* LWIP_CALLBACK_API */  

+  pcb->pollinterval = interval;

+}

+

+/**

+ * Purges a TCP PCB. Removes any buffered data and frees the buffer memory.

+ *

+ */

+void

+tcp_pcb_purge(struct tcp_pcb *pcb)

+{

+  if (pcb->state != CLOSED &&

+     pcb->state != TIME_WAIT &&

+     pcb->state != LISTEN) {

+

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));

+    

+    if (pcb->unsent != NULL) {    

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));

+    }

+    if (pcb->unacked != NULL) {    

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));

+    }

+#if TCP_QUEUE_OOSEQ /* LW */

+    if (pcb->ooseq != NULL) {    

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));

+    }

+    

+    tcp_segs_free(pcb->ooseq);

+    pcb->ooseq = NULL;

+#endif /* TCP_QUEUE_OOSEQ */

+    tcp_segs_free(pcb->unsent);

+    tcp_segs_free(pcb->unacked);

+    pcb->unacked = pcb->unsent = NULL;

+  }

+}

+

+/**

+ * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.

+ *

+ */

+void

+tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)

+{

+  TCP_RMV(pcblist, pcb);

+

+  tcp_pcb_purge(pcb);

+  

+  /* if there is an outstanding delayed ACKs, send it */

+  if (pcb->state != TIME_WAIT &&

+     pcb->state != LISTEN &&

+     pcb->flags & TF_ACK_DELAY) {

+    pcb->flags |= TF_ACK_NOW;

+    tcp_output(pcb);

+  }  

+  pcb->state = CLOSED;

+

+  LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());

+}

+

+/**

+ * Calculates a new initial sequence number for new connections.

+ *

+ */

+u32_t

+tcp_next_iss(void)

+{

+  static u32_t iss = 6510;

+  

+  iss += tcp_ticks;       /* XXX */

+  return iss;

+}

+

+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG

+void

+tcp_debug_print(struct tcp_hdr *tcphdr)

+{

+  LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",

+         ntohs(tcphdr->src), ntohs(tcphdr->dest)));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",

+          ntohl(tcphdr->seqno)));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",

+         ntohl(tcphdr->ackno)));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",

+       TCPH_HDRLEN(tcphdr),

+         TCPH_FLAGS(tcphdr) >> 5 & 1,

+         TCPH_FLAGS(tcphdr) >> 4 & 1,

+         TCPH_FLAGS(tcphdr) >> 3 & 1,

+         TCPH_FLAGS(tcphdr) >> 2 & 1,

+         TCPH_FLAGS(tcphdr) >> 1 & 1,

+         TCPH_FLAGS(tcphdr) & 1,

+         ntohs(tcphdr->wnd)));

+  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));

+  LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",

+         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+}

+

+void

+tcp_debug_print_state(enum tcp_state s)

+{

+  LWIP_DEBUGF(TCP_DEBUG, ("State: "));

+  switch (s) {

+  case CLOSED:

+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));

+    break;

+ case LISTEN:

+   LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));

+   break;

+  case SYN_SENT:

+    LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));

+    break;

+  case SYN_RCVD:

+    LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));

+    break;

+  case ESTABLISHED:

+    LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));

+    break;

+  case FIN_WAIT_1:

+    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));

+    break;

+  case FIN_WAIT_2:

+    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));

+    break;

+  case CLOSE_WAIT:

+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));

+    break;

+  case CLOSING:

+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));

+    break;

+  case LAST_ACK:

+    LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));

+    break;

+  case TIME_WAIT:

+    LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));

+   break;

+  }

+}

+

+void

+tcp_debug_print_flags(u8_t flags)

+{

+  if (flags & TCP_FIN) {

+    LWIP_DEBUGF(TCP_DEBUG, ("FIN "));

+  }

+  if (flags & TCP_SYN) {

+    LWIP_DEBUGF(TCP_DEBUG, ("SYN "));

+  }

+  if (flags & TCP_RST) {

+    LWIP_DEBUGF(TCP_DEBUG, ("RST "));

+  }

+  if (flags & TCP_PSH) {

+    LWIP_DEBUGF(TCP_DEBUG, ("PSH "));

+  }

+  if (flags & TCP_ACK) {

+    LWIP_DEBUGF(TCP_DEBUG, ("ACK "));

+  }

+  if (flags & TCP_URG) {

+    LWIP_DEBUGF(TCP_DEBUG, ("URG "));

+  }

+  if (flags & TCP_ECE) {

+    LWIP_DEBUGF(TCP_DEBUG, ("ECE "));

+  }

+  if (flags & TCP_CWR) {

+    LWIP_DEBUGF(TCP_DEBUG, ("CWR "));

+  }

+}

+

+void

+tcp_debug_print_pcbs(void)

+{

+  struct tcp_pcb *pcb;

+  LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",

+                       pcb->local_port, pcb->remote_port,

+                       pcb->snd_nxt, pcb->rcv_nxt));

+    tcp_debug_print_state(pcb->state);

+  }    

+  LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));

+  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",

+                       pcb->local_port, pcb->remote_port,

+                       pcb->snd_nxt, pcb->rcv_nxt));

+    tcp_debug_print_state(pcb->state);

+  }    

+  LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));

+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",

+                       pcb->local_port, pcb->remote_port,

+                       pcb->snd_nxt, pcb->rcv_nxt));

+    tcp_debug_print_state(pcb->state);

+  }    

+}

+

+s16_t

+tcp_pcbs_sane(void)

+{

+  struct tcp_pcb *pcb;

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);

+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);

+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);

+  }

+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);

+  }

+  return 1;

+}

+#endif /* TCP_DEBUG */

+#endif /* LWIP_TCP */

+

+

+

+

+

+

+

+

+

+

diff --git a/Demo/Common/ethernet/lwIP/core/tcp_in.c b/Demo/Common/ethernet/lwIP/core/tcp_in.c
index f6a3b87..fc79ae3 100644
--- a/Demo/Common/ethernet/lwIP/core/tcp_in.c
+++ b/Demo/Common/ethernet/lwIP/core/tcp_in.c
@@ -1,1209 +1,1209 @@
-/**
- * @file
- *
- * Transmission Control Protocol, incoming traffic
- *
- * The input processing functions of the TCP layer.
- *
- * These functions are generally called in the order (ip_input() ->)
- * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
- * 
- */
-
-/*
- * 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/def.h"
-#include "lwip/opt.h"
-
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-
-#include "lwip/inet.h"
-#include "lwip/tcp.h"
-
-#include "lwip/stats.h"
-#include "arch/perf.h"
-#include "lwip/snmp.h"
-
-#if LWIP_TCP
-/* These variables are global to all functions involved in the input
-   processing of TCP segments. They are set by the tcp_input()
-   function. */
-static struct tcp_seg inseg;
-static struct tcp_hdr *tcphdr;
-static struct ip_hdr *iphdr;
-static u32_t seqno, ackno;
-static u8_t flags;
-static u16_t tcplen;
-
-static u8_t recv_flags;
-static struct pbuf *recv_data;
-
-struct tcp_pcb *tcp_input_pcb;
-
-/* Forward declarations. */
-static err_t tcp_process(struct tcp_pcb *pcb);
-static u8_t tcp_receive(struct tcp_pcb *pcb);
-static void tcp_parseopt(struct tcp_pcb *pcb);
-
-static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
-static err_t tcp_timewait_input(struct tcp_pcb *pcb);
-
-/* tcp_input:
- *
- * The initial input processing of TCP. It verifies the TCP header, demultiplexes
- * the segment between the PCBs and passes it on to tcp_process(), which implements
- * the TCP finite state machine. This function is called by the IP layer (in
- * ip_input()).
- */
-
-void
-tcp_input(struct pbuf *p, struct netif *inp)
-{
-  struct tcp_pcb *pcb, *prev;
-  struct tcp_pcb_listen *lpcb;
-  u8_t hdrlen;
-  err_t err;
-
-  PERF_START;
-
-  TCP_STATS_INC(tcp.recv);
-  snmp_inc_tcpinsegs();
-
-  iphdr = p->payload;
-  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
-
-#if TCP_INPUT_DEBUG
-  tcp_debug_print(tcphdr);
-#endif
-
-  /* remove header from payload */
-  if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
-    /* drop short packets */
-    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
-    TCP_STATS_INC(tcp.lenerr);
-    TCP_STATS_INC(tcp.drop);
-    pbuf_free(p);
-    return;
-  }
-
-  /* Don't even process incoming broadcasts/multicasts. */
-  if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||
-      ip_addr_ismulticast(&(iphdr->dest))) {
-    snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
-  }
-
-#if CHECKSUM_CHECK_TCP
-  /* Verify TCP checksum. */
-  if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
-      (struct ip_addr *)&(iphdr->dest),
-      IP_PROTO_TCP, p->tot_len) != 0) {
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
-        inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest),
-      IP_PROTO_TCP, p->tot_len)));
-#if TCP_DEBUG
-    tcp_debug_print(tcphdr);
-#endif /* TCP_DEBUG */
-    TCP_STATS_INC(tcp.chkerr);
-    TCP_STATS_INC(tcp.drop);
-    snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
-  }
-#endif
-
-  /* Move the payload pointer in the pbuf so that it points to the
-     TCP data instead of the TCP header. */
-  hdrlen = TCPH_HDRLEN(tcphdr);
-  pbuf_header(p, -(hdrlen * 4));
-
-  /* Convert fields in TCP header to host byte order. */
-  tcphdr->src = ntohs(tcphdr->src);
-  tcphdr->dest = ntohs(tcphdr->dest);
-  seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
-  ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
-  tcphdr->wnd = ntohs(tcphdr->wnd);
-
-  flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;
-  tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);
-
-  /* Demultiplex an incoming segment. First, we check if it is destined
-     for an active connection. */
-  prev = NULL;
-
-  
-  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-    LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
-    LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
-    LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
-    if (pcb->remote_port == tcphdr->src &&
-       pcb->local_port == tcphdr->dest &&
-       ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
-       ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
-
-      /* Move this PCB to the front of the list so that subsequent
-         lookups will be faster (we exploit locality in TCP segment
-         arrivals). */
-      LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
-      if (prev != NULL) {
-        prev->next = pcb->next;
-        pcb->next = tcp_active_pcbs;
-        tcp_active_pcbs = pcb;
-      }
-      LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
-      break;
-    }
-    prev = pcb;
-  }
-
-  if (pcb == NULL) {
-    /* If it did not go to an active connection, we check the connections
-       in the TIME-WAIT state. */
-    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
-      LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
-      if (pcb->remote_port == tcphdr->src &&
-         pcb->local_port == tcphdr->dest &&
-         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
-         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
-        /* We don't really care enough to move this PCB to the front
-           of the list since we are not very likely to receive that
-           many segments for connections in TIME-WAIT. */
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
-        tcp_timewait_input(pcb);
-        pbuf_free(p);
-        return;
-      }
-    }
-
-  /* Finally, if we still did not get a match, we check all PCBs that
-     are LISTENing for incoming connections. */
-    prev = NULL;
-    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
-      if ((ip_addr_isany(&(lpcb->local_ip)) ||
-        ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&
-        lpcb->local_port == tcphdr->dest) {
-        /* Move this PCB to the front of the list so that subsequent
-           lookups will be faster (we exploit locality in TCP segment
-           arrivals). */
-        if (prev != NULL) {
-          ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
-                /* our successor is the remainder of the listening list */
-          lpcb->next = tcp_listen_pcbs.listen_pcbs;
-                /* put this listening pcb at the head of the listening list */
-          tcp_listen_pcbs.listen_pcbs = lpcb;
-        }
-      
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
-        tcp_listen_input(lpcb);
-        pbuf_free(p);
-        return;
-      }
-      prev = (struct tcp_pcb *)lpcb;
-    }
-  }
-
-#if TCP_INPUT_DEBUG
-  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
-  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
-  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
-#endif /* TCP_INPUT_DEBUG */
-
-
-  if (pcb != NULL) {
-    /* The incoming segment belongs to a connection. */
-#if TCP_INPUT_DEBUG
-#if TCP_DEBUG
-    tcp_debug_print_state(pcb->state);
-#endif /* TCP_DEBUG */
-#endif /* TCP_INPUT_DEBUG */
-
-    /* Set up a tcp_seg structure. */
-    inseg.next = NULL;
-    inseg.len = p->tot_len;
-    inseg.dataptr = p->payload;
-    inseg.p = p;
-    inseg.tcphdr = tcphdr;
-
-    recv_data = NULL;
-    recv_flags = 0;
-
-    tcp_input_pcb = pcb;
-    err = tcp_process(pcb);
-    tcp_input_pcb = NULL;
-    /* A return value of ERR_ABRT means that tcp_abort() was called
-       and that the pcb has been freed. If so, we don't do anything. */
-    if (err != ERR_ABRT) {
-      if (recv_flags & TF_RESET) {
-        /* TF_RESET means that the connection was reset by the other
-           end. We then call the error callback to inform the
-           application that the connection is dead before we
-           deallocate the PCB. */
-        TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
-        tcp_pcb_remove(&tcp_active_pcbs, pcb);
-        memp_free(MEMP_TCP_PCB, pcb);
-            } else if (recv_flags & TF_CLOSED) {
-        /* The connection has been closed and we will deallocate the
-           PCB. */
-        tcp_pcb_remove(&tcp_active_pcbs, pcb);
-        memp_free(MEMP_TCP_PCB, pcb);
-            } else {
-        err = ERR_OK;
-        /* If the application has registered a "sent" function to be
-           called when new send buffer space is available, we call it
-           now. */
-        if (pcb->acked > 0) {
-          TCP_EVENT_SENT(pcb, pcb->acked, err);
-        }
-      
-        if (recv_data != NULL) {
-          /* Notify application that data has been received. */
-          TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
-        }
-      
-        /* If a FIN segment was received, we call the callback
-           function with a NULL buffer to indicate EOF. */
-        if (recv_flags & TF_GOT_FIN) {
-          TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);
-        }
-        /* If there were no errors, we try to send something out. */
-        if (err == ERR_OK) {
-          tcp_output(pcb);
-        }
-      }
-    }
-
-
-    /* give up our reference to inseg.p */
-    if (inseg.p != NULL)
-    {
-      pbuf_free(inseg.p);
-      inseg.p = NULL;
-    }
-#if TCP_INPUT_DEBUG
-#if TCP_DEBUG
-    tcp_debug_print_state(pcb->state);
-#endif /* TCP_DEBUG */
-#endif /* TCP_INPUT_DEBUG */
-      
-  } else {
-
-    /* If no matching PCB was found, send a TCP RST (reset) to the
-       sender. */
-    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
-    if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
-      TCP_STATS_INC(tcp.proterr);
-      TCP_STATS_INC(tcp.drop);
-      tcp_rst(ackno, seqno + tcplen,
-        &(iphdr->dest), &(iphdr->src),
-        tcphdr->dest, tcphdr->src);
-    }
-    pbuf_free(p);
-  }
-
-  LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
-  PERF_STOP("tcp_input");
-}
-
-/* tcp_listen_input():
- *
- * Called by tcp_input() when a segment arrives for a listening
- * connection.
- */
-
-static err_t
-tcp_listen_input(struct tcp_pcb_listen *pcb)
-{
-  struct tcp_pcb *npcb;
-  u32_t optdata;
-
-  /* In the LISTEN state, we check for incoming SYN segments,
-     creates a new PCB, and responds with a SYN|ACK. */
-  if (flags & TCP_ACK) {
-    /* For incoming segments with the ACK flag set, respond with a
-       RST. */
-    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
-    tcp_rst(ackno + 1, seqno + tcplen,
-      &(iphdr->dest), &(iphdr->src),
-      tcphdr->dest, tcphdr->src);
-  } else if (flags & TCP_SYN) {
-    LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
-    npcb = tcp_alloc(pcb->prio);
-    /* If a new PCB could not be created (probably due to lack of memory),
-       we don't do anything, but rely on the sender will retransmit the
-       SYN at a time when we have more memory available. */
-    if (npcb == NULL) {
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
-      TCP_STATS_INC(tcp.memerr);
-      return ERR_MEM;
-    }
-    /* Set up the new PCB. */
-    ip_addr_set(&(npcb->local_ip), &(iphdr->dest));
-    npcb->local_port = pcb->local_port;
-    ip_addr_set(&(npcb->remote_ip), &(iphdr->src));
-    npcb->remote_port = tcphdr->src;
-    npcb->state = SYN_RCVD;
-    npcb->rcv_nxt = seqno + 1;
-    npcb->snd_wnd = tcphdr->wnd;
-    npcb->ssthresh = npcb->snd_wnd;
-    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
-    npcb->callback_arg = pcb->callback_arg;
-#if LWIP_CALLBACK_API
-    npcb->accept = pcb->accept;
-#endif /* LWIP_CALLBACK_API */
-    /* inherit socket options */
-    npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);
-    /* Register the new PCB so that we can begin receiving segments
-       for it. */
-    TCP_REG(&tcp_active_pcbs, npcb);
-
-    /* Parse any options in the SYN. */
-    tcp_parseopt(npcb);
-
-    snmp_inc_tcppassiveopens();
-
-    /* Build an MSS option. */
-    optdata = htonl(((u32_t)2 << 24) |
-        ((u32_t)4 << 16) |
-        (((u32_t)npcb->mss / 256) << 8) |
-        (npcb->mss & 255));
-    /* Send a SYN|ACK together with the MSS option. */
-    tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4);
-    return tcp_output(npcb);
-  }
-  return ERR_OK;
-}
-
-/* tcp_timewait_input():
- *
- * Called by tcp_input() when a segment arrives for a connection in
- * TIME_WAIT.
- */
-
-static err_t
-tcp_timewait_input(struct tcp_pcb *pcb)
-{
-  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {
-    pcb->rcv_nxt = seqno + tcplen;
-  }
-  if (tcplen > 0) {
-    tcp_ack_now(pcb);
-  }
-  return tcp_output(pcb);
-}
-
-/* tcp_process
- *
- * Implements the TCP state machine. Called by tcp_input. In some
- * states tcp_receive() is called to receive data. The tcp_seg
- * argument will be freed by the caller (tcp_input()) unless the
- * recv_data pointer in the pcb is set.
- */
-
-static err_t
-tcp_process(struct tcp_pcb *pcb)
-{
-  struct tcp_seg *rseg;
-  u8_t acceptable = 0;
-  err_t err;
-  u8_t accepted_inseq;
-
-  err = ERR_OK;
-
-  /* Process incoming RST segments. */
-  if (flags & TCP_RST) {
-    /* First, determine if the reset is acceptable. */
-    if (pcb->state == SYN_SENT) {
-      if (ackno == pcb->snd_nxt) {
-        acceptable = 1;
-      }
-    } else {
-      /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
-          TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
-      */
-      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
-        acceptable = 1;
-      }
-    }
-
-    if (acceptable) {
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
-      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
-      recv_flags = TF_RESET;
-      pcb->flags &= ~TF_ACK_DELAY;
-      return ERR_RST;
-    } else {
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
-       seqno, pcb->rcv_nxt));
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
-       seqno, pcb->rcv_nxt));
-      return ERR_OK;
-    }
-  }
-
-  /* Update the PCB (in)activity timer. */
-  pcb->tmr = tcp_ticks;
-  pcb->keep_cnt = 0;
-
-  /* Do different things depending on the TCP state. */
-  switch (pcb->state) {
-  case SYN_SENT:
-    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
-     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
-    /* received SYN ACK with expected sequence number? */
-    if ((flags & TCP_ACK) && (flags & TCP_SYN)
-        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
-      pcb->snd_buf++;
-      pcb->rcv_nxt = seqno + 1;
-      pcb->lastack = ackno;
-      pcb->snd_wnd = tcphdr->wnd;
-      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
-      pcb->state = ESTABLISHED;
-      pcb->cwnd = pcb->mss;
-      --pcb->snd_queuelen;
-      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
-      rseg = pcb->unacked;
-      pcb->unacked = rseg->next;
-      tcp_seg_free(rseg);
-
-      /* Parse any options in the SYNACK. */
-      tcp_parseopt(pcb);
-
-      /* Call the user specified function to call when sucessfully
-       * connected. */
-      TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
-      tcp_ack(pcb);
-    }
-    /* received ACK? possibly a half-open connection */
-    else if (flags & TCP_ACK) {
-      /* send a RST to bring the other side in a non-synchronized state. */
-      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
-        tcphdr->dest, tcphdr->src);
-    }
-    break;
-  case SYN_RCVD:
-    if (flags & TCP_ACK &&
-       !(flags & TCP_RST)) {
-      /* expected ACK number? */
-      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
-        pcb->state = ESTABLISHED;
-        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-#if LWIP_CALLBACK_API
-        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
-#endif
-        /* Call the accept function. */
-        TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
-        if (err != ERR_OK) {
-          /* If the accept function returns with an error, we abort
-           * the connection. */
-          tcp_abort(pcb);
-          return ERR_ABRT;
-        }
-        /* If there was any data contained within this ACK,
-         * we'd better pass it on to the application as well. */
-        tcp_receive(pcb);
-        pcb->cwnd = pcb->mss;
-      }
-      /* incorrect ACK number */
-      else {
-        /* send RST */
-        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
-          tcphdr->dest, tcphdr->src);
-      }
-    }
-    break;
-  case CLOSE_WAIT:
-    /* FALLTHROUGH */
-  case ESTABLISHED:
-    accepted_inseq = tcp_receive(pcb);
-    if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */
-      tcp_ack_now(pcb);
-      pcb->state = CLOSE_WAIT;
-    }
-    break;
-  case FIN_WAIT_1:
-    tcp_receive(pcb);
-    if (flags & TCP_FIN) {
-      if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
-        LWIP_DEBUGF(TCP_DEBUG,
-          ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-        tcp_ack_now(pcb);
-        tcp_pcb_purge(pcb);
-        TCP_RMV(&tcp_active_pcbs, pcb);
-        pcb->state = TIME_WAIT;
-        TCP_REG(&tcp_tw_pcbs, pcb);
-      } else {
-        tcp_ack_now(pcb);
-        pcb->state = CLOSING;
-      }
-    } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
-      pcb->state = FIN_WAIT_2;
-    }
-    break;
-  case FIN_WAIT_2:
-    tcp_receive(pcb);
-    if (flags & TCP_FIN) {
-      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-      tcp_ack_now(pcb);
-      tcp_pcb_purge(pcb);
-      TCP_RMV(&tcp_active_pcbs, pcb);
-      pcb->state = TIME_WAIT;
-      TCP_REG(&tcp_tw_pcbs, pcb);
-    }
-    break;
-  case CLOSING:
-    tcp_receive(pcb);
-    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
-      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-      tcp_ack_now(pcb);
-      tcp_pcb_purge(pcb);
-      TCP_RMV(&tcp_active_pcbs, pcb);
-      pcb->state = TIME_WAIT;
-      TCP_REG(&tcp_tw_pcbs, pcb);
-    }
-    break;
-  case LAST_ACK:
-    tcp_receive(pcb);
-    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
-      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-      pcb->state = CLOSED;
-      recv_flags = TF_CLOSED;
-    }
-    break;
-  default:
-    break;
-  }
-  return ERR_OK;
-}
-
-/* tcp_receive:
- *
- * Called by tcp_process. Checks if the given segment is an ACK for outstanding
- * data, and if so frees the memory of the buffered data. Next, is places the
- * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
- * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
- * i it has been removed from the buffer.
- *
- * If the incoming segment constitutes an ACK for a segment that was used for RTT
- * estimation, the RTT is estimated here as well.
- *
- * @return 1 if 
- */
-
-static u8_t
-tcp_receive(struct tcp_pcb *pcb)
-{
-  struct tcp_seg *next;
-#if TCP_QUEUE_OOSEQ
-  struct tcp_seg *prev, *cseg;
-#endif
-  struct pbuf *p;
-  s32_t off;
-  s16_t m;
-  u32_t right_wnd_edge;
-  u16_t new_tot_len;
-  u8_t accepted_inseq = 0;
-
-  if (flags & TCP_ACK) {
-    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;
-
-    /* Update window. */
-    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
-       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
-       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
-      pcb->snd_wnd = tcphdr->wnd;
-      pcb->snd_wl1 = seqno;
-      pcb->snd_wl2 = ackno;
-      LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U32_F"\n", pcb->snd_wnd));
-#if TCP_WND_DEBUG
-    } else {
-      if (pcb->snd_wnd != tcphdr->wnd) {
-        LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" snd_max %"U32_F" ackno %"U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
-                               pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
-      }
-#endif /* TCP_WND_DEBUG */
-    }
-
-    if (pcb->lastack == ackno) {
-      pcb->acked = 0;
-
-      if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){
-        ++pcb->dupacks;
-        if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
-          if (!(pcb->flags & TF_INFR)) {
-            /* This is fast retransmit. Retransmit the first unacked segment. */
-            LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n",
-                                       (u16_t)pcb->dupacks, pcb->lastack,
-                                       ntohl(pcb->unacked->tcphdr->seqno)));
-            tcp_rexmit(pcb);
-            /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */
-            /*pcb->ssthresh = LWIP_MAX((pcb->snd_max -
-                                      pcb->lastack) / 2,
-                                      2 * pcb->mss);*/
-            /* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */
-            if (pcb->cwnd > pcb->snd_wnd)
-              pcb->ssthresh = pcb->snd_wnd / 2;
-            else
-              pcb->ssthresh = pcb->cwnd / 2;
-
-            pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
-            pcb->flags |= TF_INFR;
-          } else {
-            /* Inflate the congestion window, but not if it means that
-               the value overflows. */
-            if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
-              pcb->cwnd += pcb->mss;
-            }
-          }
-        }
-      } else {
-        LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",
-                                   pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));
-      }
-    } else
-      /*if (TCP_SEQ_LT(pcb->lastack, ackno) &&
-        TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */
-      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){
-      /* We come here when the ACK acknowledges new data. */
-      
-      /* Reset the "IN Fast Retransmit" flag, since we are no longer
-         in fast retransmit. Also reset the congestion window to the
-         slow start threshold. */
-      if (pcb->flags & TF_INFR) {
-        pcb->flags &= ~TF_INFR;
-        pcb->cwnd = pcb->ssthresh;
-      }
-
-      /* Reset the number of retransmissions. */
-      pcb->nrtx = 0;
-
-      /* Reset the retransmission time-out. */
-      pcb->rto = (pcb->sa >> 3) + pcb->sv;
-
-      /* Update the send buffer space. */
-      pcb->acked = ackno - pcb->lastack;
-
-      pcb->snd_buf += pcb->acked;
-
-      /* Reset the fast retransmit variables. */
-      pcb->dupacks = 0;
-      pcb->lastack = ackno;
-
-      /* Update the congestion control variables (cwnd and
-         ssthresh). */
-      if (pcb->state >= ESTABLISHED) {
-        if (pcb->cwnd < pcb->ssthresh) {
-          if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
-            pcb->cwnd += pcb->mss;
-          }
-          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
-        } else {
-          u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
-          if (new_cwnd > pcb->cwnd) {
-            pcb->cwnd = new_cwnd;
-          }
-          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
-        }
-      }
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
-                                    ackno,
-                                    pcb->unacked != NULL?
-                                    ntohl(pcb->unacked->tcphdr->seqno): 0,
-                                    pcb->unacked != NULL?
-                                    ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
-
-      /* Remove segment from the unacknowledged list if the incoming
-         ACK acknowlegdes them. */
-      while (pcb->unacked != NULL &&
-             TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
-                         TCP_TCPLEN(pcb->unacked), ackno)) {
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
-                                      ntohl(pcb->unacked->tcphdr->seqno),
-                                      ntohl(pcb->unacked->tcphdr->seqno) +
-                                      TCP_TCPLEN(pcb->unacked)));
-
-        next = pcb->unacked;
-        pcb->unacked = pcb->unacked->next;
-
-        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
-        pcb->snd_queuelen -= pbuf_clen(next->p);
-        tcp_seg_free(next);
-
-        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
-        if (pcb->snd_queuelen != 0) {
-          LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
-                      pcb->unsent != NULL);
-        }
-      }
-      pcb->polltmr = 0;
-    }
-
-    /* We go through the ->unsent list to see if any of the segments
-       on the list are acknowledged by the ACK. This may seem
-       strange since an "unsent" segment shouldn't be acked. The
-       rationale is that lwIP puts all outstanding segments on the
-       ->unsent list after a retransmission, so these segments may
-       in fact have been sent once. */
-    while (pcb->unsent != NULL &&
-           /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&
-             TCP_SEQ_LEQ(ackno, pcb->snd_max)*/
-           TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)
-           ) {
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
-                                    ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
-                                    TCP_TCPLEN(pcb->unsent)));
-
-      next = pcb->unsent;
-      pcb->unsent = pcb->unsent->next;
-      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
-      pcb->snd_queuelen -= pbuf_clen(next->p);
-      tcp_seg_free(next);
-      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
-      if (pcb->snd_queuelen != 0) {
-        LWIP_ASSERT("tcp_receive: valid queue length",
-          pcb->unacked != NULL || pcb->unsent != NULL);
-      }
-
-      if (pcb->unsent != NULL) {
-        pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
-      }
-    }
-    /* End of ACK for new data processing. */
-
-    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
-                                pcb->rttest, pcb->rtseq, ackno));
-
-    /* RTT estimation calculations. This is done by checking if the
-       incoming segment acknowledges the segment we use to take a
-       round-trip time measurement. */
-    if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
-      m = tcp_ticks - pcb->rttest;
-
-      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
-                                  m, m * TCP_SLOW_INTERVAL));
-
-      /* This is taken directly from VJs original code in his paper */
-      m = m - (pcb->sa >> 3);
-      pcb->sa += m;
-      if (m < 0) {
-        m = -m;
-      }
-      m = m - (pcb->sv >> 2);
-      pcb->sv += m;
-      pcb->rto = (pcb->sa >> 3) + pcb->sv;
-
-      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" miliseconds)\n",
-                                  pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
-
-      pcb->rttest = 0;
-    }
-  }
-
-  /* If the incoming segment contains data, we must process it
-     further. */
-  if (tcplen > 0) {
-    /* This code basically does three things:
-
-    +) If the incoming segment contains data that is the next
-    in-sequence data, this data is passed to the application. This
-    might involve trimming the first edge of the data. The rcv_nxt
-    variable and the advertised window are adjusted.
-
-    +) If the incoming segment has data that is above the next
-    sequence number expected (->rcv_nxt), the segment is placed on
-    the ->ooseq queue. This is done by finding the appropriate
-    place in the ->ooseq queue (which is ordered by sequence
-    number) and trim the segment in both ends if needed. An
-    immediate ACK is sent to indicate that we received an
-    out-of-sequence segment.
-
-    +) Finally, we check if the first segment on the ->ooseq queue
-    now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
-    rcv_nxt > ooseq->seqno, we must trim the first edge of the
-    segment on ->ooseq before we adjust rcv_nxt. The data in the
-    segments that are now on sequence are chained onto the
-    incoming segment so that we only need to call the application
-    once.
-    */
-
-    /* First, we check if we must trim the first edge. We have to do
-       this if the sequence number of the incoming segment is less
-       than rcv_nxt, and the sequence number plus the length of the
-       segment is larger than rcv_nxt. */
-    /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
-          if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
-    if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
-      /* Trimming the first edge is done by pushing the payload
-         pointer in the pbuf downwards. This is somewhat tricky since
-         we do not want to discard the full contents of the pbuf up to
-         the new starting point of the data since we have to keep the
-         TCP header which is present in the first pbuf in the chain.
-         
-         What is done is really quite a nasty hack: the first pbuf in
-         the pbuf chain is pointed to by inseg.p. Since we need to be
-         able to deallocate the whole pbuf, we cannot change this
-         inseg.p pointer to point to any of the later pbufs in the
-         chain. Instead, we point the ->payload pointer in the first
-         pbuf to data in one of the later pbufs. We also set the
-         inseg.data pointer to point to the right place. This way, the
-         ->p pointer will still point to the first pbuf, but the
-         ->p->payload pointer will point to data in another pbuf.
-         
-         After we are done with adjusting the pbuf pointers we must
-         adjust the ->data pointer in the seg and the segment
-         length.*/
-      
-      off = pcb->rcv_nxt - seqno;
-      p = inseg.p;
-      LWIP_ASSERT("inseg.p != NULL", inseg.p);
-      if (inseg.p->len < off) {
-        new_tot_len = inseg.p->tot_len - off;
-        while (p->len < off) {
-          off -= p->len;
-          /* KJM following line changed (with addition of new_tot_len var)
-             to fix bug #9076
-             inseg.p->tot_len -= p->len; */
-          p->tot_len = new_tot_len;
-          p->len = 0;
-          p = p->next;
-        }
-        pbuf_header(p, -off);
-      } else {
-        pbuf_header(inseg.p, -off);
-      }
-      /* KJM following line changed to use p->payload rather than inseg->p->payload
-         to fix bug #9076 */
-      inseg.dataptr = p->payload;
-      inseg.len -= pcb->rcv_nxt - seqno;
-      inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
-    }
-    else {
-      if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
-        /* the whole segment is < rcv_nxt */
-        /* must be a duplicate of a packet that has already been correctly handled */
-        
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
-        tcp_ack_now(pcb);
-      }
-    }
-
-    /* The sequence number must be within the window (above rcv_nxt
-       and below rcv_nxt + rcv_wnd) in order to be further
-       processed. */
-    /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
-      TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
-    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){
-      if (pcb->rcv_nxt == seqno) {
-        accepted_inseq = 1; 
-        /* The incoming segment is the next in sequence. We check if
-           we have to trim the end of the segment and update rcv_nxt
-           and pass the data to the application. */
-#if TCP_QUEUE_OOSEQ
-        if (pcb->ooseq != NULL &&
-            TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
-          /* We have to trim the second edge of the incoming
-             segment. */
-          inseg.len = pcb->ooseq->tcphdr->seqno - seqno;
-          pbuf_realloc(inseg.p, inseg.len);
-        }
-#endif /* TCP_QUEUE_OOSEQ */
-
-        tcplen = TCP_TCPLEN(&inseg);
-
-        /* First received FIN will be ACKed +1, on any successive (duplicate)
-         * FINs we are already in CLOSE_WAIT and have already done +1.
-         */
-        if (pcb->state != CLOSE_WAIT) {
-          pcb->rcv_nxt += tcplen;
-        }
-
-        /* Update the receiver's (our) window. */
-        if (pcb->rcv_wnd < tcplen) {
-          pcb->rcv_wnd = 0;
-        } else {
-          pcb->rcv_wnd -= tcplen;
-        }
-
-        /* If there is data in the segment, we make preparations to
-           pass this up to the application. The ->recv_data variable
-           is used for holding the pbuf that goes to the
-           application. The code for reassembling out-of-sequence data
-           chains its data on this pbuf as well.
-
-           If the segment was a FIN, we set the TF_GOT_FIN flag that will
-           be used to indicate to the application that the remote side has
-           closed its end of the connection. */
-        if (inseg.p->tot_len > 0) {
-          recv_data = inseg.p;
-          /* Since this pbuf now is the responsibility of the
-             application, we delete our reference to it so that we won't
-             (mistakingly) deallocate it. */
-          inseg.p = NULL;
-        }
-        if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
-          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
-          recv_flags = TF_GOT_FIN;
-        }
-
-#if TCP_QUEUE_OOSEQ
-        /* We now check if we have segments on the ->ooseq queue that
-           is now in sequence. */
-        while (pcb->ooseq != NULL &&
-               pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
-
-          cseg = pcb->ooseq;
-          seqno = pcb->ooseq->tcphdr->seqno;
-
-          pcb->rcv_nxt += TCP_TCPLEN(cseg);
-          if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
-            pcb->rcv_wnd = 0;
-          } else {
-            pcb->rcv_wnd -= TCP_TCPLEN(cseg);
-          }
-          if (cseg->p->tot_len > 0) {
-            /* Chain this pbuf onto the pbuf that we will pass to
-               the application. */
-            if (recv_data) {
-              pbuf_cat(recv_data, cseg->p);
-            } else {
-              recv_data = cseg->p;
-            }
-            cseg->p = NULL;
-          }
-          if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
-            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
-            recv_flags = TF_GOT_FIN;
-            if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
-              pcb->state = CLOSE_WAIT;
-            } 
-          }
-
-
-          pcb->ooseq = cseg->next;
-          tcp_seg_free(cseg);
-        }
-#endif /* TCP_QUEUE_OOSEQ */
-
-
-        /* Acknowledge the segment(s). */
-        tcp_ack(pcb);
-
-      } else {
-        /* We get here if the incoming segment is out-of-sequence. */
-        tcp_ack_now(pcb);
-#if TCP_QUEUE_OOSEQ
-        /* We queue the segment on the ->ooseq queue. */
-        if (pcb->ooseq == NULL) {
-          pcb->ooseq = tcp_seg_copy(&inseg);
-        } else {
-          /* If the queue is not empty, we walk through the queue and
-             try to find a place where the sequence number of the
-             incoming segment is between the sequence numbers of the
-             previous and the next segment on the ->ooseq queue. That is
-             the place where we put the incoming segment. If needed, we
-             trim the second edges of the previous and the incoming
-             segment so that it will fit into the sequence.
-
-             If the incoming segment has the same sequence number as a
-             segment on the ->ooseq queue, we discard the segment that
-             contains less data. */
-
-          prev = NULL;
-          for(next = pcb->ooseq; next != NULL; next = next->next) {
-            if (seqno == next->tcphdr->seqno) {
-              /* The sequence number of the incoming segment is the
-                 same as the sequence number of the segment on
-                 ->ooseq. We check the lengths to see which one to
-                 discard. */
-              if (inseg.len > next->len) {
-                /* The incoming segment is larger than the old
-                   segment. We replace the old segment with the new
-                   one. */
-                cseg = tcp_seg_copy(&inseg);
-                if (cseg != NULL) {
-                  cseg->next = next->next;
-                  if (prev != NULL) {
-                    prev->next = cseg;
-                  } else {
-                    pcb->ooseq = cseg;
-                  }
-                }
-                break;
-              } else {
-                /* Either the lenghts are the same or the incoming
-                   segment was smaller than the old one; in either
-                   case, we ditch the incoming segment. */
-                break;
-              }
-            } else {
-              if (prev == NULL) {
-                if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
-                  /* The sequence number of the incoming segment is lower
-                     than the sequence number of the first segment on the
-                     queue. We put the incoming segment first on the
-                     queue. */
-
-                  if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
-                    /* We need to trim the incoming segment. */
-                    inseg.len = next->tcphdr->seqno - seqno;
-                    pbuf_realloc(inseg.p, inseg.len);
-                  }
-                  cseg = tcp_seg_copy(&inseg);
-                  if (cseg != NULL) {
-                    cseg->next = next;
-                    pcb->ooseq = cseg;
-                  }
-                  break;
-                }
-              } else 
-                /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
-                  TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
-                if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){
-                /* The sequence number of the incoming segment is in
-                   between the sequence numbers of the previous and
-                   the next segment on ->ooseq. We trim and insert the
-                   incoming segment and trim the previous segment, if
-                   needed. */
-                if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
-                  /* We need to trim the incoming segment. */
-                  inseg.len = next->tcphdr->seqno - seqno;
-                  pbuf_realloc(inseg.p, inseg.len);
-                }
-
-                cseg = tcp_seg_copy(&inseg);
-                if (cseg != NULL) {
-                  cseg->next = next;
-                  prev->next = cseg;
-                  if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
-                    /* We need to trim the prev segment. */
-                    prev->len = seqno - prev->tcphdr->seqno;
-                    pbuf_realloc(prev->p, prev->len);
-                  }
-                }
-                break;
-              }
-              /* If the "next" segment is the last segment on the
-                 ooseq queue, we add the incoming segment to the end
-                 of the list. */
-              if (next->next == NULL &&
-                  TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
-                next->next = tcp_seg_copy(&inseg);
-                if (next->next != NULL) {
-                  if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
-                    /* We need to trim the last segment. */
-                    next->len = seqno - next->tcphdr->seqno;
-                    pbuf_realloc(next->p, next->len);
-                  }
-                }
-                break;
-              }
-            }
-            prev = next;
-          }
-        }
-#endif /* TCP_QUEUE_OOSEQ */
-
-      }
-    } else {
-      /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
-        TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
-      if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
-        tcp_ack_now(pcb);
-      }
-    }
-  } else {
-    /* Segments with length 0 is taken care of here. Segments that
-       fall out of the window are ACKed. */
-    /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
-      TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
-    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
-      tcp_ack_now(pcb);
-    }
-  }
-  return accepted_inseq;
-}
-
-/*
- * tcp_parseopt:
- *
- * Parses the options contained in the incoming segment. (Code taken
- * from uIP with only small changes.)
- *
- */
-
-static void
-tcp_parseopt(struct tcp_pcb *pcb)
-{
-  u8_t c;
-  u8_t *opts, opt;
-  u16_t mss;
-
-  opts = (u8_t *)tcphdr + TCP_HLEN;
-
-  /* Parse the TCP MSS option, if present. */
-  if(TCPH_HDRLEN(tcphdr) > 0x5) {
-    for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) {
-      opt = opts[c];
-      if (opt == 0x00) {
-        /* End of options. */
-  break;
-      } else if (opt == 0x01) {
-        ++c;
-        /* NOP option. */
-      } else if (opt == 0x02 &&
-        opts[c + 1] == 0x04) {
-        /* An MSS option with the right option length. */
-        mss = (opts[c + 2] << 8) | opts[c + 3];
-        pcb->mss = mss > TCP_MSS? TCP_MSS: mss;
-
-        /* And we are done processing options. */
-        break;
-      } else {
-  if (opts[c + 1] == 0) {
-          /* If the length field is zero, the options are malformed
-             and we don't process them further. */
-          break;
-        }
-        /* All other options have a length field, so that we easily
-           can skip past them. */
-        c += opts[c + 1];
-      }
-    }
-  }
-}
-#endif /* LWIP_TCP */
-
-
+/**

+ * @file

+ *

+ * Transmission Control Protocol, incoming traffic

+ *

+ * The input processing functions of the TCP layer.

+ *

+ * These functions are generally called in the order (ip_input() ->)

+ * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).

+ * 

+ */

+

+/*

+ * 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/def.h"

+#include "lwip/opt.h"

+

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+

+#include "lwip/inet.h"

+#include "lwip/tcp.h"

+

+#include "lwip/stats.h"

+#include "arch/perf.h"

+#include "lwip/snmp.h"

+

+#if LWIP_TCP

+/* These variables are global to all functions involved in the input

+   processing of TCP segments. They are set by the tcp_input()

+   function. */

+static struct tcp_seg inseg;

+static struct tcp_hdr *tcphdr;

+static struct ip_hdr *iphdr;

+static u32_t seqno, ackno;

+static u8_t flags;

+static u16_t tcplen;

+

+static u8_t recv_flags;

+static struct pbuf *recv_data;

+

+struct tcp_pcb *tcp_input_pcb;

+

+/* Forward declarations. */

+static err_t tcp_process(struct tcp_pcb *pcb);

+static u8_t tcp_receive(struct tcp_pcb *pcb);

+static void tcp_parseopt(struct tcp_pcb *pcb);

+

+static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);

+static err_t tcp_timewait_input(struct tcp_pcb *pcb);

+

+/* tcp_input:

+ *

+ * The initial input processing of TCP. It verifies the TCP header, demultiplexes

+ * the segment between the PCBs and passes it on to tcp_process(), which implements

+ * the TCP finite state machine. This function is called by the IP layer (in

+ * ip_input()).

+ */

+

+void

+tcp_input(struct pbuf *p, struct netif *inp)

+{

+  struct tcp_pcb *pcb, *prev;

+  struct tcp_pcb_listen *lpcb;

+  u8_t hdrlen;

+  err_t err;

+

+  PERF_START;

+

+  TCP_STATS_INC(tcp.recv);

+  snmp_inc_tcpinsegs();

+

+  iphdr = p->payload;

+  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);

+

+#if TCP_INPUT_DEBUG

+  tcp_debug_print(tcphdr);

+#endif

+

+  /* remove header from payload */

+  if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {

+    /* drop short packets */

+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));

+    TCP_STATS_INC(tcp.lenerr);

+    TCP_STATS_INC(tcp.drop);

+    pbuf_free(p);

+    return;

+  }

+

+  /* Don't even process incoming broadcasts/multicasts. */

+  if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||

+      ip_addr_ismulticast(&(iphdr->dest))) {

+    snmp_inc_tcpinerrs();

+    pbuf_free(p);

+    return;

+  }

+

+#if CHECKSUM_CHECK_TCP

+  /* Verify TCP checksum. */

+  if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),

+      (struct ip_addr *)&(iphdr->dest),

+      IP_PROTO_TCP, p->tot_len) != 0) {

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",

+        inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest),

+      IP_PROTO_TCP, p->tot_len)));

+#if TCP_DEBUG

+    tcp_debug_print(tcphdr);

+#endif /* TCP_DEBUG */

+    TCP_STATS_INC(tcp.chkerr);

+    TCP_STATS_INC(tcp.drop);

+    snmp_inc_tcpinerrs();

+    pbuf_free(p);

+    return;

+  }

+#endif

+

+  /* Move the payload pointer in the pbuf so that it points to the

+     TCP data instead of the TCP header. */

+  hdrlen = TCPH_HDRLEN(tcphdr);

+  pbuf_header(p, -(hdrlen * 4));

+

+  /* Convert fields in TCP header to host byte order. */

+  tcphdr->src = ntohs(tcphdr->src);

+  tcphdr->dest = ntohs(tcphdr->dest);

+  seqno = tcphdr->seqno = ntohl(tcphdr->seqno);

+  ackno = tcphdr->ackno = ntohl(tcphdr->ackno);

+  tcphdr->wnd = ntohs(tcphdr->wnd);

+

+  flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;

+  tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);

+

+  /* Demultiplex an incoming segment. First, we check if it is destined

+     for an active connection. */

+  prev = NULL;

+

+  

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);

+    LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);

+    LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);

+    if (pcb->remote_port == tcphdr->src &&

+       pcb->local_port == tcphdr->dest &&

+       ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&

+       ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {

+

+      /* Move this PCB to the front of the list so that subsequent

+         lookups will be faster (we exploit locality in TCP segment

+         arrivals). */

+      LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);

+      if (prev != NULL) {

+        prev->next = pcb->next;

+        pcb->next = tcp_active_pcbs;

+        tcp_active_pcbs = pcb;

+      }

+      LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);

+      break;

+    }

+    prev = pcb;

+  }

+

+  if (pcb == NULL) {

+    /* If it did not go to an active connection, we check the connections

+       in the TIME-WAIT state. */

+    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+      LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);

+      if (pcb->remote_port == tcphdr->src &&

+         pcb->local_port == tcphdr->dest &&

+         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&

+         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {

+        /* We don't really care enough to move this PCB to the front

+           of the list since we are not very likely to receive that

+           many segments for connections in TIME-WAIT. */

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));

+        tcp_timewait_input(pcb);

+        pbuf_free(p);

+        return;

+      }

+    }

+

+  /* Finally, if we still did not get a match, we check all PCBs that

+     are LISTENing for incoming connections. */

+    prev = NULL;

+    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {

+      if ((ip_addr_isany(&(lpcb->local_ip)) ||

+        ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&

+        lpcb->local_port == tcphdr->dest) {

+        /* Move this PCB to the front of the list so that subsequent

+           lookups will be faster (we exploit locality in TCP segment

+           arrivals). */

+        if (prev != NULL) {

+          ((struct tcp_pcb_listen *)prev)->next = lpcb->next;

+                /* our successor is the remainder of the listening list */

+          lpcb->next = tcp_listen_pcbs.listen_pcbs;

+                /* put this listening pcb at the head of the listening list */

+          tcp_listen_pcbs.listen_pcbs = lpcb;

+        }

+      

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));

+        tcp_listen_input(lpcb);

+        pbuf_free(p);

+        return;

+      }

+      prev = (struct tcp_pcb *)lpcb;

+    }

+  }

+

+#if TCP_INPUT_DEBUG

+  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));

+  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));

+  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));

+#endif /* TCP_INPUT_DEBUG */

+

+

+  if (pcb != NULL) {

+    /* The incoming segment belongs to a connection. */

+#if TCP_INPUT_DEBUG

+#if TCP_DEBUG

+    tcp_debug_print_state(pcb->state);

+#endif /* TCP_DEBUG */

+#endif /* TCP_INPUT_DEBUG */

+

+    /* Set up a tcp_seg structure. */

+    inseg.next = NULL;

+    inseg.len = p->tot_len;

+    inseg.dataptr = p->payload;

+    inseg.p = p;

+    inseg.tcphdr = tcphdr;

+

+    recv_data = NULL;

+    recv_flags = 0;

+

+    tcp_input_pcb = pcb;

+    err = tcp_process(pcb);

+    tcp_input_pcb = NULL;

+    /* A return value of ERR_ABRT means that tcp_abort() was called

+       and that the pcb has been freed. If so, we don't do anything. */

+    if (err != ERR_ABRT) {

+      if (recv_flags & TF_RESET) {

+        /* TF_RESET means that the connection was reset by the other

+           end. We then call the error callback to inform the

+           application that the connection is dead before we

+           deallocate the PCB. */

+        TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);

+        tcp_pcb_remove(&tcp_active_pcbs, pcb);

+        memp_free(MEMP_TCP_PCB, pcb);

+            } else if (recv_flags & TF_CLOSED) {

+        /* The connection has been closed and we will deallocate the

+           PCB. */

+        tcp_pcb_remove(&tcp_active_pcbs, pcb);

+        memp_free(MEMP_TCP_PCB, pcb);

+            } else {

+        err = ERR_OK;

+        /* If the application has registered a "sent" function to be

+           called when new send buffer space is available, we call it

+           now. */

+        if (pcb->acked > 0) {

+          TCP_EVENT_SENT(pcb, pcb->acked, err);

+        }

+      

+        if (recv_data != NULL) {

+          /* Notify application that data has been received. */

+          TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);

+        }

+      

+        /* If a FIN segment was received, we call the callback

+           function with a NULL buffer to indicate EOF. */

+        if (recv_flags & TF_GOT_FIN) {

+          TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);

+        }

+        /* If there were no errors, we try to send something out. */

+        if (err == ERR_OK) {

+          tcp_output(pcb);

+        }

+      }

+    }

+

+

+    /* give up our reference to inseg.p */

+    if (inseg.p != NULL)

+    {

+      pbuf_free(inseg.p);

+      inseg.p = NULL;

+    }

+#if TCP_INPUT_DEBUG

+#if TCP_DEBUG

+    tcp_debug_print_state(pcb->state);

+#endif /* TCP_DEBUG */

+#endif /* TCP_INPUT_DEBUG */

+      

+  } else {

+

+    /* If no matching PCB was found, send a TCP RST (reset) to the

+       sender. */

+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));

+    if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {

+      TCP_STATS_INC(tcp.proterr);

+      TCP_STATS_INC(tcp.drop);

+      tcp_rst(ackno, seqno + tcplen,

+        &(iphdr->dest), &(iphdr->src),

+        tcphdr->dest, tcphdr->src);

+    }

+    pbuf_free(p);

+  }

+

+  LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());

+  PERF_STOP("tcp_input");

+}

+

+/* tcp_listen_input():

+ *

+ * Called by tcp_input() when a segment arrives for a listening

+ * connection.

+ */

+

+static err_t

+tcp_listen_input(struct tcp_pcb_listen *pcb)

+{

+  struct tcp_pcb *npcb;

+  u32_t optdata;

+

+  /* In the LISTEN state, we check for incoming SYN segments,

+     creates a new PCB, and responds with a SYN|ACK. */

+  if (flags & TCP_ACK) {

+    /* For incoming segments with the ACK flag set, respond with a

+       RST. */

+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));

+    tcp_rst(ackno + 1, seqno + tcplen,

+      &(iphdr->dest), &(iphdr->src),

+      tcphdr->dest, tcphdr->src);

+  } else if (flags & TCP_SYN) {

+    LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));

+    npcb = tcp_alloc(pcb->prio);

+    /* If a new PCB could not be created (probably due to lack of memory),

+       we don't do anything, but rely on the sender will retransmit the

+       SYN at a time when we have more memory available. */

+    if (npcb == NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));

+      TCP_STATS_INC(tcp.memerr);

+      return ERR_MEM;

+    }

+    /* Set up the new PCB. */

+    ip_addr_set(&(npcb->local_ip), &(iphdr->dest));

+    npcb->local_port = pcb->local_port;

+    ip_addr_set(&(npcb->remote_ip), &(iphdr->src));

+    npcb->remote_port = tcphdr->src;

+    npcb->state = SYN_RCVD;

+    npcb->rcv_nxt = seqno + 1;

+    npcb->snd_wnd = tcphdr->wnd;

+    npcb->ssthresh = npcb->snd_wnd;

+    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */

+    npcb->callback_arg = pcb->callback_arg;

+#if LWIP_CALLBACK_API

+    npcb->accept = pcb->accept;

+#endif /* LWIP_CALLBACK_API */

+    /* inherit socket options */

+    npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);

+    /* Register the new PCB so that we can begin receiving segments

+       for it. */

+    TCP_REG(&tcp_active_pcbs, npcb);

+

+    /* Parse any options in the SYN. */

+    tcp_parseopt(npcb);

+

+    snmp_inc_tcppassiveopens();

+

+    /* Build an MSS option. */

+    optdata = htonl(((u32_t)2 << 24) |

+        ((u32_t)4 << 16) |

+        (((u32_t)npcb->mss / 256) << 8) |

+        (npcb->mss & 255));

+    /* Send a SYN|ACK together with the MSS option. */

+    tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4);

+    return tcp_output(npcb);

+  }

+  return ERR_OK;

+}

+

+/* tcp_timewait_input():

+ *

+ * Called by tcp_input() when a segment arrives for a connection in

+ * TIME_WAIT.

+ */

+

+static err_t

+tcp_timewait_input(struct tcp_pcb *pcb)

+{

+  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {

+    pcb->rcv_nxt = seqno + tcplen;

+  }

+  if (tcplen > 0) {

+    tcp_ack_now(pcb);

+  }

+  return tcp_output(pcb);

+}

+

+/* tcp_process

+ *

+ * Implements the TCP state machine. Called by tcp_input. In some

+ * states tcp_receive() is called to receive data. The tcp_seg

+ * argument will be freed by the caller (tcp_input()) unless the

+ * recv_data pointer in the pcb is set.

+ */

+

+static err_t

+tcp_process(struct tcp_pcb *pcb)

+{

+  struct tcp_seg *rseg;

+  u8_t acceptable = 0;

+  err_t err;

+  u8_t accepted_inseq;

+

+  err = ERR_OK;

+

+  /* Process incoming RST segments. */

+  if (flags & TCP_RST) {

+    /* First, determine if the reset is acceptable. */

+    if (pcb->state == SYN_SENT) {

+      if (ackno == pcb->snd_nxt) {

+        acceptable = 1;

+      }

+    } else {

+      /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&

+          TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {

+      */

+      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {

+        acceptable = 1;

+      }

+    }

+

+    if (acceptable) {

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));

+      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);

+      recv_flags = TF_RESET;

+      pcb->flags &= ~TF_ACK_DELAY;

+      return ERR_RST;

+    } else {

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",

+       seqno, pcb->rcv_nxt));

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",

+       seqno, pcb->rcv_nxt));

+      return ERR_OK;

+    }

+  }

+

+  /* Update the PCB (in)activity timer. */

+  pcb->tmr = tcp_ticks;

+  pcb->keep_cnt = 0;

+

+  /* Do different things depending on the TCP state. */

+  switch (pcb->state) {

+  case SYN_SENT:

+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,

+     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));

+    /* received SYN ACK with expected sequence number? */

+    if ((flags & TCP_ACK) && (flags & TCP_SYN)

+        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {

+      pcb->snd_buf++;

+      pcb->rcv_nxt = seqno + 1;

+      pcb->lastack = ackno;

+      pcb->snd_wnd = tcphdr->wnd;

+      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */

+      pcb->state = ESTABLISHED;

+      pcb->cwnd = pcb->mss;

+      --pcb->snd_queuelen;

+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));

+      rseg = pcb->unacked;

+      pcb->unacked = rseg->next;

+      tcp_seg_free(rseg);

+

+      /* Parse any options in the SYNACK. */

+      tcp_parseopt(pcb);

+

+      /* Call the user specified function to call when sucessfully

+       * connected. */

+      TCP_EVENT_CONNECTED(pcb, ERR_OK, err);

+      tcp_ack(pcb);

+    }

+    /* received ACK? possibly a half-open connection */

+    else if (flags & TCP_ACK) {

+      /* send a RST to bring the other side in a non-synchronized state. */

+      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),

+        tcphdr->dest, tcphdr->src);

+    }

+    break;

+  case SYN_RCVD:

+    if (flags & TCP_ACK &&

+       !(flags & TCP_RST)) {

+      /* expected ACK number? */

+      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {

+        pcb->state = ESTABLISHED;

+        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+#if LWIP_CALLBACK_API

+        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);

+#endif

+        /* Call the accept function. */

+        TCP_EVENT_ACCEPT(pcb, ERR_OK, err);

+        if (err != ERR_OK) {

+          /* If the accept function returns with an error, we abort

+           * the connection. */

+          tcp_abort(pcb);

+          return ERR_ABRT;

+        }

+        /* If there was any data contained within this ACK,

+         * we'd better pass it on to the application as well. */

+        tcp_receive(pcb);

+        pcb->cwnd = pcb->mss;

+      }

+      /* incorrect ACK number */

+      else {

+        /* send RST */

+        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),

+          tcphdr->dest, tcphdr->src);

+      }

+    }

+    break;

+  case CLOSE_WAIT:

+    /* FALLTHROUGH */

+  case ESTABLISHED:

+    accepted_inseq = tcp_receive(pcb);

+    if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */

+      tcp_ack_now(pcb);

+      pcb->state = CLOSE_WAIT;

+    }

+    break;

+  case FIN_WAIT_1:

+    tcp_receive(pcb);

+    if (flags & TCP_FIN) {

+      if (flags & TCP_ACK && ackno == pcb->snd_nxt) {

+        LWIP_DEBUGF(TCP_DEBUG,

+          ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+        tcp_ack_now(pcb);

+        tcp_pcb_purge(pcb);

+        TCP_RMV(&tcp_active_pcbs, pcb);

+        pcb->state = TIME_WAIT;

+        TCP_REG(&tcp_tw_pcbs, pcb);

+      } else {

+        tcp_ack_now(pcb);

+        pcb->state = CLOSING;

+      }

+    } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {

+      pcb->state = FIN_WAIT_2;

+    }

+    break;

+  case FIN_WAIT_2:

+    tcp_receive(pcb);

+    if (flags & TCP_FIN) {

+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+      tcp_ack_now(pcb);

+      tcp_pcb_purge(pcb);

+      TCP_RMV(&tcp_active_pcbs, pcb);

+      pcb->state = TIME_WAIT;

+      TCP_REG(&tcp_tw_pcbs, pcb);

+    }

+    break;

+  case CLOSING:

+    tcp_receive(pcb);

+    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {

+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+      tcp_ack_now(pcb);

+      tcp_pcb_purge(pcb);

+      TCP_RMV(&tcp_active_pcbs, pcb);

+      pcb->state = TIME_WAIT;

+      TCP_REG(&tcp_tw_pcbs, pcb);

+    }

+    break;

+  case LAST_ACK:

+    tcp_receive(pcb);

+    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {

+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+      pcb->state = CLOSED;

+      recv_flags = TF_CLOSED;

+    }

+    break;

+  default:

+    break;

+  }

+  return ERR_OK;

+}

+

+/* tcp_receive:

+ *

+ * Called by tcp_process. Checks if the given segment is an ACK for outstanding

+ * data, and if so frees the memory of the buffered data. Next, is places the

+ * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment

+ * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until

+ * i it has been removed from the buffer.

+ *

+ * If the incoming segment constitutes an ACK for a segment that was used for RTT

+ * estimation, the RTT is estimated here as well.

+ *

+ * @return 1 if 

+ */

+

+static u8_t

+tcp_receive(struct tcp_pcb *pcb)

+{

+  struct tcp_seg *next;

+#if TCP_QUEUE_OOSEQ

+  struct tcp_seg *prev, *cseg;

+#endif

+  struct pbuf *p;

+  s32_t off;

+  s16_t m;

+  u32_t right_wnd_edge;

+  u16_t new_tot_len;

+  u8_t accepted_inseq = 0;

+

+  if (flags & TCP_ACK) {

+    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;

+

+    /* Update window. */

+    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||

+       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||

+       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {

+      pcb->snd_wnd = tcphdr->wnd;

+      pcb->snd_wl1 = seqno;

+      pcb->snd_wl2 = ackno;

+      LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U32_F"\n", pcb->snd_wnd));

+#if TCP_WND_DEBUG

+    } else {

+      if (pcb->snd_wnd != tcphdr->wnd) {

+        LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" snd_max %"U32_F" ackno %"U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",

+                               pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));

+      }

+#endif /* TCP_WND_DEBUG */

+    }

+

+    if (pcb->lastack == ackno) {

+      pcb->acked = 0;

+

+      if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){

+        ++pcb->dupacks;

+        if (pcb->dupacks >= 3 && pcb->unacked != NULL) {

+          if (!(pcb->flags & TF_INFR)) {

+            /* This is fast retransmit. Retransmit the first unacked segment. */

+            LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n",

+                                       (u16_t)pcb->dupacks, pcb->lastack,

+                                       ntohl(pcb->unacked->tcphdr->seqno)));

+            tcp_rexmit(pcb);

+            /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */

+            /*pcb->ssthresh = LWIP_MAX((pcb->snd_max -

+                                      pcb->lastack) / 2,

+                                      2 * pcb->mss);*/

+            /* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */

+            if (pcb->cwnd > pcb->snd_wnd)

+              pcb->ssthresh = pcb->snd_wnd / 2;

+            else

+              pcb->ssthresh = pcb->cwnd / 2;

+

+            pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;

+            pcb->flags |= TF_INFR;

+          } else {

+            /* Inflate the congestion window, but not if it means that

+               the value overflows. */

+            if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {

+              pcb->cwnd += pcb->mss;

+            }

+          }

+        }

+      } else {

+        LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",

+                                   pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));

+      }

+    } else

+      /*if (TCP_SEQ_LT(pcb->lastack, ackno) &&

+        TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */

+      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){

+      /* We come here when the ACK acknowledges new data. */

+      

+      /* Reset the "IN Fast Retransmit" flag, since we are no longer

+         in fast retransmit. Also reset the congestion window to the

+         slow start threshold. */

+      if (pcb->flags & TF_INFR) {

+        pcb->flags &= ~TF_INFR;

+        pcb->cwnd = pcb->ssthresh;

+      }

+

+      /* Reset the number of retransmissions. */

+      pcb->nrtx = 0;

+

+      /* Reset the retransmission time-out. */

+      pcb->rto = (pcb->sa >> 3) + pcb->sv;

+

+      /* Update the send buffer space. */

+      pcb->acked = ackno - pcb->lastack;

+

+      pcb->snd_buf += pcb->acked;

+

+      /* Reset the fast retransmit variables. */

+      pcb->dupacks = 0;

+      pcb->lastack = ackno;

+

+      /* Update the congestion control variables (cwnd and

+         ssthresh). */

+      if (pcb->state >= ESTABLISHED) {

+        if (pcb->cwnd < pcb->ssthresh) {

+          if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {

+            pcb->cwnd += pcb->mss;

+          }

+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));

+        } else {

+          u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);

+          if (new_cwnd > pcb->cwnd) {

+            pcb->cwnd = new_cwnd;

+          }

+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));

+        }

+      }

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",

+                                    ackno,

+                                    pcb->unacked != NULL?

+                                    ntohl(pcb->unacked->tcphdr->seqno): 0,

+                                    pcb->unacked != NULL?

+                                    ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));

+

+      /* Remove segment from the unacknowledged list if the incoming

+         ACK acknowlegdes them. */

+      while (pcb->unacked != NULL &&

+             TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +

+                         TCP_TCPLEN(pcb->unacked), ackno)) {

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",

+                                      ntohl(pcb->unacked->tcphdr->seqno),

+                                      ntohl(pcb->unacked->tcphdr->seqno) +

+                                      TCP_TCPLEN(pcb->unacked)));

+

+        next = pcb->unacked;

+        pcb->unacked = pcb->unacked->next;

+

+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));

+        pcb->snd_queuelen -= pbuf_clen(next->p);

+        tcp_seg_free(next);

+

+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));

+        if (pcb->snd_queuelen != 0) {

+          LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||

+                      pcb->unsent != NULL);

+        }

+      }

+      pcb->polltmr = 0;

+    }

+

+    /* We go through the ->unsent list to see if any of the segments

+       on the list are acknowledged by the ACK. This may seem

+       strange since an "unsent" segment shouldn't be acked. The

+       rationale is that lwIP puts all outstanding segments on the

+       ->unsent list after a retransmission, so these segments may

+       in fact have been sent once. */

+    while (pcb->unsent != NULL &&

+           /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&

+             TCP_SEQ_LEQ(ackno, pcb->snd_max)*/

+           TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)

+           ) {

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",

+                                    ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +

+                                    TCP_TCPLEN(pcb->unsent)));

+

+      next = pcb->unsent;

+      pcb->unsent = pcb->unsent->next;

+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));

+      pcb->snd_queuelen -= pbuf_clen(next->p);

+      tcp_seg_free(next);

+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));

+      if (pcb->snd_queuelen != 0) {

+        LWIP_ASSERT("tcp_receive: valid queue length",

+          pcb->unacked != NULL || pcb->unsent != NULL);

+      }

+

+      if (pcb->unsent != NULL) {

+        pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);

+      }

+    }

+    /* End of ACK for new data processing. */

+

+    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",

+                                pcb->rttest, pcb->rtseq, ackno));

+

+    /* RTT estimation calculations. This is done by checking if the

+       incoming segment acknowledges the segment we use to take a

+       round-trip time measurement. */

+    if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {

+      m = tcp_ticks - pcb->rttest;

+

+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",

+                                  m, m * TCP_SLOW_INTERVAL));

+

+      /* This is taken directly from VJs original code in his paper */

+      m = m - (pcb->sa >> 3);

+      pcb->sa += m;

+      if (m < 0) {

+        m = -m;

+      }

+      m = m - (pcb->sv >> 2);

+      pcb->sv += m;

+      pcb->rto = (pcb->sa >> 3) + pcb->sv;

+

+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" miliseconds)\n",

+                                  pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));

+

+      pcb->rttest = 0;

+    }

+  }

+

+  /* If the incoming segment contains data, we must process it

+     further. */

+  if (tcplen > 0) {

+    /* This code basically does three things:

+

+    +) If the incoming segment contains data that is the next

+    in-sequence data, this data is passed to the application. This

+    might involve trimming the first edge of the data. The rcv_nxt

+    variable and the advertised window are adjusted.

+

+    +) If the incoming segment has data that is above the next

+    sequence number expected (->rcv_nxt), the segment is placed on

+    the ->ooseq queue. This is done by finding the appropriate

+    place in the ->ooseq queue (which is ordered by sequence

+    number) and trim the segment in both ends if needed. An

+    immediate ACK is sent to indicate that we received an

+    out-of-sequence segment.

+

+    +) Finally, we check if the first segment on the ->ooseq queue

+    now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If

+    rcv_nxt > ooseq->seqno, we must trim the first edge of the

+    segment on ->ooseq before we adjust rcv_nxt. The data in the

+    segments that are now on sequence are chained onto the

+    incoming segment so that we only need to call the application

+    once.

+    */

+

+    /* First, we check if we must trim the first edge. We have to do

+       this if the sequence number of the incoming segment is less

+       than rcv_nxt, and the sequence number plus the length of the

+       segment is larger than rcv_nxt. */

+    /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){

+          if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/

+    if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){

+      /* Trimming the first edge is done by pushing the payload

+         pointer in the pbuf downwards. This is somewhat tricky since

+         we do not want to discard the full contents of the pbuf up to

+         the new starting point of the data since we have to keep the

+         TCP header which is present in the first pbuf in the chain.

+         

+         What is done is really quite a nasty hack: the first pbuf in

+         the pbuf chain is pointed to by inseg.p. Since we need to be

+         able to deallocate the whole pbuf, we cannot change this

+         inseg.p pointer to point to any of the later pbufs in the

+         chain. Instead, we point the ->payload pointer in the first

+         pbuf to data in one of the later pbufs. We also set the

+         inseg.data pointer to point to the right place. This way, the

+         ->p pointer will still point to the first pbuf, but the

+         ->p->payload pointer will point to data in another pbuf.

+         

+         After we are done with adjusting the pbuf pointers we must

+         adjust the ->data pointer in the seg and the segment

+         length.*/

+      

+      off = pcb->rcv_nxt - seqno;

+      p = inseg.p;

+      LWIP_ASSERT("inseg.p != NULL", inseg.p);

+      if (inseg.p->len < off) {

+        new_tot_len = inseg.p->tot_len - off;

+        while (p->len < off) {

+          off -= p->len;

+          /* KJM following line changed (with addition of new_tot_len var)

+             to fix bug #9076

+             inseg.p->tot_len -= p->len; */

+          p->tot_len = new_tot_len;

+          p->len = 0;

+          p = p->next;

+        }

+        pbuf_header(p, -off);

+      } else {

+        pbuf_header(inseg.p, -off);

+      }

+      /* KJM following line changed to use p->payload rather than inseg->p->payload

+         to fix bug #9076 */

+      inseg.dataptr = p->payload;

+      inseg.len -= pcb->rcv_nxt - seqno;

+      inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;

+    }

+    else {

+      if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){

+        /* the whole segment is < rcv_nxt */

+        /* must be a duplicate of a packet that has already been correctly handled */

+        

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));

+        tcp_ack_now(pcb);

+      }

+    }

+

+    /* The sequence number must be within the window (above rcv_nxt

+       and below rcv_nxt + rcv_wnd) in order to be further

+       processed. */

+    /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&

+      TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/

+    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){

+      if (pcb->rcv_nxt == seqno) {

+        accepted_inseq = 1; 

+        /* The incoming segment is the next in sequence. We check if

+           we have to trim the end of the segment and update rcv_nxt

+           and pass the data to the application. */

+#if TCP_QUEUE_OOSEQ

+        if (pcb->ooseq != NULL &&

+            TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {

+          /* We have to trim the second edge of the incoming

+             segment. */

+          inseg.len = pcb->ooseq->tcphdr->seqno - seqno;

+          pbuf_realloc(inseg.p, inseg.len);

+        }

+#endif /* TCP_QUEUE_OOSEQ */

+

+        tcplen = TCP_TCPLEN(&inseg);

+

+        /* First received FIN will be ACKed +1, on any successive (duplicate)

+         * FINs we are already in CLOSE_WAIT and have already done +1.

+         */

+        if (pcb->state != CLOSE_WAIT) {

+          pcb->rcv_nxt += tcplen;

+        }

+

+        /* Update the receiver's (our) window. */

+        if (pcb->rcv_wnd < tcplen) {

+          pcb->rcv_wnd = 0;

+        } else {

+          pcb->rcv_wnd -= tcplen;

+        }

+

+        /* If there is data in the segment, we make preparations to

+           pass this up to the application. The ->recv_data variable

+           is used for holding the pbuf that goes to the

+           application. The code for reassembling out-of-sequence data

+           chains its data on this pbuf as well.

+

+           If the segment was a FIN, we set the TF_GOT_FIN flag that will

+           be used to indicate to the application that the remote side has

+           closed its end of the connection. */

+        if (inseg.p->tot_len > 0) {

+          recv_data = inseg.p;

+          /* Since this pbuf now is the responsibility of the

+             application, we delete our reference to it so that we won't

+             (mistakingly) deallocate it. */

+          inseg.p = NULL;

+        }

+        if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {

+          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));

+          recv_flags = TF_GOT_FIN;

+        }

+

+#if TCP_QUEUE_OOSEQ

+        /* We now check if we have segments on the ->ooseq queue that

+           is now in sequence. */

+        while (pcb->ooseq != NULL &&

+               pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {

+

+          cseg = pcb->ooseq;

+          seqno = pcb->ooseq->tcphdr->seqno;

+

+          pcb->rcv_nxt += TCP_TCPLEN(cseg);

+          if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {

+            pcb->rcv_wnd = 0;

+          } else {

+            pcb->rcv_wnd -= TCP_TCPLEN(cseg);

+          }

+          if (cseg->p->tot_len > 0) {

+            /* Chain this pbuf onto the pbuf that we will pass to

+               the application. */

+            if (recv_data) {

+              pbuf_cat(recv_data, cseg->p);

+            } else {

+              recv_data = cseg->p;

+            }

+            cseg->p = NULL;

+          }

+          if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {

+            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));

+            recv_flags = TF_GOT_FIN;

+            if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */

+              pcb->state = CLOSE_WAIT;

+            } 

+          }

+

+

+          pcb->ooseq = cseg->next;

+          tcp_seg_free(cseg);

+        }

+#endif /* TCP_QUEUE_OOSEQ */

+

+

+        /* Acknowledge the segment(s). */

+        tcp_ack(pcb);

+

+      } else {

+        /* We get here if the incoming segment is out-of-sequence. */

+        tcp_ack_now(pcb);

+#if TCP_QUEUE_OOSEQ

+        /* We queue the segment on the ->ooseq queue. */

+        if (pcb->ooseq == NULL) {

+          pcb->ooseq = tcp_seg_copy(&inseg);

+        } else {

+          /* If the queue is not empty, we walk through the queue and

+             try to find a place where the sequence number of the

+             incoming segment is between the sequence numbers of the

+             previous and the next segment on the ->ooseq queue. That is

+             the place where we put the incoming segment. If needed, we

+             trim the second edges of the previous and the incoming

+             segment so that it will fit into the sequence.

+

+             If the incoming segment has the same sequence number as a

+             segment on the ->ooseq queue, we discard the segment that

+             contains less data. */

+

+          prev = NULL;

+          for(next = pcb->ooseq; next != NULL; next = next->next) {

+            if (seqno == next->tcphdr->seqno) {

+              /* The sequence number of the incoming segment is the

+                 same as the sequence number of the segment on

+                 ->ooseq. We check the lengths to see which one to

+                 discard. */

+              if (inseg.len > next->len) {

+                /* The incoming segment is larger than the old

+                   segment. We replace the old segment with the new

+                   one. */

+                cseg = tcp_seg_copy(&inseg);

+                if (cseg != NULL) {

+                  cseg->next = next->next;

+                  if (prev != NULL) {

+                    prev->next = cseg;

+                  } else {

+                    pcb->ooseq = cseg;

+                  }

+                }

+                break;

+              } else {

+                /* Either the lenghts are the same or the incoming

+                   segment was smaller than the old one; in either

+                   case, we ditch the incoming segment. */

+                break;

+              }

+            } else {

+              if (prev == NULL) {

+                if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {

+                  /* The sequence number of the incoming segment is lower

+                     than the sequence number of the first segment on the

+                     queue. We put the incoming segment first on the

+                     queue. */

+

+                  if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {

+                    /* We need to trim the incoming segment. */

+                    inseg.len = next->tcphdr->seqno - seqno;

+                    pbuf_realloc(inseg.p, inseg.len);

+                  }

+                  cseg = tcp_seg_copy(&inseg);

+                  if (cseg != NULL) {

+                    cseg->next = next;

+                    pcb->ooseq = cseg;

+                  }

+                  break;

+                }

+              } else 

+                /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&

+                  TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/

+                if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){

+                /* The sequence number of the incoming segment is in

+                   between the sequence numbers of the previous and

+                   the next segment on ->ooseq. We trim and insert the

+                   incoming segment and trim the previous segment, if

+                   needed. */

+                if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {

+                  /* We need to trim the incoming segment. */

+                  inseg.len = next->tcphdr->seqno - seqno;

+                  pbuf_realloc(inseg.p, inseg.len);

+                }

+

+                cseg = tcp_seg_copy(&inseg);

+                if (cseg != NULL) {

+                  cseg->next = next;

+                  prev->next = cseg;

+                  if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {

+                    /* We need to trim the prev segment. */

+                    prev->len = seqno - prev->tcphdr->seqno;

+                    pbuf_realloc(prev->p, prev->len);

+                  }

+                }

+                break;

+              }

+              /* If the "next" segment is the last segment on the

+                 ooseq queue, we add the incoming segment to the end

+                 of the list. */

+              if (next->next == NULL &&

+                  TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {

+                next->next = tcp_seg_copy(&inseg);

+                if (next->next != NULL) {

+                  if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {

+                    /* We need to trim the last segment. */

+                    next->len = seqno - next->tcphdr->seqno;

+                    pbuf_realloc(next->p, next->len);

+                  }

+                }

+                break;

+              }

+            }

+            prev = next;

+          }

+        }

+#endif /* TCP_QUEUE_OOSEQ */

+

+      }

+    } else {

+      /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||

+        TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/

+      if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){

+        tcp_ack_now(pcb);

+      }

+    }

+  } else {

+    /* Segments with length 0 is taken care of here. Segments that

+       fall out of the window are ACKed. */

+    /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||

+      TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/

+    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){

+      tcp_ack_now(pcb);

+    }

+  }

+  return accepted_inseq;

+}

+

+/*

+ * tcp_parseopt:

+ *

+ * Parses the options contained in the incoming segment. (Code taken

+ * from uIP with only small changes.)

+ *

+ */

+

+static void

+tcp_parseopt(struct tcp_pcb *pcb)

+{

+  u8_t c;

+  u8_t *opts, opt;

+  u16_t mss;

+

+  opts = (u8_t *)tcphdr + TCP_HLEN;

+

+  /* Parse the TCP MSS option, if present. */

+  if(TCPH_HDRLEN(tcphdr) > 0x5) {

+    for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) {

+      opt = opts[c];

+      if (opt == 0x00) {

+        /* End of options. */

+  break;

+      } else if (opt == 0x01) {

+        ++c;

+        /* NOP option. */

+      } else if (opt == 0x02 &&

+        opts[c + 1] == 0x04) {

+        /* An MSS option with the right option length. */

+        mss = (opts[c + 2] << 8) | opts[c + 3];

+        pcb->mss = mss > TCP_MSS? TCP_MSS: mss;

+

+        /* And we are done processing options. */

+        break;

+      } else {

+  if (opts[c + 1] == 0) {

+          /* If the length field is zero, the options are malformed

+             and we don't process them further. */

+          break;

+        }

+        /* All other options have a length field, so that we easily

+           can skip past them. */

+        c += opts[c + 1];

+      }

+    }

+  }

+}

+#endif /* LWIP_TCP */

+

+

diff --git a/Demo/Common/ethernet/lwIP/core/tcp_out.c b/Demo/Common/ethernet/lwIP/core/tcp_out.c
index b268201..8802fea 100644
--- a/Demo/Common/ethernet/lwIP/core/tcp_out.c
+++ b/Demo/Common/ethernet/lwIP/core/tcp_out.c
@@ -1,727 +1,727 @@
-/**
- * @file
- *
- * Transmission Control Protocol, outgoing traffic
- *
- * The output functions of TCP.
- *
- */
-
-/*
- * 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 <string.h>
-
-#include "lwip/def.h"
-#include "lwip/opt.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/sys.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/inet.h"
-#include "lwip/tcp.h"
-#include "lwip/stats.h"
-#include "lwip/snmp.h"
+/**

+ * @file

+ *

+ * Transmission Control Protocol, outgoing traffic

+ *

+ * The output functions of TCP.

+ *

+ */

 

-#if LWIP_TCP
-
-/* Forward declarations.*/
-static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
-
-err_t
-tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
-{
-  /* no data, no length, flags, copy=1, no optdata, no optdatalen */
-  return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
-}
-
-/**
- * Write data for sending (but does not send it immediately).
- *
- * It waits in the expectation of more data being sent soon (as
- * it can send them more efficiently by combining them together).
- * To prompt the system to send data now, call tcp_output() after
- * calling tcp_write().
- * 
- * @arg pcb Protocol control block of the TCP connection to enqueue data for. 
- * 
- * @see tcp_write()
- */
-
-err_t
-tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
-{
-  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%"U16_F", copy=%"U16_F")\n", (void *)pcb,
-    arg, len, (u16_t)copy));
-  /* connection is in valid state for data transmission? */
-  if (pcb->state == ESTABLISHED ||
-     pcb->state == CLOSE_WAIT ||
-     pcb->state == SYN_SENT ||
-     pcb->state == SYN_RCVD) {
-    if (len > 0) {
-      return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
-    }
-    return ERR_OK;
-  } else {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n"));
-    return ERR_CONN;
-  }
-}
-
-/**
- * Enqueue either data or TCP options (but not both) for tranmission
- * 
- * 
- * 
- * @arg pcb Protocol control block for the TCP connection to enqueue data for.
- * @arg arg Pointer to the data to be enqueued for sending.
- * @arg len Data length in bytes
- * @arg flags
- * @arg copy 1 if data must be copied, 0 if data is non-volatile and can be
- * referenced.
- * @arg optdata
- * @arg optlen
- */
-err_t
-tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
-  u8_t flags, u8_t copy,
-  u8_t *optdata, u8_t optlen)
-{
-  struct pbuf *p;
-  struct tcp_seg *seg, *useg, *queue;
-  u32_t left, seqno;
-  u16_t seglen;
-  void *ptr;
-  u8_t queuelen;
-
-  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", copy=%"U16_F")\n",
-    (void *)pcb, arg, len, (u16_t)flags, (u16_t)copy));
-  LWIP_ASSERT("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",
-      len == 0 || optlen == 0);
-  LWIP_ASSERT("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",
-      arg == NULL || optdata == NULL);
-  /* fail on too much data */
-  if (len > pcb->snd_buf) {
+/*

+ * 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 <string.h>

+

+#include "lwip/def.h"

+#include "lwip/opt.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+#include "lwip/sys.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/inet.h"

+#include "lwip/tcp.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+

+#if LWIP_TCP

+

+/* Forward declarations.*/

+static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);

+

+err_t

+tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)

+{

+  /* no data, no length, flags, copy=1, no optdata, no optdatalen */

+  return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);

+}

+

+/**

+ * Write data for sending (but does not send it immediately).

+ *

+ * It waits in the expectation of more data being sent soon (as

+ * it can send them more efficiently by combining them together).

+ * To prompt the system to send data now, call tcp_output() after

+ * calling tcp_write().

+ * 

+ * @arg pcb Protocol control block of the TCP connection to enqueue data for. 

+ * 

+ * @see tcp_write()

+ */

+

+err_t

+tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)

+{

+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%"U16_F", copy=%"U16_F")\n", (void *)pcb,

+    arg, len, (u16_t)copy));

+  /* connection is in valid state for data transmission? */

+  if (pcb->state == ESTABLISHED ||

+     pcb->state == CLOSE_WAIT ||

+     pcb->state == SYN_SENT ||

+     pcb->state == SYN_RCVD) {

+    if (len > 0) {

+      return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);

+    }

+    return ERR_OK;

+  } else {

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n"));

+    return ERR_CONN;

+  }

+}

+

+/**

+ * Enqueue either data or TCP options (but not both) for tranmission

+ * 

+ * 

+ * 

+ * @arg pcb Protocol control block for the TCP connection to enqueue data for.

+ * @arg arg Pointer to the data to be enqueued for sending.

+ * @arg len Data length in bytes

+ * @arg flags

+ * @arg copy 1 if data must be copied, 0 if data is non-volatile and can be

+ * referenced.

+ * @arg optdata

+ * @arg optlen

+ */

+err_t

+tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,

+  u8_t flags, u8_t copy,

+  u8_t *optdata, u8_t optlen)

+{

+  struct pbuf *p;

+  struct tcp_seg *seg, *useg, *queue;

+  u32_t left, seqno;

+  u16_t seglen;

+  void *ptr;

+  u8_t queuelen;

+

+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", copy=%"U16_F")\n",

+    (void *)pcb, arg, len, (u16_t)flags, (u16_t)copy));

+  LWIP_ASSERT("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",

+      len == 0 || optlen == 0);

+  LWIP_ASSERT("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",

+      arg == NULL || optdata == NULL);

+  /* fail on too much data */

+  if (len > pcb->snd_buf) {

     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));

-    return ERR_MEM;
-  }
-  left = len;
-  ptr = arg;
-
-  /* seqno will be the sequence number of the first segment enqueued
-   * by the call to this function. */
-  seqno = pcb->snd_lbb;
-
-  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
-
-  /* If total number of pbufs on the unsent/unacked queues exceeds the
-   * configured maximum, return an error */
-  queuelen = pcb->snd_queuelen;
-  if (queuelen >= TCP_SND_QUEUELEN) {
+    return ERR_MEM;

+  }

+  left = len;

+  ptr = arg;

+

+  /* seqno will be the sequence number of the first segment enqueued

+   * by the call to this function. */

+  seqno = pcb->snd_lbb;

+

+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));

+

+  /* If total number of pbufs on the unsent/unacked queues exceeds the

+   * configured maximum, return an error */

+  queuelen = pcb->snd_queuelen;

+  if (queuelen >= TCP_SND_QUEUELEN) {

     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN));

-    TCP_STATS_INC(tcp.memerr);
-    return ERR_MEM;
-  }
-  if (queuelen != 0) {
-    LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",
-      pcb->unacked != NULL || pcb->unsent != NULL);
-  } else {
-    LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",
-      pcb->unacked == NULL && pcb->unsent == NULL);
-  }
-
-  /* First, break up the data into segments and tuck them together in
-   * the local "queue" variable. */
-  useg = queue = seg = NULL;
-  seglen = 0;
-  while (queue == NULL || left > 0) {
-
-    /* The segment length should be the MSS if the data to be enqueued
-     * is larger than the MSS. */
-    seglen = left > pcb->mss? pcb->mss: left;
-
-    /* Allocate memory for tcp_seg, and fill in fields. */
-    seg = memp_malloc(MEMP_TCP_SEG);
-    if (seg == NULL) {
+    TCP_STATS_INC(tcp.memerr);

+    return ERR_MEM;

+  }

+  if (queuelen != 0) {

+    LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",

+      pcb->unacked != NULL || pcb->unsent != NULL);

+  } else {

+    LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",

+      pcb->unacked == NULL && pcb->unsent == NULL);

+  }

+

+  /* First, break up the data into segments and tuck them together in

+   * the local "queue" variable. */

+  useg = queue = seg = NULL;

+  seglen = 0;

+  while (queue == NULL || left > 0) {

+

+    /* The segment length should be the MSS if the data to be enqueued

+     * is larger than the MSS. */

+    seglen = left > pcb->mss? pcb->mss: left;

+

+    /* Allocate memory for tcp_seg, and fill in fields. */

+    seg = memp_malloc(MEMP_TCP_SEG);

+    if (seg == NULL) {

       LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));

-      goto memerr;
-    }
-    seg->next = NULL;
-    seg->p = NULL;
-
-    /* first segment of to-be-queued data? */
-    if (queue == NULL) {
-      queue = seg;
-    }
-    /* subsequent segments of to-be-queued data */
-    else {
-      /* Attach the segment to the end of the queued segments */
-      LWIP_ASSERT("useg != NULL", useg != NULL);
-      useg->next = seg;
-    }
-    /* remember last segment of to-be-queued data for next iteration */
-    useg = seg;
-
-    /* If copy is set, memory should be allocated
-     * and data copied into pbuf, otherwise data comes from
-     * ROM or other static memory, and need not be copied. If
-     * optdata is != NULL, we have options instead of data. */
-     
-    /* options? */
-    if (optdata != NULL) {
-      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
-        goto memerr;
-      }
-      ++queuelen;
-      seg->dataptr = seg->p->payload;
-    }
-    /* copy from volatile memory? */
-    else if (copy) {
-      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
+      goto memerr;

+    }

+    seg->next = NULL;

+    seg->p = NULL;

+

+    /* first segment of to-be-queued data? */

+    if (queue == NULL) {

+      queue = seg;

+    }

+    /* subsequent segments of to-be-queued data */

+    else {

+      /* Attach the segment to the end of the queued segments */

+      LWIP_ASSERT("useg != NULL", useg != NULL);

+      useg->next = seg;

+    }

+    /* remember last segment of to-be-queued data for next iteration */

+    useg = seg;

+

+    /* If copy is set, memory should be allocated

+     * and data copied into pbuf, otherwise data comes from

+     * ROM or other static memory, and need not be copied. If

+     * optdata is != NULL, we have options instead of data. */

+     

+    /* options? */

+    if (optdata != NULL) {

+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {

+        goto memerr;

+      }

+      ++queuelen;

+      seg->dataptr = seg->p->payload;

+    }

+    /* copy from volatile memory? */

+    else if (copy) {

+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {

         LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));

-        goto memerr;
-      }
-      ++queuelen;
-      if (arg != NULL) {
-        memcpy(seg->p->payload, ptr, seglen);
-      }
-      seg->dataptr = seg->p->payload;
-    }
-    /* do not copy data */
-    else {
-      /* First, allocate a pbuf for holding the data.
-       * since the referenced data is available at least until it is sent out on the
-       * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
-       * instead of PBUF_REF here.
-       */
-      if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
+        goto memerr;

+      }

+      ++queuelen;

+      if (arg != NULL) {

+        memcpy(seg->p->payload, ptr, seglen);

+      }

+      seg->dataptr = seg->p->payload;

+    }

+    /* do not copy data */

+    else {

+      /* First, allocate a pbuf for holding the data.

+       * since the referenced data is available at least until it is sent out on the

+       * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM

+       * instead of PBUF_REF here.

+       */

+      if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {

         LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));

-        goto memerr;
-      }
-      ++queuelen;
-      /* reference the non-volatile payload data */
-      p->payload = ptr;
-      seg->dataptr = ptr;
-
-      /* Second, allocate a pbuf for the headers. */
-      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {
-        /* If allocation fails, we have to deallocate the data pbuf as
-         * well. */
-        pbuf_free(p);
+        goto memerr;

+      }

+      ++queuelen;

+      /* reference the non-volatile payload data */

+      p->payload = ptr;

+      seg->dataptr = ptr;

+

+      /* Second, allocate a pbuf for the headers. */

+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {

+        /* If allocation fails, we have to deallocate the data pbuf as

+         * well. */

+        pbuf_free(p);

         LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));

-        goto memerr;
-      }
-      ++queuelen;
-
-      /* Concatenate the headers and data pbufs together. */
-      pbuf_cat(seg->p/*header*/, p/*data*/);
-      p = NULL;
-    }
-
-    /* Now that there are more segments queued, we check again if the
-    length of the queue exceeds the configured maximum. */
-    if (queuelen > TCP_SND_QUEUELEN) {
+        goto memerr;

+      }

+      ++queuelen;

+

+      /* Concatenate the headers and data pbufs together. */

+      pbuf_cat(seg->p/*header*/, p/*data*/);

+      p = NULL;

+    }

+

+    /* Now that there are more segments queued, we check again if the

+    length of the queue exceeds the configured maximum. */

+    if (queuelen > TCP_SND_QUEUELEN) {

       LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));

-      goto memerr;
-    }
-
-    seg->len = seglen;
-
-    /* build TCP header */
-    if (pbuf_header(seg->p, TCP_HLEN)) {
+      goto memerr;

+    }

+

+    seg->len = seglen;

+

+    /* build TCP header */

+    if (pbuf_header(seg->p, TCP_HLEN)) {

       LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));

-      TCP_STATS_INC(tcp.err);
-      goto memerr;
-    }
-    seg->tcphdr = seg->p->payload;
-    seg->tcphdr->src = htons(pcb->local_port);
-    seg->tcphdr->dest = htons(pcb->remote_port);
-    seg->tcphdr->seqno = htonl(seqno);
-    seg->tcphdr->urgp = 0;
-    TCPH_FLAGS_SET(seg->tcphdr, flags);
-    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */
-
-    /* Copy the options into the header, if they are present. */
-    if (optdata == NULL) {
-      TCPH_HDRLEN_SET(seg->tcphdr, 5);
-    }
-    else {
-      TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));
-      /* Copy options into data portion of segment.
-       Options can thus only be sent in non data carrying
-       segments such as SYN|ACK. */
-      memcpy(seg->dataptr, optdata, optlen);
-    }
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
-      ntohl(seg->tcphdr->seqno),
-      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
-      (u16_t)flags));
-
-    left -= seglen;
-    seqno += seglen;
-    ptr = (void *)((u8_t *)ptr + seglen);
-  }
-
-  /* Now that the data to be enqueued has been broken up into TCP
-  segments in the queue variable, we add them to the end of the
-  pcb->unsent queue. */
-  if (pcb->unsent == NULL) {
-    useg = NULL;
-  }
-  else {
-    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
-  }
-  /* { useg is last segment on the unsent queue, NULL if list is empty } */
-
-  /* If there is room in the last pbuf on the unsent queue,
-  chain the first pbuf on the queue together with that. */
-  if (useg != NULL &&
-    TCP_TCPLEN(useg) != 0 &&
-    !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
-    !(flags & (TCP_SYN | TCP_FIN)) &&
-    /* fit within max seg size */
-    useg->len + queue->len <= pcb->mss) {
-    /* Remove TCP header from first segment of our to-be-queued list */
-    pbuf_header(queue->p, -TCP_HLEN);
-    pbuf_cat(useg->p, queue->p);
-    useg->len += queue->len;
-    useg->next = queue->next;
-
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len));
-    if (seg == queue) {
-      seg = NULL;
-    }
-    memp_free(MEMP_TCP_SEG, queue);
-  }
-  else {
-    /* empty list */
-    if (useg == NULL) {
-      /* initialize list with this segment */
-      pcb->unsent = queue;
-    }
-    /* enqueue segment */
-    else {
-      useg->next = queue;
-    }
-  }
-  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
-    ++len;
-  }
-  pcb->snd_lbb += len;
-
-  pcb->snd_buf -= len;
-
-  /* update number of segments on the queues */
-  pcb->snd_queuelen = queuelen;
-  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
-  if (pcb->snd_queuelen != 0) {
-    LWIP_ASSERT("tcp_enqueue: valid queue length",
-      pcb->unacked != NULL || pcb->unsent != NULL);
-  }
-
-  /* Set the PSH flag in the last segment that we enqueued, but only
-  if the segment has data (indicated by seglen > 0). */
-  if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) {
-    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
-  }
-
-  return ERR_OK;
-memerr:
-  TCP_STATS_INC(tcp.memerr);
-
-  if (queue != NULL) {
-    tcp_segs_free(queue);
-  }
-  if (pcb->snd_queuelen != 0) {
-    LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
-      pcb->unsent != NULL);
-  }
+      TCP_STATS_INC(tcp.err);

+      goto memerr;

+    }

+    seg->tcphdr = seg->p->payload;

+    seg->tcphdr->src = htons(pcb->local_port);

+    seg->tcphdr->dest = htons(pcb->remote_port);

+    seg->tcphdr->seqno = htonl(seqno);

+    seg->tcphdr->urgp = 0;

+    TCPH_FLAGS_SET(seg->tcphdr, flags);

+    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */

+

+    /* Copy the options into the header, if they are present. */

+    if (optdata == NULL) {

+      TCPH_HDRLEN_SET(seg->tcphdr, 5);

+    }

+    else {

+      TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));

+      /* Copy options into data portion of segment.

+       Options can thus only be sent in non data carrying

+       segments such as SYN|ACK. */

+      memcpy(seg->dataptr, optdata, optlen);

+    }

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",

+      ntohl(seg->tcphdr->seqno),

+      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),

+      (u16_t)flags));

+

+    left -= seglen;

+    seqno += seglen;

+    ptr = (void *)((u8_t *)ptr + seglen);

+  }

+

+  /* Now that the data to be enqueued has been broken up into TCP

+  segments in the queue variable, we add them to the end of the

+  pcb->unsent queue. */

+  if (pcb->unsent == NULL) {

+    useg = NULL;

+  }

+  else {

+    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);

+  }

+  /* { useg is last segment on the unsent queue, NULL if list is empty } */

+

+  /* If there is room in the last pbuf on the unsent queue,

+  chain the first pbuf on the queue together with that. */

+  if (useg != NULL &&

+    TCP_TCPLEN(useg) != 0 &&

+    !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&

+    !(flags & (TCP_SYN | TCP_FIN)) &&

+    /* fit within max seg size */

+    useg->len + queue->len <= pcb->mss) {

+    /* Remove TCP header from first segment of our to-be-queued list */

+    pbuf_header(queue->p, -TCP_HLEN);

+    pbuf_cat(useg->p, queue->p);

+    useg->len += queue->len;

+    useg->next = queue->next;

+

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len));

+    if (seg == queue) {

+      seg = NULL;

+    }

+    memp_free(MEMP_TCP_SEG, queue);

+  }

+  else {

+    /* empty list */

+    if (useg == NULL) {

+      /* initialize list with this segment */

+      pcb->unsent = queue;

+    }

+    /* enqueue segment */

+    else {

+      useg->next = queue;

+    }

+  }

+  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {

+    ++len;

+  }

+  pcb->snd_lbb += len;

+

+  pcb->snd_buf -= len;

+

+  /* update number of segments on the queues */

+  pcb->snd_queuelen = queuelen;

+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));

+  if (pcb->snd_queuelen != 0) {

+    LWIP_ASSERT("tcp_enqueue: valid queue length",

+      pcb->unacked != NULL || pcb->unsent != NULL);

+  }

+

+  /* Set the PSH flag in the last segment that we enqueued, but only

+  if the segment has data (indicated by seglen > 0). */

+  if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) {

+    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);

+  }

+

+  return ERR_OK;

+memerr:

+  TCP_STATS_INC(tcp.memerr);

+

+  if (queue != NULL) {

+    tcp_segs_free(queue);

+  }

+  if (pcb->snd_queuelen != 0) {

+    LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||

+      pcb->unsent != NULL);

+  }

   LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen));

-  return ERR_MEM;
-}
-
-/* find out what we can send and send it */
-err_t
-tcp_output(struct tcp_pcb *pcb)
-{
-  struct pbuf *p;
-  struct tcp_hdr *tcphdr;
-  struct tcp_seg *seg, *useg;
-  u32_t wnd;
-#if TCP_CWND_DEBUG
-  s16_t i = 0;
-#endif /* TCP_CWND_DEBUG */
-
-  /* First, check if we are invoked by the TCP input processing
-     code. If so, we do not output anything. Instead, we rely on the
-     input processing code to call us when input processing is done
-     with. */
-  if (tcp_input_pcb == pcb) {
-    return ERR_OK;
-  }
-
-  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
-
-  seg = pcb->unsent;
-
-  /* useg should point to last segment on unacked queue */
-  useg = pcb->unacked;
-  if (useg != NULL) {
-    for (; useg->next != NULL; useg = useg->next);
-  }                                                                             
-   
-  /* If the TF_ACK_NOW flag is set and no data will be sent (either
-   * because the ->unsent queue is empty or because the window does
-   * not allow it), construct an empty ACK segment and send it.
-   *
-   * If data is to be sent, we will just piggyback the ACK (see below).
-   */
-  if (pcb->flags & TF_ACK_NOW &&
-     (seg == NULL ||
-      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
-    p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
-    if (p == NULL) {
-      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
-      return ERR_BUF;
-    }
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
-    /* remove ACK flags from the PCB, as we send an empty ACK now */
-    pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
-
-    tcphdr = p->payload;
-    tcphdr->src = htons(pcb->local_port);
-    tcphdr->dest = htons(pcb->remote_port);
-    tcphdr->seqno = htonl(pcb->snd_nxt);
-    tcphdr->ackno = htonl(pcb->rcv_nxt);
-    TCPH_FLAGS_SET(tcphdr, TCP_ACK);
-    tcphdr->wnd = htons(pcb->rcv_wnd);
-    tcphdr->urgp = 0;
-    TCPH_HDRLEN_SET(tcphdr, 5);
-
-    tcphdr->chksum = 0;
-#if CHECKSUM_GEN_TCP
-    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
-          IP_PROTO_TCP, p->tot_len);
-#endif
-    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-        IP_PROTO_TCP);
-    pbuf_free(p);
-
-    return ERR_OK;
-  }
-
-#if TCP_OUTPUT_DEBUG
-  if (seg == NULL) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", (void*)pcb->unsent));
-  }
-#endif /* TCP_OUTPUT_DEBUG */
-#if TCP_CWND_DEBUG
-  if (seg == NULL) {
-    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", seg == NULL, ack %"U32_F"\n",
-                            pcb->snd_wnd, pcb->cwnd, wnd,
-                            pcb->lastack));
-  } else {
-    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
-                            pcb->snd_wnd, pcb->cwnd, wnd,
-                            ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
-                            ntohl(seg->tcphdr->seqno), pcb->lastack));
-  }
-#endif /* TCP_CWND_DEBUG */
-  /* data available and window allows it to be sent? */
-  while (seg != NULL &&
-  ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
-#if TCP_CWND_DEBUG
-    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
-                            pcb->snd_wnd, pcb->cwnd, wnd,
-                            ntohl(seg->tcphdr->seqno) + seg->len -
-                            pcb->lastack,
-                            ntohl(seg->tcphdr->seqno), pcb->lastack, i));
-    ++i;
-#endif /* TCP_CWND_DEBUG */
-
-    pcb->unsent = seg->next;
-
-    if (pcb->state != SYN_SENT) {
-      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
-      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
-    }
-
-    tcp_output_segment(seg, pcb);
-    pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
-    if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
-      pcb->snd_max = pcb->snd_nxt;
-    }
-    /* put segment on unacknowledged list if length > 0 */
-    if (TCP_TCPLEN(seg) > 0) {
-      seg->next = NULL;
-      /* unacked list is empty? */
-      if (pcb->unacked == NULL) {
-        pcb->unacked = seg;
-        useg = seg;
-      /* unacked list is not empty? */
-      } else {
-        /* In the case of fast retransmit, the packet should not go to the tail
-         * of the unacked queue, but rather at the head. We need to check for
-         * this case. -STJ Jul 27, 2004 */
-        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
-          /* add segment to head of unacked list */
-          seg->next = pcb->unacked;
-          pcb->unacked = seg;
-        } else {
-          /* add segment to tail of unacked list */
-          useg->next = seg;
-          useg = useg->next;
-        }
-      }
-    /* do not queue empty segments on the unacked list */
-    } else {
-      tcp_seg_free(seg);
-    }
-    seg = pcb->unsent;
-  }
-  return ERR_OK;
-}
-
-/**
- * Actually send a TCP segment over IP
- */
-static void
-tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
-{
-  u16_t len;
-  struct netif *netif;
-
-  /** @bug Exclude retransmitted segments from this count. */
-  snmp_inc_tcpoutsegs();
-
-  /* The TCP header has already been constructed, but the ackno and
-   wnd fields remain. */
-  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
-
-  /* silly window avoidance */
-  if (pcb->rcv_wnd < pcb->mss) {
-    seg->tcphdr->wnd = 0;
-  } else {
-    /* advertise our receive window size in this TCP segment */
-    seg->tcphdr->wnd = htons(pcb->rcv_wnd);
-  }
-
-  /* If we don't have a local IP address, we get one by
-     calling ip_route(). */
-  if (ip_addr_isany(&(pcb->local_ip))) {
-    netif = ip_route(&(pcb->remote_ip));
-    if (netif == NULL) {
-      return;
-    }
-    ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));
-  }
-
-  pcb->rtime = 0;
-
-  if (pcb->rttest == 0) {
-    pcb->rttest = tcp_ticks;
-    pcb->rtseq = ntohl(seg->tcphdr->seqno);
-
-    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
-  }
-  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
-          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
-          seg->len));
-
-  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
-
-  seg->p->len -= len;
-  seg->p->tot_len -= len;
-
-  seg->p->payload = seg->tcphdr;
-
-  seg->tcphdr->chksum = 0;
-#if CHECKSUM_GEN_TCP
-  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
-             &(pcb->local_ip),
-             &(pcb->remote_ip),
-             IP_PROTO_TCP, seg->p->tot_len);
-#endif
-  TCP_STATS_INC(tcp.xmit);
-
-  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-      IP_PROTO_TCP);
-}
-
-void
-tcp_rst(u32_t seqno, u32_t ackno,
-  struct ip_addr *local_ip, struct ip_addr *remote_ip,
-  u16_t local_port, u16_t remote_port)
-{
-  struct pbuf *p;
-  struct tcp_hdr *tcphdr;
-  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
-  if (p == NULL) {
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
-      return;
-  }
-
-  tcphdr = p->payload;
-  tcphdr->src = htons(local_port);
-  tcphdr->dest = htons(remote_port);
-  tcphdr->seqno = htonl(seqno);
-  tcphdr->ackno = htonl(ackno);
-  TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);
-  tcphdr->wnd = htons(TCP_WND);
-  tcphdr->urgp = 0;
-  TCPH_HDRLEN_SET(tcphdr, 5);
-
-  tcphdr->chksum = 0;
-#if CHECKSUM_GEN_TCP
-  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
-              IP_PROTO_TCP, p->tot_len);
-#endif
-  TCP_STATS_INC(tcp.xmit);
-  snmp_inc_tcpoutrsts();
-   /* Send output with hardcoded TTL since we have no access to the pcb */
-  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
-  pbuf_free(p);
-  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
-}
-
-/* requeue all unacked segments for retransmission */
-void
-tcp_rexmit_rto(struct tcp_pcb *pcb)
-{
-  struct tcp_seg *seg;
-
-  if (pcb->unacked == NULL) {
-    return;
-  }
-
-  /* Move all unacked segments to the head of the unsent queue */
-  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
-  /* concatenate unsent queue after unacked queue */
-  seg->next = pcb->unsent;
-  /* unsent queue is the concatenated queue (of unacked, unsent) */
-  pcb->unsent = pcb->unacked;
-  /* unacked queue is now empty */
-  pcb->unacked = NULL;
-
-  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
-  /* increment number of retransmissions */
-  ++pcb->nrtx;
-
-  /* Don't take any RTT measurements after retransmitting. */
-  pcb->rttest = 0;
-
-  /* Do the actual retransmission */
-  tcp_output(pcb);
-}
-
-void
-tcp_rexmit(struct tcp_pcb *pcb)
-{
-  struct tcp_seg *seg;
-
-  if (pcb->unacked == NULL) {
-    return;
-  }
-
-  /* Move the first unacked segment to the unsent queue */
-  seg = pcb->unacked->next;
-  pcb->unacked->next = pcb->unsent;
-  pcb->unsent = pcb->unacked;
-  pcb->unacked = seg;
-
-  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
-
-  ++pcb->nrtx;
-
-  /* Don't take any rtt measurements after retransmitting. */
-  pcb->rttest = 0;
-
-  /* Do the actual retransmission. */
-  snmp_inc_tcpretranssegs();
-  tcp_output(pcb);
-
-}
-
-
-void
-tcp_keepalive(struct tcp_pcb *pcb)
-{
-   struct pbuf *p;
-   struct tcp_hdr *tcphdr;
-
-   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
-                           ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
-                           ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
-
-   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F"  pcb->keep_cnt %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt));
-   
-   p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
-
-   if(p == NULL) {
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n"));
-      return;
-   }
-
-   tcphdr = p->payload;
-   tcphdr->src = htons(pcb->local_port);
-   tcphdr->dest = htons(pcb->remote_port);
-   tcphdr->seqno = htonl(pcb->snd_nxt - 1);
-   tcphdr->ackno = htonl(pcb->rcv_nxt);
-   tcphdr->wnd = htons(pcb->rcv_wnd);
-   tcphdr->urgp = 0;
-   TCPH_HDRLEN_SET(tcphdr, 5);
-   
-   tcphdr->chksum = 0;
-#if CHECKSUM_GEN_TCP
-   tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len);
-#endif
-  TCP_STATS_INC(tcp.xmit);
-
-   /* Send output to IP */
-  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
-
-  pbuf_free(p);
-
-  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt));
-}
-
-#endif /* LWIP_TCP */
-
-
-
-
-
-
-
-
-
+  return ERR_MEM;

+}

+

+/* find out what we can send and send it */

+err_t

+tcp_output(struct tcp_pcb *pcb)

+{

+  struct pbuf *p;

+  struct tcp_hdr *tcphdr;

+  struct tcp_seg *seg, *useg;

+  u32_t wnd;

+#if TCP_CWND_DEBUG

+  s16_t i = 0;

+#endif /* TCP_CWND_DEBUG */

+

+  /* First, check if we are invoked by the TCP input processing

+     code. If so, we do not output anything. Instead, we rely on the

+     input processing code to call us when input processing is done

+     with. */

+  if (tcp_input_pcb == pcb) {

+    return ERR_OK;

+  }

+

+  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);

+

+  seg = pcb->unsent;

+

+  /* useg should point to last segment on unacked queue */

+  useg = pcb->unacked;

+  if (useg != NULL) {

+    for (; useg->next != NULL; useg = useg->next);

+  }                                                                             

+   

+  /* If the TF_ACK_NOW flag is set and no data will be sent (either

+   * because the ->unsent queue is empty or because the window does

+   * not allow it), construct an empty ACK segment and send it.

+   *

+   * If data is to be sent, we will just piggyback the ACK (see below).

+   */

+  if (pcb->flags & TF_ACK_NOW &&

+     (seg == NULL ||

+      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {

+    p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);

+    if (p == NULL) {

+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));

+      return ERR_BUF;

+    }

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));

+    /* remove ACK flags from the PCB, as we send an empty ACK now */

+    pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);

+

+    tcphdr = p->payload;

+    tcphdr->src = htons(pcb->local_port);

+    tcphdr->dest = htons(pcb->remote_port);

+    tcphdr->seqno = htonl(pcb->snd_nxt);

+    tcphdr->ackno = htonl(pcb->rcv_nxt);

+    TCPH_FLAGS_SET(tcphdr, TCP_ACK);

+    tcphdr->wnd = htons(pcb->rcv_wnd);

+    tcphdr->urgp = 0;

+    TCPH_HDRLEN_SET(tcphdr, 5);

+

+    tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),

+          IP_PROTO_TCP, p->tot_len);

+#endif

+    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,

+        IP_PROTO_TCP);

+    pbuf_free(p);

+

+    return ERR_OK;

+  }

+

+#if TCP_OUTPUT_DEBUG

+  if (seg == NULL) {

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", (void*)pcb->unsent));

+  }

+#endif /* TCP_OUTPUT_DEBUG */

+#if TCP_CWND_DEBUG

+  if (seg == NULL) {

+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", seg == NULL, ack %"U32_F"\n",

+                            pcb->snd_wnd, pcb->cwnd, wnd,

+                            pcb->lastack));

+  } else {

+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",

+                            pcb->snd_wnd, pcb->cwnd, wnd,

+                            ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,

+                            ntohl(seg->tcphdr->seqno), pcb->lastack));

+  }

+#endif /* TCP_CWND_DEBUG */

+  /* data available and window allows it to be sent? */

+  while (seg != NULL &&

+  ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {

+#if TCP_CWND_DEBUG

+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",

+                            pcb->snd_wnd, pcb->cwnd, wnd,

+                            ntohl(seg->tcphdr->seqno) + seg->len -

+                            pcb->lastack,

+                            ntohl(seg->tcphdr->seqno), pcb->lastack, i));

+    ++i;

+#endif /* TCP_CWND_DEBUG */

+

+    pcb->unsent = seg->next;

+

+    if (pcb->state != SYN_SENT) {

+      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);

+      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);

+    }

+

+    tcp_output_segment(seg, pcb);

+    pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);

+    if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {

+      pcb->snd_max = pcb->snd_nxt;

+    }

+    /* put segment on unacknowledged list if length > 0 */

+    if (TCP_TCPLEN(seg) > 0) {

+      seg->next = NULL;

+      /* unacked list is empty? */

+      if (pcb->unacked == NULL) {

+        pcb->unacked = seg;

+        useg = seg;

+      /* unacked list is not empty? */

+      } else {

+        /* In the case of fast retransmit, the packet should not go to the tail

+         * of the unacked queue, but rather at the head. We need to check for

+         * this case. -STJ Jul 27, 2004 */

+        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){

+          /* add segment to head of unacked list */

+          seg->next = pcb->unacked;

+          pcb->unacked = seg;

+        } else {

+          /* add segment to tail of unacked list */

+          useg->next = seg;

+          useg = useg->next;

+        }

+      }

+    /* do not queue empty segments on the unacked list */

+    } else {

+      tcp_seg_free(seg);

+    }

+    seg = pcb->unsent;

+  }

+  return ERR_OK;

+}

+

+/**

+ * Actually send a TCP segment over IP

+ */

+static void

+tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)

+{

+  u16_t len;

+  struct netif *netif;

+

+  /** @bug Exclude retransmitted segments from this count. */

+  snmp_inc_tcpoutsegs();

+

+  /* The TCP header has already been constructed, but the ackno and

+   wnd fields remain. */

+  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);

+

+  /* silly window avoidance */

+  if (pcb->rcv_wnd < pcb->mss) {

+    seg->tcphdr->wnd = 0;

+  } else {

+    /* advertise our receive window size in this TCP segment */

+    seg->tcphdr->wnd = htons(pcb->rcv_wnd);

+  }

+

+  /* If we don't have a local IP address, we get one by

+     calling ip_route(). */

+  if (ip_addr_isany(&(pcb->local_ip))) {

+    netif = ip_route(&(pcb->remote_ip));

+    if (netif == NULL) {

+      return;

+    }

+    ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));

+  }

+

+  pcb->rtime = 0;

+

+  if (pcb->rttest == 0) {

+    pcb->rttest = tcp_ticks;

+    pcb->rtseq = ntohl(seg->tcphdr->seqno);

+

+    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));

+  }

+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",

+          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +

+          seg->len));

+

+  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);

+

+  seg->p->len -= len;

+  seg->p->tot_len -= len;

+

+  seg->p->payload = seg->tcphdr;

+

+  seg->tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,

+             &(pcb->local_ip),

+             &(pcb->remote_ip),

+             IP_PROTO_TCP, seg->p->tot_len);

+#endif

+  TCP_STATS_INC(tcp.xmit);

+

+  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,

+      IP_PROTO_TCP);

+}

+

+void

+tcp_rst(u32_t seqno, u32_t ackno,

+  struct ip_addr *local_ip, struct ip_addr *remote_ip,

+  u16_t local_port, u16_t remote_port)

+{

+  struct pbuf *p;

+  struct tcp_hdr *tcphdr;

+  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);

+  if (p == NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));

+      return;

+  }

+

+  tcphdr = p->payload;

+  tcphdr->src = htons(local_port);

+  tcphdr->dest = htons(remote_port);

+  tcphdr->seqno = htonl(seqno);

+  tcphdr->ackno = htonl(ackno);

+  TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);

+  tcphdr->wnd = htons(TCP_WND);

+  tcphdr->urgp = 0;

+  TCPH_HDRLEN_SET(tcphdr, 5);

+

+  tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,

+              IP_PROTO_TCP, p->tot_len);

+#endif

+  TCP_STATS_INC(tcp.xmit);

+  snmp_inc_tcpoutrsts();

+   /* Send output with hardcoded TTL since we have no access to the pcb */

+  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);

+  pbuf_free(p);

+  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));

+}

+

+/* requeue all unacked segments for retransmission */

+void

+tcp_rexmit_rto(struct tcp_pcb *pcb)

+{

+  struct tcp_seg *seg;

+

+  if (pcb->unacked == NULL) {

+    return;

+  }

+

+  /* Move all unacked segments to the head of the unsent queue */

+  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);

+  /* concatenate unsent queue after unacked queue */

+  seg->next = pcb->unsent;

+  /* unsent queue is the concatenated queue (of unacked, unsent) */

+  pcb->unsent = pcb->unacked;

+  /* unacked queue is now empty */

+  pcb->unacked = NULL;

+

+  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);

+  /* increment number of retransmissions */

+  ++pcb->nrtx;

+

+  /* Don't take any RTT measurements after retransmitting. */

+  pcb->rttest = 0;

+

+  /* Do the actual retransmission */

+  tcp_output(pcb);

+}

+

+void

+tcp_rexmit(struct tcp_pcb *pcb)

+{

+  struct tcp_seg *seg;

+

+  if (pcb->unacked == NULL) {

+    return;

+  }

+

+  /* Move the first unacked segment to the unsent queue */

+  seg = pcb->unacked->next;

+  pcb->unacked->next = pcb->unsent;

+  pcb->unsent = pcb->unacked;

+  pcb->unacked = seg;

+

+  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);

+

+  ++pcb->nrtx;

+

+  /* Don't take any rtt measurements after retransmitting. */

+  pcb->rttest = 0;

+

+  /* Do the actual retransmission. */

+  snmp_inc_tcpretranssegs();

+  tcp_output(pcb);

+

+}

+

+

+void

+tcp_keepalive(struct tcp_pcb *pcb)

+{

+   struct pbuf *p;

+   struct tcp_hdr *tcphdr;

+

+   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+                           ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),

+                           ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));

+

+   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F"  pcb->keep_cnt %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt));

+   

+   p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);

+

+   if(p == NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n"));

+      return;

+   }

+

+   tcphdr = p->payload;

+   tcphdr->src = htons(pcb->local_port);

+   tcphdr->dest = htons(pcb->remote_port);

+   tcphdr->seqno = htonl(pcb->snd_nxt - 1);

+   tcphdr->ackno = htonl(pcb->rcv_nxt);

+   tcphdr->wnd = htons(pcb->rcv_wnd);

+   tcphdr->urgp = 0;

+   TCPH_HDRLEN_SET(tcphdr, 5);

+   

+   tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+   tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len);

+#endif

+  TCP_STATS_INC(tcp.xmit);

+

+   /* Send output to IP */

+  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);

+

+  pbuf_free(p);

+

+  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt));

+}

+

+#endif /* LWIP_TCP */

+

+

+

+

+

+

+

+

+

diff --git a/Demo/Common/ethernet/lwIP/core/udp.c b/Demo/Common/ethernet/lwIP/core/udp.c
index c487d26..3d5980f 100644
--- a/Demo/Common/ethernet/lwIP/core/udp.c
+++ b/Demo/Common/ethernet/lwIP/core/udp.c
@@ -1,665 +1,665 @@
-/**
- * @file
- * User Datagram Protocol module
- *
- */
-/*
- * 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>
- *
- */
-
-
-/* udp.c
- *
- * The code for the User Datagram Protocol UDP.
- *
- */
-
-#include <string.h>
-
-#include "lwip/opt.h"
-
-#include "lwip/def.h"
-#include "lwip/memp.h"
-#include "lwip/inet.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/udp.h"
-#include "lwip/icmp.h"
-
-#include "lwip/stats.h"
-
-#include "arch/perf.h"
-#include "lwip/snmp.h"
-
-/* The list of UDP PCBs */
-#if LWIP_UDP
-/* exported in udp.h (was static) */
-struct udp_pcb *udp_pcbs = NULL;
-
-static struct udp_pcb *pcb_cache = NULL;
-
-void
-udp_init(void)
-{
-  udp_pcbs = pcb_cache = NULL;
-}
-
-/**
- * Process an incoming UDP datagram.
- *
- * Given an incoming UDP datagram (as a chain of pbufs) this function
- * finds a corresponding UDP PCB and
- *
- * @param pbuf pbuf to be demultiplexed to a UDP PCB.
- * @param netif network interface on which the datagram was received.
- *
- */
-void
-udp_input(struct pbuf *p, struct netif *inp)
-{
-  struct udp_hdr *udphdr;
-  struct udp_pcb *pcb;
-  struct udp_pcb *uncon_pcb;
-  struct ip_hdr *iphdr;
-  u16_t src, dest;
-  u8_t local_match;
-
-  PERF_START;
-
-  UDP_STATS_INC(udp.recv);
-
-  iphdr = p->payload;
-
-  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN)) {
-    /* drop short packets */
-//    LWIP_DEBUGF(UDP_DEBUG,
+/**

+ * @file

+ * User Datagram Protocol module

+ *

+ */

+/*

+ * 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>

+ *

+ */

+

+

+/* udp.c

+ *

+ * The code for the User Datagram Protocol UDP.

+ *

+ */

+

+#include <string.h>

+

+#include "lwip/opt.h"

+

+#include "lwip/def.h"

+#include "lwip/memp.h"

+#include "lwip/inet.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/udp.h"

+#include "lwip/icmp.h"

+

+#include "lwip/stats.h"

+

+#include "arch/perf.h"

+#include "lwip/snmp.h"

+

+/* The list of UDP PCBs */

+#if LWIP_UDP

+/* exported in udp.h (was static) */

+struct udp_pcb *udp_pcbs = NULL;

+

+static struct udp_pcb *pcb_cache = NULL;

+

+void

+udp_init(void)

+{

+  udp_pcbs = pcb_cache = NULL;

+}

+

+/**

+ * Process an incoming UDP datagram.

+ *

+ * Given an incoming UDP datagram (as a chain of pbufs) this function

+ * finds a corresponding UDP PCB and

+ *

+ * @param pbuf pbuf to be demultiplexed to a UDP PCB.

+ * @param netif network interface on which the datagram was received.

+ *

+ */

+void

+udp_input(struct pbuf *p, struct netif *inp)

+{

+  struct udp_hdr *udphdr;

+  struct udp_pcb *pcb;

+  struct udp_pcb *uncon_pcb;

+  struct ip_hdr *iphdr;

+  u16_t src, dest;

+  u8_t local_match;

+

+  PERF_START;

+

+  UDP_STATS_INC(udp.recv);

+

+  iphdr = p->payload;

+

+  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN)) {

+    /* drop short packets */

+//    LWIP_DEBUGF(UDP_DEBUG,

 //                ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));

 

     LWIP_DEBUGF(UDP_DEBUG,

                 ("udp_input: short UDP datagram (%u bytes) discarded\n", p->tot_len));

-
-    UDP_STATS_INC(udp.lenerr);
-    UDP_STATS_INC(udp.drop);
-    snmp_inc_udpinerrors();
-    pbuf_free(p);
-    goto end;
-  }
-
-  pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4)));
-
-  udphdr = (struct udp_hdr *)p->payload;
-
-  LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
-
-  src = ntohs(udphdr->src);
-  dest = ntohs(udphdr->dest);
-
-  udp_debug_print(udphdr);
-
-  /* print the UDP source and destination */
-  LWIP_DEBUGF(UDP_DEBUG,
-              ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
-               "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
-               ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
-               ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
-               ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
-               ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
-
-  local_match = 0;
-  uncon_pcb = NULL;
-  /* Iterate through the UDP pcb list for a matching pcb */
-  for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
-    /* print the PCB local and remote address */
-    LWIP_DEBUGF(UDP_DEBUG,
-                ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
-                 "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
-                 ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
-                 ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
-                 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
-                 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
-
-    /* compare PCB local addr+port to UDP destination addr+port */
-    if ((pcb->local_port == dest) &&
-        (ip_addr_isany(&pcb->local_ip) ||
-         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || 
-         ip_addr_isbroadcast(&(iphdr->dest), inp))) {
-      local_match = 1;
-      if ((uncon_pcb == NULL) && 
-          ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
-        /* the first unconnected matching PCB */     
-        uncon_pcb = pcb;
-      }
-    }
-    /* compare PCB remote addr+port to UDP source addr+port */
-    if ((local_match != 0) &&
-        (pcb->remote_port == src) &&
-        (ip_addr_isany(&pcb->remote_ip) ||
-         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {
-      /* the first fully matching PCB */
-      break;
-    }
-  }
-  /* no fully matching pcb found? then look for an unconnected pcb */
-  if (pcb == NULL) {
-    pcb = uncon_pcb;
-  }
-
-  /* Check checksum if this is a match or if it was directed at us. */
-  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {
-    LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: calculating checksum\n"));
-#ifdef IPv6
-    if (iphdr->nexthdr == IP_PROTO_UDPLITE) {
-#else
-    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
-#endif /* IPv4 */
-      /* Do the UDP Lite checksum */
-#if CHECKSUM_CHECK_UDP
-      if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
-                             (struct ip_addr *)&(iphdr->dest),
-                             IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) {
-        LWIP_DEBUGF(UDP_DEBUG | 2,
-                    ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
-        UDP_STATS_INC(udp.chkerr);
-        UDP_STATS_INC(udp.drop);
-        snmp_inc_udpinerrors();
-        pbuf_free(p);
-        goto end;
-      }
-#endif
-    } else {
-#if CHECKSUM_CHECK_UDP
-      if (udphdr->chksum != 0) {
-        if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
-                               (struct ip_addr *)&(iphdr->dest),
-                               IP_PROTO_UDP, p->tot_len) != 0) {
-          LWIP_DEBUGF(UDP_DEBUG | 2,
-                      ("udp_input: UDP datagram discarded due to failing checksum\n"));
-          UDP_STATS_INC(udp.chkerr);
-          UDP_STATS_INC(udp.drop);
-          snmp_inc_udpinerrors();
-          pbuf_free(p);
-          goto end;
-        }
-      }
-#endif
-    }
-    pbuf_header(p, -UDP_HLEN);
-    if (pcb != NULL) {
-      snmp_inc_udpindatagrams();
-      /* callback */
-      if (pcb->recv != NULL)
-        pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
-    } else {
-      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n"));
-
-      /* No match was found, send ICMP destination port unreachable unless
-         destination address was broadcast/multicast. */
-
-      if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&
-          !ip_addr_ismulticast(&iphdr->dest)) {
-
-        /* restore pbuf pointer */
-        p->payload = iphdr;
-        icmp_dest_unreach(p, ICMP_DUR_PORT);
-      }
-      UDP_STATS_INC(udp.proterr);
-      UDP_STATS_INC(udp.drop);
-      snmp_inc_udpnoports();
-      pbuf_free(p);
-    }
-  } else {
-    pbuf_free(p);
-  }
-end:
-  PERF_STOP("udp_input");
-}
-
-/**
- * Send data to a specified address using UDP.
- *
- * @param pcb UDP PCB used to send the data.
- * @param pbuf chain of pbuf's to be sent.
- * @param dst_ip Destination IP address.
- * @param dst_port Destination UDP port.
- *
- * If the PCB already has a remote address association, it will
- * be restored after the data is sent.
- * 
- * @return lwIP error code.
- * - ERR_OK. Successful. No error occured.
- * - ERR_MEM. Out of memory.
- * - ERR_RTE. Could not find route to destination address.
- *
- * @see udp_disconnect() udp_send()
- */
-err_t
-udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
-  struct ip_addr *dst_ip, u16_t dst_port)
-{
-  err_t err;
-  /* temporary space for current PCB remote address */
-  struct ip_addr pcb_remote_ip;
-  u16_t pcb_remote_port;
-  /* remember current remote peer address of PCB */
-  pcb_remote_ip.addr = pcb->remote_ip.addr;
-  pcb_remote_port = pcb->remote_port;
-  /* copy packet destination address to PCB remote peer address */
-  pcb->remote_ip.addr = dst_ip->addr;
-  pcb->remote_port = dst_port;
-  /* send to the packet destination address */
-  err = udp_send(pcb, p);
-  /* restore PCB remote peer address */
-  pcb->remote_ip.addr = pcb_remote_ip.addr;
-  pcb->remote_port = pcb_remote_port;
-  return err;
-}
-
-/**
- * Send data using UDP.
- *
- * @param pcb UDP PCB used to send the data.
- * @param pbuf chain of pbuf's to be sent.
- *
- * @return lwIP error code.
- * - ERR_OK. Successful. No error occured.
- * - ERR_MEM. Out of memory.
- * - ERR_RTE. Could not find route to destination address.
- *
- * @see udp_disconnect() udp_sendto()
- */
-err_t
-udp_send(struct udp_pcb *pcb, struct pbuf *p)
-{
-  struct udp_hdr *udphdr;
-  struct netif *netif;
-  struct ip_addr *src_ip;
-  err_t err;
-  struct pbuf *q; /* q will be sent down the stack */
-
-  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_send\n"));
-
-  /* if the PCB is not yet bound to a port, bind it here */
-  if (pcb->local_port == 0) {
-    LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
-    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
-    if (err != ERR_OK) {
-      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
-      return err;
-    }
-  }
-  /* find the outgoing network interface for this packet */
-  netif = ip_route(&(pcb->remote_ip));
-  /* no outgoing network interface could be found? */
-  if (netif == NULL) {
-    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", pcb->remote_ip.addr));
-    UDP_STATS_INC(udp.rterr);
-    return ERR_RTE;
-  }
-
-  /* not enough space to add an UDP header to first pbuf in given p chain? */
-  if (pbuf_header(p, UDP_HLEN)) {
-    /* allocate header in a seperate new pbuf */
-    q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
-    /* new header pbuf could not be allocated? */
-    if (q == NULL) {
-      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
-      return ERR_MEM;
-    }
-    /* chain header q in front of given pbuf p */
-    pbuf_chain(q, p);
-    /* first pbuf q points to header pbuf */
-    LWIP_DEBUGF(UDP_DEBUG,
-                ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
-    /* adding a header within p succeeded */
-  } else {
-    /* first pbuf q equals given pbuf */
-    q = p;
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
-  }
-  /* q now represents the packet to be sent */
-  udphdr = q->payload;
-  udphdr->src = htons(pcb->local_port);
-  udphdr->dest = htons(pcb->remote_port);
-  /* in UDP, 0 checksum means 'no checksum' */
-  udphdr->chksum = 0x0000; 
-
-  /* PCB local address is IP_ANY_ADDR? */
-  if (ip_addr_isany(&pcb->local_ip)) {
-    /* use outgoing network interface IP address as source address */
-    src_ip = &(netif->ip_addr);
-  } else {
-    /* use UDP PCB local IP address as source address */
-    src_ip = &(pcb->local_ip);
-  }
-
-  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
-
-  /* UDP Lite protocol? */
-  if (pcb->flags & UDP_FLAGS_UDPLITE) {
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));
-    /* set UDP message length in UDP header */
-    udphdr->len = htons(pcb->chksum_len);
-    /* calculate checksum */
-#if CHECKSUM_GEN_UDP
-    udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip),
-                                        IP_PROTO_UDP, pcb->chksum_len);
-    /* chksum zero must become 0xffff, as zero means 'no checksum' */
-    if (udphdr->chksum == 0x0000)
-      udphdr->chksum = 0xffff;
-#else
-    udphdr->chksum = 0x0000;
-#endif
-    /* output to IP */
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
-    err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);    
-  } else {      /* UDP */
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));
-    udphdr->len = htons(q->tot_len);
-    /* calculate checksum */
-#if CHECKSUM_GEN_UDP
-    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
-      udphdr->chksum = inet_chksum_pseudo(q, src_ip, &pcb->remote_ip, IP_PROTO_UDP, q->tot_len);
-      /* chksum zero must become 0xffff, as zero means 'no checksum' */
-      if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
-    }
-#else
-    udphdr->chksum = 0x0000;
-#endif
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
-    /* output to IP */
-    err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);    
-  }
-  /* TODO: must this be increased even if error occured? */
-  snmp_inc_udpoutdatagrams();
-
-  /* did we chain a seperate header pbuf earlier? */
-  if (q != p) {
-    /* free the header pbuf */
-    pbuf_free(q);
-    q = NULL;
-    /* p is still referenced by the caller, and will live on */
-  }
-
-  UDP_STATS_INC(udp.xmit);
-  return err;
-}
-
-/**
- * Bind an UDP PCB.
- *
- * @param pcb UDP PCB to be bound with a local address ipaddr and port.
- * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
- * bind to all local interfaces.
- * @param port local UDP port to bind with.
- *
- * @return lwIP error code.
- * - ERR_OK. Successful. No error occured.
- * - ERR_USE. The specified ipaddr and port are already bound to by
- * another UDP PCB.
- *
- * @see udp_disconnect()
- */
-err_t
-udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
-{
-  struct udp_pcb *ipcb;
-  u8_t rebind;
-
-  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = "));
-  ip_addr_debug_print(UDP_DEBUG, ipaddr);
-  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %"U16_F")\n", port));
-
-  rebind = 0;
-  /* Check for double bind and rebind of the same pcb */
-  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
-    /* is this UDP PCB already on active list? */
-    if (pcb == ipcb) {
-      /* pcb may occur at most once in active list */
-      LWIP_ASSERT("rebind == 0", rebind == 0);
-      /* pcb already in list, just rebind */
-      rebind = 1;
-    }
-
-    /* this code does not allow upper layer to share a UDP port for
-       listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
-       SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
-       combine with implementation of UDP PCB flags. Leon Woestenberg. */
-#ifdef LWIP_UDP_TODO
-    /* port matches that of PCB in list? */
-    else
-      if ((ipcb->local_port == port) &&
-          /* IP address matches, or one is IP_ADDR_ANY? */
-          (ip_addr_isany(&(ipcb->local_ip)) ||
-           ip_addr_isany(ipaddr) ||
-           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
-        /* other PCB already binds to this local IP and port */
-        LWIP_DEBUGF(UDP_DEBUG,
-                    ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
-        return ERR_USE;
-      }
-#endif
-  }
-
-  ip_addr_set(&pcb->local_ip, ipaddr);
-
-  /* no port specified? */
-  if (port == 0) {
-#ifndef UDP_LOCAL_PORT_RANGE_START
-#define UDP_LOCAL_PORT_RANGE_START 4096
-#define UDP_LOCAL_PORT_RANGE_END   0x7fff
-#endif
-    port = UDP_LOCAL_PORT_RANGE_START;
-    ipcb = udp_pcbs;
-    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
-      if (ipcb->local_port == port) {
-        port++;
-        ipcb = udp_pcbs;
-      } else
-        ipcb = ipcb->next;
-    }
-    if (ipcb != NULL) {
-      /* no more ports available in local range */
-      LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
-      return ERR_USE;
-    }
-  }
-  pcb->local_port = port;
-  snmp_insert_udpidx_tree(pcb);
-  /* pcb not active yet? */
-  if (rebind == 0) {
-    /* place the PCB on the active list if not already there */
-    pcb->next = udp_pcbs;
-    udp_pcbs = pcb;
-  }
-  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE,
-              ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
-               (u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),
-               (u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),
-               (u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),
-               (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
-  return ERR_OK;
-}
-/**
- * Connect an UDP PCB.
- *
- * This will associate the UDP PCB with the remote address.
- *
- * @param pcb UDP PCB to be connected with remote address ipaddr and port.
- * @param ipaddr remote IP address to connect with.
- * @param port remote UDP port to connect with.
- *
- * @return lwIP error code
- *
- * @see udp_disconnect()
- */
-err_t
-udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
-{
-  struct udp_pcb *ipcb;
-
-  if (pcb->local_port == 0) {
-    err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
-    if (err != ERR_OK)
-      return err;
-  }
-
-  ip_addr_set(&pcb->remote_ip, ipaddr);
-  pcb->remote_port = port;
-  pcb->flags |= UDP_FLAGS_CONNECTED;
-/** TODO: this functionality belongs in upper layers */
-#ifdef LWIP_UDP_TODO
-  /* Nail down local IP for netconn_addr()/getsockname() */
-  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
-    struct netif *netif;
-
-    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
-      LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
-      UDP_STATS_INC(udp.rterr);
-      return ERR_RTE;
-    }
-    /** TODO: this will bind the udp pcb locally, to the interface which
-        is used to route output packets to the remote address. However, we
-        might want to accept incoming packets on any interface! */
-    pcb->local_ip = netif->ip_addr;
-  } else if (ip_addr_isany(&pcb->remote_ip)) {
-    pcb->local_ip.addr = 0;
-  }
-#endif
-  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE,
-              ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
-               (u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),
-               (u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),
-               (u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),
-               (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
-
-  /* Insert UDP PCB into the list of active UDP PCBs. */
-  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
-    if (pcb == ipcb) {
-      /* already on the list, just return */
-      return ERR_OK;
-    }
-  }
-  /* PCB not yet on the list, add PCB now */
-  pcb->next = udp_pcbs;
-  udp_pcbs = pcb;
-  return ERR_OK;
-}
-
-void
-udp_disconnect(struct udp_pcb *pcb)
-{
-  /* reset remote address association */
-  ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);
-  pcb->remote_port = 0;
-  /* mark PCB as unconnected */
-  pcb->flags &= ~UDP_FLAGS_CONNECTED;
-}
-
-void
-udp_recv(struct udp_pcb *pcb,
-         void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
-                       struct ip_addr *addr, u16_t port),
-         void *recv_arg)
-{
-  /* remember recv() callback and user data */
-  pcb->recv = recv;
-  pcb->recv_arg = recv_arg;
-}
-
-/**
- * Remove an UDP PCB.
- *
- * @param pcb UDP PCB to be removed. The PCB is removed from the list of
- * UDP PCB's and the data structure is freed from memory.
- *
- * @see udp_new()
- */
-void
-udp_remove(struct udp_pcb *pcb)
-{
-  struct udp_pcb *pcb2;
-
-  snmp_delete_udpidx_tree(pcb);
-  /* pcb to be removed is first in list? */
-  if (udp_pcbs == pcb) {
-    /* make list start at 2nd pcb */
-    udp_pcbs = udp_pcbs->next;
-    /* pcb not 1st in list */
-  } else
-    for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
-      /* find pcb in udp_pcbs list */
-      if (pcb2->next != NULL && pcb2->next == pcb) {
-        /* remove pcb from list */
-        pcb2->next = pcb->next;
-      }
-    }
-  memp_free(MEMP_UDP_PCB, pcb);
-}
-
-/**
- * Create a UDP PCB.
- *
- * @return The UDP PCB which was created. NULL if the PCB data structure
- * could not be allocated.
- *
- * @see udp_remove()
- */
-struct udp_pcb *
-udp_new(void)
-{
-  struct udp_pcb *pcb;
-  pcb = memp_malloc(MEMP_UDP_PCB);
-  /* could allocate UDP PCB? */
-  if (pcb != NULL) {
-    /* initialize PCB to all zeroes */
-    memset(pcb, 0, sizeof(struct udp_pcb));
-    pcb->ttl = UDP_TTL;
-  }
-  return pcb;
-}
-
-#if UDP_DEBUG
-void
-udp_debug_print(struct udp_hdr *udphdr)
-{
-  LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));
-  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     %5"U16_F"     | (src port, dest port)\n",
-                          ntohs(udphdr->src), ntohs(udphdr->dest)));
-  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     0x%04"X16_F"    | (len, chksum)\n",
-                          ntohs(udphdr->len), ntohs(udphdr->chksum)));
-  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
-}
-#endif /* UDP_DEBUG */
-
-#endif /* LWIP_UDP */
+

+    UDP_STATS_INC(udp.lenerr);

+    UDP_STATS_INC(udp.drop);

+    snmp_inc_udpinerrors();

+    pbuf_free(p);

+    goto end;

+  }

+

+  pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4)));

+

+  udphdr = (struct udp_hdr *)p->payload;

+

+  LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));

+

+  src = ntohs(udphdr->src);

+  dest = ntohs(udphdr->dest);

+

+  udp_debug_print(udphdr);

+

+  /* print the UDP source and destination */

+  LWIP_DEBUGF(UDP_DEBUG,

+              ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "

+               "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",

+               ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),

+               ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),

+               ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),

+               ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));

+

+  local_match = 0;

+  uncon_pcb = NULL;

+  /* Iterate through the UDP pcb list for a matching pcb */

+  for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {

+    /* print the PCB local and remote address */

+    LWIP_DEBUGF(UDP_DEBUG,

+                ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "

+                 "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",

+                 ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),

+                 ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,

+                 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),

+                 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));

+

+    /* compare PCB local addr+port to UDP destination addr+port */

+    if ((pcb->local_port == dest) &&

+        (ip_addr_isany(&pcb->local_ip) ||

+         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || 

+         ip_addr_isbroadcast(&(iphdr->dest), inp))) {

+      local_match = 1;

+      if ((uncon_pcb == NULL) && 

+          ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {

+        /* the first unconnected matching PCB */     

+        uncon_pcb = pcb;

+      }

+    }

+    /* compare PCB remote addr+port to UDP source addr+port */

+    if ((local_match != 0) &&

+        (pcb->remote_port == src) &&

+        (ip_addr_isany(&pcb->remote_ip) ||

+         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {

+      /* the first fully matching PCB */

+      break;

+    }

+  }

+  /* no fully matching pcb found? then look for an unconnected pcb */

+  if (pcb == NULL) {

+    pcb = uncon_pcb;

+  }

+

+  /* Check checksum if this is a match or if it was directed at us. */

+  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {

+    LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: calculating checksum\n"));

+#ifdef IPv6

+    if (iphdr->nexthdr == IP_PROTO_UDPLITE) {

+#else

+    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {

+#endif /* IPv4 */

+      /* Do the UDP Lite checksum */

+#if CHECKSUM_CHECK_UDP

+      if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),

+                             (struct ip_addr *)&(iphdr->dest),

+                             IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) {

+        LWIP_DEBUGF(UDP_DEBUG | 2,

+                    ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));

+        UDP_STATS_INC(udp.chkerr);

+        UDP_STATS_INC(udp.drop);

+        snmp_inc_udpinerrors();

+        pbuf_free(p);

+        goto end;

+      }

+#endif

+    } else {

+#if CHECKSUM_CHECK_UDP

+      if (udphdr->chksum != 0) {

+        if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),

+                               (struct ip_addr *)&(iphdr->dest),

+                               IP_PROTO_UDP, p->tot_len) != 0) {

+          LWIP_DEBUGF(UDP_DEBUG | 2,

+                      ("udp_input: UDP datagram discarded due to failing checksum\n"));

+          UDP_STATS_INC(udp.chkerr);

+          UDP_STATS_INC(udp.drop);

+          snmp_inc_udpinerrors();

+          pbuf_free(p);

+          goto end;

+        }

+      }

+#endif

+    }

+    pbuf_header(p, -UDP_HLEN);

+    if (pcb != NULL) {

+      snmp_inc_udpindatagrams();

+      /* callback */

+      if (pcb->recv != NULL)

+        pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);

+    } else {

+      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n"));

+

+      /* No match was found, send ICMP destination port unreachable unless

+         destination address was broadcast/multicast. */

+

+      if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&

+          !ip_addr_ismulticast(&iphdr->dest)) {

+

+        /* restore pbuf pointer */

+        p->payload = iphdr;

+        icmp_dest_unreach(p, ICMP_DUR_PORT);

+      }

+      UDP_STATS_INC(udp.proterr);

+      UDP_STATS_INC(udp.drop);

+      snmp_inc_udpnoports();

+      pbuf_free(p);

+    }

+  } else {

+    pbuf_free(p);

+  }

+end:

+  PERF_STOP("udp_input");

+}

+

+/**

+ * Send data to a specified address using UDP.

+ *

+ * @param pcb UDP PCB used to send the data.

+ * @param pbuf chain of pbuf's to be sent.

+ * @param dst_ip Destination IP address.

+ * @param dst_port Destination UDP port.

+ *

+ * If the PCB already has a remote address association, it will

+ * be restored after the data is sent.

+ * 

+ * @return lwIP error code.

+ * - ERR_OK. Successful. No error occured.

+ * - ERR_MEM. Out of memory.

+ * - ERR_RTE. Could not find route to destination address.

+ *

+ * @see udp_disconnect() udp_send()

+ */

+err_t

+udp_sendto(struct udp_pcb *pcb, struct pbuf *p,

+  struct ip_addr *dst_ip, u16_t dst_port)

+{

+  err_t err;

+  /* temporary space for current PCB remote address */

+  struct ip_addr pcb_remote_ip;

+  u16_t pcb_remote_port;

+  /* remember current remote peer address of PCB */

+  pcb_remote_ip.addr = pcb->remote_ip.addr;

+  pcb_remote_port = pcb->remote_port;

+  /* copy packet destination address to PCB remote peer address */

+  pcb->remote_ip.addr = dst_ip->addr;

+  pcb->remote_port = dst_port;

+  /* send to the packet destination address */

+  err = udp_send(pcb, p);

+  /* restore PCB remote peer address */

+  pcb->remote_ip.addr = pcb_remote_ip.addr;

+  pcb->remote_port = pcb_remote_port;

+  return err;

+}

+

+/**

+ * Send data using UDP.

+ *

+ * @param pcb UDP PCB used to send the data.

+ * @param pbuf chain of pbuf's to be sent.

+ *

+ * @return lwIP error code.

+ * - ERR_OK. Successful. No error occured.

+ * - ERR_MEM. Out of memory.

+ * - ERR_RTE. Could not find route to destination address.

+ *

+ * @see udp_disconnect() udp_sendto()

+ */

+err_t

+udp_send(struct udp_pcb *pcb, struct pbuf *p)

+{

+  struct udp_hdr *udphdr;

+  struct netif *netif;

+  struct ip_addr *src_ip;

+  err_t err;

+  struct pbuf *q; /* q will be sent down the stack */

+

+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_send\n"));

+

+  /* if the PCB is not yet bound to a port, bind it here */

+  if (pcb->local_port == 0) {

+    LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));

+    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);

+    if (err != ERR_OK) {

+      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));

+      return err;

+    }

+  }

+  /* find the outgoing network interface for this packet */

+  netif = ip_route(&(pcb->remote_ip));

+  /* no outgoing network interface could be found? */

+  if (netif == NULL) {

+    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", pcb->remote_ip.addr));

+    UDP_STATS_INC(udp.rterr);

+    return ERR_RTE;

+  }

+

+  /* not enough space to add an UDP header to first pbuf in given p chain? */

+  if (pbuf_header(p, UDP_HLEN)) {

+    /* allocate header in a seperate new pbuf */

+    q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);

+    /* new header pbuf could not be allocated? */

+    if (q == NULL) {

+      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: could not allocate header\n"));

+      return ERR_MEM;

+    }

+    /* chain header q in front of given pbuf p */

+    pbuf_chain(q, p);

+    /* first pbuf q points to header pbuf */

+    LWIP_DEBUGF(UDP_DEBUG,

+                ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));

+    /* adding a header within p succeeded */

+  } else {

+    /* first pbuf q equals given pbuf */

+    q = p;

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));

+  }

+  /* q now represents the packet to be sent */

+  udphdr = q->payload;

+  udphdr->src = htons(pcb->local_port);

+  udphdr->dest = htons(pcb->remote_port);

+  /* in UDP, 0 checksum means 'no checksum' */

+  udphdr->chksum = 0x0000; 

+

+  /* PCB local address is IP_ANY_ADDR? */

+  if (ip_addr_isany(&pcb->local_ip)) {

+    /* use outgoing network interface IP address as source address */

+    src_ip = &(netif->ip_addr);

+  } else {

+    /* use UDP PCB local IP address as source address */

+    src_ip = &(pcb->local_ip);

+  }

+

+  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));

+

+  /* UDP Lite protocol? */

+  if (pcb->flags & UDP_FLAGS_UDPLITE) {

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));

+    /* set UDP message length in UDP header */

+    udphdr->len = htons(pcb->chksum_len);

+    /* calculate checksum */

+#if CHECKSUM_GEN_UDP

+    udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip),

+                                        IP_PROTO_UDP, pcb->chksum_len);

+    /* chksum zero must become 0xffff, as zero means 'no checksum' */

+    if (udphdr->chksum == 0x0000)

+      udphdr->chksum = 0xffff;

+#else

+    udphdr->chksum = 0x0000;

+#endif

+    /* output to IP */

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));

+    err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);    

+  } else {      /* UDP */

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));

+    udphdr->len = htons(q->tot_len);

+    /* calculate checksum */

+#if CHECKSUM_GEN_UDP

+    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {

+      udphdr->chksum = inet_chksum_pseudo(q, src_ip, &pcb->remote_ip, IP_PROTO_UDP, q->tot_len);

+      /* chksum zero must become 0xffff, as zero means 'no checksum' */

+      if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;

+    }

+#else

+    udphdr->chksum = 0x0000;

+#endif

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));

+    /* output to IP */

+    err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);    

+  }

+  /* TODO: must this be increased even if error occured? */

+  snmp_inc_udpoutdatagrams();

+

+  /* did we chain a seperate header pbuf earlier? */

+  if (q != p) {

+    /* free the header pbuf */

+    pbuf_free(q);

+    q = NULL;

+    /* p is still referenced by the caller, and will live on */

+  }

+

+  UDP_STATS_INC(udp.xmit);

+  return err;

+}

+

+/**

+ * Bind an UDP PCB.

+ *

+ * @param pcb UDP PCB to be bound with a local address ipaddr and port.

+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to

+ * bind to all local interfaces.

+ * @param port local UDP port to bind with.

+ *

+ * @return lwIP error code.

+ * - ERR_OK. Successful. No error occured.

+ * - ERR_USE. The specified ipaddr and port are already bound to by

+ * another UDP PCB.

+ *

+ * @see udp_disconnect()

+ */

+err_t

+udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

+{

+  struct udp_pcb *ipcb;

+  u8_t rebind;

+

+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = "));

+  ip_addr_debug_print(UDP_DEBUG, ipaddr);

+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %"U16_F")\n", port));

+

+  rebind = 0;

+  /* Check for double bind and rebind of the same pcb */

+  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {

+    /* is this UDP PCB already on active list? */

+    if (pcb == ipcb) {

+      /* pcb may occur at most once in active list */

+      LWIP_ASSERT("rebind == 0", rebind == 0);

+      /* pcb already in list, just rebind */

+      rebind = 1;

+    }

+

+    /* this code does not allow upper layer to share a UDP port for

+       listening to broadcast or multicast traffic (See SO_REUSE_ADDR and

+       SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR

+       combine with implementation of UDP PCB flags. Leon Woestenberg. */

+#ifdef LWIP_UDP_TODO

+    /* port matches that of PCB in list? */

+    else

+      if ((ipcb->local_port == port) &&

+          /* IP address matches, or one is IP_ADDR_ANY? */

+          (ip_addr_isany(&(ipcb->local_ip)) ||

+           ip_addr_isany(ipaddr) ||

+           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {

+        /* other PCB already binds to this local IP and port */

+        LWIP_DEBUGF(UDP_DEBUG,

+                    ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));

+        return ERR_USE;

+      }

+#endif

+  }

+

+  ip_addr_set(&pcb->local_ip, ipaddr);

+

+  /* no port specified? */

+  if (port == 0) {

+#ifndef UDP_LOCAL_PORT_RANGE_START

+#define UDP_LOCAL_PORT_RANGE_START 4096

+#define UDP_LOCAL_PORT_RANGE_END   0x7fff

+#endif

+    port = UDP_LOCAL_PORT_RANGE_START;

+    ipcb = udp_pcbs;

+    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {

+      if (ipcb->local_port == port) {

+        port++;

+        ipcb = udp_pcbs;

+      } else

+        ipcb = ipcb->next;

+    }

+    if (ipcb != NULL) {

+      /* no more ports available in local range */

+      LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));

+      return ERR_USE;

+    }

+  }

+  pcb->local_port = port;

+  snmp_insert_udpidx_tree(pcb);

+  /* pcb not active yet? */

+  if (rebind == 0) {

+    /* place the PCB on the active list if not already there */

+    pcb->next = udp_pcbs;

+    udp_pcbs = pcb;

+  }

+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE,

+              ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",

+               (u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),

+               (u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),

+               (u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),

+               (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));

+  return ERR_OK;

+}

+/**

+ * Connect an UDP PCB.

+ *

+ * This will associate the UDP PCB with the remote address.

+ *

+ * @param pcb UDP PCB to be connected with remote address ipaddr and port.

+ * @param ipaddr remote IP address to connect with.

+ * @param port remote UDP port to connect with.

+ *

+ * @return lwIP error code

+ *

+ * @see udp_disconnect()

+ */

+err_t

+udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

+{

+  struct udp_pcb *ipcb;

+

+  if (pcb->local_port == 0) {

+    err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);

+    if (err != ERR_OK)

+      return err;

+  }

+

+  ip_addr_set(&pcb->remote_ip, ipaddr);

+  pcb->remote_port = port;

+  pcb->flags |= UDP_FLAGS_CONNECTED;

+/** TODO: this functionality belongs in upper layers */

+#ifdef LWIP_UDP_TODO

+  /* Nail down local IP for netconn_addr()/getsockname() */

+  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {

+    struct netif *netif;

+

+    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {

+      LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));

+      UDP_STATS_INC(udp.rterr);

+      return ERR_RTE;

+    }

+    /** TODO: this will bind the udp pcb locally, to the interface which

+        is used to route output packets to the remote address. However, we

+        might want to accept incoming packets on any interface! */

+    pcb->local_ip = netif->ip_addr;

+  } else if (ip_addr_isany(&pcb->remote_ip)) {

+    pcb->local_ip.addr = 0;

+  }

+#endif

+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE,

+              ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",

+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),

+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),

+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),

+               (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));

+

+  /* Insert UDP PCB into the list of active UDP PCBs. */

+  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {

+    if (pcb == ipcb) {

+      /* already on the list, just return */

+      return ERR_OK;

+    }

+  }

+  /* PCB not yet on the list, add PCB now */

+  pcb->next = udp_pcbs;

+  udp_pcbs = pcb;

+  return ERR_OK;

+}

+

+void

+udp_disconnect(struct udp_pcb *pcb)

+{

+  /* reset remote address association */

+  ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);

+  pcb->remote_port = 0;

+  /* mark PCB as unconnected */

+  pcb->flags &= ~UDP_FLAGS_CONNECTED;

+}

+

+void

+udp_recv(struct udp_pcb *pcb,

+         void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,

+                       struct ip_addr *addr, u16_t port),

+         void *recv_arg)

+{

+  /* remember recv() callback and user data */

+  pcb->recv = recv;

+  pcb->recv_arg = recv_arg;

+}

+

+/**

+ * Remove an UDP PCB.

+ *

+ * @param pcb UDP PCB to be removed. The PCB is removed from the list of

+ * UDP PCB's and the data structure is freed from memory.

+ *

+ * @see udp_new()

+ */

+void

+udp_remove(struct udp_pcb *pcb)

+{

+  struct udp_pcb *pcb2;

+

+  snmp_delete_udpidx_tree(pcb);

+  /* pcb to be removed is first in list? */

+  if (udp_pcbs == pcb) {

+    /* make list start at 2nd pcb */

+    udp_pcbs = udp_pcbs->next;

+    /* pcb not 1st in list */

+  } else

+    for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {

+      /* find pcb in udp_pcbs list */

+      if (pcb2->next != NULL && pcb2->next == pcb) {

+        /* remove pcb from list */

+        pcb2->next = pcb->next;

+      }

+    }

+  memp_free(MEMP_UDP_PCB, pcb);

+}

+

+/**

+ * Create a UDP PCB.

+ *

+ * @return The UDP PCB which was created. NULL if the PCB data structure

+ * could not be allocated.

+ *

+ * @see udp_remove()

+ */

+struct udp_pcb *

+udp_new(void)

+{

+  struct udp_pcb *pcb;

+  pcb = memp_malloc(MEMP_UDP_PCB);

+  /* could allocate UDP PCB? */

+  if (pcb != NULL) {

+    /* initialize PCB to all zeroes */

+    memset(pcb, 0, sizeof(struct udp_pcb));

+    pcb->ttl = UDP_TTL;

+  }

+  return pcb;

+}

+

+#if UDP_DEBUG

+void

+udp_debug_print(struct udp_hdr *udphdr)

+{

+  LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));

+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     %5"U16_F"     | (src port, dest port)\n",

+                          ntohs(udphdr->src), ntohs(udphdr->dest)));

+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     0x%04"X16_F"    | (len, chksum)\n",

+                          ntohs(udphdr->len), ntohs(udphdr->chksum)));

+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));

+}

+#endif /* UDP_DEBUG */

+

+#endif /* LWIP_UDP */