]> git.sur5r.net Git - freertos/commitdiff
Add AVR32 port and demo files.
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Sun, 1 Apr 2007 19:44:02 +0000 (19:44 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Sun, 1 Apr 2007 19:44:02 +0000 (19:44 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@73 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

91 files changed:
Demo/Common/ethernet/lwIP/FILES [new file with mode: 0644]
Demo/Common/ethernet/lwIP/api/api_lib.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/api/api_msg.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/api/err.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/api/sockets.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/api/tcpip.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/dhcp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/inet.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/inet6.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/ipv4/icmp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/ipv4/ip.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/ipv4/ip_addr.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/ipv4/ip_frag.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/mem.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/memp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/netif.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/pbuf.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/raw.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/snmp/asn1_enc.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/snmp/mib2.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/snmp/mib_structs.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/snmp/msg_in.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/snmp/msg_out.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/stats.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/sys.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/tcp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/tcp_in.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/tcp_out.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/core/udp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/ipv4/lwip/icmp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/ipv4/lwip/inet.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip_addr.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip_frag.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/api.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/api_msg.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/arch.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/debug.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/def.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/dhcp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/err.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/mem.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/memp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/netif.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/pbuf.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/raw.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/sio.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/snmp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/snmp_asn1.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/snmp_msg.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/snmp_structs.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/sockets.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/stats.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/sys.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/tcp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/tcpip.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/lwip/udp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/netif/etharp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/netif/loopif.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/include/netif/slipif.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/FILES [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/etharp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ethernetif.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/loopif.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/auth.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/auth.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/chap.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/chap.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/chpms.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/chpms.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/fsm.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/fsm.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/ipcp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/ipcp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/lcp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/lcp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/magic.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/magic.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/md5.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/md5.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/pap.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/ppp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/ppp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/pppdebug.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/randm.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/randm.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/vj.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/vj.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/ppp/vjbsdhdr.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP/netif/slipif.c [new file with mode: 0644]

diff --git a/Demo/Common/ethernet/lwIP/FILES b/Demo/Common/ethernet/lwIP/FILES
new file mode 100644 (file)
index 0000000..2b65731
--- /dev/null
@@ -0,0 +1,13 @@
+api/      - The code for the high-level wrapper API. Not needed if
+            you use the lowel-level call-back/raw API.
+
+core/     - The core of the TPC/IP stack; protocol implementations,
+            memory and buffer management, and the low-level raw API.
+           
+include/  - lwIP include files.
+
+netif/    - Generic network interface device drivers are kept here,
+            as well as the ARP module.
+
+For more information on the various subdirectories, check the FILES
+file in each directory.
diff --git a/Demo/Common/ethernet/lwIP/api/api_lib.c b/Demo/Common/ethernet/lwIP/api/api_lib.c
new file mode 100644 (file)
index 0000000..01683b0
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+ * 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>
+ *
+ */
+
+/* This is the part of the API that is linked with
+   the application */
+
+#include "lwip/opt.h"
+#include "lwip/api.h"
+#include "lwip/api_msg.h"
+#include "lwip/memp.h"
+
+
+struct
+netbuf *netbuf_new(void)
+{
+  struct netbuf *buf;
+
+  buf = memp_malloc(MEMP_NETBUF);
+  if (buf != NULL) {
+    buf->p = NULL;
+    buf->ptr = NULL;
+    return buf;
+  } else {
+    return NULL;
+  }
+}
+
+void
+netbuf_delete(struct netbuf *buf)
+{
+  if (buf != NULL) {
+    if (buf->p != NULL) {
+      pbuf_free(buf->p);
+      buf->p = buf->ptr = NULL;
+    }
+    memp_free(MEMP_NETBUF, buf);
+  }
+}
+
+void *
+netbuf_alloc(struct netbuf *buf, u16_t size)
+{
+  /* Deallocate any previously allocated memory. */
+  if (buf->p != NULL) {
+    pbuf_free(buf->p);
+  }
+  buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
+  if (buf->p == NULL) {
+     return NULL;
+  }
+  buf->ptr = buf->p;
+  return buf->p->payload;
+}
+
+void
+netbuf_free(struct netbuf *buf)
+{
+  if (buf->p != NULL) {
+    pbuf_free(buf->p);
+  }
+  buf->p = buf->ptr = NULL;
+}
+
+void
+netbuf_ref(struct netbuf *buf, void *dataptr, u16_t size)
+{
+  if (buf->p != NULL) {
+    pbuf_free(buf->p);
+  }
+  buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
+  buf->p->payload = dataptr;
+  buf->p->len = buf->p->tot_len = size;
+  buf->ptr = buf->p;
+}
+
+void
+netbuf_chain(struct netbuf *head, struct netbuf *tail)
+{
+  pbuf_chain(head->p, tail->p);
+  head->ptr = head->p;
+  memp_free(MEMP_NETBUF, tail);
+}
+
+u16_t
+netbuf_len(struct netbuf *buf)
+{
+  return buf->p->tot_len;
+}
+
+err_t
+netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
+{
+  if (buf->ptr == NULL) {
+    return ERR_BUF;
+  }
+  *dataptr = buf->ptr->payload;
+  *len = buf->ptr->len;
+  return ERR_OK;
+}
+
+s8_t
+netbuf_next(struct netbuf *buf)
+{
+  if (buf->ptr->next == NULL) {
+    return -1;
+  }
+  buf->ptr = buf->ptr->next;
+  if (buf->ptr->next == NULL) {
+    return 1;
+  }
+  return 0;
+}
+
+void
+netbuf_first(struct netbuf *buf)
+{
+  buf->ptr = buf->p;
+}
+
+void
+netbuf_copy_partial(struct netbuf *buf, void *dataptr, u16_t len, u16_t offset)
+{
+  struct pbuf *p;
+  u16_t i, left;
+
+  left = 0;
+
+  if(buf == NULL || dataptr == NULL) {
+    return;
+  }
+  
+  /* This implementation is bad. It should use bcopy
+     instead. */
+  for(p = buf->p; left < len && p != NULL; p = p->next) {
+    if (offset != 0 && offset >= p->len) {
+      offset -= p->len;
+    } else {    
+      for(i = offset; i < p->len; ++i) {
+  ((u8_t *)dataptr)[left] = ((u8_t *)p->payload)[i];
+  if (++left >= len) {
+    return;
+  }
+      }
+      offset = 0;
+    }
+  }
+}
+
+void
+netbuf_copy(struct netbuf *buf, void *dataptr, u16_t len)
+{
+  netbuf_copy_partial(buf, dataptr, len, 0);
+}
+
+struct ip_addr *
+netbuf_fromaddr(struct netbuf *buf)
+{
+  return buf->fromaddr;
+}
+
+u16_t
+netbuf_fromport(struct netbuf *buf)
+{
+  return buf->fromport;
+}
+
+struct
+netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,
+                                   void (*callback)(struct netconn *, enum netconn_evt, u16_t len))
+{
+  struct netconn *conn;
+  struct api_msg *msg;
+
+  conn = memp_malloc(MEMP_NETCONN);
+  if (conn == NULL) {
+    return NULL;
+  }
+  
+  conn->err = ERR_OK;
+  conn->type = t;
+  conn->pcb.tcp = NULL;
+
+  if ((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) {
+    memp_free(MEMP_NETCONN, conn);
+    return NULL;
+  }
+  conn->recvmbox = SYS_MBOX_NULL;
+  conn->acceptmbox = SYS_MBOX_NULL;
+  conn->sem = sys_sem_new(0);
+  if (conn->sem == SYS_SEM_NULL) {
+    memp_free(MEMP_NETCONN, conn);
+    return NULL;
+  }
+  conn->state = NETCONN_NONE;
+  conn->socket = 0;
+  conn->callback = callback;
+  conn->recv_avail = 0;
+
+  if((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    memp_free(MEMP_NETCONN, conn);
+    return NULL;
+  }
+  
+  msg->type = API_MSG_NEWCONN;
+  msg->msg.msg.bc.port = proto; /* misusing the port field */
+  msg->msg.conn = conn;
+  api_msg_post(msg);  
+  sys_mbox_fetch(conn->mbox, NULL);
+  memp_free(MEMP_API_MSG, msg);
+
+  if ( conn->err != ERR_OK ) {
+    memp_free(MEMP_NETCONN, conn);
+    return NULL;
+  }
+
+  return conn;
+}
+
+
+struct
+netconn *netconn_new(enum netconn_type t)
+{
+  return netconn_new_with_proto_and_callback(t,0,NULL);
+}
+
+struct
+netconn *netconn_new_with_callback(enum netconn_type t,
+                                   void (*callback)(struct netconn *, enum netconn_evt, u16_t len))
+{
+  return netconn_new_with_proto_and_callback(t,0,callback);
+}
+
+
+err_t
+netconn_delete(struct netconn *conn)
+{
+  struct api_msg *msg;
+  void *mem;
+  
+  if (conn == NULL) {
+    return ERR_OK;
+  }
+  
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    return ERR_MEM;
+  }
+  
+  msg->type = API_MSG_DELCONN;
+  msg->msg.conn = conn;
+  api_msg_post(msg);  
+  sys_mbox_fetch(conn->mbox, NULL);
+  memp_free(MEMP_API_MSG, msg);
+
+  /* Drain the recvmbox. */
+  if (conn->recvmbox != SYS_MBOX_NULL) {
+    while (sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {
+      if (conn->type == NETCONN_TCP) {
+        if(mem != NULL)
+          pbuf_free((struct pbuf *)mem);
+      } else {
+        netbuf_delete((struct netbuf *)mem);
+      }
+    }
+    sys_mbox_free(conn->recvmbox);
+    conn->recvmbox = SYS_MBOX_NULL;
+  }
+
+  /* Drain the acceptmbox. */
+  if (conn->acceptmbox != SYS_MBOX_NULL) {
+    while (sys_arch_mbox_fetch(conn->acceptmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {
+      netconn_delete((struct netconn *)mem);
+    }
+    
+    sys_mbox_free(conn->acceptmbox);
+    conn->acceptmbox = SYS_MBOX_NULL;
+  }
+
+  sys_mbox_free(conn->mbox);
+  conn->mbox = SYS_MBOX_NULL;
+  if (conn->sem != SYS_SEM_NULL) {
+    sys_sem_free(conn->sem);
+  }
+  /*  conn->sem = SYS_SEM_NULL;*/
+  memp_free(MEMP_NETCONN, conn);
+  return ERR_OK;
+}
+
+enum netconn_type
+netconn_type(struct netconn *conn)
+{
+  return conn->type;
+}
+
+err_t
+netconn_peer(struct netconn *conn, struct ip_addr *addr,
+       u16_t *port)
+{
+  switch (conn->type) {
+  case NETCONN_RAW:
+    /* return an error as connecting is only a helper for upper layers */
+    return ERR_CONN;
+  case NETCONN_UDPLITE:
+  case NETCONN_UDPNOCHKSUM:
+  case NETCONN_UDP:
+    if (conn->pcb.udp == NULL ||
+  ((conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0))
+     return ERR_CONN;
+    *addr = (conn->pcb.udp->remote_ip);
+    *port = conn->pcb.udp->remote_port;
+    break;
+  case NETCONN_TCP:
+    if (conn->pcb.tcp == NULL)
+      return ERR_CONN;
+    *addr = (conn->pcb.tcp->remote_ip);
+    *port = conn->pcb.tcp->remote_port;
+    break;
+  }
+  return (conn->err = ERR_OK);
+}
+
+err_t
+netconn_addr(struct netconn *conn, struct ip_addr **addr,
+       u16_t *port)
+{
+  switch (conn->type) {
+  case NETCONN_RAW:
+    *addr = &(conn->pcb.raw->local_ip);
+    *port = conn->pcb.raw->protocol;
+    break;
+  case NETCONN_UDPLITE:
+  case NETCONN_UDPNOCHKSUM:
+  case NETCONN_UDP:
+    *addr = &(conn->pcb.udp->local_ip);
+    *port = conn->pcb.udp->local_port;
+    break;
+  case NETCONN_TCP:
+    *addr = &(conn->pcb.tcp->local_ip);
+    *port = conn->pcb.tcp->local_port;
+    break;
+  }
+  return (conn->err = ERR_OK);
+}
+
+err_t
+netconn_bind(struct netconn *conn, struct ip_addr *addr,
+      u16_t port)
+{
+  struct api_msg *msg;
+
+  if (conn == NULL) {
+    return ERR_VAL;
+  }
+
+  if (conn->type != NETCONN_TCP &&
+     conn->recvmbox == SYS_MBOX_NULL) {
+    if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
+      return ERR_MEM;
+    }
+  }
+  
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    return (conn->err = ERR_MEM);
+  }
+  msg->type = API_MSG_BIND;
+  msg->msg.conn = conn;
+  msg->msg.msg.bc.ipaddr = addr;
+  msg->msg.msg.bc.port = port;
+  api_msg_post(msg);
+  sys_mbox_fetch(conn->mbox, NULL);
+  memp_free(MEMP_API_MSG, msg);
+  return conn->err;
+}
+
+
+err_t
+netconn_connect(struct netconn *conn, struct ip_addr *addr,
+       u16_t port)
+{
+  struct api_msg *msg;
+  
+  if (conn == NULL) {
+    return ERR_VAL;
+  }
+
+
+  if (conn->recvmbox == SYS_MBOX_NULL) {
+    if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
+      return ERR_MEM;
+    }
+  }
+  
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    return ERR_MEM;
+  }
+  msg->type = API_MSG_CONNECT;
+  msg->msg.conn = conn;  
+  msg->msg.msg.bc.ipaddr = addr;
+  msg->msg.msg.bc.port = port;
+  api_msg_post(msg);
+  sys_mbox_fetch(conn->mbox, NULL);
+  memp_free(MEMP_API_MSG, msg);
+  return conn->err;
+}
+
+err_t
+netconn_disconnect(struct netconn *conn)
+{
+  struct api_msg *msg;
+  
+  if (conn == NULL) {
+    return ERR_VAL;
+  }
+
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    return ERR_MEM;
+  }
+  msg->type = API_MSG_DISCONNECT;
+  msg->msg.conn = conn;  
+  api_msg_post(msg);
+  sys_mbox_fetch(conn->mbox, NULL);
+  memp_free(MEMP_API_MSG, msg);
+  return conn->err;
+
+}
+
+err_t
+netconn_listen(struct netconn *conn)
+{
+  struct api_msg *msg;
+
+  if (conn == NULL) {
+    return ERR_VAL;
+  }
+
+  if (conn->acceptmbox == SYS_MBOX_NULL) {
+    conn->acceptmbox = sys_mbox_new();
+    if (conn->acceptmbox == SYS_MBOX_NULL) {
+      return ERR_MEM;
+    }
+  }
+  
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    return (conn->err = ERR_MEM);
+  }
+  msg->type = API_MSG_LISTEN;
+  msg->msg.conn = conn;
+  api_msg_post(msg);
+  sys_mbox_fetch(conn->mbox, NULL);
+  memp_free(MEMP_API_MSG, msg);
+  return conn->err;
+}
+
+struct netconn *
+netconn_accept(struct netconn *conn)
+{
+  struct netconn *newconn;
+  
+  if (conn == NULL) {
+    return NULL;
+  }
+  
+  sys_mbox_fetch(conn->acceptmbox, (void *)&newconn);
+  /* Register event with callback */
+  if (conn->callback)
+      (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, 0);
+  
+  return newconn;
+}
+
+struct netbuf *
+netconn_recv(struct netconn *conn)
+{
+  struct api_msg *msg;
+  struct netbuf *buf;
+  struct pbuf *p;
+  u16_t len;
+    
+  if (conn == NULL) {
+    return NULL;
+  }
+  
+  if (conn->recvmbox == SYS_MBOX_NULL) {
+    conn->err = ERR_CONN;
+    return NULL;
+  }
+
+  if (conn->err != ERR_OK) {
+    return NULL;
+  }
+
+  if (conn->type == NETCONN_TCP) {
+    if (conn->pcb.tcp->state == LISTEN) {
+      conn->err = ERR_CONN;
+      return NULL;
+    }
+
+
+    buf = memp_malloc(MEMP_NETBUF);
+
+    if (buf == NULL) {
+      conn->err = ERR_MEM;
+      return NULL;
+    }
+    
+    sys_mbox_fetch(conn->recvmbox, (void *)&p);
+
+    if (p != NULL)
+    {
+        len = p->tot_len;
+        conn->recv_avail -= len;
+    }
+    else
+        len = 0;
+    
+    /* Register event with callback */
+      if (conn->callback)
+        (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, len);
+
+    /* If we are closed, we indicate that we no longer wish to receive
+       data by setting conn->recvmbox to SYS_MBOX_NULL. */
+    if (p == NULL) {
+      memp_free(MEMP_NETBUF, buf);
+      sys_mbox_free(conn->recvmbox);
+      conn->recvmbox = SYS_MBOX_NULL;
+      return NULL;
+    }
+
+    buf->p = p;
+    buf->ptr = p;
+    buf->fromport = 0;
+    buf->fromaddr = NULL;
+
+    /* Let the stack know that we have taken the data. */
+    if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+      conn->err = ERR_MEM;
+      return buf;
+    }
+    msg->type = API_MSG_RECV;
+    msg->msg.conn = conn;
+    if (buf != NULL) {
+      msg->msg.msg.len = buf->p->tot_len;
+    } else {
+      msg->msg.msg.len = 1;
+    }
+    api_msg_post(msg);
+
+    sys_mbox_fetch(conn->mbox, NULL);
+    memp_free(MEMP_API_MSG, msg);
+  } else {
+    sys_mbox_fetch(conn->recvmbox, (void *)&buf);
+  conn->recv_avail -= buf->p->tot_len;
+    /* Register event with callback */
+    if (conn->callback)
+        (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
+  }
+
+  
+
+    
+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
+
+
+  return buf;
+}
+
+err_t
+netconn_send(struct netconn *conn, struct netbuf *buf)
+{
+  struct api_msg *msg;
+
+  if (conn == NULL) {
+    return ERR_VAL;
+  }
+
+  if (conn->err != ERR_OK) {
+    return conn->err;
+  }
+
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    return (conn->err = ERR_MEM);
+  }
+
+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
+  msg->type = API_MSG_SEND;
+  msg->msg.conn = conn;
+  msg->msg.msg.p = buf->p;
+  api_msg_post(msg);
+
+  sys_mbox_fetch(conn->mbox, NULL);
+  memp_free(MEMP_API_MSG, msg);
+  return conn->err;
+}
+
+err_t
+netconn_write(struct netconn *conn, void *dataptr, u16_t size, u8_t copy)
+{
+  struct api_msg *msg;
+  u16_t len;
+  
+  if (conn == NULL) {
+    return ERR_VAL;
+  }
+
+  if (conn->err != ERR_OK) {
+    return conn->err;
+  }
+
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    return (conn->err = ERR_MEM);
+  }
+  msg->type = API_MSG_WRITE;
+  msg->msg.conn = conn;
+        
+
+  conn->state = NETCONN_WRITE;
+  while (conn->err == ERR_OK && size > 0) {
+    msg->msg.msg.w.dataptr = dataptr;
+    msg->msg.msg.w.copy = copy;
+    
+    if (conn->type == NETCONN_TCP) {
+      if (tcp_sndbuf(conn->pcb.tcp) == 0) {
+  sys_sem_wait(conn->sem);
+  if (conn->err != ERR_OK) {
+    goto ret;
+  }
+      }
+      if (size > tcp_sndbuf(conn->pcb.tcp)) {
+  /* We cannot send more than one send buffer's worth of data at a
+     time. */
+  len = tcp_sndbuf(conn->pcb.tcp);
+      } else {
+  len = size;
+      }
+    } else {
+      len = size;
+    }
+    
+    LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy));
+    msg->msg.msg.w.len = len;
+    api_msg_post(msg);
+    sys_mbox_fetch(conn->mbox, NULL);    
+    if (conn->err == ERR_OK) {
+      dataptr = (void *)((u8_t *)dataptr + len);
+      size -= len;
+    } else if (conn->err == ERR_MEM) {
+      conn->err = ERR_OK;
+      sys_sem_wait(conn->sem);
+    } else {
+      goto ret;
+    }
+  }
+ ret:
+  memp_free(MEMP_API_MSG, msg);
+  conn->state = NETCONN_NONE;
+  
+  return conn->err;
+}
+
+err_t
+netconn_close(struct netconn *conn)
+{
+  struct api_msg *msg;
+
+  if (conn == NULL) {
+    return ERR_VAL;
+  }
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+    return (conn->err = ERR_MEM);
+  }
+
+  conn->state = NETCONN_CLOSE;
+ again:
+  msg->type = API_MSG_CLOSE;
+  msg->msg.conn = conn;
+  api_msg_post(msg);
+  sys_mbox_fetch(conn->mbox, NULL);
+  if (conn->err == ERR_MEM &&
+     conn->sem != SYS_SEM_NULL) {
+    sys_sem_wait(conn->sem);
+    goto again;
+  }
+  conn->state = NETCONN_NONE;
+  memp_free(MEMP_API_MSG, msg);
+  return conn->err;
+}
+
+err_t
+netconn_err(struct netconn *conn)
+{
+  return conn->err;
+}
+
diff --git a/Demo/Common/ethernet/lwIP/api/api_msg.c b/Demo/Common/ethernet/lwIP/api/api_msg.c
new file mode 100644 (file)
index 0000000..b7cf03b
--- /dev/null
@@ -0,0 +1,807 @@
+/*
+ * 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/arch.h"
+#include "lwip/api_msg.h"
+#include "lwip/memp.h"
+#include "lwip/sys.h"
+#include "lwip/tcpip.h"
+
+#if LWIP_RAW
+static u8_t
+recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
+    struct ip_addr *addr)
+{
+  struct netbuf *buf;
+  struct netconn *conn;
+
+  conn = arg;
+  if (!conn) return 0;
+
+  if (conn->recvmbox != SYS_MBOX_NULL) {
+    if (!(buf = memp_malloc(MEMP_NETBUF))) {
+      return 0;
+    }
+    pbuf_ref(p);
+    buf->p = p;
+    buf->ptr = p;
+    buf->fromaddr = addr;
+    buf->fromport = pcb->protocol;
+
+    conn->recv_avail += p->tot_len;
+    /* Register event with callback */
+    if (conn->callback)
+        (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
+    sys_mbox_post(conn->recvmbox, buf);
+  }
+
+  return 0; /* do not eat the packet */
+}
+#endif
+#if LWIP_UDP
+static void
+recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+   struct ip_addr *addr, u16_t port)
+{
+  struct netbuf *buf;
+  struct netconn *conn;
+
+  conn = arg;
+  
+  if (conn == NULL) {
+    pbuf_free(p);
+    return;
+  }
+  if (conn->recvmbox != SYS_MBOX_NULL) {
+    buf = memp_malloc(MEMP_NETBUF);
+    if (buf == NULL) {
+      pbuf_free(p);
+      return;
+    } else {
+      buf->p = p;
+      buf->ptr = p;
+      buf->fromaddr = addr;
+      buf->fromport = port;
+    }
+
+  conn->recv_avail += p->tot_len;
+    /* Register event with callback */
+    if (conn->callback)
+        (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
+    sys_mbox_post(conn->recvmbox, buf);
+  }
+}
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+
+static err_t
+recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
+{
+  struct netconn *conn;
+  u16_t len;
+  
+  conn = arg;
+
+  if (conn == NULL) {
+    pbuf_free(p);
+    return ERR_VAL;
+  }
+
+  if (conn->recvmbox != SYS_MBOX_NULL) {
+        
+    conn->err = err;
+    if (p != NULL) {
+        len = p->tot_len;
+        conn->recv_avail += len;
+    }
+    else
+        len = 0;
+    /* Register event with callback */
+    if (conn->callback)
+        (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, len);
+    sys_mbox_post(conn->recvmbox, p);
+  }  
+  return ERR_OK;
+}
+
+
+static err_t
+poll_tcp(void *arg, struct tcp_pcb *pcb)
+{
+  struct netconn *conn;
+
+  conn = arg;
+  if (conn != NULL &&
+     (conn->state == NETCONN_WRITE || conn->state == NETCONN_CLOSE) &&
+     conn->sem != SYS_SEM_NULL) {
+    sys_sem_signal(conn->sem);
+  }
+  return ERR_OK;
+}
+
+static err_t
+sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
+{
+  struct netconn *conn;
+
+  conn = arg;
+  if (conn != NULL && conn->sem != SYS_SEM_NULL) {
+    sys_sem_signal(conn->sem);
+  }
+
+  if (conn && conn->callback)
+      if (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)
+          (*conn->callback)(conn, NETCONN_EVT_SENDPLUS, len);
+  
+  return ERR_OK;
+}
+
+static void
+err_tcp(void *arg, err_t err)
+{
+  struct netconn *conn;
+
+  conn = arg;
+
+  conn->pcb.tcp = NULL;
+
+  
+  conn->err = err;
+  if (conn->recvmbox != SYS_MBOX_NULL) {
+    /* Register event with callback */
+    if (conn->callback)
+      (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
+    sys_mbox_post(conn->recvmbox, NULL);
+  }
+  if (conn->mbox != SYS_MBOX_NULL) {
+    sys_mbox_post(conn->mbox, NULL);
+  }
+  if (conn->acceptmbox != SYS_MBOX_NULL) {
+     /* Register event with callback */
+    if (conn->callback)
+      (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
+    sys_mbox_post(conn->acceptmbox, NULL);
+  }
+  if (conn->sem != SYS_SEM_NULL) {
+    sys_sem_signal(conn->sem);
+  }
+}
+
+static void
+setup_tcp(struct netconn *conn)
+{
+  struct tcp_pcb *pcb;
+  
+  pcb = conn->pcb.tcp;
+  tcp_arg(pcb, conn);
+  tcp_recv(pcb, recv_tcp);
+  tcp_sent(pcb, sent_tcp);
+  tcp_poll(pcb, poll_tcp, 4);
+  tcp_err(pcb, err_tcp);
+}
+
+static err_t
+accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
+{
+  sys_mbox_t mbox;
+  struct netconn *newconn;
+  struct netconn *conn;
+  
+#if API_MSG_DEBUG
+#if TCP_DEBUG
+  tcp_debug_print_state(newpcb->state);
+#endif /* TCP_DEBUG */
+#endif /* API_MSG_DEBUG */
+  conn = (struct netconn *)arg;
+  mbox = conn->acceptmbox;
+  newconn = memp_malloc(MEMP_NETCONN);
+  if (newconn == NULL) {
+    return ERR_MEM;
+  }
+  newconn->recvmbox = sys_mbox_new();
+  if (newconn->recvmbox == SYS_MBOX_NULL) {
+    memp_free(MEMP_NETCONN, newconn);
+    return ERR_MEM;
+  }
+  newconn->mbox = sys_mbox_new();
+  if (newconn->mbox == SYS_MBOX_NULL) {
+    sys_mbox_free(newconn->recvmbox);
+    memp_free(MEMP_NETCONN, newconn);
+    return ERR_MEM;
+  }
+  newconn->sem = sys_sem_new(0);
+  if (newconn->sem == SYS_SEM_NULL) {
+    sys_mbox_free(newconn->recvmbox);
+    sys_mbox_free(newconn->mbox);
+    memp_free(MEMP_NETCONN, newconn);
+    return ERR_MEM;
+  }
+  /* Allocations were OK, setup the PCB etc */
+  newconn->type = NETCONN_TCP;
+  newconn->pcb.tcp = newpcb;
+  setup_tcp(newconn);
+  newconn->acceptmbox = SYS_MBOX_NULL;
+  newconn->err = err;
+  /* Register event with callback */
+  if (conn->callback)
+  {
+    (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
+  }
+  /* We have to set the callback here even though
+   * the new socket is unknown. Mark the socket as -1. */
+  newconn->callback = conn->callback;
+  newconn->socket = -1;
+  newconn->recv_avail = 0;
+  
+  sys_mbox_post(mbox, newconn);
+  return ERR_OK;
+}
+#endif /* LWIP_TCP */
+
+static void
+do_newconn(struct api_msg_msg *msg)
+{
+   if(msg->conn->pcb.tcp != NULL) {
+   /* This "new" connection already has a PCB allocated. */
+   /* Is this an error condition? Should it be deleted? 
+      We currently just are happy and return. */
+     sys_mbox_post(msg->conn->mbox, NULL);
+     return;
+   }
+
+   msg->conn->err = ERR_OK;
+
+   /* Allocate a PCB for this connection */
+   switch(msg->conn->type) {
+#if LWIP_RAW
+   case NETCONN_RAW:
+      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field */
+      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
+     break;
+#endif
+#if LWIP_UDP
+   case NETCONN_UDPLITE:
+      msg->conn->pcb.udp = udp_new();
+      if(msg->conn->pcb.udp == NULL) {
+         msg->conn->err = ERR_MEM;
+         break;
+      }
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+   case NETCONN_UDPNOCHKSUM:
+      msg->conn->pcb.udp = udp_new();
+      if(msg->conn->pcb.udp == NULL) {
+         msg->conn->err = ERR_MEM;
+         break;
+      }
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+   case NETCONN_UDP:
+      msg->conn->pcb.udp = udp_new();
+      if(msg->conn->pcb.udp == NULL) {
+         msg->conn->err = ERR_MEM;
+         break;
+      }
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+   case NETCONN_TCP:
+      msg->conn->pcb.tcp = tcp_new();
+      if(msg->conn->pcb.tcp == NULL) {
+         msg->conn->err = ERR_MEM;
+         break;
+      }
+      setup_tcp(msg->conn);
+      break;
+#endif
+   }
+   
+  
+  sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+
+static void
+do_delconn(struct api_msg_msg *msg)
+{
+  if (msg->conn->pcb.tcp != NULL) {
+    switch (msg->conn->type) {
+#if LWIP_RAW
+    case NETCONN_RAW:
+      raw_remove(msg->conn->pcb.raw);
+      break;
+#endif
+#if LWIP_UDP
+    case NETCONN_UDPLITE:
+      /* FALLTHROUGH */
+    case NETCONN_UDPNOCHKSUM:
+      /* FALLTHROUGH */
+    case NETCONN_UDP:
+      msg->conn->pcb.udp->recv_arg = NULL;
+      udp_remove(msg->conn->pcb.udp);
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP      
+    case NETCONN_TCP:
+      if (msg->conn->pcb.tcp->state == LISTEN) {
+  tcp_arg(msg->conn->pcb.tcp, NULL);
+  tcp_accept(msg->conn->pcb.tcp, NULL);  
+  tcp_close(msg->conn->pcb.tcp);
+      } else {
+  tcp_arg(msg->conn->pcb.tcp, NULL);
+  tcp_sent(msg->conn->pcb.tcp, NULL);
+  tcp_recv(msg->conn->pcb.tcp, NULL);  
+  tcp_poll(msg->conn->pcb.tcp, NULL, 0);
+  tcp_err(msg->conn->pcb.tcp, NULL);
+  if (tcp_close(msg->conn->pcb.tcp) != ERR_OK) {
+    tcp_abort(msg->conn->pcb.tcp);
+  }
+      }
+#endif
+    default:  
+    break;
+    }
+  }
+  /* Trigger select() in socket layer */
+  if (msg->conn->callback)
+  {
+      (*msg->conn->callback)(msg->conn, NETCONN_EVT_RCVPLUS, 0);
+      (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDPLUS, 0);
+  }
+  
+  if (msg->conn->mbox != SYS_MBOX_NULL) {
+    sys_mbox_post(msg->conn->mbox, NULL);
+  }
+}
+
+static void
+do_bind(struct api_msg_msg *msg)
+{
+  if (msg->conn->pcb.tcp == NULL) {
+    switch (msg->conn->type) {
+#if LWIP_RAW
+    case NETCONN_RAW:
+      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
+      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
+      break;
+#endif
+#if LWIP_UDP
+    case NETCONN_UDPLITE:
+      msg->conn->pcb.udp = udp_new();
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+    case NETCONN_UDPNOCHKSUM:
+      msg->conn->pcb.udp = udp_new();
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+    case NETCONN_UDP:
+      msg->conn->pcb.udp = udp_new();
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP      
+    case NETCONN_TCP:
+      msg->conn->pcb.tcp = tcp_new();
+      setup_tcp(msg->conn);
+#endif /* LWIP_TCP */
+    default:  
+    break;
+    }
+  }
+  switch (msg->conn->type) {
+#if LWIP_RAW
+  case NETCONN_RAW:
+    msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr);
+    break;
+#endif
+#if LWIP_UDP
+  case NETCONN_UDPLITE:
+    /* FALLTHROUGH */
+  case NETCONN_UDPNOCHKSUM:
+    /* FALLTHROUGH */
+  case NETCONN_UDP:
+    msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
+    break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+  case NETCONN_TCP:
+    msg->conn->err = tcp_bind(msg->conn->pcb.tcp,
+            msg->msg.bc.ipaddr, msg->msg.bc.port);
+#endif /* LWIP_TCP */
+  default:
+    break;
+  }
+  sys_mbox_post(msg->conn->mbox, NULL);
+}
+#if LWIP_TCP
+
+static err_t
+do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
+{
+  struct netconn *conn;
+
+  conn = arg;
+
+  if (conn == NULL) {
+    return ERR_VAL;
+  }
+  
+  conn->err = err;
+  if (conn->type == NETCONN_TCP && err == ERR_OK) {
+    setup_tcp(conn);
+  }    
+  sys_mbox_post(conn->mbox, NULL);
+  return ERR_OK;
+}
+#endif  
+
+static void
+do_connect(struct api_msg_msg *msg)
+{
+  if (msg->conn->pcb.tcp == NULL) {
+    switch (msg->conn->type) {
+#if LWIP_RAW
+    case NETCONN_RAW:
+      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
+      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
+      break;
+#endif
+#if LWIP_UDP
+    case NETCONN_UDPLITE:
+      msg->conn->pcb.udp = udp_new();
+      if (msg->conn->pcb.udp == NULL) {
+  msg->conn->err = ERR_MEM;
+  sys_mbox_post(msg->conn->mbox, NULL);
+  return;
+      }
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+    case NETCONN_UDPNOCHKSUM:
+      msg->conn->pcb.udp = udp_new();
+      if (msg->conn->pcb.udp == NULL) {
+  msg->conn->err = ERR_MEM;
+  sys_mbox_post(msg->conn->mbox, NULL);
+  return;
+      }
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+    case NETCONN_UDP:
+      msg->conn->pcb.udp = udp_new();
+      if (msg->conn->pcb.udp == NULL) {
+  msg->conn->err = ERR_MEM;
+  sys_mbox_post(msg->conn->mbox, NULL);
+  return;
+      }
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP      
+    case NETCONN_TCP:
+      msg->conn->pcb.tcp = tcp_new();      
+      if (msg->conn->pcb.tcp == NULL) {
+  msg->conn->err = ERR_MEM;
+  sys_mbox_post(msg->conn->mbox, NULL);
+  return;
+      }
+#endif
+    default:
+      break;
+    }
+  }
+  switch (msg->conn->type) {
+#if LWIP_RAW
+  case NETCONN_RAW:
+    raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
+    sys_mbox_post(msg->conn->mbox, NULL);
+    break;
+#endif
+#if LWIP_UDP
+  case NETCONN_UDPLITE:
+    /* FALLTHROUGH */
+  case NETCONN_UDPNOCHKSUM:
+    /* FALLTHROUGH */
+  case NETCONN_UDP:
+    udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
+    sys_mbox_post(msg->conn->mbox, NULL);
+    break;
+#endif 
+#if LWIP_TCP      
+  case NETCONN_TCP:
+    /*    tcp_arg(msg->conn->pcb.tcp, msg->conn);*/
+    setup_tcp(msg->conn);
+    tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
+    do_connected);
+    /*tcp_output(msg->conn->pcb.tcp);*/
+#endif
+
+  default:
+    break;
+  }
+}
+
+static void
+do_disconnect(struct api_msg_msg *msg)
+{
+
+  switch (msg->conn->type) {
+#if LWIP_RAW
+  case NETCONN_RAW:
+    /* Do nothing as connecting is only a helper for upper lwip layers */
+    break;
+#endif
+#if LWIP_UDP
+  case NETCONN_UDPLITE:
+    /* FALLTHROUGH */
+  case NETCONN_UDPNOCHKSUM:
+    /* FALLTHROUGH */
+  case NETCONN_UDP:
+    udp_disconnect(msg->conn->pcb.udp);
+    break;
+#endif 
+  case NETCONN_TCP:
+    break;
+  }
+  sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+
+static void
+do_listen(struct api_msg_msg *msg)
+{
+  if (msg->conn->pcb.tcp != NULL) {
+    switch (msg->conn->type) {
+#if LWIP_RAW
+    case NETCONN_RAW:
+      LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen RAW: cannot listen for RAW.\n"));
+      break;
+#endif
+#if LWIP_UDP
+    case NETCONN_UDPLITE:
+      /* FALLTHROUGH */
+    case NETCONN_UDPNOCHKSUM:
+      /* FALLTHROUGH */
+    case NETCONN_UDP:
+      LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen UDP: cannot listen for UDP.\n"));
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP      
+    case NETCONN_TCP:
+      msg->conn->pcb.tcp = tcp_listen(msg->conn->pcb.tcp);
+      if (msg->conn->pcb.tcp == NULL) {
+  msg->conn->err = ERR_MEM;
+      } else {
+  if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
+    msg->conn->acceptmbox = sys_mbox_new();
+    if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
+      msg->conn->err = ERR_MEM;
+      break;
+    }
+  }
+  tcp_arg(msg->conn->pcb.tcp, msg->conn);
+  tcp_accept(msg->conn->pcb.tcp, accept_function);
+      }
+#endif
+    default:
+      break;
+    }
+  }
+  sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+static void
+do_accept(struct api_msg_msg *msg)
+{
+  if (msg->conn->pcb.tcp != NULL) {
+    switch (msg->conn->type) {
+#if LWIP_RAW
+    case NETCONN_RAW:
+      LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept RAW: cannot accept for RAW.\n"));
+      break;
+#endif
+#if LWIP_UDP
+    case NETCONN_UDPLITE:
+      /* FALLTHROUGH */
+    case NETCONN_UDPNOCHKSUM:
+      /* FALLTHROUGH */
+    case NETCONN_UDP:    
+      LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept UDP: cannot accept for UDP.\n"));
+      break;
+#endif /* LWIP_UDP */
+    case NETCONN_TCP:
+      break;
+    }
+  }
+}
+
+static void
+do_send(struct api_msg_msg *msg)
+{
+  if (msg->conn->pcb.tcp != NULL) {
+    switch (msg->conn->type) {
+#if LWIP_RAW
+    case NETCONN_RAW:
+      raw_send(msg->conn->pcb.raw, msg->msg.p);
+      break;
+#endif
+#if LWIP_UDP
+    case NETCONN_UDPLITE:
+      /* FALLTHROUGH */
+    case NETCONN_UDPNOCHKSUM:
+      /* FALLTHROUGH */
+    case NETCONN_UDP:
+      udp_send(msg->conn->pcb.udp, msg->msg.p);
+      break;
+#endif /* LWIP_UDP */
+    case NETCONN_TCP:
+      break;
+    }
+  }
+  sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+static void
+do_recv(struct api_msg_msg *msg)
+{
+#if LWIP_TCP
+  if (msg->conn->pcb.tcp != NULL) {
+    if (msg->conn->type == NETCONN_TCP) {
+      tcp_recved(msg->conn->pcb.tcp, msg->msg.len);
+    }
+  }
+#endif  
+  sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+static void
+do_write(struct api_msg_msg *msg)
+{
+#if LWIP_TCP  
+  err_t err;
+#endif  
+  if (msg->conn->pcb.tcp != NULL) {
+    switch (msg->conn->type) {
+#if LWIP_RAW
+    case NETCONN_RAW:
+      msg->conn->err = ERR_VAL;
+      break;
+#endif
+#if LWIP_UDP 
+    case NETCONN_UDPLITE:
+      /* FALLTHROUGH */
+    case NETCONN_UDPNOCHKSUM:
+      /* FALLTHROUGH */
+    case NETCONN_UDP:
+      msg->conn->err = ERR_VAL;
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP 
+    case NETCONN_TCP:      
+      err = tcp_write(msg->conn->pcb.tcp, msg->msg.w.dataptr,
+                      msg->msg.w.len, msg->msg.w.copy);
+      /* This is the Nagle algorithm: inhibit the sending of new TCP
+   segments when new outgoing data arrives from the user if any
+   previously transmitted data on the connection remains
+   unacknowledged. */
+      if(err == ERR_OK && (msg->conn->pcb.tcp->unacked == NULL ||
+        (msg->conn->pcb.tcp->flags & TF_NODELAY) || 
+        (msg->conn->pcb.tcp->snd_queuelen) > 1)) {
+          tcp_output(msg->conn->pcb.tcp);
+      }
+      msg->conn->err = err;
+      if (msg->conn->callback)
+          if (err == ERR_OK)
+          {
+              if (tcp_sndbuf(msg->conn->pcb.tcp) <= TCP_SNDLOWAT)
+                  (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDMINUS, msg->msg.w.len);
+          }
+#endif
+    default:
+      break;
+    }
+  }
+  sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+static void
+do_close(struct api_msg_msg *msg)
+{
+  err_t err;
+
+  err = ERR_OK;
+
+  if (msg->conn->pcb.tcp != NULL) {
+    switch (msg->conn->type) {
+#if LWIP_RAW
+    case NETCONN_RAW:
+      break;
+#endif
+#if LWIP_UDP
+    case NETCONN_UDPLITE:
+      /* FALLTHROUGH */
+    case NETCONN_UDPNOCHKSUM:
+      /* FALLTHROUGH */
+    case NETCONN_UDP:
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+    case NETCONN_TCP:
+      if (msg->conn->pcb.tcp->state == LISTEN) {
+        err = tcp_close(msg->conn->pcb.tcp);
+      }
+      else if (msg->conn->pcb.tcp->state == CLOSE_WAIT) {
+        err = tcp_output(msg->conn->pcb.tcp);
+      }
+      msg->conn->err = err;      
+#endif
+    default:      
+      break;
+    }
+  }
+  sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+typedef void (* api_msg_decode)(struct api_msg_msg *msg);
+static api_msg_decode decode[API_MSG_MAX] = {
+  do_newconn,
+  do_delconn,
+  do_bind,
+  do_connect,
+  do_disconnect,
+  do_listen,
+  do_accept,
+  do_send,
+  do_recv,
+  do_write,
+  do_close
+  };
+void
+api_msg_input(struct api_msg *msg)
+{  
+  decode[msg->type](&(msg->msg));
+}
+
+void
+api_msg_post(struct api_msg *msg)
+{
+  tcpip_apimsg(msg);
+}
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/api/err.c b/Demo/Common/ethernet/lwIP/api/err.c
new file mode 100644 (file)
index 0000000..b582d88
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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/err.h"
+
+#ifdef LWIP_DEBUG
+
+static char *err_strerr[] = {"Ok.",
+           "Out of memory error.",
+           "Buffer error.",
+           "Connection aborted.",
+           "Connection reset.",
+           "Connection closed.",
+           "Not connected.",
+           "Illegal value.",
+           "Illegal argument.",
+           "Routing problem.",
+           "Address in use."
+};
+
+
+char *
+lwip_strerr(err_t err)
+{
+  return err_strerr[-err];
+
+}
+
+
+#endif /* LWIP_DEBUG */
diff --git a/Demo/Common/ethernet/lwIP/api/sockets.c b/Demo/Common/ethernet/lwIP/api/sockets.c
new file mode 100644 (file)
index 0000000..290a7b7
--- /dev/null
@@ -0,0 +1,1362 @@
+/*
+ * 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>
+ *
+ * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include "lwip/opt.h"
+#include "lwip/api.h"
+#include "lwip/arch.h"
+#include "lwip/sys.h"
+
+#include "lwip/sockets.h"
+
+#define NUM_SOCKETS MEMP_NUM_NETCONN
+
+struct lwip_socket {
+  struct netconn *conn;
+  struct netbuf *lastdata;
+  u16_t lastoffset;
+  u16_t rcvevent;
+  u16_t sendevent;
+  u16_t  flags;
+  int err;
+};
+
+struct lwip_select_cb
+{
+    struct lwip_select_cb *next;
+    fd_set *readset;
+    fd_set *writeset;
+    fd_set *exceptset;
+    int sem_signalled;
+    sys_sem_t sem;
+};
+
+static struct lwip_socket sockets[NUM_SOCKETS];
+static struct lwip_select_cb *select_cb_list = 0;
+
+static sys_sem_t socksem = 0;
+static sys_sem_t selectsem = 0;
+
+static void
+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
+
+static int err_to_errno_table[11] = {
+    0,      /* ERR_OK    0      No error, everything OK. */
+    ENOMEM,    /* ERR_MEM  -1      Out of memory error.     */
+    ENOBUFS,    /* ERR_BUF  -2      Buffer error.            */
+    ECONNABORTED,  /* ERR_ABRT -3      Connection aborted.      */
+    ECONNRESET,    /* ERR_RST  -4      Connection reset.        */
+    ESHUTDOWN,    /* ERR_CLSD -5      Connection closed.       */
+    ENOTCONN,    /* ERR_CONN -6      Not connected.           */
+    EINVAL,    /* ERR_VAL  -7      Illegal value.           */
+    EIO,    /* ERR_ARG  -8      Illegal argument.        */
+    EHOSTUNREACH,  /* ERR_RTE  -9      Routing problem.         */
+    EADDRINUSE    /* ERR_USE  -10     Address in use.          */
+};
+
+#define ERR_TO_ERRNO_TABLE_SIZE \
+  (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
+
+#define err_to_errno(err) \
+  (-(err) >= 0 && -(err) < ERR_TO_ERRNO_TABLE_SIZE ? \
+    err_to_errno_table[-(err)] : EIO)
+
+#ifdef ERRNO
+#define set_errno(err) errno = (err)
+#else
+#define set_errno(err)
+#endif
+
+#define sock_set_errno(sk, e) do { \
+      sk->err = (e); \
+      set_errno(sk->err); \
+} while (0)
+
+
+static struct lwip_socket *
+get_socket(int s)
+{
+  struct lwip_socket *sock;
+
+  if ((s < 0) || (s > NUM_SOCKETS)) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
+    set_errno(EBADF);
+    return NULL;
+  }
+
+  sock = &sockets[s];
+
+  if (!sock->conn) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
+    set_errno(EBADF);
+    return NULL;
+  }
+
+  return sock;
+}
+
+static int
+alloc_socket(struct netconn *newconn)
+{
+  int i;
+
+  if (!socksem)
+      socksem = sys_sem_new(1);
+
+  /* Protect socket array */
+  sys_sem_wait(socksem);
+
+  /* allocate a new socket identifier */
+  for(i = 0; i < NUM_SOCKETS; ++i) {
+    if (!sockets[i].conn) {
+      sockets[i].conn = newconn;
+      sockets[i].lastdata = NULL;
+      sockets[i].lastoffset = 0;
+      sockets[i].rcvevent = 0;
+      sockets[i].sendevent = 1; /* TCP send buf is empty */
+      sockets[i].flags = 0;
+      sockets[i].err = 0;
+      sys_sem_signal(socksem);
+      return i;
+    }
+  }
+  sys_sem_signal(socksem);
+  return -1;
+}
+
+int
+lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+  struct lwip_socket *sock;
+  struct netconn *newconn;
+  struct ip_addr naddr;
+  u16_t port;
+  int newsock;
+  struct sockaddr_in sin;
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  newconn = netconn_accept(sock->conn);
+
+  /* get the IP address and port of the remote host */
+  netconn_peer(newconn, &naddr, &port);
+
+  memset(&sin, 0, sizeof(sin));
+  sin.sin_len = sizeof(sin);
+  sin.sin_family = AF_INET;
+  sin.sin_port = htons(port);
+  sin.sin_addr.s_addr = naddr.addr;
+
+  if (*addrlen > sizeof(sin))
+      *addrlen = sizeof(sin);
+
+  memcpy(addr, &sin, *addrlen);
+
+  newsock = alloc_socket(newconn);
+  if (newsock == -1) {
+    netconn_delete(newconn);
+  sock_set_errno(sock, ENOBUFS);
+  return -1;
+  }
+  newconn->callback = event_callback;
+  sock = get_socket(newsock);
+
+  sys_sem_wait(socksem);
+  sock->rcvevent += -1 - newconn->socket;
+  newconn->socket = newsock;
+  sys_sem_signal(socksem);
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
+  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));
+
+  sock_set_errno(sock, 0);
+  return newsock;
+}
+
+int
+lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
+{
+  struct lwip_socket *sock;
+  struct ip_addr local_addr;
+  u16_t local_port;
+  err_t err;
+
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
+  local_port = ((struct sockaddr_in *)name)->sin_port;
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
+  ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));
+
+  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
+
+  if (err != ERR_OK) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
+    sock_set_errno(sock, err_to_errno(err));
+    return -1;
+  }
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
+  sock_set_errno(sock, 0);
+  return 0;
+}
+
+int
+lwip_close(int s)
+{
+  struct lwip_socket *sock;
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
+  if (!socksem)
+      socksem = sys_sem_new(1);
+
+  /* We cannot allow multiple closes of the same socket. */
+  sys_sem_wait(socksem);
+
+  sock = get_socket(s);
+  if (!sock) {
+      sys_sem_signal(socksem);
+      set_errno(EBADF);
+      return -1;
+  }
+
+  netconn_delete(sock->conn);
+  if (sock->lastdata) {
+    netbuf_delete(sock->lastdata);
+  }
+  sock->lastdata = NULL;
+  sock->lastoffset = 0;
+  sock->conn = NULL;
+  sys_sem_signal(socksem);
+  sock_set_errno(sock, 0);
+  return 0;
+}
+
+int
+lwip_connect(int s, struct sockaddr *name, socklen_t namelen)
+{
+  struct lwip_socket *sock;
+  err_t err;
+
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
+    err = netconn_disconnect(sock->conn);
+  } else {
+    struct ip_addr remote_addr;
+    u16_t remote_port;
+
+    remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
+    remote_port = ((struct sockaddr_in *)name)->sin_port;
+
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
+    ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));
+
+    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
+   }
+
+  if (err != ERR_OK) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
+    sock_set_errno(sock, err_to_errno(err));
+    return -1;
+  }
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
+  sock_set_errno(sock, 0);
+  return 0;
+}
+
+int
+lwip_listen(int s, int backlog)
+{
+  struct lwip_socket *sock;
+  err_t err;
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  err = netconn_listen(sock->conn);
+
+  if (err != ERR_OK) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
+    sock_set_errno(sock, err_to_errno(err));
+    return -1;
+  }
+
+  sock_set_errno(sock, 0);
+  return 0;
+}
+
+int
+lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
+        struct sockaddr *from, socklen_t *fromlen)
+{
+  struct lwip_socket *sock;
+  struct netbuf *buf;
+  u16_t buflen, copylen;
+  struct ip_addr *addr;
+  u16_t port;
+
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  /* Check if there is data left from the last recv operation. */
+  if (sock->lastdata) {
+    buf = sock->lastdata;
+  } else {
+    /* If this is non-blocking call, then check first */
+    if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK))
+  && !sock->rcvevent)
+    {
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
+      sock_set_errno(sock, EWOULDBLOCK);
+      return -1;
+    }
+
+    /* No data was left from the previous operation, so we try to get
+       some from the network. */
+    buf = netconn_recv(sock->conn);
+
+    if (!buf) {
+      /* We should really do some error checking here. */
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
+      sock_set_errno(sock, 0);
+      return 0;
+    }
+  }
+
+  buflen = netbuf_len(buf);
+
+  buflen -= sock->lastoffset;
+
+  if (len > buflen) {
+    copylen = buflen;
+  } else {
+    copylen = len;
+  }
+
+  /* copy the contents of the received buffer into
+     the supplied memory pointer mem */
+  netbuf_copy_partial(buf, mem, copylen, sock->lastoffset);
+
+  /* Check to see from where the data was. */
+  if (from && fromlen) {
+    struct sockaddr_in sin;
+
+    addr = netbuf_fromaddr(buf);
+    port = netbuf_fromport(buf);
+
+    memset(&sin, 0, sizeof(sin));
+    sin.sin_len = sizeof(sin);
+    sin.sin_family = AF_INET;
+    sin.sin_port = htons(port);
+    sin.sin_addr.s_addr = addr->addr;
+
+    if (*fromlen > sizeof(sin))
+      *fromlen = sizeof(sin);
+
+    memcpy(from, &sin, *fromlen);
+
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
+    ip_addr_debug_print(SOCKETS_DEBUG, addr);
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
+  } else {
+#if SOCKETS_DEBUG
+    addr = netbuf_fromaddr(buf);
+    port = netbuf_fromport(buf);
+
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
+    ip_addr_debug_print(SOCKETS_DEBUG, addr);
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
+#endif
+
+  }
+
+  /* If this is a TCP socket, check if there is data left in the
+     buffer. If so, it should be saved in the sock structure for next
+     time around. */
+  if (netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) {
+    sock->lastdata = buf;
+    sock->lastoffset += copylen;
+  } else {
+    sock->lastdata = NULL;
+    sock->lastoffset = 0;
+    netbuf_delete(buf);
+  }
+
+
+  sock_set_errno(sock, 0);
+  return copylen;
+}
+
+int
+lwip_read(int s, void *mem, int len)
+{
+  return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
+}
+
+int
+lwip_recv(int s, void *mem, int len, unsigned int flags)
+{
+  return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
+}
+
+int
+lwip_send(int s, void *data, int size, unsigned int flags)
+{
+  struct lwip_socket *sock;
+  struct netbuf *buf;
+  err_t err;
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", s, data, size, flags));
+
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  switch (netconn_type(sock->conn)) {
+  case NETCONN_RAW:
+  case NETCONN_UDP:
+  case NETCONN_UDPLITE:
+  case NETCONN_UDPNOCHKSUM:
+    /* create a buffer */
+    buf = netbuf_new();
+
+    if (!buf) {
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ENOBUFS\n", s));
+      sock_set_errno(sock, ENOBUFS);
+      return -1;
+    }
+
+    /* make the buffer point to the data that should
+       be sent */
+    netbuf_ref(buf, data, size);
+
+    /* send the data */
+    err = netconn_send(sock->conn, buf);
+
+    /* deallocated the buffer */
+    netbuf_delete(buf);
+    break;
+  case NETCONN_TCP:
+    err = netconn_write(sock->conn, data, size, NETCONN_COPY);
+    break;
+  default:
+    err = ERR_ARG;
+    break;
+  }
+  if (err != ERR_OK) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d\n", s, err));
+    sock_set_errno(sock, err_to_errno(err));
+    return -1;
+  }
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ok size=%d\n", s, size));
+  sock_set_errno(sock, 0);
+  return size;
+}
+
+int
+lwip_sendto(int s, void *data, int size, unsigned int flags,
+       struct sockaddr *to, socklen_t tolen)
+{
+  struct lwip_socket *sock;
+  struct ip_addr remote_addr, addr;
+  u16_t remote_port, port;
+  int ret,connected;
+
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  /* get the peer if currently connected */
+  connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK);
+
+  remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
+  remote_port = ((struct sockaddr_in *)to)->sin_port;
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, size, flags));
+  ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port)));
+
+  netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
+
+  ret = lwip_send(s, data, size, flags);
+
+  /* reset the remote address and port number
+     of the connection */
+  if (connected)
+    netconn_connect(sock->conn, &addr, port);
+  else
+  netconn_disconnect(sock->conn);
+  return ret;
+}
+
+int
+lwip_socket(int domain, int type, int protocol)
+{
+  struct netconn *conn;
+  int i;
+
+  /* create a netconn */
+  switch (type) {
+  case SOCK_RAW:
+    conn = netconn_new_with_proto_and_callback(NETCONN_RAW, protocol, event_callback);
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+    break;
+  case SOCK_DGRAM:
+    conn = netconn_new_with_callback(NETCONN_UDP, event_callback);
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+    break;
+  case SOCK_STREAM:
+    conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+    break;
+  default:
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", domain, type, protocol));
+    set_errno(EINVAL);
+    return -1;
+  }
+
+  if (!conn) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
+    set_errno(ENOBUFS);
+    return -1;
+  }
+
+  i = alloc_socket(conn);
+
+  if (i == -1) {
+    netconn_delete(conn);
+  set_errno(ENOBUFS);
+  return -1;
+  }
+  conn->socket = i;
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
+  set_errno(0);
+  return i;
+}
+
+int
+lwip_write(int s, void *data, int size)
+{
+   return lwip_send(s, data, size, 0);
+}
+
+
+static int
+lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
+{
+    int i, nready = 0;
+    fd_set lreadset, lwriteset, lexceptset;
+    struct lwip_socket *p_sock;
+
+    FD_ZERO(&lreadset);
+    FD_ZERO(&lwriteset);
+    FD_ZERO(&lexceptset);
+
+    /* Go through each socket in each list to count number of sockets which
+       currently match */
+    for(i = 0; i < maxfdp1; i++)
+    {
+        if (FD_ISSET(i, readset))
+        {
+            /* See if netconn of this socket is ready for read */
+            p_sock = get_socket(i);
+            if (p_sock && (p_sock->lastdata || p_sock->rcvevent))
+            {
+                FD_SET(i, &lreadset);
+               LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
+                nready++;
+            }
+        }
+        if (FD_ISSET(i, writeset))
+        {
+            /* See if netconn of this socket is ready for write */
+            p_sock = get_socket(i);
+            if (p_sock && p_sock->sendevent)
+            {
+                FD_SET(i, &lwriteset);
+               LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
+                nready++;
+            }
+        }
+    }
+    *readset = lreadset;
+    *writeset = lwriteset;
+    FD_ZERO(exceptset);
+
+    return nready;
+}
+
+
+
+int
+lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
+               struct timeval *timeout)
+{
+    int i;
+    int nready;
+    fd_set lreadset, lwriteset, lexceptset;
+    u32_t msectimeout;
+    struct lwip_select_cb select_cb;
+    struct lwip_select_cb *p_selcb;
+
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));
+
+    select_cb.next = 0;
+    select_cb.readset = readset;
+    select_cb.writeset = writeset;
+    select_cb.exceptset = exceptset;
+    select_cb.sem_signalled = 0;
+
+    /* Protect ourselves searching through the list */
+    if (!selectsem)
+        selectsem = sys_sem_new(1);
+    sys_sem_wait(selectsem);
+
+    if (readset)
+        lreadset = *readset;
+    else
+        FD_ZERO(&lreadset);
+    if (writeset)
+        lwriteset = *writeset;
+    else
+        FD_ZERO(&lwriteset);
+    if (exceptset)
+        lexceptset = *exceptset;
+    else
+        FD_ZERO(&lexceptset);
+
+    /* Go through each socket in each list to count number of sockets which
+       currently match */
+    nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
+
+    /* If we don't have any current events, then suspend if we are supposed to */
+    if (!nready)
+    {
+        if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
+        {
+            sys_sem_signal(selectsem);
+            if (readset)
+                FD_ZERO(readset);
+            if (writeset)
+                FD_ZERO(writeset);
+            if (exceptset)
+                FD_ZERO(exceptset);
+
+           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
+           set_errno(0);
+
+            return 0;
+        }
+
+        /* add our semaphore to list */
+        /* We don't actually need any dynamic memory. Our entry on the
+         * list is only valid while we are in this function, so it's ok
+         * to use local variables */
+
+        select_cb.sem = sys_sem_new(0);
+        /* Note that we are still protected */
+        /* Put this select_cb on top of list */
+        select_cb.next = select_cb_list;
+        select_cb_list = &select_cb;
+
+        /* Now we can safely unprotect */
+        sys_sem_signal(selectsem);
+
+        /* Now just wait to be woken */
+        if (timeout == 0)
+            /* Wait forever */
+            msectimeout = 0;
+        else
+            msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
+
+        i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
+
+        /* Take us off the list */
+        sys_sem_wait(selectsem);
+        if (select_cb_list == &select_cb)
+            select_cb_list = select_cb.next;
+        else
+            for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next)
+                if (p_selcb->next == &select_cb)
+                {
+                    p_selcb->next = select_cb.next;
+                    break;
+                }
+
+        sys_sem_signal(selectsem);
+
+        sys_sem_free(select_cb.sem);
+        if (i == 0)             /* Timeout */
+        {
+            if (readset)
+                FD_ZERO(readset);
+            if (writeset)
+                FD_ZERO(writeset);
+            if (exceptset)
+                FD_ZERO(exceptset);
+
+           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
+           set_errno(0);
+
+            return 0;
+        }
+
+        if (readset)
+            lreadset = *readset;
+        else
+            FD_ZERO(&lreadset);
+        if (writeset)
+            lwriteset = *writeset;
+        else
+            FD_ZERO(&lwriteset);
+        if (exceptset)
+            lexceptset = *exceptset;
+        else
+            FD_ZERO(&lexceptset);
+
+        /* See what's set */
+        nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
+    }
+    else
+        sys_sem_signal(selectsem);
+
+    if (readset)
+        *readset = lreadset;
+    if (writeset)
+        *writeset = lwriteset;
+    if (exceptset)
+        *exceptset = lexceptset;
+
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
+    set_errno(0);
+
+    return nready;
+}
+
+
+static void
+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
+{
+    int s;
+    struct lwip_socket *sock;
+    struct lwip_select_cb *scb;
+
+    /* Get socket */
+    if (conn)
+    {
+        s = conn->socket;
+        if (s < 0)
+        {
+            /* Data comes in right away after an accept, even though
+             * the server task might not have created a new socket yet.
+             * Just count down (or up) if that's the case and we
+             * will use the data later. Note that only receive events
+             * can happen before the new socket is set up. */
+            if (evt == NETCONN_EVT_RCVPLUS)
+                conn->socket--;
+            return;
+        }
+
+        sock = get_socket(s);
+        if (!sock)
+            return;
+    }
+    else
+        return;
+
+    if (!selectsem)
+        selectsem = sys_sem_new(1);
+
+    sys_sem_wait(selectsem);
+    /* Set event as required */
+    switch (evt)
+    {
+      case NETCONN_EVT_RCVPLUS:
+        sock->rcvevent++;
+        break;
+      case NETCONN_EVT_RCVMINUS:
+        sock->rcvevent--;
+        break;
+      case NETCONN_EVT_SENDPLUS:
+        sock->sendevent = 1;
+        break;
+      case NETCONN_EVT_SENDMINUS:
+        sock->sendevent = 0;
+        break;
+    }
+    sys_sem_signal(selectsem);
+
+    /* Now decide if anyone is waiting for this socket */
+    /* NOTE: This code is written this way to protect the select link list
+       but to avoid a deadlock situation by releasing socksem before
+       signalling for the select. This means we need to go through the list
+       multiple times ONLY IF a select was actually waiting. We go through
+       the list the number of waiting select calls + 1. This list is
+       expected to be small. */
+    while (1)
+    {
+        sys_sem_wait(selectsem);
+        for (scb = select_cb_list; scb; scb = scb->next)
+        {
+            if (scb->sem_signalled == 0)
+            {
+                /* Test this select call for our socket */
+                if (scb->readset && FD_ISSET(s, scb->readset))
+                    if (sock->rcvevent)
+                        break;
+                if (scb->writeset && FD_ISSET(s, scb->writeset))
+                    if (sock->sendevent)
+                        break;
+            }
+        }
+        if (scb)
+        {
+            scb->sem_signalled = 1;
+            sys_sem_signal(selectsem);
+            sys_sem_signal(scb->sem);
+        } else {
+            sys_sem_signal(selectsem);
+            break;
+        }
+    }
+
+}
+
+
+
+
+int lwip_shutdown(int s, int how)
+{
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
+  return lwip_close(s); /* XXX temporary hack until proper implementation */
+}
+
+int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen)
+{
+  struct lwip_socket *sock;
+  struct sockaddr_in sin;
+  struct ip_addr naddr;
+
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  memset(&sin, 0, sizeof(sin));
+  sin.sin_len = sizeof(sin);
+  sin.sin_family = AF_INET;
+
+  /* get the IP address and port of the remote host */
+  netconn_peer(sock->conn, &naddr, &sin.sin_port);
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getpeername(%d, addr=", s));
+  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
+
+  sin.sin_port = htons(sin.sin_port);
+  sin.sin_addr.s_addr = naddr.addr;
+
+  if (*namelen > sizeof(sin))
+      *namelen = sizeof(sin);
+
+  memcpy(name, &sin, *namelen);
+  sock_set_errno(sock, 0);
+  return 0;
+}
+
+int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen)
+{
+  struct lwip_socket *sock;
+  struct sockaddr_in sin;
+  struct ip_addr *naddr;
+
+  sock = get_socket(s);
+  if (!sock) {
+    set_errno(EBADF);
+    return -1;
+  }
+
+  memset(&sin, 0, sizeof(sin));
+  sin.sin_len = sizeof(sin);
+  sin.sin_family = AF_INET;
+
+  /* get the IP address and port of the remote host */
+  netconn_addr(sock->conn, &naddr, &sin.sin_port);
+
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockname(%d, addr=", s));
+  ip_addr_debug_print(SOCKETS_DEBUG, naddr);
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
+
+  sin.sin_port = htons(sin.sin_port);
+  sin.sin_addr.s_addr = naddr->addr;
+
+  if (*namelen > sizeof(sin))
+      *namelen = sizeof(sin);
+
+  memcpy(name, &sin, *namelen);
+  sock_set_errno(sock, 0);
+  return 0;
+}
+
+int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
+{
+  int err = 0;
+  struct lwip_socket *sock = get_socket(s);
+
+  if(!sock) {
+       set_errno(EBADF);
+    return -1;
+  }
+
+  if( NULL == optval || NULL == optlen ) {
+    sock_set_errno( sock, EFAULT );
+    return -1;
+  }
+
+  /* Do length and type checks for the various options first, to keep it readable. */
+  switch( level ) {
+   
+/* Level: SOL_SOCKET */
+  case SOL_SOCKET:
+      switch(optname) {
+         
+      case SO_ACCEPTCONN:
+      case SO_BROADCAST:
+      /* UNIMPL case SO_DEBUG: */
+      /* UNIMPL case SO_DONTROUTE: */
+      case SO_ERROR:
+      case SO_KEEPALIVE:
+      /* UNIMPL case SO_OOBINLINE: */
+      /* UNIMPL case SO_RCVBUF: */
+      /* UNIMPL case SO_SNDBUF: */
+      /* UNIMPL case SO_RCVLOWAT: */
+      /* UNIMPL case SO_SNDLOWAT: */
+#if SO_REUSE
+      case SO_REUSEADDR:
+      case SO_REUSEPORT:
+#endif /* SO_REUSE */
+      case SO_TYPE:
+      /* UNIMPL case SO_USELOOPBACK: */
+        if( *optlen < sizeof(int) ) {
+          err = EINVAL;
+        }
+          break;
+
+      default:
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
+        err = ENOPROTOOPT;
+      }  /* switch */
+      break;
+                     
+/* Level: IPPROTO_IP */
+  case IPPROTO_IP:
+      switch(optname) {
+      /* UNIMPL case IP_HDRINCL: */
+      /* UNIMPL case IP_RCVDSTADDR: */
+      /* UNIMPL case IP_RCVIF: */
+      case IP_TTL:
+      case IP_TOS:
+        if( *optlen < sizeof(int) ) {
+          err = EINVAL;
+        }
+        break;
+
+      default:
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
+        err = ENOPROTOOPT;
+      }  /* switch */
+      break;
+         
+/* Level: IPPROTO_TCP */
+  case IPPROTO_TCP:
+      if( *optlen < sizeof(int) ) {
+        err = EINVAL;
+        break;
+    }
+      
+      /* If this is no TCP socket, ignore any options. */
+      if ( sock->conn->type != NETCONN_TCP ) return 0;
+
+      switch( optname ) {
+      case TCP_NODELAY:
+      case TCP_KEEPALIVE:
+        break;
+         
+      default:
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
+        err = ENOPROTOOPT;
+      }  /* switch */
+      break;
+
+/* UNDEFINED LEVEL */
+  default:
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
+      err = ENOPROTOOPT;
+  }  /* switch */
+
+   
+  if( 0 != err ) {
+    sock_set_errno(sock, err);
+    return -1;
+  }
+   
+
+
+  /* Now do the actual option processing */
+
+  switch(level) {
+   
+/* Level: SOL_SOCKET */
+  case SOL_SOCKET:
+    switch( optname ) {
+
+    /* The option flags */
+    case SO_ACCEPTCONN:
+    case SO_BROADCAST:
+    /* UNIMPL case SO_DEBUG: */
+    /* UNIMPL case SO_DONTROUTE: */
+    case SO_KEEPALIVE:
+    /* UNIMPL case SO_OOBINCLUDE: */
+#if SO_REUSE
+    case SO_REUSEADDR:
+    case SO_REUSEPORT:
+#endif /* SO_REUSE */
+    /*case SO_USELOOPBACK: UNIMPL */
+      *(int*)optval = sock->conn->pcb.tcp->so_options & optname;
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off")));
+      break;
+
+    case SO_TYPE:
+      switch (sock->conn->type) {
+      case NETCONN_RAW:
+        *(int*)optval = SOCK_RAW;
+        break;
+      case NETCONN_TCP:
+        *(int*)optval = SOCK_STREAM;
+        break;
+      case NETCONN_UDP:
+      case NETCONN_UDPLITE:
+      case NETCONN_UDPNOCHKSUM:
+        *(int*)optval = SOCK_DGRAM;
+        break;
+      default: /* unrecognized socket type */
+        *(int*)optval = sock->conn->type;
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval));
+      }  /* switch */
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval));
+      break;
+
+    case SO_ERROR:
+      *(int *)optval = sock->err;
+      sock->err = 0;
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval));
+      break;
+    }  /* switch */
+    break;
+
+/* Level: IPPROTO_IP */
+  case IPPROTO_IP:
+    switch( optname ) {
+    case IP_TTL:
+      *(int*)optval = sock->conn->pcb.tcp->ttl;
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval));
+      break;
+    case IP_TOS:
+      *(int*)optval = sock->conn->pcb.tcp->tos;
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval));
+      break;
+    }  /* switch */
+    break;
+
+/* Level: IPPROTO_TCP */
+  case IPPROTO_TCP:
+    switch( optname ) {
+    case TCP_NODELAY:
+      *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") );
+      break;
+    case TCP_KEEPALIVE:
+      *(int*)optval = (int)sock->conn->pcb.tcp->keepalive;
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval));
+      break;
+    }  /* switch */
+    break;
+  }
+
+
+  sock_set_errno(sock, err);
+  return err ? -1 : 0;
+}
+
+int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
+{
+  struct lwip_socket *sock = get_socket(s);
+  int err = 0;
+
+  if(!sock) {
+       set_errno(EBADF);
+    return -1;
+  }
+
+  if( NULL == optval ) {
+    sock_set_errno( sock, EFAULT );
+    return -1;
+  }
+
+
+  /* Do length and type checks for the various options first, to keep it readable. */
+  switch( level ) {
+
+/* Level: SOL_SOCKET */
+  case SOL_SOCKET:
+    switch(optname) {
+
+    case SO_BROADCAST:
+    /* UNIMPL case SO_DEBUG: */
+    /* UNIMPL case SO_DONTROUTE: */
+    case SO_KEEPALIVE:
+    /* UNIMPL case SO_OOBINLINE: */
+    /* UNIMPL case SO_RCVBUF: */
+    /* UNIMPL case SO_SNDBUF: */
+    /* UNIMPL case SO_RCVLOWAT: */
+    /* UNIMPL case SO_SNDLOWAT: */
+#if SO_REUSE
+    case SO_REUSEADDR:
+    case SO_REUSEPORT:
+#endif /* SO_REUSE */
+    /* UNIMPL case SO_USELOOPBACK: */
+      if( optlen < sizeof(int) ) {
+        err = EINVAL;
+      }
+      break;
+    default:
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
+      err = ENOPROTOOPT;
+    }  /* switch */
+    break;
+
+/* Level: IPPROTO_IP */
+  case IPPROTO_IP:
+    switch(optname) {
+    /* UNIMPL case IP_HDRINCL: */
+    /* UNIMPL case IP_RCVDSTADDR: */
+    /* UNIMPL case IP_RCVIF: */
+    case IP_TTL:
+    case IP_TOS:
+      if( optlen < sizeof(int) ) {
+        err = EINVAL;
+      }
+        break;
+      default:
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
+      err = ENOPROTOOPT;
+    }  /* switch */
+    break;
+
+/* Level: IPPROTO_TCP */
+  case IPPROTO_TCP:
+    if( optlen < sizeof(int) ) {
+      err = EINVAL;
+        break;
+    }
+
+    /* If this is no TCP socket, ignore any options. */
+    if ( sock->conn->type != NETCONN_TCP ) return 0;
+
+    switch( optname ) {
+    case TCP_NODELAY:
+    case TCP_KEEPALIVE:
+      break;
+
+    default:
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
+      err = ENOPROTOOPT;
+    }  /* switch */
+    break;
+
+/* UNDEFINED LEVEL */      
+  default:
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
+    err = ENOPROTOOPT;
+  }  /* switch */
+
+
+  if( 0 != err ) {
+    sock_set_errno(sock, err);
+    return -1;
+  }
+
+
+
+  /* Now do the actual option processing */
+
+  switch(level) {
+
+/* Level: SOL_SOCKET */
+  case SOL_SOCKET:
+    switch(optname) {
+
+    /* The option flags */
+    case SO_BROADCAST:
+    /* UNIMPL case SO_DEBUG: */
+    /* UNIMPL case SO_DONTROUTE: */
+    case SO_KEEPALIVE:
+    /* UNIMPL case SO_OOBINCLUDE: */
+#if SO_REUSE
+    case SO_REUSEADDR:
+    case SO_REUSEPORT:
+#endif /* SO_REUSE */
+    /* UNIMPL case SO_USELOOPBACK: */
+      if ( *(int*)optval ) {
+        sock->conn->pcb.tcp->so_options |= optname;
+      } else {
+        sock->conn->pcb.tcp->so_options &= ~optname;
+      }
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off")));
+      break;
+    }  /* switch */
+    break;
+
+/* Level: IPPROTO_IP */
+  case IPPROTO_IP:
+    switch( optname ) {
+    case IP_TTL:
+      sock->conn->pcb.tcp->ttl = (u8_t)(*(int*)optval);
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", s, sock->conn->pcb.tcp->ttl));
+      break;
+    case IP_TOS:
+      sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval);
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos));
+      break;
+    }  /* switch */
+    break;
+
+/* Level: IPPROTO_TCP */
+  case IPPROTO_TCP:
+    switch( optname ) {
+    case TCP_NODELAY:
+      if ( *(int*)optval ) {
+        sock->conn->pcb.tcp->flags |= TF_NODELAY;
+      } else {
+        sock->conn->pcb.tcp->flags &= ~TF_NODELAY;
+      }
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") );
+      break;
+    case TCP_KEEPALIVE:
+      sock->conn->pcb.tcp->keepalive = (u32_t)(*(int*)optval);
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n", s, sock->conn->pcb.tcp->keepalive));
+      break;
+    }  /* switch */
+    break;
+  }  /* switch */
+
+  sock_set_errno(sock, err);
+  return err ? -1 : 0;
+}
+
+int lwip_ioctl(int s, long cmd, void *argp)
+{
+  struct lwip_socket *sock = get_socket(s);
+
+  if(!sock) {
+       set_errno(EBADF);
+    return -1;
+  }
+
+  switch (cmd) {
+  case FIONREAD:
+    if (!argp) {
+      sock_set_errno(sock, EINVAL);
+      return -1;
+    }
+
+    *((u16_t*)argp) = sock->conn->recv_avail;
+
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));
+    sock_set_errno(sock, 0);
+    return 0;
+
+  case FIONBIO:
+    if (argp && *(u32_t*)argp)
+      sock->flags |= O_NONBLOCK;
+    else
+      sock->flags &= ~O_NONBLOCK;
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));
+    sock_set_errno(sock, 0);
+    return 0;
+
+  default:
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
+    sock_set_errno(sock, ENOSYS); /* not yet implemented */
+    return -1;
+  }
+}
+
diff --git a/Demo/Common/ethernet/lwIP/api/tcpip.c b/Demo/Common/ethernet/lwIP/api/tcpip.c
new file mode 100644 (file)
index 0000000..ce8a2ca
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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/sys.h"
+
+#include "lwip/memp.h"
+#include "lwip/pbuf.h"
+
+#include "lwip/ip.h"
+#include "lwip/ip_frag.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+
+#include "lwip/tcpip.h"
+
+static void (* tcpip_init_done)(void *arg) = NULL;
+static void *tcpip_init_done_arg;
+static sys_mbox_t mbox;
+
+#if LWIP_TCP
+static int tcpip_tcp_timer_active = 0;
+
+static void
+tcpip_tcp_timer(void *arg)
+{
+  (void)arg;
+
+  /* call TCP timer handler */
+  tcp_tmr();
+  /* timer still needed? */
+  if (tcp_active_pcbs || tcp_tw_pcbs) {
+    /* restart timer */
+    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
+  } else {
+    /* disable timer */
+    tcpip_tcp_timer_active = 0;
+  }
+}
+
+#if !NO_SYS
+void
+tcp_timer_needed(void)
+{
+  /* timer is off but needed again? */
+  if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
+    /* enable and start timer */
+    tcpip_tcp_timer_active = 1;
+    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
+  }
+}
+#endif /* !NO_SYS */
+#endif /* LWIP_TCP */
+
+#if IP_REASSEMBLY
+static void
+ip_timer(void *data)
+{
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
+  ip_reass_tmr();
+  sys_timeout(1000, ip_timer, NULL);
+}
+#endif
+
+static void
+tcpip_thread(void *arg)
+{
+  struct tcpip_msg *msg;
+
+  (void)arg;
+
+  ip_init();
+#if LWIP_UDP  
+  udp_init();
+#endif
+#if LWIP_TCP
+  tcp_init();
+#endif
+#if IP_REASSEMBLY
+  sys_timeout(1000, ip_timer, NULL);
+#endif
+  if (tcpip_init_done != NULL) {
+    tcpip_init_done(tcpip_init_done_arg);
+  }
+
+  while (1) {                          /* MAIN Loop */
+    sys_mbox_fetch(mbox, (void *)&msg);
+    switch (msg->type) {
+    case TCPIP_MSG_API:
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
+      api_msg_input(msg->msg.apimsg);
+      break;
+    case TCPIP_MSG_INPUT:
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: IP packet %p\n", (void *)msg));
+      ip_input(msg->msg.inp.p, msg->msg.inp.netif);
+      break;
+    case TCPIP_MSG_CALLBACK:
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
+      msg->msg.cb.f(msg->msg.cb.ctx);
+      break;
+    default:
+      break;
+    }
+    memp_free(MEMP_TCPIP_MSG, msg);
+  }
+}
+
+err_t
+tcpip_input(struct pbuf *p, struct netif *inp)
+{
+  struct tcpip_msg *msg;
+  
+  msg = memp_malloc(MEMP_TCPIP_MSG);
+  if (msg == NULL) {
+    pbuf_free(p);    
+    return ERR_MEM;  
+  }
+  
+  msg->type = TCPIP_MSG_INPUT;
+  msg->msg.inp.p = p;
+  msg->msg.inp.netif = inp;
+  sys_mbox_post(mbox, msg);
+  return ERR_OK;
+}
+
+err_t
+tcpip_callback(void (*f)(void *ctx), void *ctx)
+{
+  struct tcpip_msg *msg;
+  
+  msg = memp_malloc(MEMP_TCPIP_MSG);
+  if (msg == NULL) {
+    return ERR_MEM;  
+  }
+  
+  msg->type = TCPIP_MSG_CALLBACK;
+  msg->msg.cb.f = f;
+  msg->msg.cb.ctx = ctx;
+  sys_mbox_post(mbox, msg);
+  return ERR_OK;
+}
+
+void
+tcpip_apimsg(struct api_msg *apimsg)
+{
+  struct tcpip_msg *msg;
+  msg = memp_malloc(MEMP_TCPIP_MSG);
+  if (msg == NULL) {
+    memp_free(MEMP_API_MSG, apimsg);
+    return;
+  }
+  msg->type = TCPIP_MSG_API;
+  msg->msg.apimsg = apimsg;
+  sys_mbox_post(mbox, msg);
+}
+
+void
+tcpip_init(void (* initfunc)(void *), void *arg)
+{
+  tcpip_init_done = initfunc;
+  tcpip_init_done_arg = arg;
+  mbox = sys_mbox_new();
+  sys_thread_new(tcpip_thread, NULL, TCPIP_THREAD_PRIO);
+}
+
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/core/dhcp.c b/Demo/Common/ethernet/lwIP/core/dhcp.c
new file mode 100644 (file)
index 0000000..2dabd4f
--- /dev/null
@@ -0,0 +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 */
diff --git a/Demo/Common/ethernet/lwIP/core/inet.c b/Demo/Common/ethernet/lwIP/core/inet.c
new file mode 100644 (file)
index 0000000..2c54389
--- /dev/null
@@ -0,0 +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) */
diff --git a/Demo/Common/ethernet/lwIP/core/inet6.c b/Demo/Common/ethernet/lwIP/core/inet6.c
new file mode 100644 (file)
index 0000000..c04915b
--- /dev/null
@@ -0,0 +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);
+}
+
diff --git a/Demo/Common/ethernet/lwIP/core/ipv4/icmp.c b/Demo/Common/ethernet/lwIP/core/ipv4/icmp.c
new file mode 100644 (file)
index 0000000..248f2c6
--- /dev/null
@@ -0,0 +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 */
+
+
+
+
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/core/ipv4/ip.c b/Demo/Common/ethernet/lwIP/core/ipv4/ip.c
new file mode 100644 (file)
index 0000000..496d76e
--- /dev/null
@@ -0,0 +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 */
+\r
+/**
+ * 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;
+\r
+  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)));\r
+    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 */
+\r
+
+
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/core/ipv4/ip_addr.c b/Demo/Common/ethernet/lwIP/core/ipv4/ip_addr.c
new file mode 100644 (file)
index 0000000..70be286
--- /dev/null
@@ -0,0 +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;
+}
diff --git a/Demo/Common/ethernet/lwIP/core/ipv4/ip_frag.c b/Demo/Common/ethernet/lwIP/core/ipv4/ip_frag.c
new file mode 100644 (file)
index 0000000..c43422c
--- /dev/null
@@ -0,0 +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;
+}
diff --git a/Demo/Common/ethernet/lwIP/core/mem.c b/Demo/Common/ethernet/lwIP/core/mem.c
new file mode 100644 (file)
index 0000000..6ef311d
--- /dev/null
@@ -0,0 +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 */
+
diff --git a/Demo/Common/ethernet/lwIP/core/memp.c b/Demo/Common/ethernet/lwIP/core/memp.c
new file mode 100644 (file)
index 0000000..b31812d
--- /dev/null
@@ -0,0 +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 */  
+}
diff --git a/Demo/Common/ethernet/lwIP/core/netif.c b/Demo/Common/ethernet/lwIP/core/netif.c
new file mode 100644 (file)
index 0000000..b1e2bc1
--- /dev/null
@@ -0,0 +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;
+}
+
diff --git a/Demo/Common/ethernet/lwIP/core/pbuf.c b/Demo/Common/ethernet/lwIP/core/pbuf.c
new file mode 100644 (file)
index 0000000..bca0725
--- /dev/null
@@ -0,0 +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"
+\r
+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);\r
+    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;
+#endif /* PBUF_STATS */\r
+      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 */\r
+        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) {\r
+      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"));\r
+
+      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);\r
+    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));\r
+  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);
+
+  LWIP_ASSERT("p != NULL", p != NULL);\r
+
+  /* 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 */\r
+\r
+  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
new file mode 100644 (file)
index 0000000..3019980
--- /dev/null
@@ -0,0 +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 */
diff --git a/Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c b/Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c
new file mode 100644 (file)
index 0000000..5e04b38
--- /dev/null
@@ -0,0 +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 */
+
diff --git a/Demo/Common/ethernet/lwIP/core/snmp/asn1_enc.c b/Demo/Common/ethernet/lwIP/core/snmp/asn1_enc.c
new file mode 100644 (file)
index 0000000..4d04f28
--- /dev/null
@@ -0,0 +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 */
diff --git a/Demo/Common/ethernet/lwIP/core/snmp/mib2.c b/Demo/Common/ethernet/lwIP/core/snmp/mib2.c
new file mode 100644 (file)
index 0000000..3e478ab
--- /dev/null
@@ -0,0 +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 */
diff --git a/Demo/Common/ethernet/lwIP/core/snmp/mib_structs.c b/Demo/Common/ethernet/lwIP/core/snmp/mib_structs.c
new file mode 100644 (file)
index 0000000..e68636a
--- /dev/null
@@ -0,0 +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 */
+
diff --git a/Demo/Common/ethernet/lwIP/core/snmp/msg_in.c b/Demo/Common/ethernet/lwIP/core/snmp/msg_in.c
new file mode 100644 (file)
index 0000000..d071850
--- /dev/null
@@ -0,0 +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 */
diff --git a/Demo/Common/ethernet/lwIP/core/snmp/msg_out.c b/Demo/Common/ethernet/lwIP/core/snmp/msg_out.c
new file mode 100644 (file)
index 0000000..c8961c9
--- /dev/null
@@ -0,0 +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 */
diff --git a/Demo/Common/ethernet/lwIP/core/stats.c b/Demo/Common/ethernet/lwIP/core/stats.c
new file mode 100644 (file)
index 0000000..d5b3740
--- /dev/null
@@ -0,0 +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 */
+
diff --git a/Demo/Common/ethernet/lwIP/core/sys.c b/Demo/Common/ethernet/lwIP/core/sys.c
new file mode 100644 (file)
index 0000000..b7bfbf9
--- /dev/null
@@ -0,0 +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 */
diff --git a/Demo/Common/ethernet/lwIP/core/tcp.c b/Demo/Common/ethernet/lwIP/core/tcp.c
new file mode 100644 (file)
index 0000000..89dfd24
--- /dev/null
@@ -0,0 +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 */
+
+
+
+
+
+
+
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/core/tcp_in.c b/Demo/Common/ethernet/lwIP/core/tcp_in.c
new file mode 100644 (file)
index 0000000..f6a3b87
--- /dev/null
@@ -0,0 +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 */
+
+
diff --git a/Demo/Common/ethernet/lwIP/core/tcp_out.c b/Demo/Common/ethernet/lwIP/core/tcp_out.c
new file mode 100644 (file)
index 0000000..b268201
--- /dev/null
@@ -0,0 +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"
+\r
+#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));\r
+    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));\r
+    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"));\r
+      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));\r
+        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"));\r
+        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"));\r
+        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));\r
+      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"));\r
+      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));\r
+  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
new file mode 100644 (file)
index 0000000..c487d26
--- /dev/null
@@ -0,0 +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,
+//                ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));\r
+\r
+    LWIP_DEBUGF(UDP_DEBUG,\r
+                ("udp_input: short UDP datagram (%u bytes) discarded\n", p->tot_len));\r
+
+    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 */
diff --git a/Demo/Common/ethernet/lwIP/include/ipv4/lwip/icmp.h b/Demo/Common/ethernet/lwIP/include/ipv4/lwip/icmp.h
new file mode 100644 (file)
index 0000000..634405b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_ICMP_H__
+#define __LWIP_ICMP_H__
+
+#include "lwip/arch.h"
+
+#include "lwip/opt.h"
+#include "lwip/pbuf.h"
+
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+
+#define ICMP_ER 0      /* echo reply */
+#define ICMP_DUR 3     /* destination unreachable */
+#define ICMP_SQ 4      /* source quench */
+#define ICMP_RD 5      /* redirect */
+#define ICMP_ECHO 8    /* echo */
+#define ICMP_TE 11     /* time exceeded */
+#define ICMP_PP 12     /* parameter problem */
+#define ICMP_TS 13     /* timestamp */
+#define ICMP_TSR 14    /* timestamp reply */
+#define ICMP_IRQ 15    /* information request */
+#define ICMP_IR 16     /* information reply */
+
+enum icmp_dur_type {
+  ICMP_DUR_NET = 0,    /* net unreachable */
+  ICMP_DUR_HOST = 1,   /* host unreachable */
+  ICMP_DUR_PROTO = 2,  /* protocol unreachable */
+  ICMP_DUR_PORT = 3,   /* port unreachable */
+  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */
+  ICMP_DUR_SR = 5      /* source route failed */
+};
+
+enum icmp_te_type {
+  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */
+  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */
+};
+
+void icmp_input(struct pbuf *p, struct netif *inp);
+
+void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
+void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct icmp_echo_hdr {
+  PACK_STRUCT_FIELD(u16_t _type_code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u16_t id);
+  PACK_STRUCT_FIELD(u16_t seqno);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+
+PACK_STRUCT_BEGIN
+struct icmp_dur_hdr {
+  PACK_STRUCT_FIELD(u16_t _type_code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u32_t unused);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+
+PACK_STRUCT_BEGIN
+struct icmp_te_hdr {
+  PACK_STRUCT_FIELD(u16_t _type_code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u32_t unused);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)
+#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)
+
+#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))
+#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))
+
+#endif /* __LWIP_ICMP_H__ */
+    
diff --git a/Demo/Common/ethernet/lwIP/include/ipv4/lwip/inet.h b/Demo/Common/ethernet/lwIP/include/ipv4/lwip/inet.h
new file mode 100644 (file)
index 0000000..57a55a3
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_INET_H__
+#define __LWIP_INET_H__
+
+#include "lwip/arch.h"
+
+#include "lwip/opt.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+
+u16_t inet_chksum(void *dataptr, u16_t len);
+#if 0 /* optimized routine */
+u16_t inet_chksum4(u8_t *dataptr, u16_t len);
+#endif
+u16_t inet_chksum_pbuf(struct pbuf *p);
+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 inet_addr(const char *cp);
+int inet_aton(const char *cp, struct in_addr *addr);
+char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
+
+#ifdef htons
+#undef htons
+#endif /* htons */
+#ifdef htonl
+#undef htonl
+#endif /* htonl */
+#ifdef ntohs
+#undef ntohs
+#endif /* ntohs */
+#ifdef ntohl
+#undef ntohl
+#endif /* ntohl */
+
+#ifndef LWIP_PLATFORM_BYTESWAP
+#define LWIP_PLATFORM_BYTESWAP 0
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define htons(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define ntohl(x) (x)
+#else /* BYTE_ORDER != BIG_ENDIAN */
+#ifdef LWIP_PREFIX_BYTEORDER_FUNCS
+/* workaround for naming collisions on some platforms */
+#define htons lwip_htons
+#define ntohs lwip_ntohs
+#define htonl lwip_htonl
+#define ntohl lwip_ntohl
+#endif
+#if LWIP_PLATFORM_BYTESWAP
+#define htons(x) LWIP_PLATFORM_HTONS(x)
+#define ntohs(x) LWIP_PLATFORM_HTONS(x)
+#define htonl(x) LWIP_PLATFORM_HTONL(x)
+#define ntohl(x) LWIP_PLATFORM_HTONL(x)
+#else
+u16_t htons(u16_t x);
+u16_t ntohs(u16_t x);
+u32_t htonl(u32_t x);
+u32_t ntohl(u32_t x);
+#endif
+
+#endif
+
+#endif /* __LWIP_INET_H__ */
+
diff --git a/Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip.h b/Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip.h
new file mode 100644 (file)
index 0000000..9f745f5
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_IP_H__
+#define __LWIP_IP_H__
+
+#include "lwip/arch.h"
+
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+
+#include "lwip/err.h"
+
+
+void ip_init(void);
+struct netif *ip_route(struct ip_addr *dest);
+err_t ip_input(struct pbuf *p, struct netif *inp);
+err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
+    u8_t ttl, u8_t tos, u8_t proto);
+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);
+
+#define IP_HLEN 20
+
+#define IP_PROTO_ICMP 1
+#define IP_PROTO_UDP 17
+#define IP_PROTO_UDPLITE 136
+#define IP_PROTO_TCP 6
+
+/* This is passed as the destination address to ip_output_if (not
+   to ip_output), meaning that an IP header already is constructed
+   in the pbuf. This is used when TCP retransmits. */
+#ifdef IP_HDRINCL
+#undef IP_HDRINCL
+#endif /* IP_HDRINCL */
+#define IP_HDRINCL  NULL
+
+
+/* This is the common part of all PCB types. It needs to be at the
+   beginning of a PCB type definition. It is located here so that
+   changes to this common part are made in one location instead of
+   having to change all PCB structs. */
+#define IP_PCB struct ip_addr local_ip; \
+  struct ip_addr remote_ip; \
+   /* Socket options */  \
+  u16_t so_options;      \
+   /* Type Of Service */ \
+  u8_t tos;              \
+  /* Time To Live */     \
+  u8_t ttl
+
+/*
+ * Option flags per-socket. These are the same like SO_XXX.
+ */
+#define SOF_DEBUG     (u16_t)0x0001U    /* turn on debugging info recording */
+#define SOF_ACCEPTCONN  (u16_t)0x0002U    /* socket has had listen() */
+#define SOF_REUSEADDR (u16_t)0x0004U    /* allow local address reuse */
+#define SOF_KEEPALIVE (u16_t)0x0008U    /* keep connections alive */
+#define SOF_DONTROUTE (u16_t)0x0010U    /* just use interface addresses */
+#define SOF_BROADCAST (u16_t)0x0020U    /* permit sending of broadcast msgs */
+#define SOF_USELOOPBACK (u16_t)0x0040U    /* bypass hardware when possible */
+#define SOF_LINGER      (u16_t)0x0080U    /* linger on close if data present */
+#define SOF_OOBINLINE (u16_t)0x0100U    /* leave received OOB data in line */
+#define SOF_REUSEPORT (u16_t)0x0200U    /* allow local address & port reuse */
+
+
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_hdr {
+  /* version / header length / type of service */
+  PACK_STRUCT_FIELD(u16_t _v_hl_tos);
+  /* total length */
+  PACK_STRUCT_FIELD(u16_t _len);
+  /* identification */
+  PACK_STRUCT_FIELD(u16_t _id);
+  /* fragment offset field */
+  PACK_STRUCT_FIELD(u16_t _offset);
+#define IP_RF 0x8000        /* reserved fragment flag */
+#define IP_DF 0x4000        /* dont fragment flag */
+#define IP_MF 0x2000        /* more fragments flag */
+#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */
+  /* time to live / protocol*/
+  PACK_STRUCT_FIELD(u16_t _ttl_proto);
+  /* checksum */
+  PACK_STRUCT_FIELD(u16_t _chksum);
+  /* source and destination IP addresses */
+  PACK_STRUCT_FIELD(struct ip_addr src);
+  PACK_STRUCT_FIELD(struct ip_addr dest); 
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define IPH_V(hdr)  (ntohs((hdr)->_v_hl_tos) >> 12)
+#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)
+#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)
+#define IPH_LEN(hdr) ((hdr)->_len)
+#define IPH_ID(hdr) ((hdr)->_id)
+#define IPH_OFFSET(hdr) ((hdr)->_offset)
+#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)
+#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)
+#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
+
+#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
+#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
+#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
+#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
+#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8)))
+#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
+#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
+
+#if IP_DEBUG
+void ip_debug_print(struct pbuf *p);
+#else
+#define ip_debug_print(p)
+#endif /* IP_DEBUG */
+
+#endif /* __LWIP_IP_H__ */
+
+
diff --git a/Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip_addr.h b/Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip_addr.h
new file mode 100644 (file)
index 0000000..d877ebe
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_IP_ADDR_H__
+#define __LWIP_IP_ADDR_H__
+
+#include "lwip/arch.h"
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_addr {
+  PACK_STRUCT_FIELD(u32_t addr);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/*
+ * struct ipaddr2 is used in the definition of the ARP packet format in
+ * order to support compilers that don't have structure packing.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_addr2 {
+  PACK_STRUCT_FIELD(u16_t addrw[2]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/* For compatibility with BSD code */
+struct in_addr {
+  u32_t s_addr;
+};
+
+struct netif;
+
+extern const struct ip_addr ip_addr_any;
+extern const struct ip_addr ip_addr_broadcast;
+
+/** IP_ADDR_ can be used as a fixed IP address
+ *  for the wildcard and the broadcast address
+ */
+#define IP_ADDR_ANY         ((struct ip_addr *)&ip_addr_any)
+#define IP_ADDR_BROADCAST   ((struct ip_addr *)&ip_addr_broadcast)
+
+#define INADDR_NONE         ((u32_t)0xffffffff)  /* 255.255.255.255 */
+#define INADDR_LOOPBACK     ((u32_t)0x7f000001)  /* 127.0.0.1 */
+
+/* Definitions of the bits in an Internet address integer.
+
+   On subnets, host and network parts are found according to
+   the subnet mask, not these masks.  */
+
+#define IN_CLASSA(a)        ((((u32_t)(a)) & 0x80000000) == 0)
+#define IN_CLASSA_NET       0xff000000
+#define IN_CLASSA_NSHIFT    24
+#define IN_CLASSA_HOST      (0xffffffff & ~IN_CLASSA_NET)
+#define IN_CLASSA_MAX       128
+
+#define IN_CLASSB(a)        ((((u32_t)(a)) & 0xc0000000) == 0x80000000)
+#define IN_CLASSB_NET       0xffff0000
+#define IN_CLASSB_NSHIFT    16
+#define IN_CLASSB_HOST      (0xffffffff & ~IN_CLASSB_NET)
+#define IN_CLASSB_MAX       65536
+
+#define IN_CLASSC(a)        ((((u32_t)(a)) & 0xe0000000) == 0xc0000000)
+#define IN_CLASSC_NET       0xffffff00
+#define IN_CLASSC_NSHIFT    8
+#define IN_CLASSC_HOST      (0xffffffff & ~IN_CLASSC_NET)
+
+#define IN_CLASSD(a)        (((u32_t)(a) & 0xf0000000) == 0xe0000000)
+#define IN_CLASSD_NET       0xf0000000          /* These ones aren't really */
+#define IN_CLASSD_NSHIFT    28                  /*   net and host fields, but */
+#define IN_CLASSD_HOST      0x0fffffff          /*   routing needn't know. */
+#define IN_MULTICAST(a)     IN_CLASSD(a)
+
+#define IN_EXPERIMENTAL(a)  (((u32_t)(a) & 0xf0000000) == 0xf0000000)
+#define IN_BADCLASS(a)      (((u32_t)(a) & 0xf0000000) == 0xf0000000)
+
+#define IN_LOOPBACKNET      127                 /* official! */
+
+#define IP4_ADDR(ipaddr, a,b,c,d) \
+        (ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \
+                               ((u32_t)((b) & 0xff) << 16) | \
+                               ((u32_t)((c) & 0xff) << 8) | \
+                                (u32_t)((d) & 0xff))
+
+#define ip_addr_set(dest, src) (dest)->addr = \
+                               ((src) == NULL? 0:\
+                               (src)->addr)
+/**
+ * Determine if two address are on the same network.
+ *
+ * @arg addr1 IP address 1
+ * @arg addr2 IP address 2
+ * @arg mask network identifier mask
+ * @return !0 if the network identifiers of both address match
+ */
+#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
+                                              (mask)->addr) == \
+                                             ((addr2)->addr & \
+                                              (mask)->addr))
+#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
+
+#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)
+
+u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
+
+#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000)) == ntohl(0xe0000000))
+
+#define ip_addr_debug_print(debug, ipaddr) \
+        LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \
+                ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0))
+
+/* These are cast to u16_t, with the intent that they are often arguments
+ * to printf using the U16_F format from cc.h. */
+#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)
+#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)
+#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)
+#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)
+
+#endif /* __LWIP_IP_ADDR_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip_frag.h b/Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip_frag.h
new file mode 100644 (file)
index 0000000..a326c1c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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>
+ *
+ */
+
+#ifndef __LWIP_IP_FRAG_H__
+#define __LWIP_IP_FRAG_H__
+
+#include "lwip/opt.h"
+#include "lwip/err.h"
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+#include "lwip/ip_addr.h"
+
+void ip_frag_init(void);
+void ip_reass_tmr(void);
+struct pbuf * ip_reass(struct pbuf *p);
+err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest);
+
+#endif /* __LWIP_IP_FRAG_H__ */
+
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/api.h b/Demo/Common/ethernet/lwIP/include/lwip/api.h
new file mode 100644 (file)
index 0000000..7f0ad59
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_API_H__
+#define __LWIP_API_H__
+
+#include "lwip/opt.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+
+#include "lwip/ip.h"
+
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+
+#include "lwip/err.h"
+
+#define NETCONN_NOCOPY 0x00
+#define NETCONN_COPY   0x01
+
+enum netconn_type {
+  NETCONN_TCP,
+  NETCONN_UDP,
+  NETCONN_UDPLITE,
+  NETCONN_UDPNOCHKSUM,
+  NETCONN_RAW
+};
+
+enum netconn_state {
+  NETCONN_NONE,
+  NETCONN_WRITE,
+  NETCONN_ACCEPT,
+  NETCONN_RECV,
+  NETCONN_CONNECT,
+  NETCONN_CLOSE
+};
+
+enum netconn_evt {
+  NETCONN_EVT_RCVPLUS,
+  NETCONN_EVT_RCVMINUS,
+  NETCONN_EVT_SENDPLUS,
+  NETCONN_EVT_SENDMINUS
+};
+
+struct netbuf {
+  struct pbuf *p, *ptr;
+  struct ip_addr *fromaddr;
+  u16_t fromport;
+  err_t err;
+};
+
+struct netconn {
+  enum netconn_type type;
+  enum netconn_state state;
+  union {
+    struct tcp_pcb *tcp;
+    struct udp_pcb *udp;
+    struct raw_pcb *raw;
+  } pcb;
+  err_t err;
+  sys_mbox_t mbox;
+  sys_mbox_t recvmbox;
+  sys_mbox_t acceptmbox;
+  sys_sem_t sem;
+  int socket;
+  u16_t recv_avail;
+  void (* callback)(struct netconn *, enum netconn_evt, u16_t len);
+};
+
+/* Network buffer functions: */
+struct netbuf *   netbuf_new      (void);
+void              netbuf_delete   (struct netbuf *buf);
+void *            netbuf_alloc    (struct netbuf *buf, u16_t size);
+void              netbuf_free     (struct netbuf *buf);
+void              netbuf_ref      (struct netbuf *buf,
+           void *dataptr, u16_t size);
+void              netbuf_chain    (struct netbuf *head,
+           struct netbuf *tail);
+
+u16_t             netbuf_len      (struct netbuf *buf);
+err_t             netbuf_data     (struct netbuf *buf,
+           void **dataptr, u16_t *len);
+s8_t              netbuf_next     (struct netbuf *buf);
+void              netbuf_first    (struct netbuf *buf);
+
+void              netbuf_copy     (struct netbuf *buf,
+           void *dataptr, u16_t len);
+void              netbuf_copy_partial(struct netbuf *buf, void *dataptr, 
+              u16_t len, u16_t offset);
+struct ip_addr *  netbuf_fromaddr (struct netbuf *buf);
+u16_t             netbuf_fromport (struct netbuf *buf);
+
+/* Network connection functions: */
+struct netconn *  netconn_new     (enum netconn_type type);
+struct
+netconn *netconn_new_with_callback(enum netconn_type t,
+                                   void (*callback)(struct netconn *, enum netconn_evt, u16_t len));
+struct
+netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,
+                                   void (*callback)(struct netconn *, enum netconn_evt, u16_t len));
+err_t             netconn_delete  (struct netconn *conn);
+enum netconn_type netconn_type    (struct netconn *conn);
+err_t             netconn_peer    (struct netconn *conn,
+           struct ip_addr *addr,
+           u16_t *port);
+err_t             netconn_addr    (struct netconn *conn,
+           struct ip_addr **addr,
+           u16_t *port);
+err_t             netconn_bind    (struct netconn *conn,
+           struct ip_addr *addr,
+           u16_t port);
+err_t             netconn_connect (struct netconn *conn,
+           struct ip_addr *addr,
+           u16_t port);
+err_t             netconn_disconnect (struct netconn *conn);
+err_t             netconn_listen  (struct netconn *conn);
+struct netconn *  netconn_accept  (struct netconn *conn);
+struct netbuf *   netconn_recv    (struct netconn *conn);
+err_t             netconn_send    (struct netconn *conn,
+           struct netbuf *buf);
+err_t             netconn_write   (struct netconn *conn,
+           void *dataptr, u16_t size,
+           u8_t copy);
+err_t             netconn_close   (struct netconn *conn);
+
+err_t             netconn_err     (struct netconn *conn);
+
+#endif /* __LWIP_API_H__ */
+
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/api_msg.h b/Demo/Common/ethernet/lwIP/include/lwip/api_msg.h
new file mode 100644 (file)
index 0000000..3fef3dd
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_API_MSG_H__
+#define __LWIP_API_MSG_H__
+
+#include "lwip/opt.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+
+#include "lwip/ip.h"
+
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+
+#include "lwip/api.h"
+
+enum api_msg_type {
+  API_MSG_NEWCONN,
+  API_MSG_DELCONN,
+  
+  API_MSG_BIND,
+  API_MSG_CONNECT,
+  API_MSG_DISCONNECT,
+
+  API_MSG_LISTEN,
+  API_MSG_ACCEPT,
+
+  API_MSG_SEND,
+  API_MSG_RECV,
+  API_MSG_WRITE,
+
+  API_MSG_CLOSE,
+  
+  API_MSG_MAX
+};
+
+struct api_msg_msg {
+  struct netconn *conn;
+  enum netconn_type conntype;
+  union {
+    struct pbuf *p;   
+    struct  {
+      struct ip_addr *ipaddr;
+      u16_t port;
+    } bc;
+    struct {
+      void *dataptr;
+      u16_t len;
+      u8_t copy;
+    } w;    
+    sys_mbox_t mbox;
+    u16_t len;
+  } msg;
+};
+
+struct api_msg {
+  enum api_msg_type type;
+  struct api_msg_msg msg;
+};
+
+void api_msg_input(struct api_msg *msg);
+void api_msg_post(struct api_msg *msg);
+
+#endif /* __LWIP_API_MSG_H__ */
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/arch.h b/Demo/Common/ethernet/lwIP/include/lwip/arch.h
new file mode 100644 (file)
index 0000000..356a016
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_ARCH_H__
+#define __LWIP_ARCH_H__
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+#include "arch/cc.h"
+
+#ifndef PACK_STRUCT_BEGIN
+#define PACK_STRUCT_BEGIN
+#endif /* PACK_STRUCT_BEGIN */
+
+#ifndef PACK_STRUCT_END
+#define PACK_STRUCT_END
+#endif /* PACK_STRUCT_END */
+
+#ifndef PACK_STRUCT_FIELD
+#define PACK_STRUCT_FIELD(x) x
+#endif /* PACK_STRUCT_FIELD */
+
+#ifndef PACK_STRUCT_STRUCT\r
+#define PACK_STRUCT_STRUCT\r
+#endif /* PACK_STRUCT_STRUCT */\r
+
+#ifdef LWIP_PROVIDE_ERRNO
+
+#define  EPERM     1  /* Operation not permitted */
+#define  ENOENT     2  /* No such file or directory */
+#define  ESRCH     3  /* No such process */
+#define  EINTR     4  /* Interrupted system call */
+#define  EIO     5  /* I/O error */
+#define  ENXIO     6  /* No such device or address */
+#define  E2BIG     7  /* Arg list too long */
+#define  ENOEXEC     8  /* Exec format error */
+#define  EBADF     9  /* Bad file number */
+#define  ECHILD    10  /* No child processes */
+#define  EAGAIN    11  /* Try again */
+#define  ENOMEM    12  /* Out of memory */
+#define  EACCES    13  /* Permission denied */
+#define  EFAULT    14  /* Bad address */
+#define  ENOTBLK    15  /* Block device required */
+#define  EBUSY    16  /* Device or resource busy */
+#define  EEXIST    17  /* File exists */
+#define  EXDEV    18  /* Cross-device link */
+#define  ENODEV    19  /* No such device */
+#define  ENOTDIR    20  /* Not a directory */
+#define  EISDIR    21  /* Is a directory */
+#define  EINVAL    22  /* Invalid argument */
+#define  ENFILE    23  /* File table overflow */
+#define  EMFILE    24  /* Too many open files */
+#define  ENOTTY    25  /* Not a typewriter */
+#define  ETXTBSY    26  /* Text file busy */
+#define  EFBIG    27  /* File too large */
+#define  ENOSPC    28  /* No space left on device */
+#define  ESPIPE    29  /* Illegal seek */
+#define  EROFS    30  /* Read-only file system */
+#define  EMLINK    31  /* Too many links */
+#define  EPIPE    32  /* Broken pipe */
+#define  EDOM    33  /* Math argument out of domain of func */
+#define  ERANGE    34  /* Math result not representable */
+#define  EDEADLK    35  /* Resource deadlock would occur */
+#define  ENAMETOOLONG  36  /* File name too long */
+#define  ENOLCK    37  /* No record locks available */
+#define  ENOSYS    38  /* Function not implemented */
+#define  ENOTEMPTY  39  /* Directory not empty */
+#define  ELOOP    40  /* Too many symbolic links encountered */
+#define  EWOULDBLOCK  EAGAIN  /* Operation would block */
+#define  ENOMSG    42  /* No message of desired type */
+#define  EIDRM    43  /* Identifier removed */
+#define  ECHRNG    44  /* Channel number out of range */
+#define  EL2NSYNC  45  /* Level 2 not synchronized */
+#define  EL3HLT    46  /* Level 3 halted */
+#define  EL3RST    47  /* Level 3 reset */
+#define  ELNRNG    48  /* Link number out of range */
+#define  EUNATCH    49  /* Protocol driver not attached */
+#define  ENOCSI    50  /* No CSI structure available */
+#define  EL2HLT    51  /* Level 2 halted */
+#define  EBADE    52  /* Invalid exchange */
+#define  EBADR    53  /* Invalid request descriptor */
+#define  EXFULL    54  /* Exchange full */
+#define  ENOANO    55  /* No anode */
+#define  EBADRQC    56  /* Invalid request code */
+#define  EBADSLT    57  /* Invalid slot */
+
+#define  EDEADLOCK  EDEADLK
+
+#define  EBFONT    59  /* Bad font file format */
+#define  ENOSTR    60  /* Device not a stream */
+#define  ENODATA    61  /* No data available */
+#define  ETIME    62  /* Timer expired */
+#define  ENOSR    63  /* Out of streams resources */
+#define  ENONET    64  /* Machine is not on the network */
+#define  ENOPKG    65  /* Package not installed */
+#define  EREMOTE    66  /* Object is remote */
+#define  ENOLINK    67  /* Link has been severed */
+#define  EADV    68  /* Advertise error */
+#define  ESRMNT    69  /* Srmount error */
+#define  ECOMM    70  /* Communication error on send */
+#define  EPROTO    71  /* Protocol error */
+#define  EMULTIHOP  72  /* Multihop attempted */
+#define  EDOTDOT    73  /* RFS specific error */
+#define  EBADMSG    74  /* Not a data message */
+#define  EOVERFLOW  75  /* Value too large for defined data type */
+#define  ENOTUNIQ  76  /* Name not unique on network */
+#define  EBADFD    77  /* File descriptor in bad state */
+#define  EREMCHG    78  /* Remote address changed */
+#define  ELIBACC    79  /* Can not access a needed shared library */
+#define  ELIBBAD    80  /* Accessing a corrupted shared library */
+#define  ELIBSCN    81  /* .lib section in a.out corrupted */
+#define  ELIBMAX    82  /* Attempting to link in too many shared libraries */
+#define  ELIBEXEC  83  /* Cannot exec a shared library directly */
+#define  EILSEQ    84  /* Illegal byte sequence */
+#define  ERESTART  85  /* Interrupted system call should be restarted */
+#define  ESTRPIPE  86  /* Streams pipe error */
+#define  EUSERS    87  /* Too many users */
+#define  ENOTSOCK  88  /* Socket operation on non-socket */
+#define  EDESTADDRREQ  89  /* Destination address required */
+#define  EMSGSIZE  90  /* Message too long */
+#define  EPROTOTYPE  91  /* Protocol wrong type for socket */
+#define  ENOPROTOOPT  92  /* Protocol not available */
+#define  EPROTONOSUPPORT  93  /* Protocol not supported */
+#define  ESOCKTNOSUPPORT  94  /* Socket type not supported */
+#define  EOPNOTSUPP  95  /* Operation not supported on transport endpoint */
+#define  EPFNOSUPPORT  96  /* Protocol family not supported */
+#define  EAFNOSUPPORT  97  /* Address family not supported by protocol */
+#define  EADDRINUSE  98  /* Address already in use */
+#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */
+#define  ENETDOWN  100  /* Network is down */
+#define  ENETUNREACH  101  /* Network is unreachable */
+#define  ENETRESET  102  /* Network dropped connection because of reset */
+#define  ECONNABORTED  103  /* Software caused connection abort */
+#define  ECONNRESET  104  /* Connection reset by peer */
+#define  ENOBUFS    105  /* No buffer space available */
+#define  EISCONN    106  /* Transport endpoint is already connected */
+#define  ENOTCONN  107  /* Transport endpoint is not connected */
+#define  ESHUTDOWN  108  /* Cannot send after transport endpoint shutdown */
+#define  ETOOMANYREFS  109  /* Too many references: cannot splice */
+#define  ETIMEDOUT  110  /* Connection timed out */
+#define  ECONNREFUSED  111  /* Connection refused */
+#define  EHOSTDOWN  112  /* Host is down */
+#define  EHOSTUNREACH  113  /* No route to host */
+#define  EALREADY  114  /* Operation already in progress */
+#define  EINPROGRESS  115  /* Operation now in progress */
+#define  ESTALE    116  /* Stale NFS file handle */
+#define  EUCLEAN    117  /* Structure needs cleaning */
+#define  ENOTNAM    118  /* Not a XENIX named type file */
+#define  ENAVAIL    119  /* No XENIX semaphores available */
+#define  EISNAM    120  /* Is a named type file */
+#define  EREMOTEIO  121  /* Remote I/O error */
+#define  EDQUOT    122  /* Quota exceeded */
+
+#define  ENOMEDIUM  123  /* No medium found */
+#define  EMEDIUMTYPE  124  /* Wrong medium type */
+
+
+#define ENSROK    0 /* DNS server returned answer with no data */
+#define ENSRNODATA  160 /* DNS server returned answer with no data */
+#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
+#define ENSRSERVFAIL 162  /* DNS server returned general failure */
+#define ENSRNOTFOUND 163  /* Domain name not found */
+#define ENSRNOTIMP  164 /* DNS server does not implement requested operation */
+#define ENSRREFUSED 165 /* DNS server refused query */
+#define ENSRBADQUERY 166  /* Misformatted DNS query */
+#define ENSRBADNAME 167 /* Misformatted domain name */
+#define ENSRBADFAMILY 168 /* Unsupported address family */
+#define ENSRBADRESP 169 /* Misformatted DNS reply */
+#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
+#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
+#define ENSROF    172 /* End of file */
+#define ENSRFILE  173 /* Error reading file */
+#define ENSRNOMEM 174 /* Out of memory */
+#define ENSRDESTRUCTION 175 /* Application terminated lookup */
+#define ENSRQUERYDOMAINTOOLONG  176 /* Domain name is too long */
+#define ENSRCNAMELOOP 177 /* Domain name is too long */
+
+#ifndef errno
+extern int errno;
+#endif
+
+#endif /* LWIP_PROVIDE_ERRNO */
+
+#endif /* __LWIP_ARCH_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/debug.h b/Demo/Common/ethernet/lwIP/include/lwip/debug.h
new file mode 100644 (file)
index 0000000..8f63a7b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_DEBUG_H__
+#define __LWIP_DEBUG_H__
+
+#include "arch/cc.h"
+
+/** lower two bits indicate debug level
+ * - 0 off
+ * - 1 warning
+ * - 2 serious
+ * - 3 severe
+ */
+
+#define DBG_LEVEL_OFF     0
+#define DBG_LEVEL_WARNING 1  /* bad checksums, dropped packets, ... */
+#define DBG_LEVEL_SERIOUS 2  /* memory allocation failures, ... */
+#define DBG_LEVEL_SEVERE  3  /* */ 
+#define DBG_MASK_LEVEL    3
+
+/** flag for LWIP_DEBUGF to enable that debug message */
+#define DBG_ON  0x80U
+/** flag for LWIP_DEBUGF to disable that debug message */
+#define DBG_OFF 0x00U
+
+/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */
+#define DBG_TRACE   0x40U
+/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */
+#define DBG_STATE   0x20U
+/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */
+#define DBG_FRESH   0x10U
+/** flag for LWIP_DEBUGF to halt after printing this debug message */
+#define DBG_HALT    0x08U
+
+#ifndef LWIP_NOASSERT
+#  define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0)
+#else
+#  define LWIP_ASSERT(x,y) 
+#endif
+
+#ifdef LWIP_DEBUG
+/** print debug message only if debug message type is enabled...
+ *  AND is of correct type AND is at least DBG_LEVEL
+ */
+#  define LWIP_DEBUGF(debug,x) do { if (((debug) & DBG_ON) && ((debug) & DBG_TYPES_ON) && ((s16_t)((debug) & DBG_MASK_LEVEL) >= DBG_MIN_LEVEL)) { LWIP_PLATFORM_DIAG(x); if ((debug) & DBG_HALT) while(1); } } while(0)
+#  define LWIP_ERROR(x)   do { LWIP_PLATFORM_DIAG(x); } while(0)  
+#else /* LWIP_DEBUG */
+#  define LWIP_DEBUGF(debug,x) 
+#  define LWIP_ERROR(x)  
+#endif /* LWIP_DEBUG */
+
+#endif /* __LWIP_DEBUG_H__ */
+
+
+
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/def.h b/Demo/Common/ethernet/lwIP/include/lwip/def.h
new file mode 100644 (file)
index 0000000..eba9b87
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_DEF_H__
+#define __LWIP_DEF_H__
+
+/* this might define NULL already */
+#include "arch/cc.h"
+
+#define LWIP_MAX(x , y)  (x) > (y) ? (x) : (y)
+#define LWIP_MIN(x , y)  (x) < (y) ? (x) : (y)
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+
+#endif /* __LWIP_DEF_H__ */
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/dhcp.h b/Demo/Common/ethernet/lwIP/include/lwip/dhcp.h
new file mode 100644 (file)
index 0000000..bfe753f
--- /dev/null
@@ -0,0 +1,223 @@
+/** @file
+ */
+
+#ifndef __LWIP_DHCP_H__
+#define __LWIP_DHCP_H__
+
+#include "lwip/opt.h"
+#include "lwip/netif.h"
+#include "lwip/udp.h"
+
+/** period (in seconds) of the application calling dhcp_coarse_tmr() */
+#define DHCP_COARSE_TIMER_SECS 60 
+/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
+#define DHCP_FINE_TIMER_MSECS 500 
+
+struct dhcp
+{
+  /** current DHCP state machine state */
+  u8_t state;
+  /** retries of current request */
+  u8_t tries;
+  /** transaction identifier of last sent request */ 
+  u32_t xid;
+  /** our connection to the DHCP server */ 
+  struct udp_pcb *pcb;
+  /** (first) pbuf of incoming msg */
+  struct pbuf *p;
+  /** incoming msg */
+  struct dhcp_msg *msg_in;
+  /** incoming msg options */
+  struct dhcp_msg *options_in; 
+  /** ingoing msg options length */
+  u16_t options_in_len;
+
+  struct pbuf *p_out; /* pbuf of outcoming msg */
+  struct dhcp_msg *msg_out; /* outgoing msg */
+  u16_t options_out_len; /* outgoing msg options length */
+  u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
+  u16_t t1_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
+  u16_t t2_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
+  struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */
+  struct ip_addr offered_ip_addr;
+  struct ip_addr offered_sn_mask;
+  struct ip_addr offered_gw_addr;
+  struct ip_addr offered_bc_addr;
+#define DHCP_MAX_DNS 2
+  u32_t dns_count; /* actual number of DNS servers obtained */
+  struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */
+  u32_t offered_t0_lease; /* lease period (in seconds) */
+  u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
+  u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period)  */
+/** Patch #1308
+ *  TODO: See dhcp.c "TODO"s
+ */
+#if 0
+  struct ip_addr offered_si_addr;
+  u8_t *boot_file_name;
+#endif
+};
+
+/* MUST be compiled with "pack structs" or equivalent! */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** minimum set of fields of any DHCP message */
+struct dhcp_msg
+{
+  PACK_STRUCT_FIELD(u8_t op);
+  PACK_STRUCT_FIELD(u8_t htype);
+  PACK_STRUCT_FIELD(u8_t hlen);
+  PACK_STRUCT_FIELD(u8_t hops);
+  PACK_STRUCT_FIELD(u32_t xid);
+  PACK_STRUCT_FIELD(u16_t secs);
+  PACK_STRUCT_FIELD(u16_t flags);
+  PACK_STRUCT_FIELD(struct ip_addr ciaddr);
+  PACK_STRUCT_FIELD(struct ip_addr yiaddr);
+  PACK_STRUCT_FIELD(struct ip_addr siaddr);
+  PACK_STRUCT_FIELD(struct ip_addr giaddr);
+#define DHCP_CHADDR_LEN 16U
+  PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
+#define DHCP_SNAME_LEN 64U
+  PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
+#define DHCP_FILE_LEN 128U
+  PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
+  PACK_STRUCT_FIELD(u32_t cookie);
+#define DHCP_MIN_OPTIONS_LEN 68U
+/** make sure user does not configure this too small */
+#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
+#  undef DHCP_OPTIONS_LEN
+#endif
+/** allow this to be configured in lwipopts.h, but not too small */
+#if (!defined(DHCP_OPTIONS_LEN))
+/** set this to be sufficient for your options in outgoing DHCP msgs */
+#  define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN
+#endif
+  PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** start DHCP configuration */
+err_t dhcp_start(struct netif *netif);
+/** enforce early lease renewal (not needed normally)*/
+err_t dhcp_renew(struct netif *netif);
+/** release the DHCP lease, usually called before dhcp_stop()*/
+err_t dhcp_release(struct netif *netif);
+/** stop DHCP configuration */
+void dhcp_stop(struct netif *netif);
+/** inform server of our manual IP address */
+void dhcp_inform(struct netif *netif);
+
+/** if enabled, check whether the offered IP address is not in use, using ARP */
+#if DHCP_DOES_ARP_CHECK
+void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);
+#endif
+
+/** to be called every minute */
+void dhcp_coarse_tmr(void);
+/** to be called every half second */
+void dhcp_fine_tmr(void);
+/** DHCP message item offsets and length */
+#define DHCP_MSG_OFS (UDP_DATA_OFS)  
+  #define DHCP_OP_OFS (DHCP_MSG_OFS + 0)
+  #define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)
+  #define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)
+  #define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)
+  #define DHCP_XID_OFS (DHCP_MSG_OFS + 4)
+  #define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)
+  #define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)
+  #define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)
+  #define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)
+  #define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)
+  #define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)
+  #define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)
+  #define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)
+  #define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)
+#define DHCP_MSG_LEN 236
+
+#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)
+#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)
+
+#define DHCP_CLIENT_PORT 68  
+#define DHCP_SERVER_PORT 67
+
+/** DHCP client states */
+#define DHCP_REQUESTING 1
+#define DHCP_INIT 2
+#define DHCP_REBOOTING 3
+#define DHCP_REBINDING 4
+#define DHCP_RENEWING 5
+#define DHCP_SELECTING 6
+#define DHCP_INFORMING 7
+#define DHCP_CHECKING 8
+#define DHCP_PERMANENT 9
+#define DHCP_BOUND 10
+/** not yet implemented #define DHCP_RELEASING 11 */
+#define DHCP_BACKING_OFF 12
+#define DHCP_OFF 13
+#define DHCP_BOOTREQUEST 1
+#define DHCP_BOOTREPLY 2
+
+#define DHCP_DISCOVER 1
+#define DHCP_OFFER 2
+#define DHCP_REQUEST 3
+#define DHCP_DECLINE 4
+#define DHCP_ACK 5
+#define DHCP_NAK 6
+#define DHCP_RELEASE 7
+#define DHCP_INFORM 8
+
+#define DHCP_HTYPE_ETH 1
+
+#define DHCP_HLEN_ETH 6
+
+#define DHCP_BROADCAST_FLAG 15
+#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)
+
+/** BootP options */
+#define DHCP_OPTION_PAD 0
+#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */
+#define DHCP_OPTION_ROUTER 3
+#define DHCP_OPTION_DNS_SERVER 6 
+#define DHCP_OPTION_HOSTNAME 12
+#define DHCP_OPTION_IP_TTL 23
+#define DHCP_OPTION_MTU 26
+#define DHCP_OPTION_BROADCAST 28
+#define DHCP_OPTION_TCP_TTL 37
+#define DHCP_OPTION_END 255
+
+/** DHCP options */
+#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
+#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
+#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */
+
+#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
+#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
+
+
+#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
+#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
+
+#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */
+#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2
+
+#define DHCP_OPTION_T1 58 /* T1 renewal time */
+#define DHCP_OPTION_T2 59 /* T2 rebinding time */
+#define DHCP_OPTION_CLIENT_ID 61
+#define DHCP_OPTION_TFTP_SERVERNAME 66
+#define DHCP_OPTION_BOOTFILE 67
+
+/** possible combinations of overloading the file and sname fields with options */
+#define DHCP_OVERLOAD_NONE 0
+#define DHCP_OVERLOAD_FILE 1
+#define DHCP_OVERLOAD_SNAME  2
+#define DHCP_OVERLOAD_SNAME_FILE 3
+
+#endif /*__LWIP_DHCP_H__*/
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/err.h b/Demo/Common/ethernet/lwIP/include/lwip/err.h
new file mode 100644 (file)
index 0000000..c92cb26
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_ERR_H__
+#define __LWIP_ERR_H__
+
+#include "lwip/opt.h"
+
+#include "arch/cc.h"
+
+typedef s8_t err_t;
+
+/* Definitions for error constants. */
+
+#define ERR_OK    0      /* No error, everything OK. */
+#define ERR_MEM  -1      /* Out of memory error.     */
+#define ERR_BUF  -2      /* Buffer error.            */
+
+
+#define ERR_ABRT -3      /* Connection aborted.      */
+#define ERR_RST  -4      /* Connection reset.        */
+#define ERR_CLSD -5      /* Connection closed.       */
+#define ERR_CONN -6      /* Not connected.           */
+
+#define ERR_VAL  -7      /* Illegal value.           */
+
+#define ERR_ARG  -8      /* Illegal argument.        */
+
+#define ERR_RTE  -9      /* Routing problem.         */
+
+#define ERR_USE  -10     /* Address in use.          */
+
+#define ERR_IF   -11     /* Low-level netif error    */
+#define ERR_ISCONN -12   /* Already connected.       */
+
+
+#ifdef LWIP_DEBUG
+extern char *lwip_strerr(err_t err);
+#else
+#define lwip_strerr(x) ""
+#endif /* LWIP_DEBUG */
+#endif /* __LWIP_ERR_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/mem.h b/Demo/Common/ethernet/lwIP/include/lwip/mem.h
new file mode 100644 (file)
index 0000000..f14d176
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_MEM_H__
+#define __LWIP_MEM_H__
+
+#include "lwip/opt.h"
+#include "lwip/arch.h"
+
+#if MEM_SIZE > 64000l
+typedef u32_t mem_size_t;
+#define MEM_SIZE_F U32_F
+#else
+typedef u16_t mem_size_t;
+#define MEM_SIZE_F U16_F
+#endif /* MEM_SIZE > 64000 */
+
+#if MEM_LIBC_MALLOC
+/* aliases for C library malloc() */
+#define mem_init()
+#define mem_free(x) free(x)
+#define mem_malloc(x) malloc(x)
+#define mem_realloc(x, size) realloc(x,size)
+#else
+/* lwIP alternative malloc */
+void mem_init(void);
+void *mem_malloc(mem_size_t size);
+void mem_free(void *mem);
+void *mem_realloc(void *mem, mem_size_t size);
+#endif
+
+#ifndef MEM_ALIGN_SIZE
+#define MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
+#endif
+
+#ifndef MEM_ALIGN
+#define MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))
+#endif
+
+#endif /* __LWIP_MEM_H__ */
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/memp.h b/Demo/Common/ethernet/lwIP/include/lwip/memp.h
new file mode 100644 (file)
index 0000000..1cd46fa
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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>
+ *
+ */
+
+#ifndef __LWIP_MEMP_H__
+#define __LWIP_MEMP_H__
+
+#include "lwip/opt.h"
+
+typedef enum {
+  MEMP_PBUF,
+  MEMP_RAW_PCB,
+  MEMP_UDP_PCB,
+  MEMP_TCP_PCB,
+  MEMP_TCP_PCB_LISTEN,
+  MEMP_TCP_SEG,
+
+  MEMP_NETBUF,
+  MEMP_NETCONN,
+  MEMP_API_MSG,
+  MEMP_TCPIP_MSG,
+
+  MEMP_SYS_TIMEOUT,
+  
+  MEMP_MAX
+} memp_t;
+
+void memp_init(void);
+
+void *memp_malloc(memp_t type);
+void *memp_realloc(memp_t fromtype, memp_t totype, void *mem);
+void memp_free(memp_t type, void *mem);
+
+#endif /* __LWIP_MEMP_H__  */
+    
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/netif.h b/Demo/Common/ethernet/lwIP/include/lwip/netif.h
new file mode 100644 (file)
index 0000000..b773769
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_NETIF_H__
+#define __LWIP_NETIF_H__
+
+#include "lwip/opt.h"
+
+#include "lwip/err.h"
+
+#include "lwip/ip_addr.h"
+
+#include "lwip/inet.h"
+#include "lwip/pbuf.h"
+#if LWIP_DHCP
+#  include "lwip/dhcp.h"
+#endif
+
+/** must be the maximum of all used hardware address lengths
+    across all types of interfaces in use */
+#define NETIF_MAX_HWADDR_LEN 6U
+
+/** TODO: define the use (where, when, whom) of netif flags */
+
+/** whether the network interface is 'up'. this is
+ * a software flag used to control whether this network
+ * interface is enabled and processes traffic.
+ */
+#define NETIF_FLAG_UP 0x1U
+/** if set, the netif has broadcast capability */
+#define NETIF_FLAG_BROADCAST 0x2U
+/** if set, the netif is one end of a point-to-point connection */
+#define NETIF_FLAG_POINTTOPOINT 0x4U
+/** if set, the interface is configured using DHCP */
+#define NETIF_FLAG_DHCP 0x08U
+/** if set, the interface has an active link
+ *  (set by the network interface driver) */
+#define NETIF_FLAG_LINK_UP 0x10U
+
+/** Generic data structure used for all lwIP network interfaces.
+ *  The following fields should be filled in by the initialization
+ *  function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
+
+struct netif {
+  /** pointer to next in linked list */
+  struct netif *next;
+
+  /** IP address configuration in network byte order */
+  struct ip_addr ip_addr;
+  struct ip_addr netmask;
+  struct ip_addr gw;
+
+  /** This function is called by the network device driver
+   *  to pass a packet up the TCP/IP stack. */
+  err_t (* input)(struct pbuf *p, struct netif *inp);
+  /** This function is called by the IP module when it wants
+   *  to send a packet on the interface. This function typically
+   *  first resolves the hardware address, then sends the packet. */
+  err_t (* output)(struct netif *netif, struct pbuf *p,
+       struct ip_addr *ipaddr);
+  /** This function is called by the ARP module when it wants
+   *  to send a packet on the interface. This function outputs
+   *  the pbuf as-is on the link medium. */
+  err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
+  /** This field can be set by the device driver and could point
+   *  to state information for the device. */
+  void *state;
+#if LWIP_DHCP
+  /** the DHCP client state information for this netif */
+  struct dhcp *dhcp;
+#endif
+  /** number of bytes used in hwaddr */
+  u8_t hwaddr_len;
+  /** link level hardware address of this interface */
+  u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
+  /** maximum transfer unit (in bytes) */
+  u16_t mtu;
+  /** flags (see NETIF_FLAG_ above) */
+  u8_t flags;
+  /** descriptive abbreviation */
+  char name[2];
+  /** number of this interface */
+  u8_t num;
+#if LWIP_SNMP
+  /** link type (ifType values per RFC1213) */
+  u8_t link_type;
+  /** (estimate) link speed */
+  u32_t link_speed;
+  /** timestamp at last change made (up/down) */
+  u32_t ts;
+  /** counters */
+  u32_t ifinoctets;
+  u32_t ifinucastpkts;
+  u32_t ifinnucastpkts;
+  u32_t ifindiscards;
+  u32_t ifoutoctets;
+  u32_t ifoutucastpkts;
+  u32_t ifoutnucastpkts;
+  u32_t ifoutdiscards;
+#endif
+};
+
+/** The list of network interfaces. */
+extern struct netif *netif_list;
+/** The default network interface. */
+extern struct netif *netif_default;
+
+/* netif_init() must be called first. */
+void netif_init(void);
+
+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));
+
+void
+netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,
+    struct ip_addr *gw);
+void netif_remove(struct netif * netif);
+
+/* Returns a network interface given its name. The name is of the form
+   "et0", where the first two letters are the "name" field in the
+   netif structure, and the digit is in the num field in the same
+   structure. */
+struct netif *netif_find(char *name);
+
+void netif_set_default(struct netif *netif);
+
+void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);
+void netif_set_netmask(struct netif *netif, struct ip_addr *netmast);
+void netif_set_gw(struct netif *netif, struct ip_addr *gw);
+void netif_set_up(struct netif *netif);
+void netif_set_down(struct netif *netif);
+u8_t netif_is_up(struct netif *netif);
+
+#endif /* __LWIP_NETIF_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/pbuf.h b/Demo/Common/ethernet/lwIP/include/lwip/pbuf.h
new file mode 100644 (file)
index 0000000..546aa30
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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>
+ *
+ */
+
+#ifndef __LWIP_PBUF_H__
+#define __LWIP_PBUF_H__
+
+#include "arch/cc.h"
+
+
+#define PBUF_TRANSPORT_HLEN 20
+#define PBUF_IP_HLEN        20
+
+typedef enum {
+  PBUF_TRANSPORT,
+  PBUF_IP,
+  PBUF_LINK,
+  PBUF_RAW
+} pbuf_layer;
+
+typedef enum {
+  PBUF_RAM,
+  PBUF_ROM,
+  PBUF_REF,
+  PBUF_POOL
+} pbuf_flag;
+
+/* Definitions for the pbuf flag field. These are NOT the flags that
+ * are passed to pbuf_alloc(). */
+#define PBUF_FLAG_RAM   0x00U    /* Flags that pbuf data is stored in RAM */
+#define PBUF_FLAG_ROM   0x01U    /* Flags that pbuf data is stored in ROM */
+#define PBUF_FLAG_POOL  0x02U    /* Flags that the pbuf comes from the pbuf pool */
+#define PBUF_FLAG_REF   0x04U    /* Flags thet the pbuf payload refers to RAM */
+
+/** indicates this packet was broadcast on the link */
+#define PBUF_FLAG_LINK_BROADCAST 0x80U
+
+struct pbuf {
+  /** next pbuf in singly linked pbuf chain */
+  struct pbuf *next;
+
+  /** pointer to the actual data in the buffer */
+  void *payload;
+  
+  /**
+   * total length of this buffer and all next buffers in chain
+   * belonging to the same packet.
+   *
+   * For non-queue packet chains this is the invariant:
+   * p->tot_len == p->len + (p->next? p->next->tot_len: 0)
+   */
+  u16_t tot_len;
+  
+  /** length of this buffer */
+  u16_t len;  
+
+  /** flags telling the type of pbuf, see PBUF_FLAG_ */
+  u16_t flags;
+  
+  /**
+   * the reference count always equals the number of pointers
+   * that refer to this pbuf. This can be pointers from an application,
+   * the stack itself, or pbuf->next pointers from a chain.
+   */
+  u16_t ref;
+  
+};
+
+void pbuf_init(void);
+
+struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag);
+void pbuf_realloc(struct pbuf *p, u16_t size); 
+u8_t pbuf_header(struct pbuf *p, s16_t header_size);
+void pbuf_ref(struct pbuf *p);
+void pbuf_ref_chain(struct pbuf *p);
+u8_t pbuf_free(struct pbuf *p);
+u8_t pbuf_clen(struct pbuf *p);  
+void pbuf_cat(struct pbuf *h, struct pbuf *t);
+void pbuf_chain(struct pbuf *h, struct pbuf *t);
+struct pbuf *pbuf_take(struct pbuf *f);
+struct pbuf *pbuf_dechain(struct pbuf *p);
+void pbuf_queue(struct pbuf *p, struct pbuf *n);
+struct pbuf * pbuf_dequeue(struct pbuf *p);
+
+#endif /* __LWIP_PBUF_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/raw.h b/Demo/Common/ethernet/lwIP/include/lwip/raw.h
new file mode 100644 (file)
index 0000000..6f7a987
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_RAW_H__
+#define __LWIP_RAW_H__
+
+#include "lwip/arch.h"
+
+#include "lwip/pbuf.h"
+#include "lwip/inet.h"
+#include "lwip/ip.h"
+
+struct raw_pcb {
+/* Common members of all PCB types */
+  IP_PCB;
+
+  struct raw_pcb *next;
+
+  u16_t protocol;
+
+  u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
+    struct ip_addr *addr);
+  void *recv_arg;
+};
+
+/* The following functions is the application layer interface to the
+   RAW code. */
+struct raw_pcb * raw_new        (u16_t proto);
+void             raw_remove     (struct raw_pcb *pcb);
+err_t            raw_bind       (struct raw_pcb *pcb, struct ip_addr *ipaddr);
+err_t            raw_connect    (struct raw_pcb *pcb, struct ip_addr *ipaddr);
+
+void             raw_recv       (struct raw_pcb *pcb,
+                                 u8_t (* recv)(void *arg, struct raw_pcb *pcb,
+                                              struct pbuf *p,
+                                              struct ip_addr *addr),
+                                 void *recv_arg);
+err_t            raw_sendto    (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);
+err_t            raw_send       (struct raw_pcb *pcb, struct pbuf *p);
+
+/* The following functions are the lower layer interface to RAW. */
+u8_t              raw_input      (struct pbuf *p, struct netif *inp);
+void             raw_init       (void);
+
+
+#endif /* __LWIP_RAW_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/sio.h b/Demo/Common/ethernet/lwIP/include/lwip/sio.h
new file mode 100644 (file)
index 0000000..8a37aa3
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+/*
+ * This is the interface to the platform specific serial IO module
+ * It needs to be implemented by those platforms which need SLIP or PPP
+ */
+
+#include "arch/cc.h"
+
+#ifndef __sio_fd_t_defined
+typedef void * sio_fd_t;
+#endif
+
+#ifndef sio_open
+sio_fd_t sio_open(u8_t);
+#endif
+
+#ifndef sio_send
+void sio_send(u8_t, sio_fd_t);
+#endif
+
+#ifndef sio_recv
+u8_t sio_recv(sio_fd_t);
+#endif
+
+#ifndef sio_read
+u32_t sio_read(sio_fd_t, u8_t *, u32_t);
+#endif
+
+#ifndef sio_write
+u32_t sio_write(sio_fd_t, u8_t *, u32_t);
+#endif
+
+#ifndef sio_read_abort
+void sio_read_abort(sio_fd_t);
+#endif
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/snmp.h b/Demo/Common/ethernet/lwIP/include/lwip/snmp.h
new file mode 100644 (file)
index 0000000..95145ce
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>
+ * Copyright (c) 2001, 2002 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 part of the lwIP TCP/IP stack.
+ * 
+ * Author: Leon Woestenberg <leon.woestenberg@axon.tv>
+ *
+ */
+#ifndef __LWIP_SNMP_H__
+#define __LWIP_SNMP_H__
+
+#include "lwip/opt.h"
+#include "lwip/netif.h"
+#include "lwip/udp.h"
+
+/* SNMP support available? */
+#if defined(LWIP_SNMP) && (LWIP_SNMP > 0)
+
+/** fixed maximum length for object identifier type */
+#define LWIP_SNMP_OBJ_ID_LEN 32
+/** internal object identifier representation */
+struct snmp_obj_id
+{
+  u8_t len;
+  s32_t id[LWIP_SNMP_OBJ_ID_LEN];
+};
+
+/* system */
+void snmp_set_sysdesr(u8_t* str, u8_t* strlen);
+void snmp_set_sysobjid(struct snmp_obj_id *oid);
+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid);
+void snmp_inc_sysuptime(void);
+void snmp_get_sysuptime(u32_t *value);
+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen);
+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen);
+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen);
+
+/* network interface */
+void snmp_add_ifinoctets(struct netif *ni, u32_t value); 
+void snmp_inc_ifinucastpkts(struct netif *ni);
+void snmp_inc_ifinnucastpkts(struct netif *ni);
+void snmp_inc_ifindiscards(struct netif *ni);
+void snmp_add_ifoutoctets(struct netif *ni, u32_t value);
+void snmp_inc_ifoutucastpkts(struct netif *ni);
+void snmp_inc_ifoutnucastpkts(struct netif *ni);
+void snmp_inc_ifoutdiscards(struct netif *ni);
+void snmp_inc_iflist(void);
+void snmp_dec_iflist(void);
+
+/* ARP (for atTable and ipNetToMediaTable) */
+void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip);
+void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip);
+
+/* IP */
+void snmp_inc_ipinreceives(void);
+void snmp_inc_ipinhdrerrors(void);
+void snmp_inc_ipinaddrerrors(void);
+void snmp_inc_ipforwdatagrams(void);
+void snmp_inc_ipinunknownprotos(void);
+void snmp_inc_ipindiscards(void);
+void snmp_inc_ipindelivers(void);
+void snmp_inc_ipoutrequests(void);
+void snmp_inc_ipoutdiscards(void);
+void snmp_inc_ipoutnoroutes(void);
+void snmp_inc_ipreasmreqds(void);
+void snmp_inc_ipreasmoks(void);
+void snmp_inc_ipreasmfails(void);
+void snmp_inc_ipfragoks(void);
+void snmp_inc_ipfragfails(void);
+void snmp_inc_ipfragcreates(void);
+void snmp_inc_iproutingdiscards(void);
+void snmp_insert_ipaddridx_tree(struct netif *ni);
+void snmp_delete_ipaddridx_tree(struct netif *ni);
+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni);
+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni);
+
+/* ICMP */
+void snmp_inc_icmpinmsgs(void);
+void snmp_inc_icmpinerrors(void);
+void snmp_inc_icmpindestunreachs(void);
+void snmp_inc_icmpintimeexcds(void);
+void snmp_inc_icmpinparmprobs(void);
+void snmp_inc_icmpinsrcquenchs(void);
+void snmp_inc_icmpinredirects(void);
+void snmp_inc_icmpinechos(void);
+void snmp_inc_icmpinechoreps(void);
+void snmp_inc_icmpintimestamps(void);
+void snmp_inc_icmpintimestampreps(void);
+void snmp_inc_icmpinaddrmasks(void);
+void snmp_inc_icmpinaddrmaskreps(void);
+void snmp_inc_icmpoutmsgs(void);
+void snmp_inc_icmpouterrors(void);
+void snmp_inc_icmpoutdestunreachs(void);
+void snmp_inc_icmpouttimeexcds(void);
+void snmp_inc_icmpoutparmprobs(void);
+void snmp_inc_icmpoutsrcquenchs(void);
+void snmp_inc_icmpoutredirects(void); 
+void snmp_inc_icmpoutechos(void);
+void snmp_inc_icmpoutechoreps(void);
+void snmp_inc_icmpouttimestamps(void);
+void snmp_inc_icmpouttimestampreps(void);
+void snmp_inc_icmpoutaddrmasks(void);
+void snmp_inc_icmpoutaddrmaskreps(void);
+
+/* TCP */
+void snmp_inc_tcpactiveopens(void);
+void snmp_inc_tcppassiveopens(void);
+void snmp_inc_tcpattemptfails(void);
+void snmp_inc_tcpestabresets(void);
+void snmp_inc_tcpinsegs(void);
+void snmp_inc_tcpoutsegs(void);
+void snmp_inc_tcpretranssegs(void);
+void snmp_inc_tcpinerrs(void);
+void snmp_inc_tcpoutrsts(void);
+
+/* UDP */
+void snmp_inc_udpindatagrams(void);
+void snmp_inc_udpnoports(void);
+void snmp_inc_udpinerrors(void);
+void snmp_inc_udpoutdatagrams(void);
+void snmp_insert_udpidx_tree(struct udp_pcb *pcb);
+void snmp_delete_udpidx_tree(struct udp_pcb *pcb);
+
+/* SNMP */
+void snmp_inc_snmpinpkts(void);
+void snmp_inc_snmpoutpkts(void);
+void snmp_inc_snmpinbadversions(void);
+void snmp_inc_snmpinbadcommunitynames(void);
+void snmp_inc_snmpinbadcommunityuses(void);
+void snmp_inc_snmpinasnparseerrs(void);
+void snmp_inc_snmpintoobigs(void);
+void snmp_inc_snmpinnosuchnames(void);
+void snmp_inc_snmpinbadvalues(void);
+void snmp_inc_snmpinreadonlys(void);
+void snmp_inc_snmpingenerrs(void);
+void snmp_add_snmpintotalreqvars(u8_t value);
+void snmp_add_snmpintotalsetvars(u8_t value);
+void snmp_inc_snmpingetrequests(void);
+void snmp_inc_snmpingetnexts(void);
+void snmp_inc_snmpinsetrequests(void);
+void snmp_inc_snmpingetresponses(void);
+void snmp_inc_snmpintraps(void);
+void snmp_inc_snmpouttoobigs(void);
+void snmp_inc_snmpoutnosuchnames(void);
+void snmp_inc_snmpoutbadvalues(void);
+void snmp_inc_snmpoutgenerrs(void);
+void snmp_inc_snmpoutgetrequests(void);
+void snmp_inc_snmpoutgetnexts(void);
+void snmp_inc_snmpoutsetrequests(void);
+void snmp_inc_snmpoutgetresponses(void);
+void snmp_inc_snmpouttraps(void);
+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid);
+void snmp_set_snmpenableauthentraps(u8_t *value);
+void snmp_get_snmpenableauthentraps(u8_t *value);
+
+/* LWIP_SNMP support not available */
+/* define everything to be empty */
+#else
+
+/* system */
+#define snmp_set_sysdesr(str, strlen)
+#define snmp_get_sysobjid_ptr(oid)
+#define snmp_inc_sysuptime()
+#define snmp_get_sysuptime(value)
+
+/* network interface */
+#define snmp_add_ifinoctets(ni,value) 
+#define snmp_inc_ifinucastpkts(ni)
+#define snmp_inc_ifinnucastpkts(ni)
+#define snmp_inc_ifindiscards(ni)
+#define snmp_add_ifoutoctets(ni,value)
+#define snmp_inc_ifoutucastpkts(ni)
+#define snmp_inc_ifoutnucastpkts(ni)
+#define snmp_inc_ifoutdiscards(ni)
+#define snmp_inc_iflist()
+#define snmp_dec_iflist()
+
+/* ARP */
+#define snmp_insert_arpidx_tree(ni,ip)
+#define snmp_delete_arpidx_tree(ni,ip)
+
+/* IP */
+#define snmp_inc_ipinreceives()
+#define snmp_inc_ipinhdrerrors()
+#define snmp_inc_ipinaddrerrors()
+#define snmp_inc_ipforwdatagrams()
+#define snmp_inc_ipinunknownprotos()
+#define snmp_inc_ipindiscards()
+#define snmp_inc_ipindelivers()
+#define snmp_inc_ipoutrequests()
+#define snmp_inc_ipoutdiscards()
+#define snmp_inc_ipoutnoroutes()
+#define snmp_inc_ipreasmreqds()
+#define snmp_inc_ipreasmoks()
+#define snmp_inc_ipreasmfails()
+#define snmp_inc_ipfragoks()
+#define snmp_inc_ipfragfails()
+#define snmp_inc_ipfragcreates()
+#define snmp_inc_iproutingdiscards()
+#define snmp_insert_ipaddridx_tree(ni)
+#define snmp_delete_ipaddridx_tree(ni)
+#define snmp_insert_iprteidx_tree(dflt, ni)
+#define snmp_delete_iprteidx_tree(dflt, ni)
+
+/* ICMP */
+#define snmp_inc_icmpinmsgs()
+#define snmp_inc_icmpinerrors() 
+#define snmp_inc_icmpindestunreachs() 
+#define snmp_inc_icmpintimeexcds()
+#define snmp_inc_icmpinparmprobs() 
+#define snmp_inc_icmpinsrcquenchs() 
+#define snmp_inc_icmpinredirects() 
+#define snmp_inc_icmpinechos() 
+#define snmp_inc_icmpinechoreps()
+#define snmp_inc_icmpintimestamps() 
+#define snmp_inc_icmpintimestampreps()
+#define snmp_inc_icmpinaddrmasks()
+#define snmp_inc_icmpinaddrmaskreps()
+#define snmp_inc_icmpoutmsgs()
+#define snmp_inc_icmpouterrors()
+#define snmp_inc_icmpoutdestunreachs() 
+#define snmp_inc_icmpouttimeexcds() 
+#define snmp_inc_icmpoutparmprobs()
+#define snmp_inc_icmpoutsrcquenchs()
+#define snmp_inc_icmpoutredirects() 
+#define snmp_inc_icmpoutechos() 
+#define snmp_inc_icmpoutechoreps()
+#define snmp_inc_icmpouttimestamps()
+#define snmp_inc_icmpouttimestampreps()
+#define snmp_inc_icmpoutaddrmasks()
+#define snmp_inc_icmpoutaddrmaskreps()
+/* TCP */
+#define snmp_inc_tcpactiveopens()
+#define snmp_inc_tcppassiveopens()
+#define snmp_inc_tcpattemptfails()
+#define snmp_inc_tcpestabresets()
+#define snmp_inc_tcpinsegs()
+#define snmp_inc_tcpoutsegs()
+#define snmp_inc_tcpretranssegs()
+#define snmp_inc_tcpinerrs()
+#define snmp_inc_tcpoutrsts()
+
+/* UDP */
+#define snmp_inc_udpindatagrams()
+#define snmp_inc_udpnoports()
+#define snmp_inc_udpinerrors()
+#define snmp_inc_udpoutdatagrams()
+#define snmp_insert_udpidx_tree(pcb)
+#define snmp_delete_udpidx_tree(pcb)
+
+/* SNMP */
+#define snmp_inc_snmpinpkts()
+#define snmp_inc_snmpoutpkts()
+#define snmp_inc_snmpinbadversions()
+#define snmp_inc_snmpinbadcommunitynames()
+#define snmp_inc_snmpinbadcommunityuses()
+#define snmp_inc_snmpinasnparseerrs()
+#define snmp_inc_snmpintoobigs()
+#define snmp_inc_snmpinnosuchnames()
+#define snmp_inc_snmpinbadvalues()
+#define snmp_inc_snmpinreadonlys()
+#define snmp_inc_snmpingenerrs()
+#define snmp_add_snmpintotalreqvars(value)
+#define snmp_add_snmpintotalsetvars(value)
+#define snmp_inc_snmpingetrequests()
+#define snmp_inc_snmpingetnexts()
+#define snmp_inc_snmpinsetrequests()
+#define snmp_inc_snmpingetresponses()
+#define snmp_inc_snmpintraps()
+#define snmp_inc_snmpouttoobigs()
+#define snmp_inc_snmpoutnosuchnames()
+#define snmp_inc_snmpoutbadvalues()
+#define snmp_inc_snmpoutgenerrs()
+#define snmp_inc_snmpoutgetrequests()
+#define snmp_inc_snmpoutgetnexts()
+#define snmp_inc_snmpoutsetrequests()
+#define snmp_inc_snmpoutgetresponses()
+#define snmp_inc_snmpouttraps()
+#define snmp_get_snmpgrpid_ptr(oid)
+#define snmp_set_snmpenableauthentraps(value)
+#define snmp_get_snmpenableauthentraps(value)
+
+#endif
+
+#endif /* __LWIP_SNMP_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/snmp_asn1.h b/Demo/Common/ethernet/lwIP/include/lwip/snmp_asn1.h
new file mode 100644 (file)
index 0000000..c1df94a
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * @file
+ * Abstract Syntax Notation One (ISO 8824, 8825) codec.
+ */
+/*
+ * 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>
+ */
+
+#ifndef __LWIP_SNMP_ASN1_H__
+#define __LWIP_SNMP_ASN1_H__
+
+#include "lwip/opt.h"
+#include "arch/cc.h"
+#include "lwip/err.h"
+#include "lwip/pbuf.h"
+#include "lwip/snmp.h"
+
+#define SNMP_ASN1_UNIV   (!0x80 | !0x40)
+#define SNMP_ASN1_APPLIC (!0x80 |  0x40)
+#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)
+
+#define SNMP_ASN1_CONSTR (0x20)
+#define SNMP_ASN1_PRIMIT (!0x20)
+
+/* universal tags */
+#define SNMP_ASN1_INTEG  2
+#define SNMP_ASN1_OC_STR 4
+#define SNMP_ASN1_NUL    5
+#define SNMP_ASN1_OBJ_ID 6
+#define SNMP_ASN1_SEQ    16
+
+/* application specific (SNMP) tags */
+#define SNMP_ASN1_IPADDR 0    /* octet string size(4) */
+#define SNMP_ASN1_COUNTER 1   /* u32_t */
+#define SNMP_ASN1_GAUGE 2     /* u32_t */
+#define SNMP_ASN1_TIMETICKS 3 /* u32_t */
+#define SNMP_ASN1_OPAQUE 4    /* octet string */
+
+/* context specific (SNMP) tags */
+#define SNMP_ASN1_PDU_GET_REQ 0
+#define SNMP_ASN1_PDU_GET_NEXT_REQ 1
+#define SNMP_ASN1_PDU_GET_RESP 2
+#define SNMP_ASN1_PDU_SET_REQ 3
+#define SNMP_ASN1_PDU_TRAP 4
+
+err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type);
+err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length);
+err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value);
+err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value);
+err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid);
+err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw);
+
+void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
+void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
+void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
+void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);
+err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);
+err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);
+err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value);
+err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value);
+err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);
+err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);
+
+#endif
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/snmp_msg.h b/Demo/Common/ethernet/lwIP/include/lwip/snmp_msg.h
new file mode 100644 (file)
index 0000000..66faedd
--- /dev/null
@@ -0,0 +1,292 @@
+/**
+ * @file
+ * SNMP Agent message handling structures.
+ */
+
+/*
+ * 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>
+ */
+
+#ifndef __LWIP_SNMP_MSG_H__
+#define __LWIP_SNMP_MSG_H__
+
+#include "lwip/opt.h"
+#include "arch/cc.h"
+#include "lwip/snmp.h"
+#include "lwip/snmp_structs.h"
+
+#if SNMP_PRIVATE_MIB
+#include "private_mib.h"
+#endif
+
+#define SNMP_IN_PORT 161
+#define SNMP_TRAP_PORT 162
+
+#define SNMP_ES_NOERROR 0
+#define SNMP_ES_TOOBIG 1
+#define SNMP_ES_NOSUCHNAME 2
+#define SNMP_ES_BADVALUE 3
+#define SNMP_ES_READONLY 4
+#define SNMP_ES_GENERROR 5
+
+#define SNMP_GENTRAP_COLDSTART 0
+#define SNMP_GENTRAP_WARMSTART 1
+#define SNMP_GENTRAP_AUTHFAIL 4
+#define SNMP_GENTRAP_ENTERPRISESPC 6
+
+struct snmp_varbind
+{
+  /* next pointer, NULL for last in list */
+  struct snmp_varbind *next;
+  /* previous pointer, NULL for first in list */
+  struct snmp_varbind *prev;
+
+  /* object identifier length (in s32_t) */
+  u8_t ident_len;
+  /* object identifier array */
+  s32_t *ident;
+
+  /* object value ASN1 type */
+  u8_t value_type;
+  /* object value length (in u8_t) */
+  u8_t value_len;
+  /* object value */
+  void *value;
+
+  /* encoding varbind seq length length */
+  u8_t seqlenlen;
+  /* encoding object identifier length length */
+  u8_t olenlen;
+  /* encoding object value length length */
+  u8_t vlenlen;
+  /* encoding varbind seq length */
+  u16_t seqlen;
+  /* encoding object identifier length */
+  u16_t olen;
+  /* encoding object value length */
+  u16_t vlen;
+};
+
+struct snmp_varbind_root
+{
+  struct snmp_varbind *head;
+  struct snmp_varbind *tail;
+  /* number of variable bindings in list */
+  u8_t count;
+  /* encoding varbind-list seq length length */
+  u8_t seqlenlen;
+  /* encoding varbind-list seq length */
+  u16_t seqlen;
+};
+
+/** output response message header length fields */
+struct snmp_resp_header_lengths
+{
+  /* encoding error-index length length */
+  u8_t erridxlenlen;
+  /* encoding error-status length length */
+  u8_t errstatlenlen;
+  /* encoding request id length length */
+  u8_t ridlenlen;
+  /* encoding pdu length length */
+  u8_t pdulenlen;
+  /* encoding community length length */
+  u8_t comlenlen;
+  /* encoding version length length */
+  u8_t verlenlen;
+  /* encoding sequence length length */
+  u8_t seqlenlen;
+
+  /* encoding error-index length */
+  u16_t erridxlen;
+  /* encoding error-status length */
+  u16_t errstatlen;
+  /* encoding request id length */
+  u16_t ridlen;
+  /* encoding pdu length */
+  u16_t pdulen;
+  /* encoding community length */
+  u16_t comlen;
+  /* encoding version length */
+  u16_t verlen;
+  /* encoding sequence length */
+  u16_t seqlen;
+};
+
+/** output response message header length fields */
+struct snmp_trap_header_lengths
+{
+  /* encoding timestamp length length */
+  u8_t tslenlen;
+  /* encoding specific-trap length length */
+  u8_t strplenlen;
+  /* encoding generic-trap length length */
+  u8_t gtrplenlen;
+  /* encoding agent-addr length length */
+  u8_t aaddrlenlen;
+  /* encoding enterprise-id length length */
+  u8_t eidlenlen;
+  /* encoding pdu length length */
+  u8_t pdulenlen;
+  /* encoding community length length */
+  u8_t comlenlen;
+  /* encoding version length length */
+  u8_t verlenlen;
+  /* encoding sequence length length */
+  u8_t seqlenlen;
+
+  /* encoding timestamp length */
+  u16_t tslen;
+  /* encoding specific-trap length */
+  u16_t strplen;
+  /* encoding generic-trap length */
+  u16_t gtrplen;
+  /* encoding agent-addr length */
+  u16_t aaddrlen;
+  /* encoding enterprise-id length */
+  u16_t eidlen;
+  /* encoding pdu length */
+  u16_t pdulen;
+  /* encoding community length */
+  u16_t comlen;
+  /* encoding version length */
+  u16_t verlen;
+  /* encoding sequence length */
+  u16_t seqlen;
+};
+
+/* Accepting new SNMP messages. */
+#define SNMP_MSG_EMPTY                 0
+/* Search for matching object for variable binding. */
+#define SNMP_MSG_SEARCH_OBJ            1
+/* Perform SNMP operation on in-memory object.
+   Pass-through states, for symmetry only. */
+#define SNMP_MSG_INTERNAL_GET_OBJDEF   2
+#define SNMP_MSG_INTERNAL_GET_VALUE    3
+#define SNMP_MSG_INTERNAL_SET_TEST     4
+#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5
+#define SNMP_MSG_INTERNAL_SET_VALUE    6
+/* Perform SNMP operation on object located externally.
+   In theory this could be used for building a proxy agent.
+   Practical use is for an enterprise spc. app. gateway. */
+#define SNMP_MSG_EXTERNAL_GET_OBJDEF   7
+#define SNMP_MSG_EXTERNAL_GET_VALUE    8
+#define SNMP_MSG_EXTERNAL_SET_TEST     9
+#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10
+#define SNMP_MSG_EXTERNAL_SET_VALUE    11
+
+#define SNMP_COMMUNITY_STR_LEN 64
+struct snmp_msg_pstat
+{
+  /* lwIP local port (161) binding */
+  struct udp_pcb *pcb;
+  /* source IP address */
+  struct ip_addr sip;
+  /* source UDP port */
+  u16_t sp;
+  /* request type */
+  u8_t rt;
+  /* request ID */
+  s32_t rid;
+  /* error status */
+  s32_t error_status;
+  /* error index */
+  s32_t error_index;
+  /* community name (zero terminated) */
+  u8_t community[SNMP_COMMUNITY_STR_LEN + 1];
+  /* community string length (exclusive zero term) */
+  u8_t com_strlen;
+  /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */
+  u8_t state;
+  /* saved arguments for MSG_EXTERNAL_x */
+  struct mib_external_node *ext_mib_node;
+  struct snmp_name_ptr ext_name_ptr;
+  struct obj_def ext_object_def;
+  struct snmp_obj_id ext_oid;
+  /* index into input variable binding list */
+  u8_t vb_idx;
+  /* ptr into input variable binding list */
+  struct snmp_varbind *vb_ptr;
+  /* list of variable bindings from input */
+  struct snmp_varbind_root invb;
+  /* list of variable bindings to output */
+  struct snmp_varbind_root outvb;
+  /* output response lengths used in ASN encoding */
+  struct snmp_resp_header_lengths rhl;
+};
+
+struct snmp_msg_trap
+{
+  /* lwIP local port (161) binding */
+  struct udp_pcb *pcb;
+  /* destination IP address in network order */
+  struct ip_addr dip;
+
+  /* source enterprise ID (sysObjectID) */
+  struct snmp_obj_id *enterprise;
+  /* source IP address, raw network order format */
+  u8_t sip_raw[4];
+  /* generic trap code */
+  u32_t gen_trap;
+  /* specific trap code */
+  u32_t spc_trap;
+  /* timestamp */
+  u32_t ts;
+  /* list of variable bindings to output */
+  struct snmp_varbind_root outvb;
+  /* output trap lengths used in ASN encoding */
+  struct snmp_trap_header_lengths thl;
+};
+
+/** Agent Version constant, 0 = v1 oddity */
+extern const s32_t snmp_version;
+/** Agent default "public" community string */
+extern const char snmp_publiccommunity[7];
+
+extern struct snmp_msg_trap trap_msg;
+
+/** Agent setup, start listening to port 161. */
+void snmp_init(void);
+void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);
+void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst);
+
+/** Varbind-list functions. */
+struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);
+void snmp_varbind_free(struct snmp_varbind *vb);
+void snmp_varbind_list_free(struct snmp_varbind_root *root);
+void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);
+struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);
+
+/** Handle an internal (recv) or external (private response) event. */
+void snmp_msg_event(u8_t request_id);
+err_t snmp_send_response(struct snmp_msg_pstat *m_stat);
+err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap);
+void snmp_coldstart_trap(void);
+void snmp_authfail_trap(void);
+
+#endif
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/snmp_structs.h b/Demo/Common/ethernet/lwIP/include/lwip/snmp_structs.h
new file mode 100644 (file)
index 0000000..f485466
--- /dev/null
@@ -0,0 +1,253 @@
+/**
+ * @file
+ * Generic MIB tree structures.
+ *
+ * @todo namespace prefixes
+ */
+
+/*
+ * 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>
+ */
+
+#ifndef __LWIP_SNMP_STRUCTS_H__
+#define __LWIP_SNMP_STRUCTS_H__
+
+#include "lwip/opt.h"
+#if LWIP_SNMP
+
+#include "arch/cc.h"
+#include "lwip/snmp.h"
+
+#if SNMP_PRIVATE_MIB
+#include "private_mib.h"
+#endif
+
+/* MIB object instance */
+#define MIB_OBJECT_NONE 0 
+#define MIB_OBJECT_SCALAR 1
+#define MIB_OBJECT_TAB 2
+
+/* MIB object access */
+#define MIB_OBJECT_READ_ONLY 0
+#define MIB_OBJECT_READ_WRITE 1
+#define MIB_OBJECT_WRITE_ONLY 2
+#define MIB_OBJECT_NOT_ACCESSIBLE 3
+
+/** object definition returned by (get_object_def)() */
+struct obj_def
+{
+  /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */
+  u8_t instance;
+  /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */
+  u8_t access;
+  /* ASN type for this object */
+  u8_t asn_type;
+  /* value length (host length) */
+  u16_t v_len;
+  /* length of instance part of supplied object identifier */
+  u8_t  id_inst_len;
+  /* instance part of supplied object identifier */
+  s32_t *id_inst_ptr;
+};
+
+struct snmp_name_ptr
+{
+  u8_t ident_len;
+  s32_t *ident;
+};
+
+/** MIB const scalar (.0) node */
+#define MIB_NODE_SC 0x01
+/** MIB const array node */
+#define MIB_NODE_AR 0x02
+/** MIB array node (mem_malloced from RAM) */
+#define MIB_NODE_RA 0x03
+/** MIB list root node (mem_malloced from RAM) */
+#define MIB_NODE_LR 0x04
+/** MIB node for external objects */
+#define MIB_NODE_EX 0x05
+
+/** node "base class" layout, the mandatory fields for a node  */
+struct mib_node
+{
+  /** returns struct obj_def for the given object identifier */
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+  /** returns object value for the given object identifier,
+     @note the caller must allocate at least len bytes for the value */
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);
+  /** tests length and/or range BEFORE setting */
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+  /** sets object value, only to be called when set_test()  */
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);  
+  /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */
+  const u8_t node_type;
+  /* array or max list length */
+  const u16_t maxlength;
+};
+
+/** derived node for scalars .0 index */
+typedef struct mib_node mib_scalar_node;
+
+/** derived node, points to a fixed size const array
+    of sub-identifiers plus a 'child' pointer */
+struct mib_array_node
+{
+  /* inherited "base class" members */
+  void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+  void (* const get_value)(struct obj_def *od, u16_t len, void *value);
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);
+
+  const u8_t node_type;
+  const u16_t maxlength;
+
+  /* aditional struct members */
+  const s32_t *objid;
+  struct mib_node* const *nptr;
+};
+
+/** derived node, points to a fixed size mem_malloced array
+    of sub-identifiers plus a 'child' pointer */
+struct mib_ram_array_node
+{
+  /* inherited "base class" members */
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);
+
+  u8_t node_type;
+  u16_t maxlength;
+
+  /* aditional struct members */
+  s32_t *objid;
+  struct mib_node **nptr;
+};
+
+struct mib_list_node
+{
+  struct mib_list_node *prev;  
+  struct mib_list_node *next;
+  s32_t objid;
+  struct mib_node *nptr;
+};
+
+/** derived node, points to a doubly linked list
+    of sub-identifiers plus a 'child' pointer */
+struct mib_list_rootnode
+{
+  /* inherited "base class" members */
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);
+
+  u8_t node_type;
+  u16_t maxlength;
+
+  /* aditional struct members */
+  struct mib_list_node *head;
+  struct mib_list_node *tail;
+  /* counts list nodes in list  */
+  u16_t count;
+};
+
+/** derived node, has access functions for mib object in external memory or device
+    using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */
+struct mib_external_node
+{
+  /* inherited "base class" members */
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);
+
+  u8_t node_type;
+  u16_t maxlength;
+
+  /* aditional struct members */
+  /** points to an extenal (in memory) record of some sort of addressing
+      information, passed to and interpreted by the funtions below */
+  void* addr_inf;
+  /** tree levels under this node */
+  u8_t tree_levels;
+  /** number of objects at this level */
+  u16_t (*level_length)(void* addr_inf, u8_t level);
+  /** compares object sub identifier with external id
+      return zero when equal, nonzero when unequal */
+  s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id);
+  void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id);
+
+  /** async Questions */
+  void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident);
+  void (*get_value_q)(u8_t rid, struct obj_def *od);
+  void (*set_test_q)(u8_t rid, struct obj_def *od);
+  void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value);
+  /** async Answers */
+  void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od);
+  void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
+  u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
+  void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
+  /** async Panic Close (agent returns error reply, 
+      e.g. used for external transaction cleanup) */
+  void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident);
+  void (*get_value_pc)(u8_t rid, struct obj_def *od);
+  void (*set_test_pc)(u8_t rid, struct obj_def *od);
+  void (*set_value_pc)(u8_t rid, struct obj_def *od);
+};
+
+/** export MIB tree from mib2.c */
+extern const struct mib_array_node internet;
+
+/** dummy function pointers for non-leaf MIB nodes from mib2.c */
+void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+void noleafs_get_value(struct obj_def *od, u16_t len, void *value);
+u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);
+void noleafs_set_value(struct obj_def *od, u16_t len, void *value);
+
+void snmp_oidtoip(s32_t *ident, struct ip_addr *ip);
+void snmp_iptooid(struct ip_addr *ip, s32_t *ident);
+void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);
+void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);
+
+struct mib_list_node* snmp_mib_ln_alloc(s32_t id);
+void snmp_mib_ln_free(struct mib_list_node *ln);
+struct mib_list_rootnode* snmp_mib_lrn_alloc(void);
+void snmp_mib_lrn_free(struct mib_list_rootnode *lrn);
+
+s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn);
+s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn);
+struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n);
+
+struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np);
+struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);
+u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident);
+u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);
+
+#endif /* LWIP_SNMP */
+#endif
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/sockets.h b/Demo/Common/ethernet/lwIP/include/lwip/sockets.h
new file mode 100644 (file)
index 0000000..d5f8ccf
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * 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>
+ *
+ */
+
+
+#ifndef __LWIP_SOCKETS_H__
+#define __LWIP_SOCKETS_H__
+#include "lwip/ip_addr.h"
+
+struct sockaddr_in {
+  u8_t sin_len;
+  u8_t sin_family;
+  u16_t sin_port;
+  struct in_addr sin_addr;
+  char sin_zero[8];
+};
+
+struct sockaddr {
+  u8_t sa_len;
+  u8_t sa_family;
+  char sa_data[14];
+};
+
+#ifndef socklen_t
+#  define socklen_t int
+#endif
+
+
+#define SOCK_STREAM     1
+#define SOCK_DGRAM      2
+#define SOCK_RAW        3
+
+/*
+ * Option flags per-socket.
+ */
+#define  SO_DEBUG  0x0001    /* turn on debugging info recording */
+#define  SO_ACCEPTCONN  0x0002    /* socket has had listen() */
+#define  SO_REUSEADDR  0x0004    /* allow local address reuse */
+#define  SO_KEEPALIVE  0x0008    /* keep connections alive */
+#define  SO_DONTROUTE  0x0010    /* just use interface addresses */
+#define  SO_BROADCAST  0x0020    /* permit sending of broadcast msgs */
+#define  SO_USELOOPBACK  0x0040    /* bypass hardware when possible */
+#define  SO_LINGER  0x0080    /* linger on close if data present */
+#define  SO_OOBINLINE  0x0100    /* leave received OOB data in line */
+#define         SO_REUSEPORT   0x0200          /* allow local address & port reuse */
+
+#define SO_DONTLINGER   (int)(~SO_LINGER)
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF  0x1001    /* send buffer size */
+#define SO_RCVBUF  0x1002    /* receive buffer size */
+#define SO_SNDLOWAT  0x1003    /* send low-water mark */
+#define SO_RCVLOWAT  0x1004    /* receive low-water mark */
+#define SO_SNDTIMEO  0x1005    /* send timeout */
+#define SO_RCVTIMEO  0x1006    /* receive timeout */
+#define  SO_ERROR  0x1007    /* get error status and clear */
+#define  SO_TYPE    0x1008    /* get socket type */
+
+
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+       int l_onoff;                /* option on/off */
+       int l_linger;               /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define  SOL_SOCKET  0xfff    /* options for socket level */
+
+
+#define AF_UNSPEC       0
+#define AF_INET         2
+#define PF_INET         AF_INET
+#define PF_UNSPEC       AF_UNSPEC
+
+#define IPPROTO_IP      0
+#define IPPROTO_TCP     6
+#define IPPROTO_UDP     17
+
+#define INADDR_ANY      0
+#define INADDR_BROADCAST 0xffffffff
+
+/* Flags we can use with send and recv. */
+#define MSG_DONTWAIT    0x40            /* Nonblocking i/o for this operation only */
+
+
+/*
+ * Options for level IPPROTO_IP
+ */
+#define IP_TOS       1
+#define IP_TTL       2
+
+
+#define IPTOS_TOS_MASK          0x1E
+#define IPTOS_TOS(tos)          ((tos) & IPTOS_TOS_MASK)
+#define IPTOS_LOWDELAY          0x10
+#define IPTOS_THROUGHPUT        0x08
+#define IPTOS_RELIABILITY       0x04
+#define IPTOS_LOWCOST           0x02
+#define IPTOS_MINCOST           IPTOS_LOWCOST
+
+/*
+ * Definitions for IP precedence (also in ip_tos) (hopefully unused)
+ */
+#define IPTOS_PREC_MASK                 0xe0
+#define IPTOS_PREC(tos)                ((tos) & IPTOS_PREC_MASK)
+#define IPTOS_PREC_NETCONTROL           0xe0
+#define IPTOS_PREC_INTERNETCONTROL      0xc0
+#define IPTOS_PREC_CRITIC_ECP           0xa0
+#define IPTOS_PREC_FLASHOVERRIDE        0x80
+#define IPTOS_PREC_FLASH                0x60
+#define IPTOS_PREC_IMMEDIATE            0x40
+#define IPTOS_PREC_PRIORITY             0x20
+#define IPTOS_PREC_ROUTINE              0x00
+
+
+/*
+ * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.
+ *
+ *
+ * Ioctl's have the command encoded in the lower word,
+ * and the size of any in or out parameters in the upper
+ * word.  The high 2 bits of the upper word are used
+ * to encode the in/out status of the parameter; for now
+ * we restrict parameters to at most 128 bytes.
+ */
+#if !defined(FIONREAD) || !defined(FIONBIO)
+#define IOCPARM_MASK    0x7f            /* parameters must be < 128 bytes */
+#define IOC_VOID        0x20000000      /* no parameters */
+#define IOC_OUT         0x40000000      /* copy out parameters */
+#define IOC_IN          0x80000000      /* copy in parameters */
+#define IOC_INOUT       (IOC_IN|IOC_OUT)
+                                        /* 0x20000000 distinguishes new &
+                                           old ioctl's */
+#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y))
+
+#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+
+#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+#endif
+
+#ifndef FIONREAD
+#define FIONREAD    _IOR('f', 127, unsigned long) /* get # bytes to read */
+#endif
+#ifndef FIONBIO
+#define FIONBIO     _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */
+#endif
+
+/* Socket I/O Controls */
+#ifndef SIOCSHIWAT
+#define SIOCSHIWAT  _IOW('s',  0, unsigned long)  /* set high watermark */
+#define SIOCGHIWAT  _IOR('s',  1, unsigned long)  /* get high watermark */
+#define SIOCSLOWAT  _IOW('s',  2, unsigned long)  /* set low watermark */
+#define SIOCGLOWAT  _IOR('s',  3, unsigned long)  /* get low watermark */
+#define SIOCATMARK  _IOR('s',  7, unsigned long)  /* at oob mark? */
+#endif
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK    04000U
+#endif
+
+#ifndef FD_SET
+  #undef  FD_SETSIZE
+  #define FD_SETSIZE    16
+  #define FD_SET(n, p)  ((p)->fd_bits[(n)/8] |=  (1 << ((n) & 7)))
+  #define FD_CLR(n, p)  ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7)))
+  #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] &   (1 << ((n) & 7)))
+  #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p)))
+
+  typedef struct fd_set {
+          unsigned char fd_bits [(FD_SETSIZE+7)/8];
+        } fd_set;
+
+/* 
+ * only define this in sockets.c so it does not interfere
+ * with other projects namespaces where timeval is present
+ */ 
+#ifndef LWIP_TIMEVAL_PRIVATE
+#define LWIP_TIMEVAL_PRIVATE 1
+#endif
+
+#if LWIP_TIMEVAL_PRIVATE
+  struct timeval {
+    long    tv_sec;         /* seconds */
+    long    tv_usec;        /* and microseconds */
+  };
+#endif
+
+#endif
+
+int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+int lwip_bind(int s, struct sockaddr *name, socklen_t namelen);
+int lwip_shutdown(int s, int how);
+int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);
+int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen);
+int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen);
+int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen);
+int lwip_close(int s);
+int lwip_connect(int s, struct sockaddr *name, socklen_t namelen);
+int lwip_listen(int s, int backlog);
+int lwip_recv(int s, void *mem, int len, unsigned int flags);
+int lwip_read(int s, void *mem, int len);
+int lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
+      struct sockaddr *from, socklen_t *fromlen);
+int lwip_send(int s, void *dataptr, int size, unsigned int flags);
+int lwip_sendto(int s, void *dataptr, int size, unsigned int flags,
+    struct sockaddr *to, socklen_t tolen);
+int lwip_socket(int domain, int type, int protocol);
+int lwip_write(int s, void *dataptr, int size);
+int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
+                struct timeval *timeout);
+int lwip_ioctl(int s, long cmd, void *argp);
+
+#if LWIP_COMPAT_SOCKETS
+#define accept(a,b,c)         lwip_accept(a,b,c)
+#define bind(a,b,c)           lwip_bind(a,b,c)
+#define shutdown(a,b)         lwip_shutdown(a,b)
+#define close(s)              lwip_close(s)
+#define connect(a,b,c)        lwip_connect(a,b,c)
+#define getsockname(a,b,c)    lwip_getsockname(a,b,c)
+#define getpeername(a,b,c)    lwip_getpeername(a,b,c)
+#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)
+#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)
+#define listen(a,b)           lwip_listen(a,b)
+#define recv(a,b,c,d)         lwip_recv(a,b,c,d)
+#define read(a,b,c)           lwip_read(a,b,c)
+#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)
+#define send(a,b,c,d)         lwip_send(a,b,c,d)
+#define sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f)
+#define socket(a,b,c)         lwip_socket(a,b,c)
+#define write(a,b,c)          lwip_write(a,b,c)
+#define select(a,b,c,d,e)     lwip_select(a,b,c,d,e)
+#define ioctlsocket(a,b,c)    lwip_ioctl(a,b,c)
+#endif /* LWIP_COMPAT_SOCKETS */
+
+#endif /* __LWIP_SOCKETS_H__ */
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/stats.h b/Demo/Common/ethernet/lwIP/include/lwip/stats.h
new file mode 100644 (file)
index 0000000..71acfd0
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_STATS_H__
+#define __LWIP_STATS_H__
+
+#include "lwip/opt.h"
+#include "arch/cc.h"
+
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+
+#if LWIP_STATS
+
+struct stats_proto {
+  u16_t xmit;    /* Transmitted packets. */
+  u16_t rexmit;  /* Retransmitted packets. */
+  u16_t recv;    /* Received packets. */
+  u16_t fw;      /* Forwarded packets. */
+  u16_t drop;    /* Dropped packets. */
+  u16_t chkerr;  /* Checksum error. */
+  u16_t lenerr;  /* Invalid length error. */
+  u16_t memerr;  /* Out of memory error. */
+  u16_t rterr;   /* Routing error. */
+  u16_t proterr; /* Protocol error. */
+  u16_t opterr;  /* Error in options. */
+  u16_t err;     /* Misc error. */
+  u16_t cachehit;
+};
+
+struct stats_mem {
+  mem_size_t avail;
+  mem_size_t used;
+  mem_size_t max;  
+  mem_size_t err;
+};
+
+struct stats_pbuf {
+  u16_t avail;
+  u16_t used;
+  u16_t max;  
+  u16_t err;
+
+  u16_t alloc_locked;
+  u16_t refresh_locked;
+};
+
+struct stats_syselem {
+  u16_t used;
+  u16_t max;
+  u16_t err;
+};
+
+struct stats_sys {
+  struct stats_syselem sem;
+  struct stats_syselem mbox;
+};
+
+struct stats_ {
+  struct stats_proto link;
+  struct stats_proto ip_frag;
+  struct stats_proto ip;
+  struct stats_proto icmp;
+  struct stats_proto udp;
+  struct stats_proto tcp;
+  struct stats_pbuf pbuf;
+  struct stats_mem mem;
+  struct stats_mem memp[MEMP_MAX];
+  struct stats_sys sys;
+};
+
+extern struct stats_ lwip_stats;
+
+
+void stats_init(void);
+
+#define STATS_INC(x) ++lwip_stats.x
+#else
+#define stats_init()
+#define STATS_INC(x)
+#endif /* LWIP_STATS */
+
+#if TCP_STATS
+#define TCP_STATS_INC(x) STATS_INC(x)
+#else
+#define TCP_STATS_INC(x)
+#endif
+
+#if UDP_STATS
+#define UDP_STATS_INC(x) STATS_INC(x)
+#else
+#define UDP_STATS_INC(x)
+#endif
+
+#if ICMP_STATS
+#define ICMP_STATS_INC(x) STATS_INC(x)
+#else
+#define ICMP_STATS_INC(x)
+#endif
+
+#if IP_STATS
+#define IP_STATS_INC(x) STATS_INC(x)
+#else
+#define IP_STATS_INC(x)
+#endif
+
+#if IPFRAG_STATS
+#define IPFRAG_STATS_INC(x) STATS_INC(x)
+#else
+#define IPFRAG_STATS_INC(x)
+#endif
+
+#if LINK_STATS
+#define LINK_STATS_INC(x) STATS_INC(x)
+#else
+#define LINK_STATS_INC(x)
+#endif
+
+/* Display of statistics */
+#if LWIP_STATS_DISPLAY
+void stats_display(void);
+#else
+#define stats_display()
+#endif
+
+#endif /* __LWIP_STATS_H__ */
+
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/sys.h b/Demo/Common/ethernet/lwIP/include/lwip/sys.h
new file mode 100644 (file)
index 0000000..c18c3ab
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_SYS_H__
+#define __LWIP_SYS_H__
+
+#include "arch/cc.h"
+
+#include "lwip/opt.h"
+
+
+#if NO_SYS
+
+/* For a totally minimal and standalone system, we provide null
+   definitions of the sys_ functions. */
+typedef u8_t sys_sem_t;
+typedef u8_t sys_mbox_t;
+struct sys_timeo {u8_t dummy;};
+
+#define sys_init()
+#define sys_timeout(m,h,a)
+#define sys_untimeout(m,a)
+#define sys_sem_new(c) c
+#define sys_sem_signal(s)
+#define sys_sem_wait(s)
+#define sys_sem_free(s)
+#define sys_mbox_new() 0
+#define sys_mbox_fetch(m,d)
+#define sys_mbox_post(m,d)
+#define sys_mbox_free(m)
+
+#define sys_thread_new(t,a,p)
+
+#else /* NO_SYS */
+
+#include "arch/sys_arch.h"
+
+/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */
+#define SYS_ARCH_TIMEOUT 0xffffffff
+
+typedef void (* sys_timeout_handler)(void *arg);
+
+struct sys_timeo {
+  struct sys_timeo *next;
+  u32_t time;
+  sys_timeout_handler h;
+  void *arg;
+};
+
+struct sys_timeouts {
+  struct sys_timeo *next;
+};
+
+/* sys_init() must be called before anthing else. */
+void sys_init(void);
+
+/*
+ * sys_timeout():
+ *
+ * Schedule a timeout a specified amount of milliseconds in the
+ * future. When the timeout occurs, the specified timeout handler will
+ * be called. The handler will be passed the "arg" argument when
+ * called.
+ *
+ */
+void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
+void sys_untimeout(sys_timeout_handler h, void *arg);
+struct sys_timeouts *sys_arch_timeouts(void);
+
+/* Semaphore functions. */
+sys_sem_t sys_sem_new(u8_t count);
+void sys_sem_signal(sys_sem_t sem);
+u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout);
+void sys_sem_free(sys_sem_t sem);
+void sys_sem_wait(sys_sem_t sem);
+int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout);
+
+/* Time functions. */
+#ifndef sys_msleep
+void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */
+#endif
+#ifndef sys_jiffies
+u32_t sys_jiffies(void); /* since power up. */
+#endif
+
+/* Mailbox functions. */
+sys_mbox_t sys_mbox_new(void);
+void sys_mbox_post(sys_mbox_t mbox, void *msg);
+u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout);
+void sys_mbox_free(sys_mbox_t mbox);
+void sys_mbox_fetch(sys_mbox_t mbox, void **msg);
+
+
+/* Thread functions. */
+sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio);
+
+/* The following functions are used only in Unix code, and
+   can be omitted when porting the stack. */
+/* Returns the current time in microseconds. */
+unsigned long sys_now(void);
+
+#endif /* NO_SYS */
+
+/* Critical Region Protection */
+/* These functions must be implemented in the sys_arch.c file.
+   In some implementations they can provide a more light-weight protection
+   mechanism than using semaphores. Otherwise semaphores can be used for
+   implementation */
+#ifndef SYS_ARCH_PROTECT
+/** SYS_LIGHTWEIGHT_PROT
+ * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection
+ * for certain critical regions during buffer allocation, deallocation and memory
+ * allocation and deallocation.
+ */
+#if SYS_LIGHTWEIGHT_PROT
+
+/** SYS_ARCH_DECL_PROTECT
+ * declare a protection variable. This macro will default to defining a variable of
+ * type sys_prot_t. If a particular port needs a different implementation, then
+ * this macro may be defined in sys_arch.h.
+ */
+#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev
+/** SYS_ARCH_PROTECT
+ * Perform a "fast" protect. This could be implemented by
+ * disabling interrupts for an embedded system or by using a semaphore or
+ * mutex. The implementation should allow calling SYS_ARCH_PROTECT when
+ * already protected. The old protection level is returned in the variable
+ * "lev". This macro will default to calling the sys_arch_protect() function
+ * which should be implemented in sys_arch.c. If a particular port needs a
+ * different implementation, then this macro may be defined in sys_arch.h
+ */
+#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()
+/** SYS_ARCH_UNPROTECT
+ * Perform a "fast" set of the protection level to "lev". This could be
+ * implemented by setting the interrupt level to "lev" within the MACRO or by
+ * using a semaphore or mutex.  This macro will default to calling the
+ * sys_arch_unprotect() function which should be implemented in
+ * sys_arch.c. If a particular port needs a different implementation, then
+ * this macro may be defined in sys_arch.h
+ */
+#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)
+sys_prot_t sys_arch_protect(void);
+void sys_arch_unprotect(sys_prot_t pval);
+
+#else
+
+#define SYS_ARCH_DECL_PROTECT(lev)
+#define SYS_ARCH_PROTECT(lev)
+#define SYS_ARCH_UNPROTECT(lev)
+
+#endif /* SYS_LIGHTWEIGHT_PROT */
+
+#endif /* SYS_ARCH_PROTECT */
+
+#endif /* __LWIP_SYS_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/tcp.h b/Demo/Common/ethernet/lwIP/include/lwip/tcp.h
new file mode 100644 (file)
index 0000000..9f86892
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_TCP_H__
+#define __LWIP_TCP_H__
+
+#include "lwip/sys.h"
+#include "lwip/mem.h"
+
+#include "lwip/pbuf.h"
+#include "lwip/opt.h"
+#include "lwip/ip.h"
+#include "lwip/icmp.h"
+
+#include "lwip/err.h"
+
+struct tcp_pcb;
+
+/* Functions for interfacing with TCP: */
+
+/* Lower layer interface to TCP: */
+void             tcp_init    (void);  /* Must be called first to
+           initialize TCP. */
+void             tcp_tmr     (void);  /* Must be called every
+           TCP_TMR_INTERVAL
+           ms. (Typically 250 ms). */
+/* Application program's interface: */
+struct tcp_pcb * tcp_new     (void);
+struct tcp_pcb * tcp_alloc   (u8_t prio);
+
+void             tcp_arg     (struct tcp_pcb *pcb, void *arg);
+void             tcp_accept  (struct tcp_pcb *pcb,
+            err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
+                 err_t err));
+void             tcp_recv    (struct tcp_pcb *pcb,
+            err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
+          struct pbuf *p, err_t err));
+void             tcp_sent    (struct tcp_pcb *pcb,
+            err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
+               u16_t len));
+void             tcp_poll    (struct tcp_pcb *pcb,
+            err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
+            u8_t interval);
+void             tcp_err     (struct tcp_pcb *pcb,
+            void (* err)(void *arg, err_t err));
+
+#define          tcp_mss(pcb)      ((pcb)->mss)
+#define          tcp_sndbuf(pcb)   ((pcb)->snd_buf)
+
+void             tcp_recved  (struct tcp_pcb *pcb, u16_t len);
+err_t            tcp_bind    (struct tcp_pcb *pcb, struct ip_addr *ipaddr,
+            u16_t port);
+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));
+struct tcp_pcb * tcp_listen  (struct tcp_pcb *pcb);
+void             tcp_abort   (struct tcp_pcb *pcb);
+err_t            tcp_close   (struct tcp_pcb *pcb);
+err_t            tcp_write   (struct tcp_pcb *pcb, const void *dataptr, u16_t len,
+            u8_t copy);
+
+void             tcp_setprio (struct tcp_pcb *pcb, u8_t prio);
+
+#define TCP_PRIO_MIN    1
+#define TCP_PRIO_NORMAL 64
+#define TCP_PRIO_MAX    127
+
+/* It is also possible to call these two functions at the right
+   intervals (instead of calling tcp_tmr()). */
+void             tcp_slowtmr (void);
+void             tcp_fasttmr (void);
+
+
+/* Only used by IP to pass a TCP segment to TCP: */
+void             tcp_input   (struct pbuf *p, struct netif *inp);
+/* Used within the TCP code only: */
+err_t            tcp_output  (struct tcp_pcb *pcb);
+void             tcp_rexmit  (struct tcp_pcb *pcb);
+void             tcp_rexmit_rto  (struct tcp_pcb *pcb);
+
+
+
+#define TCP_SEQ_LT(a,b)     ((s32_t)((a)-(b)) < 0)
+#define TCP_SEQ_LEQ(a,b)    ((s32_t)((a)-(b)) <= 0)
+#define TCP_SEQ_GT(a,b)     ((s32_t)((a)-(b)) > 0)
+#define TCP_SEQ_GEQ(a,b)    ((s32_t)((a)-(b)) >= 0)
+/* is b<=a<=c? */
+#if 0 /* see bug #10548 */
+#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
+#endif
+#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))
+#define TCP_FIN 0x01U
+#define TCP_SYN 0x02U
+#define TCP_RST 0x04U
+#define TCP_PSH 0x08U
+#define TCP_ACK 0x10U
+#define TCP_URG 0x20U
+#define TCP_ECE 0x40U
+#define TCP_CWR 0x80U
+
+#define TCP_FLAGS 0x3fU
+
+/* Length of the TCP header, excluding options. */
+#define TCP_HLEN 20
+
+#ifndef TCP_TMR_INTERVAL
+#define TCP_TMR_INTERVAL       250  /* The TCP timer interval in
+                                       milliseconds. */
+#endif /* TCP_TMR_INTERVAL */
+
+#ifndef TCP_FAST_INTERVAL
+#define TCP_FAST_INTERVAL      TCP_TMR_INTERVAL /* the fine grained timeout in
+                                       milliseconds */
+#endif /* TCP_FAST_INTERVAL */
+
+#ifndef TCP_SLOW_INTERVAL
+#define TCP_SLOW_INTERVAL      (2*TCP_TMR_INTERVAL)  /* the coarse grained timeout in
+                                       milliseconds */
+#endif /* TCP_SLOW_INTERVAL */
+
+#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */
+#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */
+
+#define TCP_OOSEQ_TIMEOUT        6U /* x RTO */
+
+#define TCP_MSL 60000  /* The maximum segment lifetime in microseconds */
+
+/*
+ * User-settable options (used with setsockopt).
+ */
+#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */
+#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keepalive miliseconds */
+
+/* Keepalive values */
+#define  TCP_KEEPDEFAULT   7200000                       /* KEEPALIVE timer in miliseconds */
+#define  TCP_KEEPINTVL     75000                         /* Time between KEEPALIVE probes in miliseconds */
+#define  TCP_KEEPCNT       9                             /* Counter for KEEPALIVE probes */
+#define  TCP_MAXIDLE       TCP_KEEPCNT * TCP_KEEPINTVL   /* Maximum KEEPALIVE probe time */
+
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct tcp_hdr {
+  PACK_STRUCT_FIELD(u16_t src);
+  PACK_STRUCT_FIELD(u16_t dest);
+  PACK_STRUCT_FIELD(u32_t seqno);
+  PACK_STRUCT_FIELD(u32_t ackno);
+  PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);
+  PACK_STRUCT_FIELD(u16_t wnd);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u16_t urgp);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)
+#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)
+#define TCPH_FLAGS(phdr)  (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)
+
+#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))
+#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))
+#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags))
+#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags))
+#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )
+
+#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \
+          TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0))
+
+enum tcp_state {
+  CLOSED      = 0,
+  LISTEN      = 1,
+  SYN_SENT    = 2,
+  SYN_RCVD    = 3,
+  ESTABLISHED = 4,
+  FIN_WAIT_1  = 5,
+  FIN_WAIT_2  = 6,
+  CLOSE_WAIT  = 7,
+  CLOSING     = 8,
+  LAST_ACK    = 9,
+  TIME_WAIT   = 10
+};
+
+/* the TCP protocol control block */
+struct tcp_pcb {
+/** common PCB members */
+  IP_PCB;
+/** protocol specific PCB members */
+  struct tcp_pcb *next; /* for the linked list */
+  enum tcp_state state; /* TCP state */
+  u8_t prio;
+  void *callback_arg;
+
+  u16_t local_port;
+  u16_t remote_port;
+  
+  u8_t flags;
+#define TF_ACK_DELAY (u8_t)0x01U   /* Delayed ACK. */
+#define TF_ACK_NOW   (u8_t)0x02U   /* Immediate ACK. */
+#define TF_INFR      (u8_t)0x04U   /* In fast recovery. */
+#define TF_RESET     (u8_t)0x08U   /* Connection was reset. */
+#define TF_CLOSED    (u8_t)0x10U   /* Connection was sucessfully closed. */
+#define TF_GOT_FIN   (u8_t)0x20U   /* Connection was closed by the remote end. */
+#define TF_NODELAY   (u8_t)0x40U   /* Disable Nagle algorithm */
+
+  /* receiver variables */
+  u32_t rcv_nxt;   /* next seqno expected */
+  u16_t rcv_wnd;   /* receiver window */
+  
+  /* Timers */
+  u32_t tmr;
+  u8_t polltmr, pollinterval;
+  
+  /* Retransmission timer. */
+  u16_t rtime;
+  
+  u16_t mss;   /* maximum segment size */
+  
+  /* RTT (round trip time) estimation variables */
+  u32_t rttest; /* RTT estimate in 500ms ticks */
+  u32_t rtseq;  /* sequence number being timed */
+  s16_t sa, sv; /* @todo document this */
+
+  u16_t rto;    /* retransmission time-out */
+  u8_t nrtx;    /* number of retransmissions */
+
+  /* fast retransmit/recovery */
+  u32_t lastack; /* Highest acknowledged seqno. */
+  u8_t dupacks;
+  
+  /* congestion avoidance/control variables */
+  u16_t cwnd;  
+  u16_t ssthresh;
+
+  /* sender variables */
+  u32_t snd_nxt,       /* next seqno to be sent */
+    snd_max,       /* Highest seqno sent. */
+    snd_wnd,       /* sender window */
+    snd_wl1, snd_wl2, /* Sequence and acknowledgement numbers of last
+       window update. */
+    snd_lbb;       /* Sequence number of next byte to be buffered. */
+
+  u16_t acked;
+  
+  u16_t snd_buf;   /* Available buffer space for sending (in bytes). */
+  u8_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */
+  
+  
+  /* These are ordered by sequence number: */
+  struct tcp_seg *unsent;   /* Unsent (queued) segments. */
+  struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */
+#if TCP_QUEUE_OOSEQ  
+  struct tcp_seg *ooseq;    /* Received out of sequence segments. */
+#endif /* TCP_QUEUE_OOSEQ */
+
+#if LWIP_CALLBACK_API
+  /* Function to be called when more send buffer space is available. */
+  err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space);
+  
+  /* Function to be called when (in-sequence) data has arrived. */
+  err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
+
+  /* Function to be called when a connection has been set up. */
+  err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);
+
+  /* Function to call when a listener has been connected. */
+  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
+
+  /* Function which is called periodically. */
+  err_t (* poll)(void *arg, struct tcp_pcb *pcb);
+
+  /* Function to be called whenever a fatal error occurs. */
+  void (* errf)(void *arg, err_t err);
+#endif /* LWIP_CALLBACK_API */
+
+  /* idle time before KEEPALIVE is sent */
+  u32_t keepalive;
+  
+  /* KEEPALIVE counter */
+  u8_t keep_cnt;
+};
+
+struct tcp_pcb_listen {  
+/* Common members of all PCB types */
+  IP_PCB;
+
+/* Protocol specific PCB members */
+  struct tcp_pcb_listen *next;   /* for the linked list */
+  
+  /* Even if state is obviously LISTEN this is here for
+   * field compatibility with tpc_pcb to which it is cast sometimes
+   * Until a cleaner solution emerges this is here.FIXME
+   */ 
+  enum tcp_state state;   /* TCP state */
+
+  u8_t prio;
+  void *callback_arg;
+  
+  u16_t local_port; 
+
+#if LWIP_CALLBACK_API
+  /* Function to call when a listener has been connected. */
+  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
+#endif /* LWIP_CALLBACK_API */
+};
+
+#if LWIP_EVENT_API
+
+enum lwip_event {
+  LWIP_EVENT_ACCEPT,
+  LWIP_EVENT_SENT,
+  LWIP_EVENT_RECV,
+  LWIP_EVENT_CONNECTED,
+  LWIP_EVENT_POLL,
+  LWIP_EVENT_ERR
+};
+
+err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
+         enum lwip_event,
+         struct pbuf *p,
+         u16_t size,
+         err_t err);
+
+#define TCP_EVENT_ACCEPT(pcb,err,ret)    ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+                LWIP_EVENT_ACCEPT, NULL, 0, err)
+#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+                   LWIP_EVENT_SENT, NULL, space, ERR_OK)
+#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+                LWIP_EVENT_RECV, (p), 0, (err))
+#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+                LWIP_EVENT_CONNECTED, NULL, 0, (err))
+#define TCP_EVENT_POLL(pcb,ret)       ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+                LWIP_EVENT_POLL, NULL, 0, ERR_OK)
+#define TCP_EVENT_ERR(errf,arg,err)  lwip_tcp_event((arg), NULL, \
+                LWIP_EVENT_ERR, NULL, 0, (err))
+#else /* LWIP_EVENT_API */
+#define TCP_EVENT_ACCEPT(pcb,err,ret)     \
+                        if((pcb)->accept != NULL) \
+                        (ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err)))
+#define TCP_EVENT_SENT(pcb,space,ret) \
+                        if((pcb)->sent != NULL) \
+                        (ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space)))
+#define TCP_EVENT_RECV(pcb,p,err,ret) \
+                        if((pcb)->recv != NULL) \
+                        { ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \
+                          if (p) pbuf_free(p); }
+#define TCP_EVENT_CONNECTED(pcb,err,ret) \
+                        if((pcb)->connected != NULL) \
+                        (ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))
+#define TCP_EVENT_POLL(pcb,ret) \
+                        if((pcb)->poll != NULL) \
+                        (ret = (pcb)->poll((pcb)->callback_arg,(pcb)))
+#define TCP_EVENT_ERR(errf,arg,err) \
+                        if((errf) != NULL) \
+                        (errf)((arg),(err))
+#endif /* LWIP_EVENT_API */
+
+/* This structure represents a TCP segment on the unsent and unacked queues */
+struct tcp_seg {
+  struct tcp_seg *next;    /* used when putting segements on a queue */
+  struct pbuf *p;          /* buffer containing data + TCP header */
+  void *dataptr;           /* pointer to the TCP data in the pbuf */
+  u16_t len;               /* the TCP length of this segment */
+  struct tcp_hdr *tcphdr;  /* the TCP header */
+};
+
+/* Internal functions and global variables: */
+struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
+void tcp_pcb_purge(struct tcp_pcb *pcb);
+void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);
+
+u8_t tcp_segs_free(struct tcp_seg *seg);
+u8_t tcp_seg_free(struct tcp_seg *seg);
+struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
+
+#define tcp_ack(pcb)     if((pcb)->flags & TF_ACK_DELAY) { \
+                            (pcb)->flags &= ~TF_ACK_DELAY; \
+                            (pcb)->flags |= TF_ACK_NOW; \
+                            tcp_output(pcb); \
+                         } else { \
+                            (pcb)->flags |= TF_ACK_DELAY; \
+                         }
+
+#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \
+                         tcp_output(pcb)
+
+err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags);
+err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,
+    u8_t flags, u8_t copy,
+                u8_t *optdata, u8_t optlen);
+
+void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
+
+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);
+
+u32_t tcp_next_iss(void);
+
+void tcp_keepalive(struct tcp_pcb *pcb);
+
+extern struct tcp_pcb *tcp_input_pcb;
+extern u32_t tcp_ticks;
+
+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
+void tcp_debug_print(struct tcp_hdr *tcphdr);
+void tcp_debug_print_flags(u8_t flags);
+void tcp_debug_print_state(enum tcp_state s);
+void tcp_debug_print_pcbs(void);
+s16_t tcp_pcbs_sane(void);
+#else
+#  define tcp_debug_print(tcphdr)
+#  define tcp_debug_print_flags(flags)
+#  define tcp_debug_print_state(s)
+#  define tcp_debug_print_pcbs()
+#  define tcp_pcbs_sane() 1
+#endif /* TCP_DEBUG */
+
+#if NO_SYS
+#define tcp_timer_needed()
+#else
+void tcp_timer_needed(void);
+#endif
+
+/* The TCP PCB lists. */
+union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */
+  struct tcp_pcb_listen *listen_pcbs; 
+  struct tcp_pcb *pcbs;
+};
+extern union tcp_listen_pcbs_t tcp_listen_pcbs;
+extern struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a
+              state in which they accept or send
+              data. */
+extern struct tcp_pcb *tcp_tw_pcbs;      /* List of all TCP PCBs in TIME-WAIT. */
+
+extern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */
+
+/* Axioms about the above lists:   
+   1) Every TCP PCB that is not CLOSED is in one of the lists.
+   2) A PCB is only in one of the lists.
+   3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.
+   4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.
+*/
+
+/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB
+   with a PCB list or removes a PCB from a list, respectively. */
+#if 0
+#define TCP_REG(pcbs, npcb) do {\
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \
+                            for(tcp_tmp_pcb = *pcbs; \
+          tcp_tmp_pcb != NULL; \
+        tcp_tmp_pcb = tcp_tmp_pcb->next) { \
+                                LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \
+                            } \
+                            LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \
+                            npcb->next = *pcbs; \
+                            LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \
+                            *(pcbs) = npcb; \
+                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
+              tcp_timer_needed(); \
+                            } while(0)
+#define TCP_RMV(pcbs, npcb) do { \
+                            LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \
+                            if(*pcbs == npcb) { \
+                               *pcbs = (*pcbs)->next; \
+                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
+                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \
+                                  tcp_tmp_pcb->next = npcb->next; \
+                                  break; \
+                               } \
+                            } \
+                            npcb->next = NULL; \
+                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \
+                            } while(0)
+
+#else /* LWIP_DEBUG */
+#define TCP_REG(pcbs, npcb) do { \
+                            npcb->next = *pcbs; \
+                            *(pcbs) = npcb; \
+              tcp_timer_needed(); \
+                            } while(0)
+#define TCP_RMV(pcbs, npcb) do { \
+                            if(*(pcbs) == npcb) { \
+                               (*(pcbs)) = (*pcbs)->next; \
+                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
+                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \
+                                  tcp_tmp_pcb->next = npcb->next; \
+                                  break; \
+                               } \
+                            } \
+                            npcb->next = NULL; \
+                            } while(0)
+#endif /* LWIP_DEBUG */
+#endif /* __LWIP_TCP_H__ */
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/tcpip.h b/Demo/Common/ethernet/lwIP/include/lwip/tcpip.h
new file mode 100644 (file)
index 0000000..316ae4f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_TCPIP_H__
+#define __LWIP_TCPIP_H__
+
+#include "lwip/api_msg.h"
+#include "lwip/pbuf.h"
+
+void tcpip_init(void (* tcpip_init_done)(void *), void *arg);
+void tcpip_apimsg(struct api_msg *apimsg);
+err_t tcpip_input(struct pbuf *p, struct netif *inp);
+err_t tcpip_callback(void (*f)(void *ctx), void *ctx);
+
+void tcpip_tcp_timer_needed(void);
+
+enum tcpip_msg_type {
+  TCPIP_MSG_API,
+  TCPIP_MSG_INPUT,
+  TCPIP_MSG_CALLBACK
+};
+
+struct tcpip_msg {
+  enum tcpip_msg_type type;
+  sys_sem_t *sem;
+  union {
+    struct api_msg *apimsg;
+    struct {
+      struct pbuf *p;
+      struct netif *netif;
+    } inp;
+    struct {
+      void (*f)(void *ctx);
+      void *ctx;
+    } cb;
+  } msg;
+};
+
+
+#endif /* __LWIP_TCPIP_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/lwip/udp.h b/Demo/Common/ethernet/lwIP/include/lwip/udp.h
new file mode 100644 (file)
index 0000000..346898e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __LWIP_UDP_H__
+#define __LWIP_UDP_H__
+
+#include "lwip/arch.h"
+
+#include "lwip/pbuf.h"
+#include "lwip/inet.h"
+#include "lwip/ip.h"
+
+#define UDP_HLEN 8
+
+struct udp_hdr {
+  PACK_STRUCT_FIELD(u16_t src);
+  PACK_STRUCT_FIELD(u16_t dest);  /* src/dest UDP ports */
+  PACK_STRUCT_FIELD(u16_t len);
+  PACK_STRUCT_FIELD(u16_t chksum);
+} PACK_STRUCT_STRUCT;
+
+#define UDP_FLAGS_NOCHKSUM 0x01U
+#define UDP_FLAGS_UDPLITE  0x02U
+#define UDP_FLAGS_CONNECTED  0x04U
+
+struct udp_pcb {
+/* Common members of all PCB types */
+  IP_PCB;
+
+/* Protocol specific PCB members */
+
+  struct udp_pcb *next;
+
+  u8_t flags;
+  u16_t local_port, remote_port;
+  
+  u16_t chksum_len;
+  
+  void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+    struct ip_addr *addr, u16_t port);
+  void *recv_arg;  
+};
+/* udp_pcbs export for exernal reference (e.g. SNMP agent) */
+extern struct udp_pcb *udp_pcbs;
+
+/* The following functions is the application layer interface to the
+   UDP code. */
+struct udp_pcb * udp_new        (void);
+void             udp_remove     (struct udp_pcb *pcb);
+err_t            udp_bind       (struct udp_pcb *pcb, struct ip_addr *ipaddr,
+                 u16_t port);
+err_t            udp_connect    (struct udp_pcb *pcb, struct ip_addr *ipaddr,
+                 u16_t port);
+void             udp_disconnect    (struct udp_pcb *pcb);
+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);
+err_t            udp_sendto     (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port);
+err_t            udp_send       (struct udp_pcb *pcb, struct pbuf *p);
+
+#define          udp_flags(pcb)  ((pcb)->flags)
+#define          udp_setflags(pcb, f)  ((pcb)->flags = (f))
+
+/* The following functions are the lower layer interface to UDP. */
+void             udp_input      (struct pbuf *p, struct netif *inp);
+void             udp_init       (void);
+
+#if UDP_DEBUG
+void udp_debug_print(struct udp_hdr *udphdr);
+#else
+#define udp_debug_print(udphdr)
+#endif
+#endif /* __LWIP_UDP_H__ */
+
+
diff --git a/Demo/Common/ethernet/lwIP/include/netif/etharp.h b/Demo/Common/ethernet/lwIP/include/netif/etharp.h
new file mode 100644 (file)
index 0000000..d64f55e
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
+ * Copyright (c) 2003-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 part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __NETIF_ETHARP_H__
+#define __NETIF_ETHARP_H__
+
+#ifndef ETH_PAD_SIZE
+#define ETH_PAD_SIZE 0
+#endif
+
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/ip.h"
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct eth_addr {
+  PACK_STRUCT_FIELD(u8_t addr[6]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct eth_hdr {
+#if ETH_PAD_SIZE
+  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
+#endif
+  PACK_STRUCT_FIELD(struct eth_addr dest);
+  PACK_STRUCT_FIELD(struct eth_addr src);
+  PACK_STRUCT_FIELD(u16_t type);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** the ARP message */
+struct etharp_hdr {
+  PACK_STRUCT_FIELD(struct eth_hdr ethhdr);
+  PACK_STRUCT_FIELD(u16_t hwtype);
+  PACK_STRUCT_FIELD(u16_t proto);
+  PACK_STRUCT_FIELD(u16_t _hwlen_protolen);
+  PACK_STRUCT_FIELD(u16_t opcode);
+  PACK_STRUCT_FIELD(struct eth_addr shwaddr);
+  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
+  PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
+  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ethip_hdr {
+  PACK_STRUCT_FIELD(struct eth_hdr eth);
+  PACK_STRUCT_FIELD(struct ip_hdr ip);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** 5 seconds period */
+#define ARP_TMR_INTERVAL 5000
+
+#define ETHTYPE_ARP 0x0806
+#define ETHTYPE_IP  0x0800
+
+
+void etharp_init(void);
+void etharp_tmr(void);
+s8_t etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,
+         struct eth_addr **eth_ret, struct ip_addr **ip_ret);
+void etharp_ip_input(struct netif *netif, struct pbuf *p);
+void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
+         struct pbuf *p);
+err_t etharp_output(struct netif *netif, struct ip_addr *ipaddr,
+         struct pbuf *q);
+err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);
+err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);
+
+#endif /* __NETIF_ARP_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/netif/loopif.h b/Demo/Common/ethernet/lwIP/include/netif/loopif.h
new file mode 100644 (file)
index 0000000..97b3c67
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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>
+ *
+ */
+#ifndef __NETIF_LOOPIF_H__
+#define __NETIF_LOOPIF_H__
+
+#include "lwip/netif.h"
+
+err_t loopif_init(struct netif *netif);
+
+#endif /* __NETIF_LOOPIF_H__ */
diff --git a/Demo/Common/ethernet/lwIP/include/netif/slipif.h b/Demo/Common/ethernet/lwIP/include/netif/slipif.h
new file mode 100644 (file)
index 0000000..bf70046
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2001, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE. 
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __NETIF_SLIPIF_H__
+#define __NETIF_SLIPIF_H__
+
+#include "lwip/netif.h"
+
+err_t slipif_init(struct netif * netif);
+#endif 
+
diff --git a/Demo/Common/ethernet/lwIP/netif/FILES b/Demo/Common/ethernet/lwIP/netif/FILES
new file mode 100644 (file)
index 0000000..825d407
--- /dev/null
@@ -0,0 +1,27 @@
+This directory contains generic network interface device drivers that
+do not contain any hardware or architecture specific code. The files
+are:
+
+etharp.c
+          Implements the ARP (Address Resolution Protocol) over
+          Ethernet. The code in this file should be used together with
+          Ethernet device drivers. Note that this module has been
+          largely made Ethernet independent so you should be able to
+          adapt this for other link layers (such as Firewire).
+
+ethernetif.c
+          An example of how an Ethernet device driver could look. This
+          file can be used as a "skeleton" for developing new Ethernet
+          network device drivers. It uses the etharp.c ARP code.
+
+loopif.c
+          An example network interface that shows how a "loopback"
+          interface would work. This is not really intended for actual
+          use, but as a very basic example of how initialization and
+          output functions work.
+
+slipif.c
+          A generic implementation of the SLIP (Serial Line IP)
+          protocol. It requires a sio (serial I/O) module to work.
+         
+ppp/      Point-to-Point Protocol stack
diff --git a/Demo/Common/ethernet/lwIP/netif/etharp.c b/Demo/Common/ethernet/lwIP/netif/etharp.c
new file mode 100644 (file)
index 0000000..9787f6d
--- /dev/null
@@ -0,0 +1,892 @@
+/**
+ * @file
+ * Address Resolution Protocol module for IP over Ethernet
+ *
+ * Functionally, ARP is divided into two parts. The first maps an IP address
+ * to a physical address when sending a packet, and the second part answers
+ * requests from other machines for our physical address.
+ *
+ * This implementation complies with RFC 826 (Ethernet ARP). It supports
+ * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
+ * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon
+ * address change.
+ */
+
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
+ * Copyright (c) 2003-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 part of the lwIP TCP/IP stack.
+ *
+ */
+#include <string.h>
+#include "lwip/opt.h"
+#include "lwip/inet.h"
+#include "netif/etharp.h"
+#include "lwip/ip.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+
+/* ARP needs to inform DHCP of any ARP replies? */
+#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
+#  include "lwip/dhcp.h"
+#endif
+
+/** the time an ARP entry stays valid after its last update,
+ * (240 * 5) seconds = 20 minutes.
+ */
+#define ARP_MAXAGE 240
+/** the time an ARP entry stays pending after first request,
+ * (2 * 5) seconds = 10 seconds.
+ * 
+ * @internal Keep this number at least 2, otherwise it might
+ * run out instantly if the timeout occurs directly after a request.
+ */
+#define ARP_MAXPENDING 2
+
+#define HWTYPE_ETHERNET 1
+
+/** ARP message types */
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)
+#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)
+
+#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
+#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
+
+enum etharp_state {
+  ETHARP_STATE_EMPTY,
+  ETHARP_STATE_PENDING,
+  ETHARP_STATE_STABLE,
+  /** @internal transitional state used in etharp_tmr() for convenience*/
+  ETHARP_STATE_EXPIRED
+};
+
+struct etharp_entry {
+#if ARP_QUEUEING
+  /** 
+   * Pointer to queue of pending outgoing packets on this ARP entry.
+   */
+   struct pbuf *p;
+#endif
+  struct ip_addr ipaddr;
+  struct eth_addr ethaddr;
+  enum etharp_state state;
+  u8_t ctime;
+  struct netif *netif;
+};
+
+static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
+static struct etharp_entry arp_table[ARP_TABLE_SIZE];
+
+/**
+ * Try hard to create a new entry - we want the IP address to appear in
+ * the cache (even if this means removing an active entry or so). */
+#define ETHARP_TRY_HARD 1
+
+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);
+static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
+/**
+ * Initializes ARP module.
+ */
+void
+etharp_init(void)
+{
+  u8_t i;
+  /* clear ARP entries */
+  for(i = 0; i < ARP_TABLE_SIZE; ++i) {
+    arp_table[i].state = ETHARP_STATE_EMPTY;
+#if ARP_QUEUEING
+    arp_table[i].p = NULL;
+#endif
+    arp_table[i].ctime = 0;
+    arp_table[i].netif = NULL;
+  }
+}
+
+/**
+ * Clears expired entries in the ARP table.
+ *
+ * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
+ * in order to expire entries in the ARP table.
+ */
+void
+etharp_tmr(void)
+{
+  u8_t i;
+
+  LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
+  /* remove expired entries from the ARP table */
+  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
+    arp_table[i].ctime++;
+    /* stable entry? */
+    if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
+         /* entry has become old? */
+        (arp_table[i].ctime >= ARP_MAXAGE)) {
+      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %"U16_F".\n", (u16_t)i));
+      arp_table[i].state = ETHARP_STATE_EXPIRED;
+    /* pending entry? */
+    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
+      /* entry unresolved/pending for too long? */
+      if (arp_table[i].ctime >= ARP_MAXPENDING) {
+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %"U16_F".\n", (u16_t)i));
+        arp_table[i].state = ETHARP_STATE_EXPIRED;
+#if ARP_QUEUEING
+      } else if (arp_table[i].p != NULL) {
+        /* resend an ARP query here */
+#endif
+      }
+    }
+    /* clean up entries that have just been expired */
+    if (arp_table[i].state == ETHARP_STATE_EXPIRED) {
+      /* remove from SNMP ARP index tree */
+      snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
+#if ARP_QUEUEING
+      /* and empty packet queue */
+      if (arp_table[i].p != NULL) {
+        /* remove all queued packets */
+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].p)));
+        pbuf_free(arp_table[i].p);
+        arp_table[i].p = NULL;
+      }
+#endif
+      /* recycle entry for re-use */      
+      arp_table[i].state = ETHARP_STATE_EMPTY;
+    }
+  }
+}
+
+/**
+ * Search the ARP table for a matching or new entry.
+ * 
+ * If an IP address is given, return a pending or stable ARP entry that matches
+ * the address. If no match is found, create a new entry with this address set,
+ * but in state ETHARP_EMPTY. The caller must check and possibly change the
+ * state of the returned entry.
+ * 
+ * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
+ * 
+ * In all cases, attempt to create new entries from an empty entry. If no
+ * empty entries are available and ETHARP_TRY_HARD flag is set, recycle
+ * old entries. Heuristic choose the least important entry for recycling.
+ *
+ * @param ipaddr IP address to find in ARP cache, or to add if not found.
+ * @param flags
+ * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
+ * active (stable or pending) entries.
+ *  
+ * @return The ARP entry index that matched or is created, ERR_MEM if no
+ * entry is found or could be recycled.
+ */
+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
+{
+  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
+  s8_t empty = ARP_TABLE_SIZE;
+  u8_t i = 0, age_pending = 0, age_stable = 0;
+#if ARP_QUEUEING
+  /* oldest entry with packets on queue */
+  s8_t old_queue = ARP_TABLE_SIZE;
+  /* its age */
+  u8_t age_queue = 0;
+#endif
+
+  /**
+   * a) do a search through the cache, remember candidates
+   * b) select candidate entry
+   * c) create new entry
+   */
+
+  /* a) in a single search sweep, do all of this
+   * 1) remember the first empty entry (if any)
+   * 2) remember the oldest stable entry (if any)
+   * 3) remember the oldest pending entry without queued packets (if any)
+   * 4) remember the oldest pending entry with queued packets (if any)
+   * 5) search for a matching IP entry, either pending or stable
+   *    until 5 matches, or all entries are searched for.
+   */
+
+  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
+    /* no empty entry found yet and now we do find one? */
+    if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {
+      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
+      /* remember first empty entry */
+      empty = i;
+    }
+    /* pending entry? */
+    else if (arp_table[i].state == ETHARP_STATE_PENDING) {
+      /* if given, does IP address match IP address in ARP entry? */
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));
+        /* found exact IP address match, simply bail out */
+        return i;
+#if ARP_QUEUEING
+      /* pending with queued packets? */
+      } else if (arp_table[i].p != NULL) {
+        if (arp_table[i].ctime >= age_queue) {
+          old_queue = i;
+          age_queue = arp_table[i].ctime;
+        }
+#endif
+      /* pending without queued packets? */
+      } else {
+        if (arp_table[i].ctime >= age_pending) {
+          old_pending = i;
+          age_pending = arp_table[i].ctime;
+        }
+      }        
+    }
+    /* stable entry? */
+    else if (arp_table[i].state == ETHARP_STATE_STABLE) {
+      /* if given, does IP address match IP address in ARP entry? */
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));
+        /* found exact IP address match, simply bail out */
+        return i;
+      /* remember entry with oldest stable entry in oldest, its age in maxtime */
+      } else if (arp_table[i].ctime >= age_stable) {
+        old_stable = i;
+        age_stable = arp_table[i].ctime;
+      }
+    }
+  }
+  /* { we have no match } => try to create a new entry */
+   
+  /* no empty entry found and not allowed to recycle? */
+  if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))
+  {
+    return (s8_t)ERR_MEM;
+  }
+  
+  /* b) choose the least destructive entry to recycle:
+   * 1) empty entry
+   * 2) oldest stable entry
+   * 3) oldest pending entry without queued packets
+   * 4) oldest pending entry without queued packets
+   * 
+   * { ETHARP_TRY_HARD is set at this point }
+   */ 
+
+  /* 1) empty entry available? */
+  if (empty < ARP_TABLE_SIZE) {
+    i = empty;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
+  }
+  /* 2) found recyclable stable entry? */
+  else if (old_stable < ARP_TABLE_SIZE) {
+    /* recycle oldest stable*/
+    i = old_stable;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
+#if ARP_QUEUEING
+    /* no queued packets should exist on stable entries */
+    LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL);
+#endif
+  /* 3) found recyclable pending entry without queued packets? */
+  } else if (old_pending < ARP_TABLE_SIZE) {
+    /* recycle oldest pending */
+    i = old_pending;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
+#if ARP_QUEUEING
+  /* 4) found recyclable pending entry with queued packets? */
+  } else if (old_queue < ARP_TABLE_SIZE) {
+    /* recycle oldest pending */
+    i = old_queue;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].p)));
+    pbuf_free(arp_table[i].p);
+    arp_table[i].p = NULL;
+#endif
+    /* no empty or recyclable entries found */
+  } else {
+    return (s8_t)ERR_MEM;
+  }
+
+  /* { empty or recyclable entry found } */
+  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
+
+  if (arp_table[i].state != ETHARP_STATE_EMPTY)
+  {
+    snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
+  }
+  /* recycle entry (no-op for an already empty entry) */
+  arp_table[i].state = ETHARP_STATE_EMPTY;
+
+  /* IP address given? */
+  if (ipaddr != NULL) {
+    /* set IP address */
+    ip_addr_set(&arp_table[i].ipaddr, ipaddr);
+  }
+  arp_table[i].ctime = 0;
+  return (err_t)i;
+}
+
+/**
+ * Update (or insert) a IP/MAC address pair in the ARP cache.
+ *
+ * If a pending entry is resolved, any queued packets will be sent
+ * at this point.
+ * 
+ * @param ipaddr IP address of the inserted ARP entry.
+ * @param ethaddr Ethernet address of the inserted ARP entry.
+ * @param flags Defines behaviour:
+ * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
+ * only existing ARP entries will be updated.
+ *
+ * @return
+ * - ERR_OK Succesfully updated ARP cache.
+ * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
+ *
+ * @see pbuf_free()
+ */
+static err_t
+update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
+{
+  s8_t i;
+  u8_t k;
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n"));
+  LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0);
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
+                                        ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), 
+                                        ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
+                                        ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
+  /* non-unicast address? */
+  if (ip_addr_isany(ipaddr) ||
+      ip_addr_isbroadcast(ipaddr, netif) ||
+      ip_addr_ismulticast(ipaddr)) {
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
+    return ERR_ARG;
+  }
+  /* find or create ARP entry */
+  i = find_entry(ipaddr, flags);
+  /* bail out if no entry could be found */
+  if (i < 0) return (err_t)i;
+  
+  /* mark it stable */
+  arp_table[i].state = ETHARP_STATE_STABLE;
+  /* record network interface */
+  arp_table[i].netif = netif;
+
+  /* insert in SNMP ARP index tree */
+  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
+
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
+  /* update address */
+  k = netif->hwaddr_len;
+  while (k > 0) {
+    k--;
+    arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
+  }
+  /* reset time stamp */
+  arp_table[i].ctime = 0;
+/* this is where we will send out queued packets! */
+#if ARP_QUEUEING
+  while (arp_table[i].p != NULL) {
+    /* get the first packet on the queue */
+    struct pbuf *p = arp_table[i].p;
+    /* Ethernet header */
+    struct eth_hdr *ethhdr = p->payload;
+    /* remember (and reference) remainder of queue */
+    /* note: this will also terminate the p pbuf chain */
+    arp_table[i].p = pbuf_dequeue(p);
+    /* fill-in Ethernet header */
+    k = netif->hwaddr_len;
+    while(k > 0) {
+      k--;
+      ethhdr->dest.addr[k] = ethaddr->addr[k];
+      ethhdr->src.addr[k] = netif->hwaddr[k];
+    }
+    ethhdr->type = htons(ETHTYPE_IP);
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
+    /* send the queued IP packet */
+    netif->linkoutput(netif, p);
+    /* free the queued IP packet */
+    pbuf_free(p);
+  }
+#endif
+  return ERR_OK;
+}
+
+/**
+ * Finds (stable) ethernet/IP address pair from ARP table
+ * using interface and IP address index.
+ * @note the addresses in the ARP table are in network order!
+ *
+ * @param netif points to interface index
+ * @param ipaddr points to the (network order) IP address index
+ * @param eth_ret points to return pointer
+ * @param ip_ret points to return pointer
+ * @return table index if found, -1 otherwise
+ */
+s8_t
+etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,
+         struct eth_addr **eth_ret, struct ip_addr **ip_ret)
+{
+  s8_t i;
+
+  i = 0;
+  while (i < ARP_TABLE_SIZE)
+  {
+    if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
+        (arp_table[i].netif == netif) && 
+        ip_addr_cmp(ipaddr, &arp_table[i].ipaddr) )
+    {
+      *eth_ret = &arp_table[i].ethaddr;
+      *ip_ret = &arp_table[i].ipaddr;
+      return i;
+    }
+    i++;
+  }
+  return -1;
+}
+
+/**
+ * Updates the ARP table using the given IP packet.
+ *
+ * Uses the incoming IP packet's source address to update the
+ * ARP cache for the local network. The function does not alter
+ * or free the packet. This function must be called before the
+ * packet p is passed to the IP layer.
+ *
+ * @param netif The lwIP network interface on which the IP packet pbuf arrived.
+ * @param pbuf The IP packet that arrived on netif.
+ *
+ * @return NULL
+ *
+ * @see pbuf_free()
+ */
+void
+etharp_ip_input(struct netif *netif, struct pbuf *p)
+{
+  struct ethip_hdr *hdr;
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+  /* Only insert an entry if the source IP address of the
+     incoming IP packet comes from a host on the local network. */
+  hdr = p->payload;
+  /* source is not on the local network? */
+  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
+    /* do nothing */
+    return;
+  }
+
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
+  /* update ARP table */
+  /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
+   * back soon (for example, if the destination IP address is ours. */
+  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);
+}
+
+
+/**
+ * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache  
+ * send out queued IP packets. Updates cache with snooped address pairs.
+ *
+ * Should be called for incoming ARP packets. The pbuf in the argument
+ * is freed by this function.
+ *
+ * @param netif The lwIP network interface on which the ARP packet pbuf arrived.
+ * @param pbuf The ARP packet that arrived on netif. Is freed by this function.
+ * @param ethaddr Ethernet address of netif.
+ *
+ * @return NULL
+ *
+ * @see pbuf_free()
+ */
+void
+etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
+{
+  struct etharp_hdr *hdr;
+  /* these are aligned properly, whereas the ARP header fields might not be */
+  struct ip_addr sipaddr, dipaddr;
+  u8_t i;
+  u8_t for_us;
+
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+  
+  /* drop short ARP packets */
+  if (p->tot_len < sizeof(struct etharp_hdr)) {
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)sizeof(struct etharp_hdr)));
+    pbuf_free(p);
+    return;
+  }
+
+  hdr = p->payload;
+  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
+   * structure packing (not using structure copy which breaks strict-aliasing rules). */
+  memcpy(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
+  memcpy(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
+
+  /* this interface is not configured? */
+  if (netif->ip_addr.addr == 0) {
+    for_us = 0;
+  } else {
+    /* ARP packet directed to us? */
+    for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));
+  }
+
+  /* ARP message directed to us? */
+  if (for_us) {
+    /* add IP address in ARP cache; assume requester wants to talk to us.
+     * can result in directly sending the queued packets for this host. */
+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
+  /* ARP message not directed to us? */
+  } else {
+    /* update the source IP address in the cache, if present */
+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);
+  }
+
+  /* now act on the message itself */
+  switch (htons(hdr->opcode)) {
+  /* ARP request? */
+  case ARP_REQUEST:
+    /* ARP request. If it asked for our address, we send out a
+     * reply. In any case, we time-stamp any existing ARP entry,
+     * and possiby send out an IP packet that was queued on it. */
+
+    LWIP_DEBUGF (ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
+    /* ARP request for our address? */
+    if (for_us) {
+
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
+      /* re-use pbuf to send ARP reply */
+      hdr->opcode = htons(ARP_REPLY);
+
+      hdr->dipaddr = hdr->sipaddr;
+      hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
+
+      i = netif->hwaddr_len;
+      while(i > 0) {
+        i--;
+        hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
+        hdr->shwaddr.addr[i] = ethaddr->addr[i];
+        hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];
+        hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
+      }
+
+      hdr->hwtype = htons(HWTYPE_ETHERNET);
+      ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
+
+      hdr->proto = htons(ETHTYPE_IP);
+      ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
+
+      hdr->ethhdr.type = htons(ETHTYPE_ARP);
+      /* return ARP reply */
+      netif->linkoutput(netif, p);
+    /* we are not configured? */
+    } else if (netif->ip_addr.addr == 0) {
+      /* { for_us == 0 and netif->ip_addr.addr == 0 } */
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
+    /* request was not directed to us */
+    } else {
+      /* { for_us == 0 and netif->ip_addr.addr != 0 } */
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));
+    }
+    break;
+  case ARP_REPLY:
+    /* ARP reply. We already updated the ARP cache earlier. */
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
+#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
+    /* DHCP wants to know about ARP replies from any host with an
+     * IP address also offered to us by the DHCP server. We do not
+     * want to take a duplicate IP address on a single network.
+     * @todo How should we handle redundant (fail-over) interfaces?
+     * */
+    dhcp_arp_reply(netif, &sipaddr);
+#endif
+    break;
+  default:
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
+    break;
+  }
+  /* free ARP packet */
+  pbuf_free(p);
+}
+
+/**
+ * Resolve and fill-in Ethernet address header for outgoing packet.
+ *
+ * For IP multicast and broadcast, corresponding Ethernet addresses
+ * are selected and the packet is transmitted on the link.
+ *
+ * For unicast addresses, the packet is submitted to etharp_query(). In
+ * case the IP address is outside the local network, the IP address of
+ * the gateway is used.
+ *
+ * @param netif The lwIP network interface which the IP packet will be sent on.
+ * @param ipaddr The IP address of the packet destination.
+ * @param pbuf The pbuf(s) containing the IP packet to be sent.
+ *
+ * @return
+ * - ERR_RTE No route to destination (no gateway to external networks),
+ * or the return type of either etharp_query() or netif->linkoutput().
+ */
+err_t
+etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
+{
+  struct eth_addr *dest, *srcaddr, mcastaddr;
+  struct eth_hdr *ethhdr;
+  u8_t i;
+
+  /* make room for Ethernet header - should not fail */
+  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
+    /* bail out */
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));
+    LINK_STATS_INC(link.lenerr);
+    return ERR_BUF;
+  }
+
+  /* assume unresolved Ethernet address */
+  dest = NULL;
+  /* Determine on destination hardware address. Broadcasts and multicasts
+   * are special, other IP addresses are looked up in the ARP table. */
+
+  /* broadcast destination IP address? */
+  if (ip_addr_isbroadcast(ipaddr, netif)) {
+    /* broadcast on Ethernet also */
+    dest = (struct eth_addr *)&ethbroadcast;
+  /* multicast destination IP address? */
+  } else if (ip_addr_ismulticast(ipaddr)) {
+    /* Hash IP multicast address to MAC address.*/
+    mcastaddr.addr[0] = 0x01;
+    mcastaddr.addr[1] = 0x00;
+    mcastaddr.addr[2] = 0x5e;
+    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
+    mcastaddr.addr[4] = ip4_addr3(ipaddr);
+    mcastaddr.addr[5] = ip4_addr4(ipaddr);
+    /* destination Ethernet address is multicast */
+    dest = &mcastaddr;
+  /* unicast destination IP address? */
+  } else {
+    /* outside local network? */
+    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
+      /* interface has default gateway? */
+      if (netif->gw.addr != 0) {
+        /* send to hardware address of default gateway IP address */
+        ipaddr = &(netif->gw);
+      /* no default gateway available */
+      } else {
+        /* no route to destination error (default gateway missing) */
+        return ERR_RTE;
+      }
+    }
+    /* queue on destination Ethernet address belonging to ipaddr */
+    return etharp_query(netif, ipaddr, q);
+  }
+
+  /* continuation for multicast/broadcast destinations */
+  /* obtain source Ethernet address of the given interface */
+  srcaddr = (struct eth_addr *)netif->hwaddr;
+  ethhdr = q->payload;
+  i = netif->hwaddr_len;
+  while(i > 0) {
+    i--;
+    ethhdr->dest.addr[i] = dest->addr[i];
+    ethhdr->src.addr[i] = srcaddr->addr[i];
+  }
+  ethhdr->type = htons(ETHTYPE_IP);
+  /* send packet directly on the link */
+  return netif->linkoutput(netif, q);
+}
+
+/**
+ * Send an ARP request for the given IP address and/or queue a packet.
+ *
+ * If the IP address was not yet in the cache, a pending ARP cache entry
+ * is added and an ARP request is sent for the given address. The packet
+ * is queued on this entry.
+ *
+ * If the IP address was already pending in the cache, a new ARP request
+ * is sent for the given address. The packet is queued on this entry.
+ *
+ * If the IP address was already stable in the cache, and a packet is
+ * given, it is directly sent and no ARP request is sent out. 
+ * 
+ * If the IP address was already stable in the cache, and no packet is
+ * given, an ARP request is sent out.
+ * 
+ * @param netif The lwIP network interface on which ipaddr
+ * must be queried for.
+ * @param ipaddr The IP address to be resolved.
+ * @param q If non-NULL, a pbuf that must be delivered to the IP address.
+ * q is not freed by this function.
+ *
+ * @return
+ * - ERR_BUF Could not make room for Ethernet header.
+ * - ERR_MEM Hardware address unknown, and no more ARP entries available
+ *   to query for address or queue the packet.
+ * - ERR_MEM Could not queue packet due to memory shortage.
+ * - ERR_RTE No route to destination (no gateway to external networks).
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
+ *
+ */
+err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
+{
+  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
+  err_t result = ERR_MEM;
+  s8_t i; /* ARP entry index */
+  u8_t k; /* Ethernet address octet index */
+
+  /* non-unicast address? */
+  if (ip_addr_isbroadcast(ipaddr, netif) ||
+      ip_addr_ismulticast(ipaddr) ||
+      ip_addr_isany(ipaddr)) {
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
+    return ERR_ARG;
+  }
+
+  /* find entry in ARP cache, ask to create entry if queueing packet */
+  i = find_entry(ipaddr, ETHARP_TRY_HARD);
+
+  /* could not find or create entry? */
+  if (i < 0)
+  {
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
+    if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));
+    return (err_t)i;
+  }
+
+  /* mark a fresh entry as pending (we just sent a request) */
+  if (arp_table[i].state == ETHARP_STATE_EMPTY) {
+    arp_table[i].state = ETHARP_STATE_PENDING;
+  }
+
+  /* { i is either a STABLE or (new or existing) PENDING entry } */
+  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
+  ((arp_table[i].state == ETHARP_STATE_PENDING) ||
+   (arp_table[i].state == ETHARP_STATE_STABLE)));
+
+  /* do we have a pending entry? or an implicit query request? */
+  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
+    /* try to resolve it; send out ARP request */
+    result = etharp_request(netif, ipaddr);
+  }
+  
+  /* packet given? */
+  if (q != NULL) {
+    /* stable entry? */
+    if (arp_table[i].state == ETHARP_STATE_STABLE) {
+      /* we have a valid IP->Ethernet address mapping,
+       * fill in the Ethernet header for the outgoing packet */
+      struct eth_hdr *ethhdr = q->payload;
+      k = netif->hwaddr_len;
+      while(k > 0) {
+        k--;
+        ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];
+        ethhdr->src.addr[k]  = srcaddr->addr[k];
+      }
+      ethhdr->type = htons(ETHTYPE_IP);
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));
+      /* send the packet */
+      result = netif->linkoutput(netif, q);
+    /* pending entry? (either just created or already pending */
+    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
+#if ARP_QUEUEING /* queue the given q packet */
+      struct pbuf *p;
+      /* copy any PBUF_REF referenced payloads into PBUF_RAM */
+      /* (the caller of lwIP assumes the referenced payload can be
+       * freed after it returns from the lwIP call that brought us here) */
+      p = pbuf_take(q);
+      /* packet could be taken over? */
+      if (p != NULL) {
+        /* queue packet ... */
+        if (arp_table[i].p == NULL) {
+          /* ... in the empty queue */
+          pbuf_ref(p);
+          arp_table[i].p = p;
+#if 0 /* multi-packet-queueing disabled, see bug #11400 */
+        } else {
+          /* ... at tail of non-empty queue */
+          pbuf_queue(arp_table[i].p, p);
+#endif
+        }
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
+        result = ERR_OK;
+      } else {
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
+        /* { result == ERR_MEM } through initialization */
+      }
+#else /* ARP_QUEUEING == 0 */
+      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
+      /* { result == ERR_MEM } through initialization */
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
+#endif
+    }
+  }
+  return result;
+}
+
+err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)
+{
+  struct pbuf *p;
+  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
+  err_t result = ERR_OK;
+  u8_t k; /* ARP entry index */
+
+  /* allocate a pbuf for the outgoing ARP request packet */
+  p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
+  /* could allocate a pbuf for an ARP request? */
+  if (p != NULL) {
+    struct etharp_hdr *hdr = p->payload;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));
+    hdr->opcode = htons(ARP_REQUEST);
+    k = netif->hwaddr_len;
+    while(k > 0) {
+      k--;
+      hdr->shwaddr.addr[k] = srcaddr->addr[k];
+      /* the hardware address is what we ask for, in
+       * a request it is a don't-care value, we use zeroes */
+      hdr->dhwaddr.addr[k] = 0x00;
+    }
+    hdr->dipaddr = *(struct ip_addr2 *)ipaddr;
+    hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
+
+    hdr->hwtype = htons(HWTYPE_ETHERNET);
+    ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
+
+    hdr->proto = htons(ETHTYPE_IP);
+    ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
+    k = netif->hwaddr_len;
+    while(k > 0) {
+      k--;
+      /* broadcast to all network interfaces on the local network */
+      hdr->ethhdr.dest.addr[k] = 0xff;
+      hdr->ethhdr.src.addr[k] = srcaddr->addr[k];
+    }
+    hdr->ethhdr.type = htons(ETHTYPE_ARP);
+    /* send ARP query */
+    result = netif->linkoutput(netif, p);
+    /* free ARP query packet */
+    pbuf_free(p);
+    p = NULL;
+  /* could not allocate pbuf for ARP request */
+  } else {
+    result = ERR_MEM;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));
+  }
+  return result;
+}
diff --git a/Demo/Common/ethernet/lwIP/netif/ethernetif.c b/Demo/Common/ethernet/lwIP/netif/ethernetif.c
new file mode 100644 (file)
index 0000000..87d5917
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * 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>
+ *
+ */
+
+/*
+ * This file is a skeleton for developing Ethernet network interface
+ * drivers for lwIP. Add code to the low_level functions and do a
+ * search-and-replace for the word "ethernetif" to replace it with
+ * something that better describes your network interface.
+ */
+
+#include "lwip/opt.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include <lwip/stats.h>
+
+#include "netif/etharp.h"
+
+/* Define those to better describe your network interface. */
+#define IFNAME0 'e'
+#define IFNAME1 'n'
+
+struct ethernetif {
+  struct eth_addr *ethaddr;
+  /* Add whatever per-interface state that is needed here. */
+};
+
+static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
+
+/* Forward declarations. */
+static void  ethernetif_input(struct netif *netif);
+static err_t ethernetif_output(struct netif *netif, struct pbuf *p,
+             struct ip_addr *ipaddr);
+
+static void
+low_level_init(struct netif *netif)
+{
+  struct ethernetif *ethernetif = netif->state;
+  
+  /* set MAC hardware address length */
+  netif->hwaddr_len = 6;
+
+  /* set MAC hardware address */
+  netif->hwaddr[0] = ;
+  ...
+  netif->hwaddr[5] = ;
+
+  /* maximum transfer unit */
+  netif->mtu = 1500;
+  
+  /* broadcast capability */
+  netif->flags = NETIF_FLAG_BROADCAST;
+  /* Do whatever else is needed to initialize interface. */  
+}
+
+/*
+ * low_level_output():
+ *
+ * Should do the actual transmission of the packet. The packet is
+ * contained in the pbuf that is passed to the function. This pbuf
+ * might be chained.
+ *
+ */
+
+static err_t
+low_level_output(struct netif *netif, struct pbuf *p)
+{
+  struct ethernetif *ethernetif = netif->state;
+  struct pbuf *q;
+
+  initiate transfer();
+  
+#if ETH_PAD_SIZE
+  pbuf_header(p, -ETH_PAD_SIZE);                       /* drop the padding word */
+#endif
+
+  for(q = p; q != NULL; q = q->next) {
+    /* Send the data from the pbuf to the interface, one pbuf at a
+       time. The size of the data in each pbuf is kept in the ->len
+       variable. */
+    send data from(q->payload, q->len);
+  }
+
+  signal that packet should be sent();
+
+#if ETH_PAD_SIZE
+  pbuf_header(p, ETH_PAD_SIZE);                        /* reclaim the padding word */
+#endif
+  
+#if LINK_STATS
+  lwip_stats.link.xmit++;
+#endif /* LINK_STATS */      
+
+  return ERR_OK;
+}
+
+/*
+ * low_level_input():
+ *
+ * Should allocate a pbuf and transfer the bytes of the incoming
+ * packet from the interface into the pbuf.
+ *
+ */
+
+static struct pbuf *
+low_level_input(struct netif *netif)
+{
+  struct ethernetif *ethernetif = netif->state;
+  struct pbuf *p, *q;
+  u16_t len;
+
+  /* Obtain the size of the packet and put it into the "len"
+     variable. */
+  len = ;
+
+#if ETH_PAD_SIZE
+  len += ETH_PAD_SIZE;                                         /* allow room for Ethernet padding */
+#endif
+
+  /* We allocate a pbuf chain of pbufs from the pool. */
+  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
+  
+  if (p != NULL) {
+
+#if ETH_PAD_SIZE
+    pbuf_header(p, -ETH_PAD_SIZE);                     /* drop the padding word */
+#endif
+
+    /* We iterate over the pbuf chain until we have read the entire
+     * packet into the pbuf. */
+    for(q = p; q != NULL; q = q->next) {
+      /* Read enough bytes to fill this pbuf in the chain. The
+       * available data in the pbuf is given by the q->len
+       * variable. */
+      read data into(q->payload, q->len);
+    }
+    acknowledge that packet has been read();
+
+#if ETH_PAD_SIZE
+    pbuf_header(p, ETH_PAD_SIZE);                      /* reclaim the padding word */
+#endif
+
+#if LINK_STATS
+    lwip_stats.link.recv++;
+#endif /* LINK_STATS */      
+  } else {
+    drop packet();
+#if LINK_STATS
+    lwip_stats.link.memerr++;
+    lwip_stats.link.drop++;
+#endif /* LINK_STATS */      
+  }
+
+  return p;  
+}
+
+/*
+ * ethernetif_output():
+ *
+ * This function is called by the TCP/IP stack when an IP packet
+ * should be sent. It calls the function called low_level_output() to
+ * do the actual transmission of the packet.
+ *
+ */
+
+static err_t
+ethernetif_output(struct netif *netif, struct pbuf *p,
+      struct ip_addr *ipaddr)
+{
+  
+ /* resolve hardware address, then send (or queue) packet */
+  return etharp_output(netif, ipaddr, p);
+}
+
+/*
+ * ethernetif_input():
+ *
+ * This function should be called when a packet is ready to be read
+ * from the interface. It uses the function low_level_input() that
+ * should handle the actual reception of bytes from the network
+ * interface.
+ *
+ */
+
+static void
+ethernetif_input(struct netif *netif)
+{
+  struct ethernetif *ethernetif;
+  struct eth_hdr *ethhdr;
+  struct pbuf *p;
+
+  ethernetif = netif->state;
+  
+  /* move received packet into a new pbuf */
+  p = low_level_input(netif);
+  /* no packet could be read, silently ignore this */
+  if (p == NULL) return;
+  /* points to packet payload, which starts with an Ethernet header */
+  ethhdr = p->payload;
+
+#if LINK_STATS
+  lwip_stats.link.recv++;
+#endif /* LINK_STATS */
+
+  ethhdr = p->payload;
+    
+  switch (htons(ethhdr->type)) {
+  /* IP packet? */
+  case ETHTYPE_IP:
+#if 0
+/* CSi disabled ARP table update on ingress IP packets.
+   This seems to work but needs thorough testing. */
+    /* update ARP table */
+    etharp_ip_input(netif, p);
+#endif
+    /* skip Ethernet header */
+    pbuf_header(p, -sizeof(struct eth_hdr));
+    /* pass to network layer */
+    netif->input(p, netif);
+    break;
+      
+    case ETHTYPE_ARP:
+      /* pass p to ARP module  */
+      etharp_arp_input(netif, ethernetif->ethaddr, p);
+      break;
+    default:
+      pbuf_free(p);
+      p = NULL;
+      break;
+  }
+}
+
+static void
+arp_timer(void *arg)
+{
+  etharp_tmr();
+  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
+}
+
+/*
+ * ethernetif_init():
+ *
+ * Should be called at the beginning of the program to set up the
+ * network interface. It calls the function low_level_init() to do the
+ * actual setup of the hardware.
+ *
+ */
+
+err_t
+ethernetif_init(struct netif *netif)
+{
+  struct ethernetif *ethernetif;
+    
+  ethernetif = mem_malloc(sizeof(struct ethernetif));
+  
+  if (ethernetif == NULL)
+  {
+       LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
+       return ERR_MEM;
+  }
+
+#if LWIP_SNMP
+  /* ifType ethernetCsmacd(6) @see RFC1213 */
+  netif->link_type = 6;
+  /* your link speed here */
+  netif->link_speed = ;
+  netif->ts = 0;
+  netif->ifinoctets = 0;
+  netif->ifinucastpkts = 0;
+  netif->ifinnucastpkts = 0;
+  netif->ifindiscards = 0;
+  netif->ifoutoctets = 0;
+  netif->ifoutucastpkts = 0;
+  netif->ifoutnucastpkts = 0;
+  netif->ifoutdiscards = 0;
+#endif
+  
+  netif->state = ethernetif;
+  netif->name[0] = IFNAME0;
+  netif->name[1] = IFNAME1;
+  netif->output = ethernetif_output;
+  netif->linkoutput = low_level_output;
+  
+  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
+  
+  low_level_init(netif);
+
+  etharp_init();
+
+  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
+
+  return ERR_OK;
+}
+
diff --git a/Demo/Common/ethernet/lwIP/netif/loopif.c b/Demo/Common/ethernet/lwIP/netif/loopif.c
new file mode 100644 (file)
index 0000000..0464cb8
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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"
+
+#if LWIP_HAVE_LOOPIF
+
+#include "netif/loopif.h"
+#include "lwip/mem.h"
+
+#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
+#include "netif/tcpdump.h"
+#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
+
+#include "lwip/tcp.h"
+#include "lwip/ip.h"
+
+static void
+loopif_input( void * arg )
+{
+       struct netif *netif = (struct netif *)( ((void **)arg)[ 0 ] );
+       struct pbuf *r = (struct pbuf *)( ((void **)arg)[ 1 ] );
+
+       mem_free( arg );
+       netif -> input( r, netif );
+}
+
+static err_t
+loopif_output(struct netif *netif, struct pbuf *p,
+       struct ip_addr *ipaddr)
+{
+  struct pbuf *q, *r;
+  u8_t *ptr;
+  void **arg;
+
+#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
+  tcpdump(p);
+#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
+  
+  r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
+  if (r != NULL) {
+    ptr = r->payload;
+    
+    for(q = p; q != NULL; q = q->next) {
+      memcpy(ptr, q->payload, q->len);
+      ptr += q->len;
+    }
+
+    arg = mem_malloc( sizeof( void *[2]));
+       if( NULL == arg ) {
+               return ERR_MEM;
+       }
+       
+       arg[0] = netif;
+       arg[1] = r;
+       /**
+        * workaround (patch #1779) to try to prevent bug #2595:
+        * When connecting to "localhost" with the loopif interface,
+        * tcp_output doesn't get the opportunity to finnish sending the
+        * segment before tcp_process gets it, resulting in tcp_process
+        * referencing pcb->unacked-> which still is NULL.
+        * 
+        * TODO: Is there still a race condition here? Leon
+        */
+       sys_timeout( 1, loopif_input, arg );
+       
+    return ERR_OK;    
+  }
+  return ERR_MEM;
+}
+
+err_t
+loopif_init(struct netif *netif)
+{
+  netif->name[0] = 'l';
+  netif->name[1] = 'o';
+#if 0 /** TODO: I think this should be enabled, or not? Leon */
+  netif->input = loopif_input;
+#endif
+  netif->output = loopif_output;
+  return ERR_OK;
+}
+
+#endif /* LWIP_HAVE_LOOPIF */
+
+
+
+
+
+
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/auth.c b/Demo/Common/ethernet/lwIP/netif/ppp/auth.c
new file mode 100644 (file)
index 0000000..3334964
--- /dev/null
@@ -0,0 +1,927 @@
+/*****************************************************************************
+* auth.c - Network Authentication and Phase Control program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*   Ported from public pppd code.
+*****************************************************************************/
+/*
+ * auth.c - PPP authentication and phase control.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "ppp.h"
+#if PPP_SUPPORT > 0
+#include "fsm.h"
+#include "lcp.h"
+#include "pap.h"
+#include "chap.h"
+#include "auth.h"
+#include "ipcp.h"
+
+#if CBCP_SUPPORT > 0
+#include "cbcp.h"
+#endif
+
+#include "pppdebug.h"
+
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+
+/* Bits in auth_pending[] */
+#define PAP_WITHPEER    1
+#define PAP_PEER    2
+#define CHAP_WITHPEER   4
+#define CHAP_PEER   8
+
+
+                                                                    
+/************************/
+/*** LOCAL DATA TYPES ***/
+/************************/
+/* Used for storing a sequence of words.  Usually malloced. */
+struct wordlist {
+    struct wordlist *next;
+    char        word[1];
+};
+
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+extern char *crypt (const char *, const char *);
+
+/* Prototypes for procedures local to this file. */
+
+static void network_phase (int);
+static void check_idle (void *);
+static void connect_time_expired (void *);
+#if 0
+static int  login (char *, char *, char **, int *);
+#endif
+static void logout (void);
+static int  null_login (int);
+static int  get_pap_passwd (int, char *, char *);
+static int  have_pap_secret (void);
+static int  have_chap_secret (char *, char *, u32_t);
+static int  ip_addr_check (u32_t, struct wordlist *);
+#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT > 0 */
+static void set_allowed_addrs(int unit, struct wordlist *addrs);
+static void free_wordlist (struct wordlist *);
+#endif
+#if CBCP_SUPPORT > 0
+static void callback_phase (int);
+#endif
+
+
+/******************************/
+/*** PUBLIC DATA STRUCTURES ***/
+/******************************/
+
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
+/* The name by which the peer authenticated itself to us. */
+static char peer_authname[MAXNAMELEN];
+#endif
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[NUM_PPP];
+
+/* Set if we have successfully called login() */
+static int logged_in;
+
+/* Set if we have run the /etc/ppp/auth-up script. */
+static int did_authup;
+
+/* List of addresses which the peer may use. */
+static struct wordlist *addresses[NUM_PPP];
+
+/* Number of network protocols which we have opened. */
+static int num_np_open;
+
+/* Number of network protocols which have come up. */
+static int num_np_up;
+
+#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
+/* Set if we got the contents of passwd[] from the pap-secrets file. */
+static int passwd_from_file;
+#endif
+
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/*
+ * An Open on LCP has requested a change from Dead to Establish phase.
+ * Do what's necessary to bring the physical layer up.
+ */
+void link_required(int unit)
+{
+    AUTHDEBUG((LOG_INFO, "link_required: %d\n", unit));
+}
+
+/*
+ * LCP has terminated the link; go to the Dead phase and take the
+ * physical layer down.
+ */
+void link_terminated(int unit)
+{
+    AUTHDEBUG((LOG_INFO, "link_terminated: %d\n", unit));
+    
+    if (lcp_phase[unit] == PHASE_DEAD)
+        return;
+    if (logged_in)
+        logout();
+    lcp_phase[unit] = PHASE_DEAD;
+    AUTHDEBUG((LOG_NOTICE, "Connection terminated.\n"));
+       pppMainWakeup(unit);
+}
+
+/*
+ * LCP has gone down; it will either die or try to re-establish.
+ */
+void link_down(int unit)
+{
+    int i;
+    struct protent *protp;
+    
+    AUTHDEBUG((LOG_INFO, "link_down: %d\n", unit));
+    if (did_authup) {
+        /* XXX Do link down processing. */
+        did_authup = 0;
+    }
+    for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
+        if (!protp->enabled_flag)
+            continue;
+        if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)
+            (*protp->lowerdown)(unit);
+        if (protp->protocol < 0xC000 && protp->close != NULL)
+            (*protp->close)(unit, "LCP down");
+    }
+    num_np_open = 0;
+    num_np_up = 0;
+    if (lcp_phase[unit] != PHASE_DEAD)
+        lcp_phase[unit] = PHASE_TERMINATE;
+       pppMainWakeup(unit);
+}
+
+/*
+ * The link is established.
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.
+ */
+void link_established(int unit)
+{
+    int auth;
+    int i;
+    struct protent *protp;
+    lcp_options *wo = &lcp_wantoptions[unit];
+    lcp_options *go = &lcp_gotoptions[unit];
+#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
+    lcp_options *ho = &lcp_hisoptions[unit];
+#endif
+    
+    AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit));
+    /*
+     * Tell higher-level protocols that LCP is up.
+     */
+    for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i)
+        if (protp->protocol != PPP_LCP && protp->enabled_flag
+                && protp->lowerup != NULL)
+            (*protp->lowerup)(unit);
+    
+    if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) {
+        /*
+         * We wanted the peer to authenticate itself, and it refused:
+         * treat it as though it authenticated with PAP using a username
+         * of "" and a password of "".  If that's not OK, boot it out.
+         */
+        if (!wo->neg_upap || !null_login(unit)) {
+            AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n"));
+            lcp_close(unit, "peer refused to authenticate");
+            return;
+        }
+    }
+    
+    lcp_phase[unit] = PHASE_AUTHENTICATE;
+    auth = 0;
+#if CHAP_SUPPORT > 0
+    if (go->neg_chap) {
+        ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype);
+        auth |= CHAP_PEER;
+    } 
+#endif
+#if PAP_SUPPORT > 0 && CHAP_SUPPORT > 0
+    else
+#endif
+#if PAP_SUPPORT > 0
+    if (go->neg_upap) {
+        upap_authpeer(unit);
+        auth |= PAP_PEER;
+    }
+#endif
+#if CHAP_SUPPORT > 0
+    if (ho->neg_chap) {
+        ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype);
+        auth |= CHAP_WITHPEER;
+    }
+#endif
+#if PAP_SUPPORT > 0 && CHAP_SUPPORT > 0
+    else
+#endif
+#if PAP_SUPPORT > 0
+    if (ho->neg_upap) {
+        if (ppp_settings.passwd[0] == 0) {
+            passwd_from_file = 1;
+            if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd))
+                AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n"));
+        }
+        upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd);
+        auth |= PAP_WITHPEER;
+    }
+#endif
+    auth_pending[unit] = auth;
+    
+    if (!auth)
+        network_phase(unit);
+}
+
+
+/*
+ * The peer has failed to authenticate himself using `protocol'.
+ */
+void auth_peer_fail(int unit, u16_t protocol)
+{
+    AUTHDEBUG((LOG_INFO, "auth_peer_fail: %d proto=%X\n", unit, protocol));
+    /*
+     * Authentication failure: take the link down
+     */
+    lcp_close(unit, "Authentication failed");
+}
+
+
+#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
+/*
+ * The peer has been successfully authenticated using `protocol'.
+ */
+void auth_peer_success(int unit, u16_t protocol, char *name, int namelen)
+{
+    int pbit;
+    
+    AUTHDEBUG((LOG_INFO, "auth_peer_success: %d proto=%X\n", unit, protocol));
+    switch (protocol) {
+    case PPP_CHAP:
+        pbit = CHAP_PEER;
+        break;
+    case PPP_PAP:
+        pbit = PAP_PEER;
+        break;
+    default:
+        AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n",
+               protocol));
+        return;
+    }
+    
+    /*
+     * Save the authenticated name of the peer for later.
+     */
+    if (namelen > sizeof(peer_authname) - 1)
+        namelen = sizeof(peer_authname) - 1;
+    BCOPY(name, peer_authname, namelen);
+    peer_authname[namelen] = 0;
+    
+    /*
+     * If there is no more authentication still to be done,
+     * proceed to the network (or callback) phase.
+     */
+    if ((auth_pending[unit] &= ~pbit) == 0)
+        network_phase(unit);
+}
+
+/*
+ * We have failed to authenticate ourselves to the peer using `protocol'.
+ */
+void auth_withpeer_fail(int unit, u16_t protocol)
+{
+    int errCode = PPPERR_AUTHFAIL;
+    
+    AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol));
+    if (passwd_from_file)
+        BZERO(ppp_settings.passwd, MAXSECRETLEN);
+    /* 
+     * XXX Warning: the unit number indicates the interface which is
+     * not necessarily the PPP connection.  It works here as long
+     * as we are only supporting PPP interfaces.
+     */
+    pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode);
+
+    /*
+     * We've failed to authenticate ourselves to our peer.
+     * He'll probably take the link down, and there's not much
+     * we can do except wait for that.
+     */
+}
+
+/*
+ * We have successfully authenticated ourselves with the peer using `protocol'.
+ */
+void auth_withpeer_success(int unit, u16_t protocol)
+{
+    int pbit;
+    
+    AUTHDEBUG((LOG_INFO, "auth_withpeer_success: %d proto=%X\n", unit, protocol));
+    switch (protocol) {
+    case PPP_CHAP:
+        pbit = CHAP_WITHPEER;
+        break;
+    case PPP_PAP:
+        if (passwd_from_file)
+            BZERO(ppp_settings.passwd, MAXSECRETLEN);
+        pbit = PAP_WITHPEER;
+        break;
+    default:
+        AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n",
+               protocol));
+        pbit = 0;
+    }
+    
+    /*
+     * If there is no more authentication still being done,
+     * proceed to the network (or callback) phase.
+     */
+    if ((auth_pending[unit] &= ~pbit) == 0)
+        network_phase(unit);
+}
+#endif
+
+
+/*
+ * np_up - a network protocol has come up.
+ */
+void np_up(int unit, u16_t proto)
+{
+    AUTHDEBUG((LOG_INFO, "np_up: %d proto=%X\n", unit, proto));
+    if (num_np_up == 0) {
+       AUTHDEBUG((LOG_INFO, "np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit));
+        /*
+         * At this point we consider that the link has come up successfully.
+         */
+        if (ppp_settings.idle_time_limit > 0)
+            TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit);
+        
+        /*
+         * Set a timeout to close the connection once the maximum
+         * connect time has expired.
+         */
+        if (ppp_settings.maxconnect > 0)
+            TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect);
+    }
+    ++num_np_up;
+}
+
+/*
+ * np_down - a network protocol has gone down.
+ */
+void np_down(int unit, u16_t proto)
+{
+    AUTHDEBUG((LOG_INFO, "np_down: %d proto=%X\n", unit, proto));
+    if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) {
+        UNTIMEOUT(check_idle, NULL);
+    }
+}
+
+/*
+ * np_finished - a network protocol has finished using the link.
+ */
+void np_finished(int unit, u16_t proto)
+{
+    AUTHDEBUG((LOG_INFO, "np_finished: %d proto=%X\n", unit, proto));
+    if (--num_np_open <= 0) {
+        /* no further use for the link: shut up shop. */
+        lcp_close(0, "No network protocols running");
+    }
+}
+
+/*
+ * auth_reset - called when LCP is starting negotiations to recheck
+ * authentication options, i.e. whether we have appropriate secrets
+ * to use for authenticating ourselves and/or the peer.
+ */
+void auth_reset(int unit)
+{
+    lcp_options *go = &lcp_gotoptions[unit];
+    lcp_options *ao = &lcp_allowoptions[0];
+    ipcp_options *ipwo = &ipcp_wantoptions[0];
+    u32_t remote;
+    
+    AUTHDEBUG((LOG_INFO, "auth_reset: %d\n", unit));
+    ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL));
+    ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/;
+    
+    if (go->neg_upap && !have_pap_secret())
+        go->neg_upap = 0;
+    if (go->neg_chap) {
+        remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+        if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote))
+            go->neg_chap = 0;
+    }
+}
+
+
+#if PAP_SUPPORT > 0
+/*
+ * check_passwd - Check the user name and passwd against the PAP secrets
+ * file.  If requested, also check against the system password database,
+ * and login the user if OK.
+ *
+ * returns:
+ *  UPAP_AUTHNAK: Authentication failed.
+ *  UPAP_AUTHACK: Authentication succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+int check_passwd(
+       int unit,
+       char *auser,
+       int userlen,
+       char *apasswd,
+       int passwdlen,
+       char **msg,
+       int *msglen
+)
+{
+#if 1
+       *msg = (char *) 0;
+       return UPAP_AUTHACK;     /* XXX Assume all entries OK. */
+#else
+    int ret = 0;
+    struct wordlist *addrs = NULL;
+    char passwd[256], user[256];
+    char secret[MAXWORDLEN];
+    static u_short attempts = 0;
+    
+    /*
+     * Make copies of apasswd and auser, then null-terminate them.
+     */
+    BCOPY(apasswd, passwd, passwdlen);
+    passwd[passwdlen] = '\0';
+    BCOPY(auser, user, userlen);
+    user[userlen] = '\0';
+    *msg = (char *) 0;
+
+    /* XXX Validate user name and password. */
+    ret = UPAP_AUTHACK;     /* XXX Assume all entries OK. */
+        
+    if (ret == UPAP_AUTHNAK) {
+        if (*msg == (char *) 0)
+            *msg = "Login incorrect";
+        *msglen = strlen(*msg);
+        /*
+         * Frustrate passwd stealer programs.
+         * Allow 10 tries, but start backing off after 3 (stolen from login).
+         * On 10'th, drop the connection.
+         */
+        if (attempts++ >= 10) {
+            AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user));
+            /*ppp_panic("Excess Bad Logins");*/
+        }
+        if (attempts > 3) {
+            sys_msleep((attempts - 3) * 5);
+        }
+        if (addrs != NULL) {
+            free_wordlist(addrs);
+        }
+    } else {
+        attempts = 0;           /* Reset count */
+        if (*msg == (char *) 0)
+            *msg = "Login ok";
+        *msglen = strlen(*msg);
+        set_allowed_addrs(unit, addrs);
+    }
+    
+    BZERO(passwd, sizeof(passwd));
+    BZERO(secret, sizeof(secret));
+    
+    return ret;
+#endif
+}
+#endif
+
+
+/*
+ * auth_ip_addr - check whether the peer is authorized to use
+ * a given IP address.  Returns 1 if authorized, 0 otherwise.
+ */
+int auth_ip_addr(int unit, u32_t addr)
+{
+    return ip_addr_check(addr, addresses[unit]);
+}
+
+/*
+ * bad_ip_adrs - return 1 if the IP address is one we don't want
+ * to use, such as an address in the loopback net or a multicast address.
+ * addr is in network byte order.
+ */
+int bad_ip_adrs(u32_t addr)
+{
+    addr = ntohl(addr);
+    return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
+        || IN_MULTICAST(addr) || IN_BADCLASS(addr);
+}
+
+
+#if CHAP_SUPPORT > 0
+/*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+ * (We could be either client or server).
+ */
+int get_secret(
+    int unit,
+    char *client,
+    char *server,
+    char *secret,
+    int *secret_len,
+    int save_addrs
+)
+{
+#if 1
+    int len;
+    struct wordlist *addrs;
+    
+    addrs = NULL;
+
+    if(!client || !client[0] || strcmp(client, ppp_settings.user)) {
+       return 0;
+    }
+
+    len = strlen(ppp_settings.passwd);
+    if (len > MAXSECRETLEN) {
+        AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));
+        len = MAXSECRETLEN;
+    }
+    BCOPY(ppp_settings.passwd, secret, len);
+    *secret_len = len;
+    
+    return 1;
+#else
+    int ret = 0, len;
+    struct wordlist *addrs;
+    char secbuf[MAXWORDLEN];
+    
+    addrs = NULL;
+    secbuf[0] = 0;
+
+    /* XXX Find secret. */  
+    if (ret < 0)
+        return 0;
+    
+    if (save_addrs)
+        set_allowed_addrs(unit, addrs);
+    
+    len = strlen(secbuf);
+    if (len > MAXSECRETLEN) {
+        AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));
+        len = MAXSECRETLEN;
+    }
+    BCOPY(secbuf, secret, len);
+    BZERO(secbuf, sizeof(secbuf));
+    *secret_len = len;
+    
+    return 1;
+#endif
+}
+#endif
+
+
+#if 0 /* UNUSED */
+/*
+ * auth_check_options - called to check authentication options.
+ */
+void auth_check_options(void)
+{
+    lcp_options *wo = &lcp_wantoptions[0];
+    int can_auth;
+    ipcp_options *ipwo = &ipcp_wantoptions[0];
+    u32_t remote;
+    
+    /* Default our_name to hostname, and user to our_name */
+    if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname)
+        strcpy(ppp_settings.our_name, ppp_settings.hostname);
+    if (ppp_settings.user[0] == 0)
+        strcpy(ppp_settings.user, ppp_settings.our_name);
+    
+    /* If authentication is required, ask peer for CHAP or PAP. */
+    if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) {
+        wo->neg_chap = 1;
+        wo->neg_upap = 1;
+    }
+    
+    /*
+     * Check whether we have appropriate secrets to use
+     * to authenticate the peer.
+     */
+    can_auth = wo->neg_upap && have_pap_secret();
+    if (!can_auth && wo->neg_chap) {
+        remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+        can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote);
+    }
+    
+    if (ppp_settings.auth_required && !can_auth) {
+        ppp_panic("No auth secret");
+    }
+}
+#endif
+
+
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+/*
+ * Proceed to the network phase.
+ */
+static void network_phase(int unit)
+{
+    int i;
+    struct protent *protp;
+    lcp_options *go = &lcp_gotoptions[unit];
+    
+    /*
+     * If the peer had to authenticate, run the auth-up script now.
+     */
+    if ((go->neg_chap || go->neg_upap) && !did_authup) {
+        /* XXX Do setup for peer authentication. */
+        did_authup = 1;
+    }
+    
+#if CBCP_SUPPORT > 0
+    /*
+     * If we negotiated callback, do it now.
+     */
+    if (go->neg_cbcp) {
+        lcp_phase[unit] = PHASE_CALLBACK;
+        (*cbcp_protent.open)(unit);
+        return;
+    }
+#endif
+    
+    lcp_phase[unit] = PHASE_NETWORK;
+    for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i)
+        if (protp->protocol < 0xC000 && protp->enabled_flag
+                && protp->open != NULL) {
+            (*protp->open)(unit);
+            if (protp->protocol != PPP_CCP)
+                ++num_np_open;
+        }
+    
+    if (num_np_open == 0)
+        /* nothing to do */
+        lcp_close(0, "No network protocols running");
+}
+
+/*
+ * check_idle - check whether the link has been idle for long
+ * enough that we can shut it down.
+ */
+static void check_idle(void *arg)
+{
+    struct ppp_idle idle;
+    u_short itime;
+    
+       (void)arg;
+    if (!get_idle_time(0, &idle))
+        return;
+    itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle);
+    if (itime >= ppp_settings.idle_time_limit) {
+        /* link is idle: shut it down. */
+        AUTHDEBUG((LOG_INFO, "Terminating connection due to lack of activity.\n"));
+        lcp_close(0, "Link inactive");
+    } else {
+        TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime);
+    }
+}
+
+/*
+ * connect_time_expired - log a message and close the connection.
+ */
+static void connect_time_expired(void *arg)
+{
+       (void)arg;
+
+    AUTHDEBUG((LOG_INFO, "Connect time expired\n"));
+    lcp_close(0, "Connect time expired");   /* Close connection */
+}
+
+#if 0
+/*
+ * login - Check the user name and password against the system
+ * password database, and login the user if OK.
+ *
+ * returns:
+ *  UPAP_AUTHNAK: Login failed.
+ *  UPAP_AUTHACK: Login succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+static int login(char *user, char *passwd, char **msg, int *msglen)
+{
+    /* XXX Fail until we decide that we want to support logins. */
+    return (UPAP_AUTHNAK);
+}
+#endif
+
+/*
+ * logout - Logout the user.
+ */
+static void logout(void)
+{
+    logged_in = 0;
+}
+
+
+/*
+ * null_login - Check if a username of "" and a password of "" are
+ * acceptable, and iff so, set the list of acceptable IP addresses
+ * and return 1.
+ */
+static int null_login(int unit)
+{
+       (void)unit;
+    /* XXX Fail until we decide that we want to support logins. */
+    return 0;
+}
+
+
+/*
+ * get_pap_passwd - get a password for authenticating ourselves with
+ * our peer using PAP.  Returns 1 on success, 0 if no suitable password
+ * could be found.
+ */
+static int get_pap_passwd(int unit, char *user, char *passwd)
+{
+/* normally we would reject PAP if no password is provided,
+   but this causes problems with some providers (like CHT in Taiwan)
+   who incorrectly request PAP and expect a bogus/empty password, so
+   always provide a default user/passwd of "none"/"none"
+*/
+    if(user)
+       strcpy(user,   "none");
+    if(passwd)
+       strcpy(passwd, "none");
+
+    return 1;
+}
+
+
+/*
+ * have_pap_secret - check whether we have a PAP file with any
+ * secrets that we could possibly use for authenticating the peer.
+ */
+static int have_pap_secret(void)
+{
+    /* XXX Fail until we set up our passwords. */
+    return 0;
+}
+
+
+/*
+ * have_chap_secret - check whether we have a CHAP file with a
+ * secret that we could possibly use for authenticating `client'
+ * on `server'.  Either can be the null string, meaning we don't
+ * know the identity yet.
+ */
+static int have_chap_secret(char *client, char *server, u32_t remote)
+{
+       (void)client;
+       (void)server;
+       (void)remote;
+    /* XXX Fail until we set up our passwords. */
+    return 0;
+}
+
+
+#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT > 0 */
+/*
+ * set_allowed_addrs() - set the list of allowed addresses.
+ */
+static void set_allowed_addrs(int unit, struct wordlist *addrs)
+{
+    if (addresses[unit] != NULL)
+        free_wordlist(addresses[unit]);
+    addresses[unit] = addrs;
+
+#if 0
+    /*
+     * If there's only one authorized address we might as well
+     * ask our peer for that one right away
+     */
+    if (addrs != NULL && addrs->next == NULL) {
+        char *p = addrs->word;
+        struct ipcp_options *wo = &ipcp_wantoptions[unit];
+        u32_t a;
+        struct hostent *hp;
+        
+        if (wo->hisaddr == 0 && *p != '!' && *p != '-'
+                && strchr(p, '/') == NULL) {
+            hp = gethostbyname(p);
+            if (hp != NULL && hp->h_addrtype == AF_INET)
+                a = *(u32_t *)hp->h_addr;
+            else
+                a = inet_addr(p);
+            if (a != (u32_t) -1)
+                wo->hisaddr = a;
+        }
+    }
+#endif
+}
+#endif
+
+static int ip_addr_check(u32_t addr, struct wordlist *addrs)
+{
+    
+    /* don't allow loopback or multicast address */
+    if (bad_ip_adrs(addr))
+        return 0;
+    
+    if (addrs == NULL)
+        return !ppp_settings.auth_required;      /* no addresses authorized */
+    
+    /* XXX All other addresses allowed. */
+    return 1;
+}
+
+#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT */
+/*
+ * free_wordlist - release memory allocated for a wordlist.
+ */
+static void free_wordlist(struct wordlist *wp)
+{
+    struct wordlist *next;
+    
+    while (wp != NULL) {
+        next = wp->next;
+        free(wp);
+        wp = next;
+    }
+}
+#endif
+
+#endif /* PPP_SUPPORT */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/auth.h b/Demo/Common/ethernet/lwIP/netif/ppp/auth.h
new file mode 100644 (file)
index 0000000..d6a5de5
--- /dev/null
@@ -0,0 +1,94 @@
+/*****************************************************************************
+* auth.h -  PPP Authentication and phase control header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1998 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original derived from BSD pppd.h.
+*****************************************************************************/
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef AUTH_H
+#define AUTH_H
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+void link_required (int);              /* we are starting to use the link */
+void link_terminated (int);    /* we are finished with the link */
+void link_down (int);                  /* the LCP layer has left the Opened state */
+void link_established (int);   /* the link is up; authenticate now */
+void np_up (int, u16_t);                       /* a network protocol has come up */
+void np_down (int, u16_t);             /* a network protocol has gone down */
+void np_finished (int, u16_t); /* a network protocol no longer needs link */
+void auth_peer_fail (int, u16_t);/* peer failed to authenticate itself */
+
+/* peer successfully authenticated itself */
+void auth_peer_success (int, u16_t, char *, int);
+
+/* we failed to authenticate ourselves */
+void auth_withpeer_fail (int, u16_t);
+
+/* we successfully authenticated ourselves */
+void auth_withpeer_success (int, u16_t);
+
+/* check authentication options supplied */
+void auth_check_options (void);
+void auth_reset (int);                 /* check what secrets we have */
+
+/* Check peer-supplied username/password */
+int  check_passwd (int, char *, int, char *, int, char **, int *);
+
+/* get "secret" for chap */
+int  get_secret (int, char *, char *, char *, int *, int);
+
+/* check if IP address is authorized */
+int  auth_ip_addr (int, u32_t);
+
+/* check if IP address is unreasonable */
+int  bad_ip_adrs (u32_t);
+
+
+#endif /* AUTH_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/chap.c b/Demo/Common/ethernet/lwIP/netif/ppp/chap.c
new file mode 100644 (file)
index 0000000..4d1dc0d
--- /dev/null
@@ -0,0 +1,872 @@
+/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/
+/*****************************************************************************
+* chap.c - Network Challenge Handshake Authentication Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original based on BSD chap.c.
+*****************************************************************************/
+/*
+ * chap.c - Challenge Handshake Authentication Protocol.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1991 Gregory M. Christy.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Gregory M. Christy.  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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "ppp.h"
+#if PPP_SUPPORT > 0
+#include "magic.h"
+
+#if CHAP_SUPPORT > 0
+
+#include "randm.h"
+#include "auth.h"
+#include "md5.h"
+#include "chap.h"
+#include "chpms.h"
+#include "pppdebug.h"
+
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+
+
+/************************/
+/*** LOCAL DATA TYPES ***/
+/************************/
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+/*
+ * Protocol entry points.
+ */
+static void ChapInit (int);
+static void ChapLowerUp (int);
+static void ChapLowerDown (int);
+static void ChapInput (int, u_char *, int);
+static void ChapProtocolReject (int);
+static int  ChapPrintPkt (u_char *, int,
+                             void (*) (void *, char *, ...), void *);
+
+static void ChapChallengeTimeout (void *);
+static void ChapResponseTimeout (void *);
+static void ChapReceiveChallenge (chap_state *, u_char *, int, int);
+static void ChapRechallenge (void *);
+static void ChapReceiveResponse (chap_state *, u_char *, int, int);
+static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
+static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
+static void ChapSendStatus (chap_state *, int);
+static void ChapSendChallenge (chap_state *);
+static void ChapSendResponse (chap_state *);
+static void ChapGenChallenge (chap_state *);
+
+
+/******************************/
+/*** PUBLIC DATA STRUCTURES ***/
+/******************************/
+chap_state chap[NUM_PPP];              /* CHAP state; one for each unit */
+
+struct protent chap_protent = {
+    PPP_CHAP,
+    ChapInit,
+    ChapInput,
+    ChapProtocolReject,
+    ChapLowerUp,
+    ChapLowerDown,
+    NULL,
+    NULL,
+#if 0
+    ChapPrintPkt,
+    NULL,
+#endif
+    1,
+    "CHAP",
+#if 0
+    NULL,
+    NULL,
+    NULL
+#endif
+};
+
+
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+static char *ChapCodenames[] = {
+       "Challenge", "Response", "Success", "Failure"
+};
+
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/*
+ * ChapAuthWithPeer - Authenticate us with our peer (start client).
+ *
+ */
+void ChapAuthWithPeer(int unit, char *our_name, int digest)
+{
+       chap_state *cstate = &chap[unit];
+       
+       cstate->resp_name = our_name;
+       cstate->resp_type = digest;
+       
+       if (cstate->clientstate == CHAPCS_INITIAL ||
+                       cstate->clientstate == CHAPCS_PENDING) {
+               /* lower layer isn't up - wait until later */
+               cstate->clientstate = CHAPCS_PENDING;
+               return;
+       }
+       
+       /*
+        * We get here as a result of LCP coming up.
+        * So even if CHAP was open before, we will 
+        * have to re-authenticate ourselves.
+        */
+       cstate->clientstate = CHAPCS_LISTEN;
+}
+
+
+/*
+ * ChapAuthPeer - Authenticate our peer (start server).
+ */
+void ChapAuthPeer(int unit, char *our_name, int digest)
+{
+       chap_state *cstate = &chap[unit];
+       
+       cstate->chal_name = our_name;
+       cstate->chal_type = digest;
+       
+       if (cstate->serverstate == CHAPSS_INITIAL ||
+                       cstate->serverstate == CHAPSS_PENDING) {
+               /* lower layer isn't up - wait until later */
+               cstate->serverstate = CHAPSS_PENDING;
+               return;
+       }
+       
+       ChapGenChallenge(cstate);
+       ChapSendChallenge(cstate);              /* crank it up dude! */
+       cstate->serverstate = CHAPSS_INITIAL_CHAL;
+}
+
+
+
+
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+/*
+ * ChapInit - Initialize a CHAP unit.
+ */
+static void ChapInit(int unit)
+{
+       chap_state *cstate = &chap[unit];
+       
+       BZERO(cstate, sizeof(*cstate));
+       cstate->unit = unit;
+       cstate->clientstate = CHAPCS_INITIAL;
+       cstate->serverstate = CHAPSS_INITIAL;
+       cstate->timeouttime = CHAP_DEFTIMEOUT;
+       cstate->max_transmits = CHAP_DEFTRANSMITS;
+       /* random number generator is initialized in magic_init */
+}
+
+
+/*
+ * ChapChallengeTimeout - Timeout expired on sending challenge.
+ */
+static void ChapChallengeTimeout(void *arg)
+{
+       chap_state *cstate = (chap_state *) arg;
+       
+       /* if we aren't sending challenges, don't worry.  then again we */
+       /* probably shouldn't be here either */
+       if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
+                       cstate->serverstate != CHAPSS_RECHALLENGE)
+               return;
+       
+       if (cstate->chal_transmits >= cstate->max_transmits) {
+               /* give up on peer */
+               CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));
+               cstate->serverstate = CHAPSS_BADAUTH;
+               auth_peer_fail(cstate->unit, PPP_CHAP);
+               return;
+       }
+       
+       ChapSendChallenge(cstate);              /* Re-send challenge */
+}
+
+
+/*
+ * ChapResponseTimeout - Timeout expired on sending response.
+ */
+static void ChapResponseTimeout(void *arg)
+{
+       chap_state *cstate = (chap_state *) arg;
+       
+       /* if we aren't sending a response, don't worry. */
+       if (cstate->clientstate != CHAPCS_RESPONSE)
+               return;
+       
+       ChapSendResponse(cstate);               /* re-send response */
+}
+
+
+/*
+ * ChapRechallenge - Time to challenge the peer again.
+ */
+static void ChapRechallenge(void *arg)
+{
+       chap_state *cstate = (chap_state *) arg;
+       
+       /* if we aren't sending a response, don't worry. */
+       if (cstate->serverstate != CHAPSS_OPEN)
+               return;
+       
+       ChapGenChallenge(cstate);
+       ChapSendChallenge(cstate);
+       cstate->serverstate = CHAPSS_RECHALLENGE;
+}
+
+
+/*
+ * ChapLowerUp - The lower layer is up.
+ *
+ * Start up if we have pending requests.
+ */
+static void ChapLowerUp(int unit)
+{
+       chap_state *cstate = &chap[unit];
+       
+       if (cstate->clientstate == CHAPCS_INITIAL)
+               cstate->clientstate = CHAPCS_CLOSED;
+       else if (cstate->clientstate == CHAPCS_PENDING)
+               cstate->clientstate = CHAPCS_LISTEN;
+       
+       if (cstate->serverstate == CHAPSS_INITIAL)
+               cstate->serverstate = CHAPSS_CLOSED;
+       else if (cstate->serverstate == CHAPSS_PENDING) {
+               ChapGenChallenge(cstate);
+               ChapSendChallenge(cstate);
+               cstate->serverstate = CHAPSS_INITIAL_CHAL;
+       }
+}
+
+
+/*
+ * ChapLowerDown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void ChapLowerDown(int unit)
+{
+       chap_state *cstate = &chap[unit];
+       
+       /* Timeout(s) pending?  Cancel if so. */
+       if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+                       cstate->serverstate == CHAPSS_RECHALLENGE)
+               UNTIMEOUT(ChapChallengeTimeout, cstate);
+       else if (cstate->serverstate == CHAPSS_OPEN
+                       && cstate->chal_interval != 0)
+               UNTIMEOUT(ChapRechallenge, cstate);
+       if (cstate->clientstate == CHAPCS_RESPONSE)
+               UNTIMEOUT(ChapResponseTimeout, cstate);
+       
+       cstate->clientstate = CHAPCS_INITIAL;
+       cstate->serverstate = CHAPSS_INITIAL;
+}
+
+
+/*
+ * ChapProtocolReject - Peer doesn't grok CHAP.
+ */
+static void ChapProtocolReject(int unit)
+{
+       chap_state *cstate = &chap[unit];
+       
+       if (cstate->serverstate != CHAPSS_INITIAL &&
+                       cstate->serverstate != CHAPSS_CLOSED)
+               auth_peer_fail(unit, PPP_CHAP);
+       if (cstate->clientstate != CHAPCS_INITIAL &&
+                       cstate->clientstate != CHAPCS_CLOSED)
+               auth_withpeer_fail(unit, PPP_CHAP);
+       ChapLowerDown(unit);            /* shutdown chap */
+}
+
+
+/*
+ * ChapInput - Input CHAP packet.
+ */
+static void ChapInput(int unit, u_char *inpacket, int packet_len)
+{
+       chap_state *cstate = &chap[unit];
+       u_char *inp;
+       u_char code, id;
+       int len;
+       
+       /*
+        * Parse header (code, id and length).
+        * If packet too short, drop it.
+        */
+       inp = inpacket;
+       if (packet_len < CHAP_HEADERLEN) {
+               CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));
+               return;
+       }
+       GETCHAR(code, inp);
+       GETCHAR(id, inp);
+       GETSHORT(len, inp);
+       if (len < CHAP_HEADERLEN) {
+               CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));
+               return;
+       }
+       if (len > packet_len) {
+               CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));
+               return;
+       }
+       len -= CHAP_HEADERLEN;
+       
+       /*
+        * Action depends on code (as in fact it usually does :-).
+        */
+       switch (code) {
+       case CHAP_CHALLENGE:
+               ChapReceiveChallenge(cstate, inp, id, len);
+               break;
+       
+       case CHAP_RESPONSE:
+               ChapReceiveResponse(cstate, inp, id, len);
+               break;
+       
+       case CHAP_FAILURE:
+               ChapReceiveFailure(cstate, inp, id, len);
+               break;
+       
+       case CHAP_SUCCESS:
+               ChapReceiveSuccess(cstate, inp, id, len);
+               break;
+       
+       default:                                /* Need code reject? */
+               CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));
+               break;
+       }
+}
+
+
+/*
+ * ChapReceiveChallenge - Receive Challenge and send Response.
+ */
+static void ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
+{
+       int rchallenge_len;
+       u_char *rchallenge;
+       int secret_len;
+       char secret[MAXSECRETLEN];
+       char rhostname[256];
+       MD5_CTX mdContext;
+       u_char hash[MD5_SIGNATURE_SIZE];
+       
+       CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));
+       if (cstate->clientstate == CHAPCS_CLOSED ||
+               cstate->clientstate == CHAPCS_PENDING) {
+               CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",
+                          cstate->clientstate));
+               return;
+       }
+       
+       if (len < 2) {
+               CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
+               return;
+       }
+       
+       GETCHAR(rchallenge_len, inp);
+       len -= sizeof (u_char) + rchallenge_len;        /* now name field length */
+       if (len < 0) {
+               CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
+               return;
+       }
+       rchallenge = inp;
+       INCPTR(rchallenge_len, inp);
+       
+       if (len >= sizeof(rhostname))
+               len = sizeof(rhostname) - 1;
+       BCOPY(inp, rhostname, len);
+       rhostname[len] = '\000';
+       
+       CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n",
+              rhostname));
+       
+       /* Microsoft doesn't send their name back in the PPP packet */
+       if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
+               strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
+               rhostname[sizeof(rhostname) - 1] = 0;
+               CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n",
+                          rhostname));
+       }
+       
+       /* get secret for authenticating ourselves with the specified host */
+       if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+                           secret, &secret_len, 0)) {
+               secret_len = 0;         /* assume null secret if can't find one */
+               CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));
+       }
+       
+       /* cancel response send timeout if necessary */
+       if (cstate->clientstate == CHAPCS_RESPONSE)
+               UNTIMEOUT(ChapResponseTimeout, cstate);
+       
+       cstate->resp_id = id;
+       cstate->resp_transmits = 0;
+       
+       /*  generate MD based on negotiated type */
+       switch (cstate->resp_type) { 
+       
+       case CHAP_DIGEST_MD5:
+               MD5Init(&mdContext);
+               MD5Update(&mdContext, &cstate->resp_id, 1);
+               MD5Update(&mdContext, (u_char*)secret, secret_len);
+               MD5Update(&mdContext, rchallenge, rchallenge_len);
+               MD5Final(hash, &mdContext);
+               BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
+               cstate->resp_length = MD5_SIGNATURE_SIZE;
+               break;
+       
+#ifdef CHAPMS
+       case CHAP_MICROSOFT:
+               ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
+               break;
+#endif
+       
+       default:
+               CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));
+               return;
+       }
+       
+       BZERO(secret, sizeof(secret));
+       ChapSendResponse(cstate);
+}
+
+
+/*
+ * ChapReceiveResponse - Receive and process response.
+ */
+static void ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
+{
+       u_char *remmd, remmd_len;
+       int secret_len, old_state;
+       int code;
+       char rhostname[256];
+       MD5_CTX mdContext;
+       char secret[MAXSECRETLEN];
+       u_char hash[MD5_SIGNATURE_SIZE];
+       
+       CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));
+       
+       if (cstate->serverstate == CHAPSS_CLOSED ||
+                       cstate->serverstate == CHAPSS_PENDING) {
+               CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",
+               cstate->serverstate));
+               return;
+       }
+       
+       if (id != cstate->chal_id)
+               return;                 /* doesn't match ID of last challenge */
+       
+       /*
+       * If we have received a duplicate or bogus Response,
+       * we have to send the same answer (Success/Failure)
+       * as we did for the first Response we saw.
+       */
+       if (cstate->serverstate == CHAPSS_OPEN) {
+               ChapSendStatus(cstate, CHAP_SUCCESS);
+               return;
+       }
+       if (cstate->serverstate == CHAPSS_BADAUTH) {
+               ChapSendStatus(cstate, CHAP_FAILURE);
+               return;
+       }
+       
+       if (len < 2) {
+               CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
+               return;
+       }
+       GETCHAR(remmd_len, inp);                /* get length of MD */
+       remmd = inp;                    /* get pointer to MD */
+       INCPTR(remmd_len, inp);
+       
+       len -= sizeof (u_char) + remmd_len;
+       if (len < 0) {
+               CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
+               return;
+       }
+       
+       UNTIMEOUT(ChapChallengeTimeout, cstate);
+       
+       if (len >= sizeof(rhostname))
+               len = sizeof(rhostname) - 1;
+       BCOPY(inp, rhostname, len);
+       rhostname[len] = '\000';
+       
+       CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n",
+                               rhostname));
+       
+       /*
+       * Get secret for authenticating them with us,
+       * do the hash ourselves, and compare the result.
+       */
+       code = CHAP_FAILURE;
+       if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
+       secret, &secret_len, 1)) {
+/*        CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */
+               CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",
+               rhostname));
+       } else {
+       
+               /*  generate MD based on negotiated type */
+               switch (cstate->chal_type) { 
+               
+               case CHAP_DIGEST_MD5:           /* only MD5 is defined for now */
+                       if (remmd_len != MD5_SIGNATURE_SIZE)
+                               break;                  /* it's not even the right length */
+                       MD5Init(&mdContext);
+                       MD5Update(&mdContext, &cstate->chal_id, 1);
+                       MD5Update(&mdContext, (u_char*)secret, secret_len);
+                       MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+                       MD5Final(hash, &mdContext); 
+                       
+                       /* compare local and remote MDs and send the appropriate status */
+                       if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
+                               code = CHAP_SUCCESS;    /* they are the same! */
+                       break;
+               
+               default:
+                       CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));
+               }
+       }
+       
+       BZERO(secret, sizeof(secret));
+       ChapSendStatus(cstate, code);
+       
+       if (code == CHAP_SUCCESS) {
+               old_state = cstate->serverstate;
+               cstate->serverstate = CHAPSS_OPEN;
+               if (old_state == CHAPSS_INITIAL_CHAL) {
+                       auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
+               }
+               if (cstate->chal_interval != 0)
+                       TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
+       } else {
+               CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));
+               cstate->serverstate = CHAPSS_BADAUTH;
+               auth_peer_fail(cstate->unit, PPP_CHAP);
+       }
+}
+
+/*
+ * ChapReceiveSuccess - Receive Success
+ */
+static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
+{
+
+       CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));
+       
+       if (cstate->clientstate == CHAPCS_OPEN)
+               /* presumably an answer to a duplicate response */
+               return;
+       
+       if (cstate->clientstate != CHAPCS_RESPONSE) {
+               /* don't know what this is */
+               CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
+                          cstate->clientstate));
+               return;
+       }
+       
+       UNTIMEOUT(ChapResponseTimeout, cstate);
+       
+       /*
+        * Print message.
+        */
+       if (len > 0)
+               PRINTMSG(inp, len);
+       
+       cstate->clientstate = CHAPCS_OPEN;
+       
+       auth_withpeer_success(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapReceiveFailure - Receive failure.
+ */
+static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
+{
+       CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));
+       
+       if (cstate->clientstate != CHAPCS_RESPONSE) {
+               /* don't know what this is */
+               CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
+                          cstate->clientstate));
+               return;
+       }
+       
+       UNTIMEOUT(ChapResponseTimeout, cstate);
+       
+       /*
+        * Print message.
+        */
+       if (len > 0)
+               PRINTMSG(inp, len);
+       
+       CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));
+       auth_withpeer_fail(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapSendChallenge - Send an Authenticate challenge.
+ */
+static void ChapSendChallenge(chap_state *cstate)
+{
+       u_char *outp;
+       int chal_len, name_len;
+       int outlen;
+       
+       chal_len = cstate->chal_len;
+       name_len = strlen(cstate->chal_name);
+       outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
+       outp = outpacket_buf[cstate->unit];
+       
+       MAKEHEADER(outp, PPP_CHAP);             /* paste in a CHAP header */
+       
+       PUTCHAR(CHAP_CHALLENGE, outp);
+       PUTCHAR(cstate->chal_id, outp);
+       PUTSHORT(outlen, outp);
+       
+       PUTCHAR(chal_len, outp);                /* put length of challenge */
+       BCOPY(cstate->challenge, outp, chal_len);
+       INCPTR(chal_len, outp);
+       
+       BCOPY(cstate->chal_name, outp, name_len);       /* append hostname */
+       
+       pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
+       
+       CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
+       
+       TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
+       ++cstate->chal_transmits;
+}
+
+
+/*
+ * ChapSendStatus - Send a status response (ack or nak).
+ */
+static void ChapSendStatus(chap_state *cstate, int code)
+{
+       u_char *outp;
+       int outlen, msglen;
+       char msg[256];
+       
+       if (code == CHAP_SUCCESS)
+               strcpy(msg, "Welcome!");
+       else
+               strcpy(msg, "I don't like you.  Go 'way.");
+       msglen = strlen(msg);
+       
+       outlen = CHAP_HEADERLEN + msglen;
+       outp = outpacket_buf[cstate->unit];
+       
+       MAKEHEADER(outp, PPP_CHAP);             /* paste in a header */
+       
+       PUTCHAR(code, outp);
+       PUTCHAR(cstate->chal_id, outp);
+       PUTSHORT(outlen, outp);
+       BCOPY(msg, outp, msglen);
+       pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
+       
+       CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code,
+              cstate->chal_id));
+}
+
+/*
+ * ChapGenChallenge is used to generate a pseudo-random challenge string of
+ * a pseudo-random length between min_len and max_len.  The challenge
+ * string and its length are stored in *cstate, and various other fields of
+ * *cstate are initialized.
+ */
+
+static void ChapGenChallenge(chap_state *cstate)
+{
+       int chal_len;
+       u_char *ptr = cstate->challenge;
+       int i;
+       
+       /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
+          MAX_CHALLENGE_LENGTH */  
+       chal_len = (unsigned)
+                               ((((magic() >> 16) *
+                               (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
+                            + MIN_CHALLENGE_LENGTH);
+       cstate->chal_len = chal_len;
+       cstate->chal_id = ++cstate->id;
+       cstate->chal_transmits = 0;
+       
+       /* generate a random string */
+       for (i = 0; i < chal_len; i++ )
+               *ptr++ = (char) (magic() & 0xff);
+}
+
+/*
+ * ChapSendResponse - send a response packet with values as specified
+ * in *cstate.
+ */
+/* ARGSUSED */
+static void ChapSendResponse(chap_state *cstate)
+{
+       u_char *outp;
+       int outlen, md_len, name_len;
+       
+       md_len = cstate->resp_length;
+       name_len = strlen(cstate->resp_name);
+       outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
+       outp = outpacket_buf[cstate->unit];
+       
+       MAKEHEADER(outp, PPP_CHAP);
+       
+       PUTCHAR(CHAP_RESPONSE, outp);   /* we are a response */
+       PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
+       PUTSHORT(outlen, outp);                 /* packet length */
+       
+       PUTCHAR(md_len, outp);                  /* length of MD */
+       BCOPY(cstate->response, outp, md_len);          /* copy MD to buffer */
+       INCPTR(md_len, outp);
+       
+       BCOPY(cstate->resp_name, outp, name_len);       /* append our name */
+       
+       /* send the packet */
+       pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
+       
+       cstate->clientstate = CHAPCS_RESPONSE;
+       TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
+       ++cstate->resp_transmits;
+}
+
+/*
+ * ChapPrintPkt - print the contents of a CHAP packet.
+ */
+static int ChapPrintPkt(
+       u_char *p,
+       int plen,
+       void (*printer) (void *, char *, ...),
+       void *arg
+)
+{
+       int code, id, len;
+       int clen, nlen;
+       u_char x;
+       
+       if (plen < CHAP_HEADERLEN)
+               return 0;
+       GETCHAR(code, p);
+       GETCHAR(id, p);
+       GETSHORT(len, p);
+       if (len < CHAP_HEADERLEN || len > plen)
+               return 0;
+       
+       if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
+               printer(arg, " %s", ChapCodenames[code-1]);
+       else
+               printer(arg, " code=0x%x", code);
+       printer(arg, " id=0x%x", id);
+       len -= CHAP_HEADERLEN;
+       switch (code) {
+       case CHAP_CHALLENGE:
+       case CHAP_RESPONSE:
+               if (len < 1)
+                       break;
+               clen = p[0];
+               if (len < clen + 1)
+                       break;
+               ++p;
+               nlen = len - clen - 1;
+               printer(arg, " <");
+               for (; clen > 0; --clen) {
+                       GETCHAR(x, p);
+                       printer(arg, "%.2x", x);
+               }
+               printer(arg, ">, name = %.*Z", nlen, p);
+               break;
+       case CHAP_FAILURE:
+       case CHAP_SUCCESS:
+               printer(arg, " %.*Z", len, p);
+               break;
+       default:
+               for (clen = len; clen > 0; --clen) {
+                       GETCHAR(x, p);
+                       printer(arg, " %.2x", x);
+               }
+       }
+       
+       return len + CHAP_HEADERLEN;
+}
+
+#endif
+
+#endif /* PPP_SUPPORT */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/chap.h b/Demo/Common/ethernet/lwIP/netif/ppp/chap.h
new file mode 100644 (file)
index 0000000..6fd9727
--- /dev/null
@@ -0,0 +1,167 @@
+/*****************************************************************************
+* chap.h - Network Challenge Handshake Authentication Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1998 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original built from BSD network code.
+******************************************************************************/
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1991 Gregory M. Christy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the author.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap.h,v 1.1 2003/05/27 14:37:56 jani Exp $
+ */
+
+#ifndef CHAP_H
+#define CHAP_H
+
+/*************************
+*** PUBLIC DEFINITIONS ***
+*************************/
+
+/* Code + ID + length */
+#define CHAP_HEADERLEN         4
+
+/*
+ * CHAP codes.
+ */
+
+#define CHAP_DIGEST_MD5                5       /* use MD5 algorithm */
+#define MD5_SIGNATURE_SIZE     16      /* 16 bytes in a MD5 message digest */
+#define CHAP_MICROSOFT         0x80    /* use Microsoft-compatible alg. */
+#define MS_CHAP_RESPONSE_LEN   49      /* Response length for MS-CHAP */
+
+#define CHAP_CHALLENGE         1
+#define CHAP_RESPONSE          2
+#define CHAP_SUCCESS           3
+#define CHAP_FAILURE           4
+
+/*
+ *  Challenge lengths (for challenges we send) and other limits.
+ */
+#define MIN_CHALLENGE_LENGTH   32
+#define MAX_CHALLENGE_LENGTH   64
+#define MAX_RESPONSE_LENGTH    64      /* sufficient for MD5 or MS-CHAP */
+
+/*
+ * Client (peer) states.
+ */
+#define CHAPCS_INITIAL         0       /* Lower layer down, not opened */
+#define CHAPCS_CLOSED          1       /* Lower layer up, not opened */
+#define CHAPCS_PENDING         2       /* Auth us to peer when lower up */
+#define CHAPCS_LISTEN          3       /* Listening for a challenge */
+#define CHAPCS_RESPONSE                4       /* Sent response, waiting for status */
+#define CHAPCS_OPEN            5       /* We've received Success */
+
+/*
+ * Server (authenticator) states.
+ */
+#define CHAPSS_INITIAL         0       /* Lower layer down, not opened */
+#define CHAPSS_CLOSED          1       /* Lower layer up, not opened */
+#define CHAPSS_PENDING         2       /* Auth peer when lower up */
+#define CHAPSS_INITIAL_CHAL    3       /* We've sent the first challenge */
+#define CHAPSS_OPEN            4       /* We've sent a Success msg */
+#define CHAPSS_RECHALLENGE     5       /* We've sent another challenge */
+#define CHAPSS_BADAUTH         6       /* We've sent a Failure msg */
+
+/************************
+*** PUBLIC DATA TYPES ***
+************************/
+
+/*
+ * Each interface is described by a chap structure.
+ */
+
+typedef struct chap_state {
+    int unit;                  /* Interface unit number */
+    int clientstate;           /* Client state */
+    int serverstate;           /* Server state */
+    u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
+    u_char chal_len;           /* challenge length */
+    u_char chal_id;            /* ID of last challenge */
+    u_char chal_type;          /* hash algorithm for challenges */
+    u_char id;                 /* Current id */
+    char *chal_name;           /* Our name to use with challenge */
+    int chal_interval;         /* Time until we challenge peer again */
+    int timeouttime;           /* Timeout time in seconds */
+    int max_transmits;         /* Maximum # of challenge transmissions */
+    int chal_transmits;                /* Number of transmissions of challenge */
+    int resp_transmits;                /* Number of transmissions of response */
+    u_char response[MAX_RESPONSE_LENGTH];      /* Response to send */
+    u_char resp_length;                /* length of response */
+    u_char resp_id;            /* ID for response messages */
+    u_char resp_type;          /* hash algorithm for responses */
+    char *resp_name;           /* Our name to send with response */
+} chap_state;
+
+
+/******************
+*** PUBLIC DATA ***
+******************/
+extern chap_state chap[];
+
+extern struct protent chap_protent;
+
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+
+void ChapAuthWithPeer (int, char *, int);
+void ChapAuthPeer (int, char *, int);
+
+#endif /* CHAP_H */
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/chpms.c b/Demo/Common/ethernet/lwIP/netif/ppp/chpms.c
new file mode 100644 (file)
index 0000000..01755ba
--- /dev/null
@@ -0,0 +1,398 @@
+/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
+/*****************************************************************************
+* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original based on BSD chap_ms.c.
+*****************************************************************************/
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist.  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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
+ *
+ *   Implemented LANManager type password response to MS-CHAP challenges.
+ *   Now pppd provides both NT style and LANMan style blocks, and the
+ *   prefered is set by option "ms-lanman". Default is to use NT.
+ *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
+ *
+ *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
+ */
+
+#define USE_CRYPT
+
+
+#include "ppp.h"
+
+#if MSCHAP_SUPPORT > 0
+
+#include "md4.h"
+#ifndef USE_CRYPT
+#include "des.h"
+#endif
+#include "chap.h"
+#include "chpms.h"
+#include "pppdebug.h"
+
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+
+
+/************************/
+/*** LOCAL DATA TYPES ***/
+/************************/
+typedef struct {
+    u_char LANManResp[24];
+    u_char NTResp[24];
+    u_char UseNT;              /* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
+   in case this struct gets padded. */
+
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+
+/* XXX Don't know what to do with these. */
+extern void setkey(const char *);
+extern void encrypt(char *, int);
+
+static void    DesEncrypt (u_char *, u_char *, u_char *);
+static void    MakeKey (u_char *, u_char *);
+
+#ifdef USE_CRYPT
+static void    Expand (u_char *, u_char *);
+static void    Collapse (u_char *, u_char *);
+#endif
+
+static void ChallengeResponse(
+       u_char *challenge,      /* IN   8 octets */
+       u_char *pwHash,         /* IN  16 octets */
+       u_char *response        /* OUT 24 octets */
+);
+static void ChapMS_NT(
+       char *rchallenge,
+       int rchallenge_len,
+       char *secret,
+       int secret_len,
+       MS_ChapResponse *response
+);
+static u_char Get7Bits(
+       u_char *input,
+       int startBit
+);
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+void ChapMS(
+       chap_state *cstate,
+       char *rchallenge,
+       int rchallenge_len,
+       char *secret,
+       int secret_len
+)
+{
+       MS_ChapResponse response;
+#ifdef MSLANMAN
+       extern int ms_lanman;
+#endif
+       
+#if 0
+       CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));
+#endif
+       BZERO(&response, sizeof(response));
+       
+       /* Calculate both always */
+       ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
+       
+#ifdef MSLANMAN
+       ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
+       
+       /* prefered method is set by option  */
+       response.UseNT = !ms_lanman;
+#else
+       response.UseNT = 1;
+#endif
+       
+       BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+       cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+}
+
+
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+static void ChallengeResponse(
+       u_char *challenge,      /* IN   8 octets */
+       u_char *pwHash,         /* IN  16 octets */
+       u_char *response        /* OUT 24 octets */
+)
+{
+       char    ZPasswordHash[21];
+       
+       BZERO(ZPasswordHash, sizeof(ZPasswordHash));
+       BCOPY(pwHash, ZPasswordHash, 16);
+       
+#if 0
+       log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
+#endif
+       
+       DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
+       DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
+       DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
+       
+#if 0
+       log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
+#endif
+}
+
+
+#ifdef USE_CRYPT
+static void DesEncrypt(
+       u_char *clear,  /* IN  8 octets */
+       u_char *key,    /* IN  7 octets */
+       u_char *cipher  /* OUT 8 octets */
+)
+{
+       u_char des_key[8];
+       u_char crypt_key[66];
+       u_char des_input[66];
+       
+       MakeKey(key, des_key);
+       
+       Expand(des_key, crypt_key);
+       setkey(crypt_key);
+       
+#if 0
+       CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
+              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+       
+       Expand(clear, des_input);
+       encrypt(des_input, 0);
+       Collapse(des_input, cipher);
+       
+#if 0
+       CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
+              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+#else /* USE_CRYPT */
+
+static void DesEncrypt(
+       u_char *clear,  /* IN  8 octets */
+       u_char *key,    /* IN  7 octets */
+       u_char *cipher  /* OUT 8 octets */
+)
+{
+       des_cblock              des_key;
+       des_key_schedule        key_schedule;
+       
+       MakeKey(key, des_key);
+       
+       des_set_key(&des_key, key_schedule);
+       
+#if 0
+       CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
+              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+       
+       des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+       
+#if 0
+       CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
+              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+#endif /* USE_CRYPT */
+
+
+static u_char Get7Bits(
+       u_char *input,
+       int startBit
+)
+{
+       register unsigned int   word;
+       
+       word  = (unsigned)input[startBit / 8] << 8;
+       word |= (unsigned)input[startBit / 8 + 1];
+       
+       word >>= 15 - (startBit % 8 + 7);
+       
+       return word & 0xFE;
+}
+
+#ifdef USE_CRYPT
+
+/* in == 8-byte string (expanded version of the 56-bit key)
+ * out == 64-byte string where each byte is either 1 or 0
+ * Note that the low-order "bit" is always ignored by by setkey()
+ */
+static void Expand(u_char *in, u_char *out)
+{
+       int j, c;
+       int i;
+       
+       for(i = 0; i < 64; in++){
+               c = *in;
+               for(j = 7; j >= 0; j--)
+                       *out++ = (c >> j) & 01;
+               i += 8;
+       }
+}
+
+/* The inverse of Expand
+ */
+static void Collapse(u_char *in, u_char *out)
+{
+       int j;
+       int i;
+       unsigned int c;
+       
+       for (i = 0; i < 64; i += 8, out++) {
+               c = 0;
+               for (j = 7; j >= 0; j--, in++)
+                       c |= *in << j;
+               *out = c & 0xff;
+       }
+}
+#endif
+
+static void MakeKey(
+       u_char *key,            /* IN  56 bit DES key missing parity bits */
+       u_char *des_key         /* OUT 64 bit DES key with parity bits added */
+)
+{
+       des_key[0] = Get7Bits(key,  0);
+       des_key[1] = Get7Bits(key,  7);
+       des_key[2] = Get7Bits(key, 14);
+       des_key[3] = Get7Bits(key, 21);
+       des_key[4] = Get7Bits(key, 28);
+       des_key[5] = Get7Bits(key, 35);
+       des_key[6] = Get7Bits(key, 42);
+       des_key[7] = Get7Bits(key, 49);
+       
+#ifndef USE_CRYPT
+       des_set_odd_parity((des_cblock *)des_key);
+#endif
+       
+#if 0
+       CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
+              key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
+       CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
+              des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
+#endif
+}
+
+static void ChapMS_NT(
+       char *rchallenge,
+       int rchallenge_len,
+       char *secret,
+       int secret_len,
+       MS_ChapResponse *response
+)
+{
+       int                     i;
+       MDstruct        md4Context;
+       u_char          unicodePassword[MAX_NT_PASSWORD * 2];
+       static int      low_byte_first = -1;
+       
+       /* Initialize the Unicode version of the secret (== password). */
+       /* This implicitly supports 8-bit ISO8859/1 characters. */
+       BZERO(unicodePassword, sizeof(unicodePassword));
+       for (i = 0; i < secret_len; i++)
+               unicodePassword[i * 2] = (u_char)secret[i];
+       
+       MDbegin(&md4Context);
+       MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);     /* Unicode is 2 bytes/char, *8 for bit count */
+       
+       if (low_byte_first == -1)
+               low_byte_first = (htons((unsigned short int)1) != 1);
+       if (low_byte_first == 0)
+               MDreverse((u_long *)&md4Context);  /*  sfb 961105 */
+       
+       MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
+       
+       ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);
+}
+
+#ifdef MSLANMAN
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
+
+static ChapMS_LANMan(
+       char *rchallenge,
+       int rchallenge_len,
+       char *secret,
+       int secret_len,
+       MS_ChapResponse *response
+)
+{
+       int                     i;
+       u_char          UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
+       u_char          PasswordHash[16];
+       
+       /* LANMan password is case insensitive */
+       BZERO(UcasePassword, sizeof(UcasePassword));
+       for (i = 0; i < secret_len; i++)
+               UcasePassword[i] = (u_char)toupper(secret[i]);
+       DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
+       DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
+       ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
+}
+#endif
+
+#endif /* MSCHAP_SUPPORT */
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/chpms.h b/Demo/Common/ethernet/lwIP/netif/ppp/chpms.h
new file mode 100644 (file)
index 0000000..c584472
--- /dev/null
@@ -0,0 +1,64 @@
+/*****************************************************************************
+* chpms.h - Network Microsoft Challenge Handshake Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1998 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 98-01-30 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original built from BSD network code.
+******************************************************************************/
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist.  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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chpms.h,v 1.3 2004/02/07 00:30:03 likewise Exp $
+ */
+
+#ifndef CHPMS_H
+#define CHPMS_H
+
+#define MAX_NT_PASSWORD        256     /* Maximum number of (Unicode) chars in an NT password */
+
+void ChapMS (chap_state *, char *, int, char *, int);
+
+#endif /* CHPMS_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/fsm.c b/Demo/Common/ethernet/lwIP/netif/ppp/fsm.c
new file mode 100644 (file)
index 0000000..fe8b38a
--- /dev/null
@@ -0,0 +1,838 @@
+/*****************************************************************************
+* fsm.c - Network Control Protocol Finite State Machine program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original based on BSD fsm.c.
+*****************************************************************************/
+/*
+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ * TODO:
+ * Randomize fsm id on link/init.
+ * Deal with variable outgoing MTU.
+ */
+
+#include "ppp.h"
+#if PPP_SUPPORT > 0
+#include "fsm.h"
+#include "pppdebug.h"
+
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+
+
+/************************/
+/*** LOCAL DATA TYPES ***/
+/************************/
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+static void fsm_timeout (void *);
+static void fsm_rconfreq (fsm *, u_char, u_char *, int);
+static void fsm_rconfack (fsm *, int, u_char *, int);
+static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
+static void fsm_rtermreq (fsm *, int, u_char *, int);
+static void fsm_rtermack (fsm *);
+static void fsm_rcoderej (fsm *, u_char *, int);
+static void fsm_sconfreq (fsm *, int);
+
+#define PROTO_NAME(f)  ((f)->callbacks->proto_name)
+
+
+/******************************/
+/*** PUBLIC DATA STRUCTURES ***/
+/******************************/
+
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+int peer_mru[NUM_PPP];
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+
+/*
+ * fsm_init - Initialize fsm.
+ *
+ * Initialize fsm state.
+ */
+void fsm_init(fsm *f)
+{
+       f->state = INITIAL;
+       f->flags = 0;
+       f->id = 0;                              /* XXX Start with random id? */
+       f->timeouttime = FSM_DEFTIMEOUT;
+       f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
+       f->maxtermtransmits = FSM_DEFMAXTERMREQS;
+       f->maxnakloops = FSM_DEFMAXNAKLOOPS;
+       f->term_reason_len = 0;
+}
+
+
+/*
+ * fsm_lowerup - The lower layer is up.
+ */
+void fsm_lowerup(fsm *f)
+{
+       int oldState = f->state;
+
+       switch( f->state ){
+       case INITIAL:
+               f->state = CLOSED;
+               break;
+       
+       case STARTING:
+               if( f->flags & OPT_SILENT )
+                       f->state = STOPPED;
+               else {
+                       /* Send an initial configure-request */
+                       fsm_sconfreq(f, 0);
+                       f->state = REQSENT;
+               }
+       break;
+       
+       default:
+               FSMDEBUG((LOG_INFO, "%s: Up event in state %d!\n",
+                               PROTO_NAME(f), f->state));
+       }
+       
+       FSMDEBUG((LOG_INFO, "%s: lowerup state %d -> %d\n",
+                       PROTO_NAME(f), oldState, f->state));
+}
+
+
+/*
+ * fsm_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts and inform upper layers.
+ */
+void fsm_lowerdown(fsm *f)
+{
+       int oldState = f->state;
+       
+       switch( f->state ){
+       case CLOSED:
+               f->state = INITIAL;
+               break;
+       
+       case STOPPED:
+               f->state = STARTING;
+               if( f->callbacks->starting )
+                       (*f->callbacks->starting)(f);
+               break;
+       
+       case CLOSING:
+               f->state = INITIAL;
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               break;
+       
+       case STOPPING:
+       case REQSENT:
+       case ACKRCVD:
+       case ACKSENT:
+               f->state = STARTING;
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               break;
+       
+       case OPENED:
+               if( f->callbacks->down )
+                       (*f->callbacks->down)(f);
+               f->state = STARTING;
+               break;
+       
+       default:
+               FSMDEBUG((LOG_INFO, "%s: Down event in state %d!\n",
+                               PROTO_NAME(f), f->state));
+       }
+       
+       FSMDEBUG((LOG_INFO, "%s: lowerdown state %d -> %d\n",
+                       PROTO_NAME(f), oldState, f->state));
+}
+
+
+/*
+ * fsm_open - Link is allowed to come up.
+ */
+void fsm_open(fsm *f)
+{
+       int oldState = f->state;
+       
+       switch( f->state ){
+               case INITIAL:
+                       f->state = STARTING;
+                       if( f->callbacks->starting )
+                               (*f->callbacks->starting)(f);
+                       break;
+               
+               case CLOSED:
+               if( f->flags & OPT_SILENT )
+                       f->state = STOPPED;
+               else {
+                       /* Send an initial configure-request */
+                       fsm_sconfreq(f, 0);
+                       f->state = REQSENT;
+               }
+               break;
+       
+       case CLOSING:
+               f->state = STOPPING;
+               /* fall through */
+       case STOPPED:
+       case OPENED:
+               if( f->flags & OPT_RESTART ){
+                       fsm_lowerdown(f);
+                       fsm_lowerup(f);
+               }
+               break;
+       }
+       
+       FSMDEBUG((LOG_INFO, "%s: open state %d -> %d\n",
+                       PROTO_NAME(f), oldState, f->state));
+}
+
+
+/*
+ * fsm_close - Start closing connection.
+ *
+ * Cancel timeouts and either initiate close or possibly go directly to
+ * the CLOSED state.
+ */
+void fsm_close(fsm *f, char *reason)
+{
+       int oldState = f->state;
+       
+       f->term_reason = reason;
+       f->term_reason_len = (reason == NULL? 0: strlen(reason));
+       switch( f->state ){
+       case STARTING:
+               f->state = INITIAL;
+               break;
+       case STOPPED:
+               f->state = CLOSED;
+               break;
+       case STOPPING:
+               f->state = CLOSING;
+               break;
+       
+       case REQSENT:
+       case ACKRCVD:
+       case ACKSENT:
+       case OPENED:
+               if( f->state != OPENED )
+                       UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               else if( f->callbacks->down )
+                       (*f->callbacks->down)(f);       /* Inform upper layers we're down */
+               
+               /* Init restart counter, send Terminate-Request */
+               f->retransmits = f->maxtermtransmits;
+               fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+                                       (u_char *) f->term_reason, f->term_reason_len);
+               TIMEOUT(fsm_timeout, f, f->timeouttime);
+               --f->retransmits;
+               
+               f->state = CLOSING;
+               break;
+       }
+       
+       FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d -> %d\n",
+                       PROTO_NAME(f), reason, oldState, f->state));
+}
+
+
+/*
+ * fsm_sdata - Send some data.
+ *
+ * Used for all packets sent to our peer by this module.
+ */
+void fsm_sdata(
+       fsm *f,
+       u_char code, 
+       u_char id,
+       u_char *data,
+       int datalen
+)
+{
+       u_char *outp;
+       int outlen;
+       
+       /* Adjust length to be smaller than MTU */
+       outp = outpacket_buf[f->unit];
+       if (datalen > peer_mru[f->unit] - (int)HEADERLEN)
+               datalen = peer_mru[f->unit] - HEADERLEN;
+       if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
+               BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
+       outlen = datalen + HEADERLEN;
+       MAKEHEADER(outp, f->protocol);
+       PUTCHAR(code, outp);
+       PUTCHAR(id, outp);
+       PUTSHORT(outlen, outp);
+       pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
+       FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n",
+                               PROTO_NAME(f), code, id, outlen));
+}
+
+
+/*
+ * fsm_input - Input packet.
+ */
+void fsm_input(fsm *f, u_char *inpacket, int l)
+{
+       u_char *inp = inpacket;
+       u_char code, id;
+       int len;
+       
+       /*
+       * Parse header (code, id and length).
+       * If packet too short, drop it.
+       */
+       if (l < HEADERLEN) {
+               FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n",
+                                       f->protocol));
+               return;
+       }
+       GETCHAR(code, inp);
+       GETCHAR(id, inp);
+       GETSHORT(len, inp);
+       if (len < HEADERLEN) {
+               FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n",
+                               f->protocol));
+               return;
+       }
+       if (len > l) {
+               FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n",
+                               f->protocol));
+               return;
+       }
+       len -= HEADERLEN;               /* subtract header length */
+       
+       if( f->state == INITIAL || f->state == STARTING ){
+               FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.\n",
+                               f->protocol, f->state));
+               return;
+       }
+       FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
+       /*
+        * Action depends on code.
+        */
+       switch (code) {
+       case CONFREQ:
+               fsm_rconfreq(f, id, inp, len);
+               break;
+       
+       case CONFACK:
+               fsm_rconfack(f, id, inp, len);
+               break;
+       
+       case CONFNAK:
+       case CONFREJ:
+               fsm_rconfnakrej(f, code, id, inp, len);
+               break;
+       
+       case TERMREQ:
+               fsm_rtermreq(f, id, inp, len);
+               break;
+       
+       case TERMACK:
+               fsm_rtermack(f);
+               break;
+       
+       case CODEREJ:
+               fsm_rcoderej(f, inp, len);
+               break;
+       
+       default:
+               if( !f->callbacks->extcode
+                               || !(*f->callbacks->extcode)(f, code, id, inp, len) )
+                       fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
+               break;
+       }
+}
+
+
+/*
+ * fsm_protreject - Peer doesn't speak this protocol.
+ *
+ * Treat this as a catastrophic error (RXJ-).
+ */
+void fsm_protreject(fsm *f)
+{
+       switch( f->state ){
+       case CLOSING:
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               /* fall through */
+       case CLOSED:
+               f->state = CLOSED;
+               if( f->callbacks->finished )
+                       (*f->callbacks->finished)(f);
+               break;
+       
+       case STOPPING:
+       case REQSENT:
+       case ACKRCVD:
+       case ACKSENT:
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               /* fall through */
+       case STOPPED:
+               f->state = STOPPED;
+               if( f->callbacks->finished )
+                       (*f->callbacks->finished)(f);
+               break;
+       
+       case OPENED:
+               if( f->callbacks->down )
+                       (*f->callbacks->down)(f);
+               
+               /* Init restart counter, send Terminate-Request */
+               f->retransmits = f->maxtermtransmits;
+               fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+                                       (u_char *) f->term_reason, f->term_reason_len);
+               TIMEOUT(fsm_timeout, f, f->timeouttime);
+               --f->retransmits;
+               
+               f->state = STOPPING;
+               break;
+       
+       default:
+               FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!\n",
+                                       PROTO_NAME(f), f->state));
+       }
+}
+
+
+
+
+
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+
+/*
+ * fsm_timeout - Timeout expired.
+ */
+static void fsm_timeout(void *arg)
+{
+    fsm *f = (fsm *) arg;
+
+    switch (f->state) {
+    case CLOSING:
+    case STOPPING:
+               if( f->retransmits <= 0 ){
+                   FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d\n",
+                                          PROTO_NAME(f), f->state));
+                   /*
+                    * We've waited for an ack long enough.  Peer probably heard us.
+                    */
+                   f->state = (f->state == CLOSING)? CLOSED: STOPPED;
+                   if( f->callbacks->finished )
+                       (*f->callbacks->finished)(f);
+               } else {
+                   FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d\n",
+                                          PROTO_NAME(f), f->state));
+                   /* Send Terminate-Request */
+                   fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+                             (u_char *) f->term_reason, f->term_reason_len);
+                   TIMEOUT(fsm_timeout, f, f->timeouttime);
+                   --f->retransmits;
+               }
+               break;
+
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+               if (f->retransmits <= 0) {
+                   FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d\n",
+                          PROTO_NAME(f), f->state));
+                   f->state = STOPPED;
+                   if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
+                               (*f->callbacks->finished)(f);
+       
+               } else {
+                   FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d\n",
+                          PROTO_NAME(f), f->state));
+                   /* Retransmit the configure-request */
+                   if (f->callbacks->retransmit)
+                               (*f->callbacks->retransmit)(f);
+                   fsm_sconfreq(f, 1);         /* Re-send Configure-Request */
+                   if( f->state == ACKRCVD )
+                               f->state = REQSENT;
+               }
+               break;
+
+    default:
+               FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!\n",
+                                 PROTO_NAME(f), f->state));
+           }
+}
+
+
+/*
+ * fsm_rconfreq - Receive Configure-Request.
+ */
+static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
+{
+       int code, reject_if_disagree;
+       
+       FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d\n", 
+                               PROTO_NAME(f), id, f->state));
+       switch( f->state ){
+       case CLOSED:
+               /* Go away, we're closed */
+               fsm_sdata(f, TERMACK, id, NULL, 0);
+               return;
+       case CLOSING:
+       case STOPPING:
+               return;
+       
+       case OPENED:
+               /* Go down and restart negotiation */
+               if( f->callbacks->down )
+                       (*f->callbacks->down)(f);       /* Inform upper layers */
+               fsm_sconfreq(f, 0);             /* Send initial Configure-Request */
+               break;
+       
+       case STOPPED:
+               /* Negotiation started by our peer */
+               fsm_sconfreq(f, 0);             /* Send initial Configure-Request */
+               f->state = REQSENT;
+               break;
+       }
+       
+       /*
+       * Pass the requested configuration options
+       * to protocol-specific code for checking.
+       */
+       if (f->callbacks->reqci){               /* Check CI */
+               reject_if_disagree = (f->nakloops >= f->maxnakloops);
+               code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
+       } 
+       else if (len)
+               code = CONFREJ;                 /* Reject all CI */
+       else
+               code = CONFACK;
+       
+       /* send the Ack, Nak or Rej to the peer */
+       fsm_sdata(f, (u_char)code, id, inp, len);
+       
+       if (code == CONFACK) {
+               if (f->state == ACKRCVD) {
+                       UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+                       f->state = OPENED;
+                       if (f->callbacks->up)
+                               (*f->callbacks->up)(f); /* Inform upper layers */
+               } 
+               else
+                       f->state = ACKSENT;
+               f->nakloops = 0;
+       } 
+       else {
+               /* we sent CONFACK or CONFREJ */
+               if (f->state != ACKRCVD)
+                       f->state = REQSENT;
+               if( code == CONFNAK )
+                       ++f->nakloops;
+       }
+}
+
+
+/*
+ * fsm_rconfack - Receive Configure-Ack.
+ */
+static void fsm_rconfack(fsm *f, int id, u_char *inp, int len)
+{
+       FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d\n",
+                               PROTO_NAME(f), id, f->state));
+       
+       if (id != f->reqid || f->seen_ack)              /* Expected id? */
+               return;                                 /* Nope, toss... */
+       if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
+                                                               (len == 0)) ){
+               /* Ack is bad - ignore it */
+               FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n",
+                                       PROTO_NAME(f), len));
+               return;
+       }
+       f->seen_ack = 1;
+       
+       switch (f->state) {
+       case CLOSED:
+       case STOPPED:
+               fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
+               break;
+       
+       case REQSENT:
+               f->state = ACKRCVD;
+               f->retransmits = f->maxconfreqtransmits;
+               break;
+       
+       case ACKRCVD:
+               /* Huh? an extra valid Ack? oh well... */
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               fsm_sconfreq(f, 0);
+               f->state = REQSENT;
+               break;
+       
+       case ACKSENT:
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               f->state = OPENED;
+               f->retransmits = f->maxconfreqtransmits;
+               if (f->callbacks->up)
+                       (*f->callbacks->up)(f); /* Inform upper layers */
+               break;
+       
+       case OPENED:
+               /* Go down and restart negotiation */
+               if (f->callbacks->down)
+                       (*f->callbacks->down)(f);       /* Inform upper layers */
+               fsm_sconfreq(f, 0);             /* Send initial Configure-Request */
+               f->state = REQSENT;
+               break;
+       }
+}
+
+
+/*
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ */
+static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
+{
+       int (*proc) (fsm *, u_char *, int);
+       int ret;
+       
+       FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d\n",
+                               PROTO_NAME(f), id, f->state));
+       
+       if (id != f->reqid || f->seen_ack)      /* Expected id? */
+               return;                         /* Nope, toss... */
+       proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+       if (!proc || !(ret = proc(f, inp, len))) {
+               /* Nak/reject is bad - ignore it */
+               FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n",
+                                       PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
+               return;
+       }
+       f->seen_ack = 1;
+       
+       switch (f->state) {
+       case CLOSED:
+       case STOPPED:
+               fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
+               break;
+       
+       case REQSENT:
+       case ACKSENT:
+               /* They didn't agree to what we wanted - try another request */
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               if (ret < 0)
+                       f->state = STOPPED;             /* kludge for stopping CCP */
+               else
+                       fsm_sconfreq(f, 0);             /* Send Configure-Request */
+               break;
+       
+       case ACKRCVD:
+               /* Got a Nak/reject when we had already had an Ack?? oh well... */
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
+               fsm_sconfreq(f, 0);
+               f->state = REQSENT;
+               break;
+       
+       case OPENED:
+               /* Go down and restart negotiation */
+               if (f->callbacks->down)
+                       (*f->callbacks->down)(f);       /* Inform upper layers */
+               fsm_sconfreq(f, 0);             /* Send initial Configure-Request */
+               f->state = REQSENT;
+               break;
+       }
+}
+
+
+/*
+ * fsm_rtermreq - Receive Terminate-Req.
+ */
+static void fsm_rtermreq(fsm *f, int id, u_char *p, int len)
+{
+       FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d\n",
+                               PROTO_NAME(f), id, f->state));
+       
+       switch (f->state) {
+       case ACKRCVD:
+       case ACKSENT:
+               f->state = REQSENT;             /* Start over but keep trying */
+               break;
+       
+       case OPENED:
+               if (len > 0) {
+                       FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p));
+               } else {
+                       FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f)));
+               }
+               if (f->callbacks->down)
+                       (*f->callbacks->down)(f);       /* Inform upper layers */
+               f->retransmits = 0;
+               f->state = STOPPING;
+               TIMEOUT(fsm_timeout, f, f->timeouttime);
+               break;
+       }
+       
+       fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
+}
+
+
+/*
+ * fsm_rtermack - Receive Terminate-Ack.
+ */
+static void fsm_rtermack(fsm *f)
+{
+       FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d\n", 
+                               PROTO_NAME(f), f->state));
+       
+       switch (f->state) {
+       case CLOSING:
+               UNTIMEOUT(fsm_timeout, f);
+               f->state = CLOSED;
+               if( f->callbacks->finished )
+                       (*f->callbacks->finished)(f);
+               break;
+       case STOPPING:
+               UNTIMEOUT(fsm_timeout, f);
+               f->state = STOPPED;
+               if( f->callbacks->finished )
+                       (*f->callbacks->finished)(f);
+               break;
+       
+       case ACKRCVD:
+               f->state = REQSENT;
+               break;
+       
+       case OPENED:
+               if (f->callbacks->down)
+                       (*f->callbacks->down)(f);       /* Inform upper layers */
+               fsm_sconfreq(f, 0);
+               break;
+       }
+}
+
+
+/*
+ * fsm_rcoderej - Receive an Code-Reject.
+ */
+static void fsm_rcoderej(fsm *f, u_char *inp, int len)
+{
+       u_char code, id;
+       
+       FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d\n", 
+                               PROTO_NAME(f), f->state));
+       
+       if (len < HEADERLEN) {
+               FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
+               return;
+       }
+       GETCHAR(code, inp);
+       GETCHAR(id, inp);
+       FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n",
+                               PROTO_NAME(f), code, id));
+       
+       if( f->state == ACKRCVD )
+               f->state = REQSENT;
+}
+
+
+/*
+ * fsm_sconfreq - Send a Configure-Request.
+ */
+static void fsm_sconfreq(fsm *f, int retransmit)
+{
+       u_char *outp;
+       int cilen;
+       
+       if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
+               /* Not currently negotiating - reset options */
+               if( f->callbacks->resetci )
+                       (*f->callbacks->resetci)(f);
+               f->nakloops = 0;
+               }
+       
+       if( !retransmit ){
+               /* New request - reset retransmission counter, use new ID */
+               f->retransmits = f->maxconfreqtransmits;
+               f->reqid = ++f->id;
+       }
+       
+       f->seen_ack = 0;
+       
+       /*
+        * Make up the request packet
+        */
+       outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
+       if( f->callbacks->cilen && f->callbacks->addci ){
+               cilen = (*f->callbacks->cilen)(f);
+               if( cilen > peer_mru[f->unit] - (int)HEADERLEN )
+                       cilen = peer_mru[f->unit] - HEADERLEN;
+               if (f->callbacks->addci)
+                       (*f->callbacks->addci)(f, outp, &cilen);
+       } else
+               cilen = 0;
+       
+       /* send the request to our peer */
+       fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+       
+       /* start the retransmit timer */
+       --f->retransmits;
+       TIMEOUT(fsm_timeout, f, f->timeouttime);
+       
+       FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n",
+                               PROTO_NAME(f), f->reqid));
+}
+
+#endif /* PPP_SUPPORT */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/fsm.h b/Demo/Common/ethernet/lwIP/netif/ppp/fsm.h
new file mode 100644 (file)
index 0000000..0e1d9f6
--- /dev/null
@@ -0,0 +1,187 @@
+/*****************************************************************************
+* fsm.h - Network Control Protocol Finite State Machine header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+*      Original based on BSD code.
+*****************************************************************************/
+/*
+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: fsm.h,v 1.1 2003/05/27 14:37:56 jani Exp $
+ */
+
+#ifndef FSM_H
+#define FSM_H
+
+
+/*****************************************************************************
+************************* PUBLIC DEFINITIONS *********************************
+*****************************************************************************/
+/*
+ * LCP Packet header = Code, id, length.
+ */
+#define HEADERLEN      (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+
+
+/*
+ *  CP (LCP, IPCP, etc.) codes.
+ */
+#define CONFREQ                1               /* Configuration Request */
+#define CONFACK                2               /* Configuration Ack */
+#define CONFNAK                3               /* Configuration Nak */
+#define CONFREJ                4               /* Configuration Reject */
+#define TERMREQ                5               /* Termination Request */
+#define TERMACK                6               /* Termination Ack */
+#define CODEREJ                7               /* Code Reject */
+
+/*
+ * Link states.
+ */
+#define INITIAL                0               /* Down, hasn't been opened */
+#define STARTING       1               /* Down, been opened */
+#define CLOSED         2               /* Up, hasn't been opened */
+#define STOPPED                3               /* Open, waiting for down event */
+#define CLOSING                4               /* Terminating the connection, not open */
+#define STOPPING       5               /* Terminating, but open */
+#define REQSENT                6               /* We've sent a Config Request */
+#define ACKRCVD                7               /* We've received a Config Ack */
+#define ACKSENT                8               /* We've sent a Config Ack */
+#define OPENED         9               /* Connection available */
+
+
+/*
+ * Flags - indicate options controlling FSM operation
+ */
+#define OPT_PASSIVE    1               /* Don't die if we don't get a response */
+#define OPT_RESTART    2               /* Treat 2nd OPEN as DOWN, UP */
+#define OPT_SILENT     4               /* Wait for peer to speak first */
+
+
+/*****************************************************************************
+************************* PUBLIC DATA TYPES **********************************
+*****************************************************************************/
+/*
+ * Each FSM is described by an fsm structure and fsm callbacks.
+ */
+typedef struct fsm {
+    int unit;                          /* Interface unit number */
+    u_short protocol;          /* Data Link Layer Protocol field value */
+    int state;                         /* State */
+    int flags;                         /* Contains option bits */
+    u_char id;                         /* Current id */
+    u_char reqid;                      /* Current request id */
+    u_char seen_ack;           /* Have received valid Ack/Nak/Rej to Req */
+    int timeouttime;           /* Timeout time in milliseconds */
+    int maxconfreqtransmits;/* Maximum Configure-Request transmissions */
+    int retransmits;           /* Number of retransmissions left */
+    int maxtermtransmits;      /* Maximum Terminate-Request transmissions */
+    int nakloops;                      /* Number of nak loops since last ack */
+    int maxnakloops;           /* Maximum number of nak loops tolerated */
+    struct fsm_callbacks* callbacks;/* Callback routines */
+    char* term_reason;         /* Reason for closing protocol */
+    int term_reason_len;       /* Length of term_reason */
+} fsm;
+
+
+typedef struct fsm_callbacks {
+    void (*resetci)                    /* Reset our Configuration Information */
+               (fsm*);
+    int  (*cilen)                      /* Length of our Configuration Information */
+               (fsm*);
+    void (*addci)                      /* Add our Configuration Information */
+               (fsm*, u_char*, int*);
+    int  (*ackci)                      /* ACK our Configuration Information */
+               (fsm*, u_char*, int);
+    int  (*nakci)                      /* NAK our Configuration Information */
+               (fsm*, u_char*, int);
+    int  (*rejci)                      /* Reject our Configuration Information */
+               (fsm*, u_char*, int);
+    int  (*reqci)                      /* Request peer's Configuration Information */
+               (fsm*, u_char*, int*, int);
+    void (*up)                         /* Called when fsm reaches OPENED state */
+               (fsm*);
+    void (*down)                       /* Called when fsm leaves OPENED state */
+               (fsm*);
+    void (*starting)           /* Called when we want the lower layer */
+               (fsm*);
+    void (*finished)           /* Called when we don't want the lower layer */
+               (fsm*);
+    void (*protreject)         /* Called when Protocol-Reject received */
+               (int);
+    void (*retransmit)         /* Retransmission is necessary */
+               (fsm*);
+    int  (*extcode)                    /* Called when unknown code received */
+               (fsm*, int, u_char, u_char*, int);
+    char *proto_name;          /* String name for protocol (for messages) */
+} fsm_callbacks;
+
+
+/*****************************************************************************
+*********************** PUBLIC DATA STRUCTURES *******************************
+*****************************************************************************/
+/*
+ * Variables
+ */
+extern int peer_mru[];         /* currently negotiated peer MRU (per unit) */
+
+
+/*****************************************************************************
+************************** PUBLIC FUNCTIONS **********************************
+*****************************************************************************/
+
+/*
+ * Prototypes
+ */
+void fsm_init (fsm*);
+void fsm_lowerup (fsm*);
+void fsm_lowerdown (fsm*);
+void fsm_open (fsm*);
+void fsm_close (fsm*, char*);
+void fsm_input (fsm*, u_char*, int);
+void fsm_protreject (fsm*);
+void fsm_sdata (fsm*, u_char, u_char, u_char*, int);
+
+
+#endif /* FSM_H */
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/ipcp.c b/Demo/Common/ethernet/lwIP/netif/ppp/ipcp.c
new file mode 100644 (file)
index 0000000..d5b2518
--- /dev/null
@@ -0,0 +1,1377 @@
+/*****************************************************************************
+* ipcp.c - Network PPP IP Control Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original.
+*****************************************************************************/
+/*
+ * ipcp.c - PPP IP Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <string.h>
+
+#include "ppp.h"
+#if PPP_SUPPORT > 0
+#include "auth.h"
+#include "fsm.h"
+#include "vj.h"
+#include "ipcp.h"
+#include "pppdebug.h"
+
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+/* #define OLD_CI_ADDRS 1 */   /* Support deprecated address negotiation. */
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID     2
+#define CILEN_COMPRESS 4       /* min length for compression protocol opt. */
+#define CILEN_VJ       6       /* length for RFC1332 Van-Jacobson opt. */
+#define CILEN_ADDR     6       /* new-style single address option */
+#define CILEN_ADDRS    10      /* old-style dual address option */
+
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void ipcp_resetci (fsm *);      /* Reset our CI */
+static int  ipcp_cilen (fsm *);                /* Return length of our CI */
+static void ipcp_addci (fsm *, u_char *, int *); /* Add our CI */
+static int  ipcp_ackci (fsm *, u_char *, int); /* Peer ack'd our CI */
+static int  ipcp_nakci (fsm *, u_char *, int); /* Peer nak'd our CI */
+static int  ipcp_rejci (fsm *, u_char *, int); /* Peer rej'd our CI */
+static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */
+static void ipcp_up (fsm *);           /* We're UP */
+static void ipcp_down (fsm *);         /* We're DOWN */
+#if 0
+static void ipcp_script (fsm *, char *); /* Run an up/down script */
+#endif
+static void ipcp_finished (fsm *);     /* Don't need lower layer */
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ipcp_init (int);
+static void ipcp_open (int);
+static void ipcp_close (int, char *);
+static void ipcp_lowerup (int);
+static void ipcp_lowerdown (int);
+static void ipcp_input (int, u_char *, int);
+static void ipcp_protrej (int);
+
+static void ipcp_clear_addrs (int);
+
+#define CODENAME(x)    ((x) == CONFACK ? "ACK" : \
+                        (x) == CONFNAK ? "NAK" : "REJ")
+
+
+
+/******************************/
+/*** PUBLIC DATA STRUCTURES ***/
+/******************************/
+/* global vars */
+ipcp_options ipcp_wantoptions[NUM_PPP];        /* Options that we want to request */
+ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[NUM_PPP];       /* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+
+fsm ipcp_fsm[NUM_PPP];         /* IPCP fsm structure */
+
+struct protent ipcp_protent = {
+    PPP_IPCP,
+    ipcp_init,
+    ipcp_input,
+    ipcp_protrej,
+    ipcp_lowerup,
+    ipcp_lowerdown,
+    ipcp_open,
+    ipcp_close,
+#if 0
+    ipcp_printpkt,
+    NULL,
+#endif
+    1,
+    "IPCP",
+#if 0
+    ip_check_options,
+    NULL,
+    ip_active_pkt
+#endif
+};
+
+
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+/* local vars */
+static int cis_received[NUM_PPP];              /* # Conf-Reqs received */
+static int default_route_set[NUM_PPP]; /* Have set up a default route */
+
+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
+    ipcp_resetci,              /* Reset our Configuration Information */
+    ipcp_cilen,                        /* Length of our Configuration Information */
+    ipcp_addci,                        /* Add our Configuration Information */
+    ipcp_ackci,                        /* ACK our Configuration Information */
+    ipcp_nakci,                        /* NAK our Configuration Information */
+    ipcp_rejci,                        /* Reject our Configuration Information */
+    ipcp_reqci,                        /* Request peer's Configuration Information */
+    ipcp_up,                   /* Called when fsm reaches OPENED state */
+    ipcp_down,                 /* Called when fsm leaves OPENED state */
+    NULL,                              /* Called when we want the lower layer up */
+    ipcp_finished,             /* Called when we want the lower layer down */
+    NULL,                              /* Called when Protocol-Reject received */
+    NULL,                              /* Retransmission is necessary */
+    NULL,                              /* Called to handle protocol-specific codes */
+    "IPCP"                             /* String name of protocol */
+};
+
+
+
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+
+/*
+ * Non-standard inet_ntoa left here for compat with original ppp
+ * sources. Assumes u32_t instead of struct in_addr.
+ */ 
+
+char * _inet_ntoa(u32_t n)
+{
+       struct in_addr ia;
+       ia.s_addr = n;
+       return inet_ntoa(ia);
+}
+
+#define inet_ntoa _inet_ntoa
+
+/*
+ * ipcp_init - Initialize IPCP.
+ */
+static void ipcp_init(int unit)
+{
+       fsm *f = &ipcp_fsm[unit];
+       ipcp_options *wo = &ipcp_wantoptions[unit];
+       ipcp_options *ao = &ipcp_allowoptions[unit];
+       
+       f->unit = unit;
+       f->protocol = PPP_IPCP;
+       f->callbacks = &ipcp_callbacks;
+       fsm_init(&ipcp_fsm[unit]);
+       
+       memset(wo, 0, sizeof(*wo));
+       memset(ao, 0, sizeof(*ao));
+       
+       wo->neg_addr = 1;
+       wo->ouraddr = 0;
+#if VJ_SUPPORT > 0
+       wo->neg_vj = 1;
+#else
+       wo->neg_vj = 0;
+#endif
+       wo->vj_protocol = IPCP_VJ_COMP;
+       wo->maxslotindex = MAX_SLOTS - 1;
+       wo->cflag = 0;
+       
+       wo->default_route = 1;
+       
+       ao->neg_addr = 1;
+#if VJ_SUPPORT > 0
+       ao->neg_vj = 1;
+#else
+       ao->neg_vj = 0;
+#endif
+       ao->maxslotindex = MAX_SLOTS - 1;
+       ao->cflag = 1;
+       
+       ao->default_route = 1;
+}
+
+
+/*
+ * ipcp_open - IPCP is allowed to come up.
+ */
+static void ipcp_open(int unit)
+{
+       fsm_open(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_close - Take IPCP down.
+ */
+static void ipcp_close(int unit, char *reason)
+{
+       fsm_close(&ipcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipcp_lowerup - The lower layer is up.
+ */
+static void ipcp_lowerup(int unit)
+{
+       fsm_lowerup(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_lowerdown - The lower layer is down.
+ */
+static void ipcp_lowerdown(int unit)
+{
+       fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_input - Input IPCP packet.
+ */
+static void ipcp_input(int unit, u_char *p, int len)
+{
+       fsm_input(&ipcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipcp_protrej - A Protocol-Reject was received for IPCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void ipcp_protrej(int unit)
+{
+       fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_resetci - Reset our CI.
+ */
+static void ipcp_resetci(fsm *f)
+{
+       ipcp_options *wo = &ipcp_wantoptions[f->unit];
+       
+       wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+       if (wo->ouraddr == 0)
+               wo->accept_local = 1;
+       if (wo->hisaddr == 0)
+               wo->accept_remote = 1;
+       /* Request DNS addresses from the peer */
+       wo->req_dns1 = ppp_settings.usepeerdns;
+       wo->req_dns2 = ppp_settings.usepeerdns;
+       ipcp_gotoptions[f->unit] = *wo;
+       cis_received[f->unit] = 0;
+}
+
+
+/*
+ * ipcp_cilen - Return length of our CI.
+ */
+static int ipcp_cilen(fsm *f)
+{
+       ipcp_options *go = &ipcp_gotoptions[f->unit];
+       ipcp_options *wo = &ipcp_wantoptions[f->unit];
+       ipcp_options *ho = &ipcp_hisoptions[f->unit];
+       
+#define LENCIVJ(neg, old)      (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
+#define LENCIADDR(neg, old)    (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
+#define LENCIDNS(neg)          (neg ? (CILEN_ADDR) : 0)
+       
+       /*
+        * First see if we want to change our options to the old
+        * forms because we have received old forms from the peer.
+        */
+       if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
+               /* use the old style of address negotiation */
+               go->neg_addr = 1;
+               go->old_addrs = 1;
+       }
+       if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+               /* try an older style of VJ negotiation */
+               if (cis_received[f->unit] == 0) {
+                       /* keep trying the new style until we see some CI from the peer */
+                       go->neg_vj = 1;
+               } else {
+                       /* use the old style only if the peer did */
+                       if (ho->neg_vj && ho->old_vj) {
+                               go->neg_vj = 1;
+                               go->old_vj = 1;
+                               go->vj_protocol = ho->vj_protocol;
+                       }
+               }
+       }
+       
+       return (LENCIADDR(go->neg_addr, go->old_addrs)
+                       + LENCIVJ(go->neg_vj, go->old_vj) +
+                       LENCIDNS(go->req_dns1) +
+                       LENCIDNS(go->req_dns2));
+}
+
+
+/*
+ * ipcp_addci - Add our desired CIs to a packet.
+ */
+static void ipcp_addci(fsm *f, u_char *ucp, int *lenp)
+{
+       ipcp_options *go = &ipcp_gotoptions[f->unit];
+       int len = *lenp;
+       
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+       if (neg) { \
+               int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+               if (len >= vjlen) { \
+                       PUTCHAR(opt, ucp); \
+                       PUTCHAR(vjlen, ucp); \
+                       PUTSHORT(val, ucp); \
+                       if (!old) { \
+                               PUTCHAR(maxslotindex, ucp); \
+                               PUTCHAR(cflag, ucp); \
+                       } \
+                       len -= vjlen; \
+               } else \
+                       neg = 0; \
+       }
+       
+#define ADDCIADDR(opt, neg, old, val1, val2) \
+       if (neg) { \
+               int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+               if (len >= addrlen) { \
+                       u32_t l; \
+                       PUTCHAR(opt, ucp); \
+                       PUTCHAR(addrlen, ucp); \
+                       l = ntohl(val1); \
+                       PUTLONG(l, ucp); \
+                       if (old) { \
+                               l = ntohl(val2); \
+                               PUTLONG(l, ucp); \
+                       } \
+                       len -= addrlen; \
+               } else \
+                       neg = 0; \
+       }
+
+#define ADDCIDNS(opt, neg, addr) \
+       if (neg) { \
+               if (len >= CILEN_ADDR) { \
+                       u32_t l; \
+                       PUTCHAR(opt, ucp); \
+                       PUTCHAR(CILEN_ADDR, ucp); \
+                       l = ntohl(addr); \
+                       PUTLONG(l, ucp); \
+                       len -= CILEN_ADDR; \
+               } else \
+                       neg = 0; \
+       }
+       
+       ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+                         go->old_addrs, go->ouraddr, go->hisaddr);
+       
+       ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+                       go->maxslotindex, go->cflag);
+       
+       ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+       ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+       *lenp -= len;
+}
+
+
+/*
+ * ipcp_ackci - Ack our CIs.
+ *
+ * Returns:
+ *     0 - Ack was bad.
+ *     1 - Ack was good.
+ */
+static int ipcp_ackci(fsm *f, u_char *p, int len)
+{
+       ipcp_options *go = &ipcp_gotoptions[f->unit];
+       u_short cilen, citype, cishort;
+       u32_t cilong;
+       u_char cimaxslotindex, cicflag;
+       
+       /*
+        * CIs must be in exactly the same order that we sent...
+        * Check packet length and CI length at each step.
+        * If we find any deviations, then this packet is bad.
+        */
+       
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+       if (neg) { \
+               int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+               if ((len -= vjlen) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != vjlen || \
+                               citype != opt)  \
+                       goto bad; \
+               GETSHORT(cishort, p); \
+               if (cishort != val) \
+                       goto bad; \
+               if (!old) { \
+                       GETCHAR(cimaxslotindex, p); \
+                       if (cimaxslotindex != maxslotindex) \
+                               goto bad; \
+                       GETCHAR(cicflag, p); \
+                       if (cicflag != cflag) \
+                               goto bad; \
+               } \
+       }
+       
+#define ACKCIADDR(opt, neg, old, val1, val2) \
+       if (neg) { \
+               int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+               u32_t l; \
+               if ((len -= addrlen) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != addrlen || \
+                               citype != opt) \
+                       goto bad; \
+               GETLONG(l, p); \
+               cilong = htonl(l); \
+               if (val1 != cilong) \
+                       goto bad; \
+               if (old) { \
+                       GETLONG(l, p); \
+                       cilong = htonl(l); \
+                       if (val2 != cilong) \
+                               goto bad; \
+               } \
+       }
+
+#define ACKCIDNS(opt, neg, addr) \
+       if (neg) { \
+               u32_t l; \
+               if ((len -= CILEN_ADDR) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != CILEN_ADDR || \
+                               citype != opt) \
+                       goto bad; \
+               GETLONG(l, p); \
+               cilong = htonl(l); \
+               if (addr != cilong) \
+                       goto bad; \
+       }
+       
+       ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+                         go->old_addrs, go->ouraddr, go->hisaddr);
+       
+       ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+                       go->maxslotindex, go->cflag);
+       
+       ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+       ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+       /*
+        * If there are any remaining CIs, then this packet is bad.
+        */
+       if (len != 0)
+               goto bad;
+       return (1);
+       
+bad:
+       IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!\n"));
+       return (0);
+}
+
+/*
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPCP is in the OPENED state.
+ *
+ * Returns:
+ *     0 - Nak was bad.
+ *     1 - Nak was good.
+ */
+static int ipcp_nakci(fsm *f, u_char *p, int len)
+{
+       ipcp_options *go = &ipcp_gotoptions[f->unit];
+       u_char cimaxslotindex, cicflag;
+       u_char citype, cilen, *next;
+       u_short cishort;
+       u32_t ciaddr1, ciaddr2, l, cidnsaddr;
+       ipcp_options no;                /* options we've seen Naks for */
+       ipcp_options try;               /* options to request next time */
+       
+       BZERO(&no, sizeof(no));
+       try = *go;
+       
+       /*
+        * Any Nak'd CIs must be in exactly the same order that we sent.
+        * Check packet length and CI length at each step.
+        * If we find any deviations, then this packet is bad.
+        */
+#define NAKCIADDR(opt, neg, old, code) \
+       if (go->neg && \
+                       len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+                       p[1] == cilen && \
+                       p[0] == opt) { \
+               len -= cilen; \
+               INCPTR(2, p); \
+               GETLONG(l, p); \
+               ciaddr1 = htonl(l); \
+               if (old) { \
+                       GETLONG(l, p); \
+                       ciaddr2 = htonl(l); \
+                       no.old_addrs = 1; \
+               } else \
+                       ciaddr2 = 0; \
+               no.neg = 1; \
+               code \
+       }
+       
+#define NAKCIVJ(opt, neg, code) \
+       if (go->neg && \
+                       ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+                       len >= cilen && \
+                       p[0] == opt) { \
+               len -= cilen; \
+               INCPTR(2, p); \
+               GETSHORT(cishort, p); \
+               no.neg = 1; \
+               code \
+       }
+       
+#define NAKCIDNS(opt, neg, code) \
+       if (go->neg && \
+                       ((cilen = p[1]) == CILEN_ADDR) && \
+                       len >= cilen && \
+                       p[0] == opt) { \
+               len -= cilen; \
+               INCPTR(2, p); \
+               GETLONG(l, p); \
+               cidnsaddr = htonl(l); \
+               no.neg = 1; \
+               code \
+       }
+       
+       /*
+        * Accept the peer's idea of {our,his} address, if different
+        * from our idea, only if the accept_{local,remote} flag is set.
+        */
+       NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
+         if (go->accept_local && ciaddr1) { /* Do we know our address? */
+                 try.ouraddr = ciaddr1;
+                 IPCPDEBUG((LOG_INFO, "local IP address %s\n",
+                            inet_ntoa(ciaddr1)));
+         }
+         if (go->accept_remote && ciaddr2) { /* Does he know his? */
+                 try.hisaddr = ciaddr2;
+                 IPCPDEBUG((LOG_INFO, "remote IP address %s\n",
+                            inet_ntoa(ciaddr2)));
+         }
+       );
+       
+       /*
+        * Accept the peer's value of maxslotindex provided that it
+        * is less than what we asked for.  Turn off slot-ID compression
+        * if the peer wants.  Send old-style compress-type option if
+        * the peer wants.
+        */
+       NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+               if (cilen == CILEN_VJ) {
+                       GETCHAR(cimaxslotindex, p);
+                       GETCHAR(cicflag, p);
+                       if (cishort == IPCP_VJ_COMP) {
+                               try.old_vj = 0;
+                               if (cimaxslotindex < go->maxslotindex)
+                                       try.maxslotindex = cimaxslotindex;
+                               if (!cicflag)
+                                       try.cflag = 0;
+                       } else {
+                               try.neg_vj = 0;
+                       }
+               } else {
+                       if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
+                               try.old_vj = 1;
+                               try.vj_protocol = cishort;
+                       } else {
+                               try.neg_vj = 0;
+                       }
+               }
+       );
+       
+       NAKCIDNS(CI_MS_DNS1, req_dns1,
+                       try.dnsaddr[0] = cidnsaddr;
+                       IPCPDEBUG((LOG_INFO, "primary DNS address %s\n", inet_ntoa(cidnsaddr)));
+                       );
+
+       NAKCIDNS(CI_MS_DNS2, req_dns2,
+                       try.dnsaddr[1] = cidnsaddr;
+                       IPCPDEBUG((LOG_INFO, "secondary DNS address %s\n", inet_ntoa(cidnsaddr)));
+                       );
+
+       /*
+       * There may be remaining CIs, if the peer is requesting negotiation
+       * on an option that we didn't include in our request packet.
+       * If they want to negotiate about IP addresses, we comply.
+       * If they want us to ask for compression, we refuse.
+       */
+       while (len > CILEN_VOID) {
+               GETCHAR(citype, p);
+               GETCHAR(cilen, p);
+               if( (len -= cilen) < 0 )
+                       goto bad;
+               next = p + cilen - 2;
+               
+               switch (citype) {
+               case CI_COMPRESSTYPE:
+                       if (go->neg_vj || no.neg_vj ||
+                                       (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
+                               goto bad;
+                       no.neg_vj = 1;
+                       break;
+               case CI_ADDRS:
+                       if ((go->neg_addr && go->old_addrs) || no.old_addrs
+                                       || cilen != CILEN_ADDRS)
+                               goto bad;
+                       try.neg_addr = 1;
+                       try.old_addrs = 1;
+                       GETLONG(l, p);
+                       ciaddr1 = htonl(l);
+                       if (ciaddr1 && go->accept_local)
+                               try.ouraddr = ciaddr1;
+                       GETLONG(l, p);
+                       ciaddr2 = htonl(l);
+                       if (ciaddr2 && go->accept_remote)
+                               try.hisaddr = ciaddr2;
+                       no.old_addrs = 1;
+                       break;
+               case CI_ADDR:
+                       if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+                               goto bad;
+                       try.old_addrs = 0;
+                       GETLONG(l, p);
+                       ciaddr1 = htonl(l);
+                       if (ciaddr1 && go->accept_local)
+                               try.ouraddr = ciaddr1;
+                       if (try.ouraddr != 0)
+                               try.neg_addr = 1;
+                       no.neg_addr = 1;
+                       break;
+               }
+               p = next;
+       }
+       
+       /* If there is still anything left, this packet is bad. */
+       if (len != 0)
+               goto bad;
+       
+       /*
+        * OK, the Nak is good.  Now we can update state.
+        */
+       if (f->state != OPENED)
+               *go = try;
+       
+       return 1;
+       
+bad:
+       IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!\n"));
+       return 0;
+}
+
+
+/*
+ * ipcp_rejci - Reject some of our CIs.
+ */
+static int ipcp_rejci(fsm *f, u_char *p, int len)
+{
+       ipcp_options *go = &ipcp_gotoptions[f->unit];
+       u_char cimaxslotindex, ciflag, cilen;
+       u_short cishort;
+       u32_t cilong;
+       ipcp_options try;               /* options to request next time */
+       
+       try = *go;
+       /*
+        * Any Rejected CIs must be in exactly the same order that we sent.
+        * Check packet length and CI length at each step.
+        * If we find any deviations, then this packet is bad.
+        */
+#define REJCIADDR(opt, neg, old, val1, val2) \
+       if (go->neg && \
+                       len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+                       p[1] == cilen && \
+                       p[0] == opt) { \
+               u32_t l; \
+               len -= cilen; \
+               INCPTR(2, p); \
+               GETLONG(l, p); \
+               cilong = htonl(l); \
+               /* Check rejected value. */ \
+               if (cilong != val1) \
+                       goto bad; \
+               if (old) { \
+                       GETLONG(l, p); \
+                       cilong = htonl(l); \
+                       /* Check rejected value. */ \
+                       if (cilong != val2) \
+                               goto bad; \
+               } \
+               try.neg = 0; \
+       }
+       
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
+       if (go->neg && \
+                       p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+                       len >= p[1] && \
+                       p[0] == opt) { \
+               len -= p[1]; \
+               INCPTR(2, p); \
+               GETSHORT(cishort, p); \
+               /* Check rejected value. */  \
+               if (cishort != val) \
+                       goto bad; \
+               if (!old) { \
+                       GETCHAR(cimaxslotindex, p); \
+                       if (cimaxslotindex != maxslot) \
+                               goto bad; \
+                       GETCHAR(ciflag, p); \
+                       if (ciflag != cflag) \
+                               goto bad; \
+               } \
+               try.neg = 0; \
+       }
+       
+#define REJCIDNS(opt, neg, dnsaddr) \
+       if (go->neg && \
+                       ((cilen = p[1]) == CILEN_ADDR) && \
+                       len >= cilen && \
+                       p[0] == opt) { \
+               u32_t l; \
+               len -= cilen; \
+               INCPTR(2, p); \
+               GETLONG(l, p); \
+               cilong = htonl(l); \
+               /* Check rejected value. */ \
+               if (cilong != dnsaddr) \
+                       goto bad; \
+               try.neg = 0; \
+       }
+
+       REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+                         go->old_addrs, go->ouraddr, go->hisaddr);
+       
+       REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+                       go->maxslotindex, go->cflag);
+       
+       REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
+
+       REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
+
+       /*
+        * If there are any remaining CIs, then this packet is bad.
+        */
+       if (len != 0)
+               goto bad;
+       /*
+        * Now we can update state.
+        */
+       if (f->state != OPENED)
+               *go = try;
+       return 1;
+       
+bad:
+       IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!\n"));
+       return 0;
+}
+
+
+/*
+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int ipcp_reqci(
+       fsm *f,
+       u_char *inp,            /* Requested CIs */
+       int *len,                       /* Length of requested CIs */
+       int reject_if_disagree
+)
+{
+       ipcp_options *wo = &ipcp_wantoptions[f->unit];
+       ipcp_options *ho = &ipcp_hisoptions[f->unit];
+       ipcp_options *ao = &ipcp_allowoptions[f->unit];
+#ifdef OLD_CI_ADDRS
+       ipcp_options *go = &ipcp_gotoptions[f->unit];
+#endif
+       u_char *cip, *next;                             /* Pointer to current and next CIs */
+       u_short cilen, citype;                  /* Parsed len, type */
+       u_short cishort;                                /* Parsed short value */
+       u32_t tl, ciaddr1;                      /* Parsed address values */
+#ifdef OLD_CI_ADDRS
+       u32_t ciaddr2;                          /* Parsed address values */
+#endif
+       int rc = CONFACK;                               /* Final packet return code */
+       int orc;                                                /* Individual option return code */
+       u_char *p;                                              /* Pointer to next char to parse */
+       u_char *ucp = inp;                              /* Pointer to current output char */
+       int l = *len;                                   /* Length left */
+       u_char maxslotindex, cflag;
+       int d;
+       
+       cis_received[f->unit] = 1;
+       
+       /*
+        * Reset all his options.
+        */
+       BZERO(ho, sizeof(*ho));
+       
+       /*
+        * Process all his options.
+        */
+       next = inp;
+       while (l) {
+               orc = CONFACK;                          /* Assume success */
+               cip = p = next;                         /* Remember begining of CI */
+               if (l < 2 ||                            /* Not enough data for CI header or */
+                               p[1] < 2 ||                     /*  CI length too small or */
+                               p[1] > l) {                     /*  CI length too big? */
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!\n"));
+                       orc = CONFREJ;                  /* Reject bad CI */
+                       cilen = l;                              /* Reject till end of packet */
+                       l = 0;                                  /* Don't loop again */
+                       goto endswitch;
+               }
+               GETCHAR(citype, p);                     /* Parse CI type */
+               GETCHAR(cilen, p);                      /* Parse CI length */
+               l -= cilen;                                     /* Adjust remaining length */
+               next += cilen;                          /* Step to next CI */
+
+               switch (citype) {                       /* Check CI type */
+#ifdef OLD_CI_ADDRS /* Need to save space... */
+               case CI_ADDRS:
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS\n"));
+                       if (!ao->neg_addr ||
+                                       cilen != CILEN_ADDRS) { /* Check CI length */
+                               orc = CONFREJ;          /* Reject CI */
+                               break;
+                       }
+                       
+                       /*
+                        * If he has no address, or if we both have his address but
+                        * disagree about it, then NAK it with our idea.
+                        * In particular, if we don't know his address, but he does,
+                        * then accept it.
+                        */
+                       GETLONG(tl, p);         /* Parse source address (his) */
+                       ciaddr1 = htonl(tl);
+                       IPCPDEBUG((LOG_INFO, "his addr %s\n", inet_ntoa(ciaddr1)));
+                       if (ciaddr1 != wo->hisaddr
+                                       && (ciaddr1 == 0 || !wo->accept_remote)) {
+                               orc = CONFNAK;
+                               if (!reject_if_disagree) {
+                                       DECPTR(sizeof(u32_t), p);
+                                       tl = ntohl(wo->hisaddr);
+                                       PUTLONG(tl, p);
+                               }
+                       } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+                               /*
+                                * If neither we nor he knows his address, reject the option.
+                                */
+                               orc = CONFREJ;
+                               wo->req_addr = 0;       /* don't NAK with 0.0.0.0 later */
+                               break;
+                       }
+                       
+                       /*
+                        * If he doesn't know our address, or if we both have our address
+                        * but disagree about it, then NAK it with our idea.
+                        */
+                       GETLONG(tl, p);         /* Parse desination address (ours) */
+                       ciaddr2 = htonl(tl);
+                       IPCPDEBUG((LOG_INFO, "our addr %s\n", inet_ntoa(ciaddr2)));
+                       if (ciaddr2 != wo->ouraddr) {
+                               if (ciaddr2 == 0 || !wo->accept_local) {
+                                       orc = CONFNAK;
+                                       if (!reject_if_disagree) {
+                                               DECPTR(sizeof(u32_t), p);
+                                               tl = ntohl(wo->ouraddr);
+                                               PUTLONG(tl, p);
+                                       }
+                               } else {
+                                       go->ouraddr = ciaddr2;  /* accept peer's idea */
+                               }
+                       }
+                       
+                       ho->neg_addr = 1;
+                       ho->old_addrs = 1;
+                       ho->hisaddr = ciaddr1;
+                       ho->ouraddr = ciaddr2;
+                       break;
+#endif
+               
+               case CI_ADDR:
+                       if (!ao->neg_addr) {
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR not allowed\n"));
+                               orc = CONFREJ;                          /* Reject CI */
+                               break;
+                       } else if (cilen != CILEN_ADDR) {       /* Check CI length */
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR bad len\n"));
+                               orc = CONFREJ;                          /* Reject CI */
+                               break;
+                       }
+                       
+                       /*
+                        * If he has no address, or if we both have his address but
+                        * disagree about it, then NAK it with our idea.
+                        * In particular, if we don't know his address, but he does,
+                        * then accept it.
+                        */
+                       GETLONG(tl, p); /* Parse source address (his) */
+                       ciaddr1 = htonl(tl);
+                       if (ciaddr1 != wo->hisaddr
+                                       && (ciaddr1 == 0 || !wo->accept_remote)) {
+                               orc = CONFNAK;
+                               if (!reject_if_disagree) {
+                                       DECPTR(sizeof(u32_t), p);
+                                       tl = ntohl(wo->hisaddr);
+                                       PUTLONG(tl, p);
+                               }
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1)));
+                       } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+                               /*
+                                * Don't ACK an address of 0.0.0.0 - reject it instead.
+                                */
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1)));
+                               orc = CONFREJ;
+                               wo->req_addr = 0;       /* don't NAK with 0.0.0.0 later */
+                               break;
+                       }
+                       
+                       ho->neg_addr = 1;
+                       ho->hisaddr = ciaddr1;
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1)));
+                       break;
+               
+               case CI_MS_DNS1:
+               case CI_MS_DNS2:
+                       /* Microsoft primary or secondary DNS request */
+                       d = citype == CI_MS_DNS2;
+                       
+                       /* If we do not have a DNS address then we cannot send it */
+                       if (ao->dnsaddr[d] == 0 ||
+                                       cilen != CILEN_ADDR) {  /* Check CI length */
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting DNS%d Request\n", d+1));
+                               orc = CONFREJ;                          /* Reject CI */
+                               break;
+                       }
+                       GETLONG(tl, p);
+                       if (htonl(tl) != ao->dnsaddr[d]) {
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking DNS%d Request %d\n",
+                                                       d+1, inet_ntoa(tl)));
+                               DECPTR(sizeof(u32_t), p);
+                               tl = ntohl(ao->dnsaddr[d]);
+                               PUTLONG(tl, p);
+                               orc = CONFNAK;
+                       }
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: received DNS%d Request\n", d+1));
+                       break;
+               
+               case CI_MS_WINS1:
+               case CI_MS_WINS2:
+                       /* Microsoft primary or secondary WINS request */
+                       d = citype == CI_MS_WINS2;
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: received WINS%d Request\n", d+1));
+                       
+                       /* If we do not have a DNS address then we cannot send it */
+                       if (ao->winsaddr[d] == 0 ||
+                               cilen != CILEN_ADDR) {  /* Check CI length */
+                               orc = CONFREJ;                  /* Reject CI */
+                               break;
+                       }
+                       GETLONG(tl, p);
+                       if (htonl(tl) != ao->winsaddr[d]) {
+                               DECPTR(sizeof(u32_t), p);
+                               tl = ntohl(ao->winsaddr[d]);
+                               PUTLONG(tl, p);
+                               orc = CONFNAK;
+                       }
+                       break;
+               
+               case CI_COMPRESSTYPE:
+                       if (!ao->neg_vj) {
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n"));
+                               orc = CONFREJ;
+                               break;
+                       } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) {
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen));
+                               orc = CONFREJ;
+                               break;
+                       }
+                       GETSHORT(cishort, p);
+                       
+                       if (!(cishort == IPCP_VJ_COMP ||
+                                       (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort));
+                               orc = CONFREJ;
+                               break;
+                       }
+                       
+                       ho->neg_vj = 1;
+                       ho->vj_protocol = cishort;
+                       if (cilen == CILEN_VJ) {
+                               GETCHAR(maxslotindex, p);
+                               if (maxslotindex > ao->maxslotindex) { 
+                                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ max slot %d\n", maxslotindex));
+                                       orc = CONFNAK;
+                                       if (!reject_if_disagree){
+                                               DECPTR(1, p);
+                                               PUTCHAR(ao->maxslotindex, p);
+                                       }
+                               }
+                               GETCHAR(cflag, p);
+                               if (cflag && !ao->cflag) {
+                                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ cflag %d\n", cflag));
+                                       orc = CONFNAK;
+                                       if (!reject_if_disagree){
+                                               DECPTR(1, p);
+                                               PUTCHAR(wo->cflag, p);
+                                       }
+                               }
+                               ho->maxslotindex = maxslotindex;
+                               ho->cflag = cflag;
+                       } else {
+                               ho->old_vj = 1;
+                               ho->maxslotindex = MAX_SLOTS - 1;
+                               ho->cflag = 1;
+                       }
+                       IPCPDEBUG((LOG_INFO, 
+                                               "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n",
+                                               ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag));
+                       break;
+                       
+               default:
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting unknown CI type %d\n", citype));
+                       orc = CONFREJ;
+                       break;
+               }
+               
+endswitch:
+               if (orc == CONFACK &&           /* Good CI */
+                               rc != CONFACK)          /*  but prior CI wasnt? */
+                       continue;                               /* Don't send this one */
+               
+               if (orc == CONFNAK) {           /* Nak this CI? */
+                       if (reject_if_disagree) {       /* Getting fed up with sending NAKs? */
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting too many naks\n"));
+                               orc = CONFREJ;          /* Get tough if so */
+                       } else {
+                               if (rc == CONFREJ)      /* Rejecting prior CI? */
+                                       continue;               /* Don't send this one */
+                               if (rc == CONFACK) {    /* Ack'd all prior CIs? */
+                                       rc = CONFNAK;   /* Not anymore... */
+                                       ucp = inp;              /* Backup */
+                               }
+                       }
+               }
+               
+               if (orc == CONFREJ &&           /* Reject this CI */
+                               rc != CONFREJ) {        /*  but no prior ones? */
+                       rc = CONFREJ;
+                       ucp = inp;                              /* Backup */
+               }
+               
+               /* Need to move CI? */
+               if (ucp != cip)
+                       BCOPY(cip, ucp, cilen); /* Move it */
+               
+               /* Update output pointer */
+               INCPTR(cilen, ucp);
+       }
+       
+       /*
+        * If we aren't rejecting this packet, and we want to negotiate
+        * their address, and they didn't send their address, then we
+        * send a NAK with a CI_ADDR option appended.  We assume the
+        * input buffer is long enough that we can append the extra
+        * option safely.
+        */
+       if (rc != CONFREJ && !ho->neg_addr &&
+                       wo->req_addr && !reject_if_disagree) {
+               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Requesting peer address\n"));
+               if (rc == CONFACK) {
+                       rc = CONFNAK;
+                       ucp = inp;                              /* reset pointer */
+                       wo->req_addr = 0;               /* don't ask again */
+               }
+               PUTCHAR(CI_ADDR, ucp);
+               PUTCHAR(CILEN_ADDR, ucp);
+               tl = ntohl(wo->hisaddr);
+               PUTLONG(tl, ucp);
+       }
+       
+       *len = (int)(ucp - inp);                /* Compute output length */
+       IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning Configure-%s\n", CODENAME(rc)));
+       return (rc);                    /* Return final code */
+}
+
+
+#if 0
+/*
+ * ip_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void ip_check_options(u_long localAddr)
+{
+       ipcp_options *wo = &ipcp_wantoptions[0];
+
+       /*
+        * Load our default IP address but allow the remote host to give us
+        * a new address.
+        */
+       if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) {
+               wo->accept_local = 1;   /* don't insist on this default value */
+               wo->ouraddr = htonl(localAddr);
+       }
+}
+#endif
+
+
+/*
+ * ipcp_up - IPCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+static void ipcp_up(fsm *f)
+{
+       u32_t mask;
+       ipcp_options *ho = &ipcp_hisoptions[f->unit];
+       ipcp_options *go = &ipcp_gotoptions[f->unit];
+       ipcp_options *wo = &ipcp_wantoptions[f->unit];
+       
+       np_up(f->unit, PPP_IP);
+       IPCPDEBUG((LOG_INFO, "ipcp: up\n"));
+       
+       /*
+        * We must have a non-zero IP address for both ends of the link.
+        */
+       if (!ho->neg_addr)
+               ho->hisaddr = wo->hisaddr;
+       
+       if (ho->hisaddr == 0) {
+               IPCPDEBUG((LOG_ERR, "Could not determine remote IP address\n"));
+               ipcp_close(f->unit, "Could not determine remote IP address");
+               return;
+       }
+       if (go->ouraddr == 0) {
+               IPCPDEBUG((LOG_ERR, "Could not determine local IP address\n"));
+               ipcp_close(f->unit, "Could not determine local IP address");
+               return;
+       }
+       
+       if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
+               /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/
+       }
+
+       /*
+        * Check that the peer is allowed to use the IP address it wants.
+        */
+       if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+               IPCPDEBUG((LOG_ERR, "Peer is not authorized to use remote address %s\n",
+                               inet_ntoa(ho->hisaddr)));
+               ipcp_close(f->unit, "Unauthorized remote IP address");
+               return;
+       }
+       
+       /* set tcp compression */
+       sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
+       
+       /*
+        * Set IP addresses and (if specified) netmask.
+        */
+       mask = GetMask(go->ouraddr);
+       
+       if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {
+               IPCPDEBUG((LOG_WARNING, "sifaddr failed\n"));
+               ipcp_close(f->unit, "Interface configuration failed");
+               return;
+       }
+       
+       /* bring the interface up for IP */
+       if (!sifup(f->unit)) {
+               IPCPDEBUG((LOG_WARNING, "sifup failed\n"));
+               ipcp_close(f->unit, "Interface configuration failed");
+               return;
+       }
+       
+       sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+       
+       /* assign a default route through the interface if required */
+       if (ipcp_wantoptions[f->unit].default_route) 
+               if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+                       default_route_set[f->unit] = 1;
+       
+       IPCPDEBUG((LOG_NOTICE, "local  IP address %s\n", inet_ntoa(go->ouraddr)));
+       IPCPDEBUG((LOG_NOTICE, "remote IP address %s\n", inet_ntoa(ho->hisaddr)));
+       if (go->dnsaddr[0]) {
+               IPCPDEBUG((LOG_NOTICE, "primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0])));
+       }
+       if (go->dnsaddr[1]) {
+               IPCPDEBUG((LOG_NOTICE, "secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));
+       }
+}
+
+
+/*
+ * ipcp_down - IPCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+static void ipcp_down(fsm *f)
+{
+       IPCPDEBUG((LOG_INFO, "ipcp: down\n"));
+       np_down(f->unit, PPP_IP);
+       sifvjcomp(f->unit, 0, 0, 0);
+       
+       sifdown(f->unit);
+       ipcp_clear_addrs(f->unit);
+}
+
+
+/*
+ * ipcp_clear_addrs() - clear the interface addresses, routes, etc.
+ */
+static void ipcp_clear_addrs(int unit)
+{
+       u32_t ouraddr, hisaddr;
+       
+       ouraddr = ipcp_gotoptions[unit].ouraddr;
+       hisaddr = ipcp_hisoptions[unit].hisaddr;
+       if (default_route_set[unit]) {
+               cifdefaultroute(unit, ouraddr, hisaddr);
+               default_route_set[unit] = 0;
+       }
+       cifaddr(unit, ouraddr, hisaddr);
+}
+
+
+/*
+ * ipcp_finished - possibly shut down the lower layers.
+ */
+static void ipcp_finished(fsm *f)
+{
+       np_finished(f->unit, PPP_IP);
+}
+
+#if 0
+static int ipcp_printpkt(
+       u_char *p,
+       int plen,
+       void (*printer) (void *, char *, ...),
+       void *arg
+)
+{
+       (void)p;
+       (void)plen;
+       (void)printer;
+       (void)arg;
+       return 0;
+}
+
+/*
+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.
+ * We don't bring the link up for IP fragments or for TCP FIN packets
+ * with no data.
+ */
+#define IP_HDRLEN      20      /* bytes */
+#define IP_OFFMASK     0x1fff
+#define IPPROTO_TCP    6
+#define TCP_HDRLEN     20
+#define TH_FIN         0x01
+
+/*
+ * We use these macros because the IP header may be at an odd address,
+ * and some compilers might use word loads to get th_off or ip_hl.
+ */
+
+#define net_short(x)   (((x)[0] << 8) + (x)[1])
+#define get_iphl(x)    (((unsigned char *)(x))[0] & 0xF)
+#define get_ipoff(x)   net_short((unsigned char *)(x) + 6)
+#define get_ipproto(x) (((unsigned char *)(x))[9])
+#define get_tcpoff(x)  (((unsigned char *)(x))[12] >> 4)
+#define get_tcpflags(x)        (((unsigned char *)(x))[13])
+
+static int ip_active_pkt(u_char *pkt, int len)
+{
+       u_char *tcp;
+       int hlen;
+       
+       len -= PPP_HDRLEN;
+       pkt += PPP_HDRLEN;
+       if (len < IP_HDRLEN)
+               return 0;
+       if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
+               return 0;
+       if (get_ipproto(pkt) != IPPROTO_TCP)
+               return 1;
+       hlen = get_iphl(pkt) * 4;
+       if (len < hlen + TCP_HDRLEN)
+               return 0;
+       tcp = pkt + hlen;
+       if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
+               return 0;
+       return 1;
+}
+#endif
+
+#endif /* PPP_SUPPORT */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/ipcp.h b/Demo/Common/ethernet/lwIP/netif/ppp/ipcp.h
new file mode 100644 (file)
index 0000000..416aa79
--- /dev/null
@@ -0,0 +1,126 @@
+/*****************************************************************************
+* ipcp.h -  PPP IP NCP: Internet Protocol Network Control Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+*      Original derived from BSD codes.
+*****************************************************************************/
+/*
+ * ipcp.h - IP Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipcp.h,v 1.1 2003/05/27 14:37:56 jani Exp $
+ */
+
+#ifndef IPCP_H
+#define IPCP_H
+
+/*************************
+*** PUBLIC DEFINITIONS ***
+*************************/
+/*
+ * Options.
+ */
+#define CI_ADDRS       1                       /* IP Addresses */
+#define CI_COMPRESSTYPE        2               /* Compression Type */
+#define        CI_ADDR         3
+
+#define CI_MS_WINS1    128                     /* Primary WINS value */
+#define CI_MS_DNS1     129                     /* Primary DNS value */
+#define CI_MS_WINS2    130                     /* Secondary WINS value */
+#define CI_MS_DNS2     131                     /* Secondary DNS value */
+
+#define IPCP_VJMODE_OLD 1              /* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2  /* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3  /* "new-rfc"mode (option # = 0x002d, */
+                                /*  maxslot and slot number compression) */
+
+#define IPCP_VJ_COMP 0x002d            /* current value for VJ compression option*/
+#define IPCP_VJ_COMP_OLD 0x0037        /* "old" (i.e, broken) value for VJ */
+                                                               /* compression option*/ 
+
+
+/************************
+*** PUBLIC DATA TYPES ***
+************************/
+
+typedef struct ipcp_options {
+    u_int neg_addr : 1;                        /* Negotiate IP Address? */
+    u_int old_addrs : 1;                       /* Use old (IP-Addresses) option? */
+    u_int req_addr : 1;                        /* Ask peer to send IP address? */
+    u_int default_route : 1;           /* Assign default route through interface? */
+    u_int proxy_arp : 1;                       /* Make proxy ARP entry for peer? */
+    u_int neg_vj : 1;                          /* Van Jacobson Compression? */
+    u_int old_vj : 1;                          /* use old (short) form of VJ option? */
+    u_int accept_local : 1;            /* accept peer's value for ouraddr */
+    u_int accept_remote : 1;           /* accept peer's value for hisaddr */
+    u_int req_dns1 : 1;                        /* Ask peer to send primary DNS address? */
+    u_int req_dns2 : 1;                        /* Ask peer to send secondary DNS address? */
+    u_short vj_protocol;               /* protocol value to use in VJ option */
+    u_char maxslotindex;               /* VJ slots - 1. */
+    u_char cflag;                              /* VJ slot compression flag. */
+    u32_t ouraddr, hisaddr;    /* Addresses in NETWORK BYTE ORDER */
+    u32_t dnsaddr[2];          /* Primary and secondary MS DNS entries */
+    u32_t winsaddr[2];         /* Primary and secondary MS WINS entries */
+} ipcp_options;
+
+
+/*****************************
+*** PUBLIC DATA STRUCTURES ***
+*****************************/
+
+extern fsm ipcp_fsm[];
+extern ipcp_options ipcp_wantoptions[];
+extern ipcp_options ipcp_gotoptions[];
+extern ipcp_options ipcp_allowoptions[];
+extern ipcp_options ipcp_hisoptions[];
+
+extern struct protent ipcp_protent;
+
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+
+
+#endif /* IPCP_H */
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/lcp.c b/Demo/Common/ethernet/lwIP/netif/ppp/lcp.c
new file mode 100644 (file)
index 0000000..6a988d6
--- /dev/null
@@ -0,0 +1,1991 @@
+/*****************************************************************************
+* lcp.c - Network Link Control Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original.
+*****************************************************************************/
+
+/*
+ * lcp.c - PPP Link Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <string.h>
+#include "ppp.h"
+#if PPP_SUPPORT > 0
+#include "fsm.h"
+#include "chap.h"
+#include "magic.h"
+#include "auth.h"
+#include "lcp.h"
+#include "pppdebug.h"
+
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID     2
+#define CILEN_CHAR     3
+#define CILEN_SHORT    4       /* CILEN_VOID + sizeof(short) */
+#define CILEN_CHAP     5       /* CILEN_VOID + sizeof(short) + 1 */
+#define CILEN_LONG     6       /* CILEN_VOID + sizeof(long) */
+#define CILEN_LQR      8       /* CILEN_VOID + sizeof(short) + sizeof(long) */
+#define CILEN_CBCP     3
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void lcp_resetci (fsm*);                /* Reset our CI */
+static int  lcp_cilen (fsm*);                  /* Return length of our CI */
+static void lcp_addci (fsm*, u_char*, int*);       /* Add our CI to pkt */
+static int  lcp_ackci (fsm*, u_char*, int);/* Peer ack'd our CI */
+static int  lcp_nakci (fsm*, u_char*, int);/* Peer nak'd our CI */
+static int  lcp_rejci (fsm*, u_char*, int);/* Peer rej'd our CI */
+static int  lcp_reqci (fsm*, u_char*, int*, int);  /* Rcv peer CI */
+static void lcp_up (fsm*);                         /* We're UP */
+static void lcp_down (fsm*);               /* We're DOWN */
+static void lcp_starting (fsm*);           /* We need lower layer up */
+static void lcp_finished (fsm*);               /* We need lower layer down */
+static int  lcp_extcode (fsm*, int, u_char, u_char*, int);
+
+static void lcp_rprotrej (fsm*, u_char*, int);
+
+/*
+ * routines to send LCP echos to peer
+ */
+static void lcp_echo_lowerup (int);
+static void lcp_echo_lowerdown (int);
+static void LcpEchoTimeout (void*);
+static void lcp_received_echo_reply (fsm*, int, u_char*, int);
+static void LcpSendEchoRequest (fsm*);
+static void LcpLinkFailure (fsm*);
+static void LcpEchoCheck (fsm*);
+
+/*
+ * Protocol entry points.
+ * Some of these are called directly.
+ */
+static void lcp_input (int, u_char *, int);
+static void lcp_protrej (int);
+
+#define CODENAME(x)    ((x) == CONFACK ? "ACK" : \
+                        (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/******************************/
+/*** PUBLIC DATA STRUCTURES ***/
+/******************************/
+/* global vars */
+LinkPhase lcp_phase[NUM_PPP];                  /* Phase of link session (RFC 1661) */
+lcp_options lcp_wantoptions[NUM_PPP];  /* Options that we want to request */
+lcp_options lcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */
+lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+lcp_options lcp_hisoptions[NUM_PPP];   /* Options that we ack'd */
+ext_accm xmit_accm[NUM_PPP];                   /* extended transmit ACCM */
+
+
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+static fsm lcp_fsm[NUM_PPP];                   /* LCP fsm structure (global)*/
+static u_int    lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */
+static u_int    lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */
+static u32_t lcp_echos_pending = 0;    /* Number of outstanding echo msgs */
+static u32_t lcp_echo_number   = 0;    /* ID number of next echo frame */
+static u32_t lcp_echo_timer_running = 0;  /* TRUE if a timer is running */
+
+static u_char nak_buffer[PPP_MRU];     /* where we construct a nak packet */
+
+static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
+    lcp_resetci,               /* Reset our Configuration Information */
+    lcp_cilen,                 /* Length of our Configuration Information */
+    lcp_addci,                 /* Add our Configuration Information */
+    lcp_ackci,                 /* ACK our Configuration Information */
+    lcp_nakci,                 /* NAK our Configuration Information */
+    lcp_rejci,                 /* Reject our Configuration Information */
+    lcp_reqci,                 /* Request peer's Configuration Information */
+    lcp_up,                            /* Called when fsm reaches OPENED state */
+    lcp_down,                  /* Called when fsm leaves OPENED state */
+    lcp_starting,              /* Called when we want the lower layer up */
+    lcp_finished,              /* Called when we want the lower layer down */
+    NULL,                              /* Called when Protocol-Reject received */
+    NULL,                              /* Retransmission is necessary */
+    lcp_extcode,               /* Called to handle LCP-specific codes */
+    "LCP"                              /* String name of protocol */
+};
+
+struct protent lcp_protent = {
+    PPP_LCP,
+    lcp_init,
+    lcp_input,
+    lcp_protrej,
+    lcp_lowerup,
+    lcp_lowerdown,
+    lcp_open,
+    lcp_close,
+#if 0
+    lcp_printpkt,
+    NULL,
+#endif
+    1,
+    "LCP",
+#if 0
+    NULL,
+    NULL,
+    NULL
+#endif
+};
+
+int lcp_loopbackfail = DEFLOOPBACKFAIL;
+
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/*
+ * lcp_init - Initialize LCP.
+ */
+void lcp_init(int unit)
+{
+       fsm *f = &lcp_fsm[unit];
+       lcp_options *wo = &lcp_wantoptions[unit];
+       lcp_options *ao = &lcp_allowoptions[unit];
+       
+       f->unit = unit;
+       f->protocol = PPP_LCP;
+       f->callbacks = &lcp_callbacks;
+       
+       fsm_init(f);
+       
+       wo->passive = 0;
+       wo->silent = 0;
+       wo->restart = 0;                        /* Set to 1 in kernels or multi-line
+                                                                * implementations */
+       wo->neg_mru = 1;
+       wo->mru = PPP_DEFMRU;
+       wo->neg_asyncmap = 1;
+       wo->asyncmap = 0x00000000l;     /* Assume don't need to escape any ctl chars. */
+       wo->neg_chap = 0;                       /* Set to 1 on server */
+       wo->neg_upap = 0;                       /* Set to 1 on server */
+       wo->chap_mdtype = CHAP_DIGEST_MD5;
+       wo->neg_magicnumber = 1;
+       wo->neg_pcompression = 1;
+       wo->neg_accompression = 1;
+       wo->neg_lqr = 0;                        /* no LQR implementation yet */
+       wo->neg_cbcp = 0;
+       
+       ao->neg_mru = 1;
+       ao->mru = PPP_MAXMRU;
+       ao->neg_asyncmap = 1;
+       ao->asyncmap = 0x00000000l;     /* Assume don't need to escape any ctl chars. */
+       ao->neg_chap = (CHAP_SUPPORT != 0);
+       ao->chap_mdtype = CHAP_DIGEST_MD5;
+       ao->neg_upap = (PAP_SUPPORT != 0);
+       ao->neg_magicnumber = 1;
+       ao->neg_pcompression = 1;
+       ao->neg_accompression = 1;
+       ao->neg_lqr = 0;                        /* no LQR implementation yet */
+       ao->neg_cbcp = (CBCP_SUPPORT != 0);
+
+       /* 
+        * Set transmit escape for the flag and escape characters plus anything
+        * set for the allowable options.
+        */
+       memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
+       xmit_accm[unit][15] = 0x60;
+       xmit_accm[unit][0] = (u_char)(ao->asyncmap & 0xFF);
+       xmit_accm[unit][1] = (u_char)((ao->asyncmap >> 8) & 0xFF);
+       xmit_accm[unit][2] = (u_char)((ao->asyncmap >> 16) & 0xFF);
+       xmit_accm[unit][3] = (u_char)((ao->asyncmap >> 24) & 0xFF);
+       LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n",
+                               xmit_accm[unit][0],
+                               xmit_accm[unit][1],
+                               xmit_accm[unit][2],
+                               xmit_accm[unit][3]));
+       
+       lcp_phase[unit] = PHASE_INITIALIZE;
+}
+
+
+/*
+ * lcp_open - LCP is allowed to come up.
+ */
+void lcp_open(int unit)
+{
+       fsm *f = &lcp_fsm[unit];
+       lcp_options *wo = &lcp_wantoptions[unit];
+       
+       f->flags = 0;
+       if (wo->passive)
+               f->flags |= OPT_PASSIVE;
+       if (wo->silent)
+               f->flags |= OPT_SILENT;
+       fsm_open(f);
+       
+       lcp_phase[unit] = PHASE_ESTABLISH; 
+}
+
+
+/*
+ * lcp_close - Take LCP down.
+ */
+void lcp_close(int unit, char *reason)
+{
+       fsm *f = &lcp_fsm[unit];
+       
+       if (lcp_phase[unit] != PHASE_DEAD)
+               lcp_phase[unit] = PHASE_TERMINATE;
+       if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
+               /*
+                * This action is not strictly according to the FSM in RFC1548,
+                * but it does mean that the program terminates if you do an
+                * lcp_close() in passive/silent mode when a connection hasn't
+                * been established.
+                */
+               f->state = CLOSED;
+               lcp_finished(f);
+       }
+       else
+               fsm_close(&lcp_fsm[unit], reason);
+}
+
+
+/*
+ * lcp_lowerup - The lower layer is up.
+ */
+void lcp_lowerup(int unit)
+{
+       lcp_options *wo = &lcp_wantoptions[unit];
+       
+       /*
+       * Don't use A/C or protocol compression on transmission,
+       * but accept A/C and protocol compressed packets
+       * if we are going to ask for A/C and protocol compression.
+       */
+       ppp_set_xaccm(unit, &xmit_accm[unit]);
+       ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0);
+       ppp_recv_config(unit, PPP_MRU, 0x00000000l,
+                                       wo->neg_pcompression, wo->neg_accompression);
+       peer_mru[unit] = PPP_MRU;
+       lcp_allowoptions[unit].asyncmap 
+               = (u_long)xmit_accm[unit][0]
+                       | ((u_long)xmit_accm[unit][1] << 8)
+                       | ((u_long)xmit_accm[unit][2] << 16)
+                       | ((u_long)xmit_accm[unit][3] << 24);
+       LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n",
+                               xmit_accm[unit][3],
+                               xmit_accm[unit][2],
+                               xmit_accm[unit][1],
+                               xmit_accm[unit][0]));
+       
+       fsm_lowerup(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_lowerdown - The lower layer is down.
+ */
+void lcp_lowerdown(int unit)
+{
+       fsm_lowerdown(&lcp_fsm[unit]);
+}
+
+/*
+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.
+ */
+void lcp_sprotrej(int unit, u_char *p, int len)
+{
+       /*
+       * Send back the protocol and the information field of the
+       * rejected packet.  We only get here if LCP is in the OPENED state.
+       */
+
+       fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id,
+                               p, len);
+}
+
+
+
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+/*
+ * lcp_input - Input LCP packet.
+ */
+static void lcp_input(int unit, u_char *p, int len)
+{
+       fsm *f = &lcp_fsm[unit];
+       
+       fsm_input(f, p, len);
+}
+
+
+/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len)
+{
+       u_char *magp;
+       
+       switch( code ){
+       case PROTREJ:
+               lcp_rprotrej(f, inp, len);
+               break;
+       
+       case ECHOREQ:
+               if (f->state != OPENED)
+                       break;
+               LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id));
+               magp = inp;
+               PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
+               fsm_sdata(f, ECHOREP, id, inp, len);
+               break;
+       
+       case ECHOREP:
+               lcp_received_echo_reply(f, id, inp, len);
+               break;
+       
+       case DISCREQ:
+               break;
+       
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+    
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void lcp_rprotrej(fsm *f, u_char *inp, int len)
+{
+       int i;
+       struct protent *protp;
+       u_short prot;
+       
+       if (len < sizeof (u_short)) {
+               LCPDEBUG((LOG_INFO,
+                               "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n"));
+               return;
+       }
+       
+       GETSHORT(prot, inp);
+       
+       LCPDEBUG((LOG_INFO,
+                       "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n",
+                       prot));
+       
+       /*
+       * Protocol-Reject packets received in any state other than the LCP
+       * OPENED state SHOULD be silently discarded.
+       */
+       if( f->state != OPENED ){
+               LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n",
+                               f->state));
+               return;
+       }
+       
+       /*
+       * Upcall the proper Protocol-Reject routine.
+       */
+       for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i)
+               if (protp->protocol == prot && protp->enabled_flag) {
+                       (*protp->protrej)(f->unit);
+                       return;
+               }
+       
+       LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n",
+                       prot));
+}
+
+
+/*
+ * lcp_protrej - A Protocol-Reject was received.
+ */
+static void lcp_protrej(int unit)
+{
+       (void)unit;
+       /*
+       * Can't reject LCP!
+       */
+       LCPDEBUG((LOG_WARNING,
+                       "lcp_protrej: Received Protocol-Reject for LCP!\n"));
+       fsm_protreject(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_resetci - Reset our CI.
+ */
+static void lcp_resetci(fsm *f)
+{
+       lcp_wantoptions[f->unit].magicnumber = magic();
+       lcp_wantoptions[f->unit].numloops = 0;
+       lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
+       peer_mru[f->unit] = PPP_MRU;
+       auth_reset(f->unit);
+}
+
+
+/*
+ * lcp_cilen - Return length of our CI.
+ */
+static int lcp_cilen(fsm *f)
+{
+       lcp_options *go = &lcp_gotoptions[f->unit];
+
+#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0)
+#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0)
+#define LENCISHORT(neg)        ((neg) ? CILEN_SHORT : 0)
+#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0)
+#define LENCILQR(neg)  ((neg) ? CILEN_LQR: 0)
+#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0)
+       /*
+       * NB: we only ask for one of CHAP and UPAP, even if we will
+       * accept either.
+       */
+       return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +
+               LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +
+               LENCICHAP(go->neg_chap) +
+               LENCISHORT(!go->neg_chap && go->neg_upap) +
+               LENCILQR(go->neg_lqr) +
+               LENCICBCP(go->neg_cbcp) +
+               LENCILONG(go->neg_magicnumber) +
+               LENCIVOID(go->neg_pcompression) +
+               LENCIVOID(go->neg_accompression));
+}
+
+
+/*
+ * lcp_addci - Add our desired CIs to a packet.
+ */
+static void lcp_addci(fsm *f, u_char *ucp, int *lenp)
+{
+       lcp_options *go = &lcp_gotoptions[f->unit];
+       u_char *start_ucp = ucp;
+       
+#define ADDCIVOID(opt, neg) \
+       if (neg) { \
+           LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \
+               PUTCHAR(opt, ucp); \
+               PUTCHAR(CILEN_VOID, ucp); \
+       }
+#define ADDCISHORT(opt, neg, val) \
+       if (neg) { \
+           LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \
+               PUTCHAR(opt, ucp); \
+               PUTCHAR(CILEN_SHORT, ucp); \
+               PUTSHORT(val, ucp); \
+       }
+#define ADDCICHAP(opt, neg, val, digest) \
+       if (neg) { \
+           LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \
+               PUTCHAR(opt, ucp); \
+               PUTCHAR(CILEN_CHAP, ucp); \
+               PUTSHORT(val, ucp); \
+               PUTCHAR(digest, ucp); \
+       }
+#define ADDCILONG(opt, neg, val) \
+       if (neg) { \
+           LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \
+               PUTCHAR(opt, ucp); \
+               PUTCHAR(CILEN_LONG, ucp); \
+               PUTLONG(val, ucp); \
+       }
+#define ADDCILQR(opt, neg, val) \
+       if (neg) { \
+           LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \
+               PUTCHAR(opt, ucp); \
+               PUTCHAR(CILEN_LQR, ucp); \
+               PUTSHORT(PPP_LQR, ucp); \
+               PUTLONG(val, ucp); \
+       }
+#define ADDCICHAR(opt, neg, val) \
+       if (neg) { \
+           LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \
+               PUTCHAR(opt, ucp); \
+               PUTCHAR(CILEN_CHAR, ucp); \
+               PUTCHAR(val, ucp); \
+       }
+       
+       ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
+       ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl,
+                       go->asyncmap);
+       ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+       ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+       ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+       ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+       ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+       ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+       ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+       
+       if (ucp - start_ucp != *lenp) {
+               /* this should never happen, because peer_mtu should be 1500 */
+               LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n"));
+       }
+}
+
+
+/*
+ * lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
+ *
+ * Returns:
+ *     0 - Ack was bad.
+ *     1 - Ack was good.
+ */
+static int lcp_ackci(fsm *f, u_char *p, int len)
+{
+       lcp_options *go = &lcp_gotoptions[f->unit];
+       u_char cilen, citype, cichar;
+       u_short cishort;
+       u32_t cilong;
+       
+       /*
+       * CIs must be in exactly the same order that we sent.
+       * Check packet length and CI length at each step.
+       * If we find any deviations, then this packet is bad.
+       */
+#define ACKCIVOID(opt, neg) \
+       if (neg) { \
+               if ((len -= CILEN_VOID) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != CILEN_VOID || \
+                               citype != opt) \
+                       goto bad; \
+       }
+#define ACKCISHORT(opt, neg, val) \
+       if (neg) { \
+               if ((len -= CILEN_SHORT) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != CILEN_SHORT || \
+                               citype != opt) \
+                       goto bad; \
+               GETSHORT(cishort, p); \
+               if (cishort != val) \
+                       goto bad; \
+       }
+#define ACKCICHAR(opt, neg, val) \
+       if (neg) { \
+               if ((len -= CILEN_CHAR) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != CILEN_CHAR || \
+                               citype != opt) \
+                       goto bad; \
+               GETCHAR(cichar, p); \
+               if (cichar != val) \
+                       goto bad; \
+       }
+#define ACKCICHAP(opt, neg, val, digest) \
+       if (neg) { \
+               if ((len -= CILEN_CHAP) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != CILEN_CHAP || \
+                               citype != opt) \
+                       goto bad; \
+               GETSHORT(cishort, p); \
+               if (cishort != val) \
+                       goto bad; \
+               GETCHAR(cichar, p); \
+               if (cichar != digest) \
+                       goto bad; \
+       }
+#define ACKCILONG(opt, neg, val) \
+       if (neg) { \
+               if ((len -= CILEN_LONG) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != CILEN_LONG || \
+                               citype != opt) \
+                       goto bad; \
+               GETLONG(cilong, p); \
+               if (cilong != val) \
+                       goto bad; \
+       }
+#define ACKCILQR(opt, neg, val) \
+       if (neg) { \
+               if ((len -= CILEN_LQR) < 0) \
+                       goto bad; \
+               GETCHAR(citype, p); \
+               GETCHAR(cilen, p); \
+               if (cilen != CILEN_LQR || \
+                               citype != opt) \
+                       goto bad; \
+               GETSHORT(cishort, p); \
+               if (cishort != PPP_LQR) \
+                       goto bad; \
+               GETLONG(cilong, p); \
+               if (cilong != val) \
+                       goto bad; \
+       }
+       
+       ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
+       ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl,
+                       go->asyncmap);
+       ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+       ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+       ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+       ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+       ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+       ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+       ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+       
+       /*
+        * If there are any remaining CIs, then this packet is bad.
+        */
+       if (len != 0)
+               goto bad;
+       LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n"));
+       return (1);
+bad:
+       LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n"));
+       return (0);
+}
+
+
+/*
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ *     0 - Nak was bad.
+ *     1 - Nak was good.
+ */
+static int lcp_nakci(fsm *f, u_char *p, int len)
+{
+       lcp_options *go = &lcp_gotoptions[f->unit];
+       lcp_options *wo = &lcp_wantoptions[f->unit];
+       u_char citype, cichar, *next;
+       u_short cishort;
+       u32_t cilong;
+       lcp_options no;         /* options we've seen Naks for */
+       lcp_options try;                /* options to request next time */
+       int looped_back = 0;
+       int cilen;
+       
+       BZERO(&no, sizeof(no));
+       try = *go;
+       
+       /*
+       * Any Nak'd CIs must be in exactly the same order that we sent.
+       * Check packet length and CI length at each step.
+       * If we find any deviations, then this packet is bad.
+       */
+#define NAKCIVOID(opt, neg, code) \
+       if (go->neg && \
+                       len >= CILEN_VOID && \
+                       p[1] == CILEN_VOID && \
+                       p[0] == opt) { \
+               len -= CILEN_VOID; \
+               INCPTR(CILEN_VOID, p); \
+               no.neg = 1; \
+               code \
+       }
+#define NAKCICHAP(opt, neg, code) \
+       if (go->neg && \
+                       len >= CILEN_CHAP && \
+                       p[1] == CILEN_CHAP && \
+                       p[0] == opt) { \
+               len -= CILEN_CHAP; \
+               INCPTR(2, p); \
+               GETSHORT(cishort, p); \
+               GETCHAR(cichar, p); \
+               no.neg = 1; \
+               code \
+       }
+#define NAKCICHAR(opt, neg, code) \
+       if (go->neg && \
+                       len >= CILEN_CHAR && \
+                       p[1] == CILEN_CHAR && \
+                       p[0] == opt) { \
+               len -= CILEN_CHAR; \
+               INCPTR(2, p); \
+               GETCHAR(cichar, p); \
+               no.neg = 1; \
+               code \
+       }
+#define NAKCISHORT(opt, neg, code) \
+       if (go->neg && \
+                       len >= CILEN_SHORT && \
+                       p[1] == CILEN_SHORT && \
+                       p[0] == opt) { \
+               len -= CILEN_SHORT; \
+               INCPTR(2, p); \
+               GETSHORT(cishort, p); \
+               no.neg = 1; \
+               code \
+       }
+#define NAKCILONG(opt, neg, code) \
+       if (go->neg && \
+                       len >= CILEN_LONG && \
+                       p[1] == CILEN_LONG && \
+                       p[0] == opt) { \
+               len -= CILEN_LONG; \
+               INCPTR(2, p); \
+               GETLONG(cilong, p); \
+               no.neg = 1; \
+               code \
+       }
+#define NAKCILQR(opt, neg, code) \
+       if (go->neg && \
+                       len >= CILEN_LQR && \
+                       p[1] == CILEN_LQR && \
+                       p[0] == opt) { \
+               len -= CILEN_LQR; \
+               INCPTR(2, p); \
+               GETSHORT(cishort, p); \
+               GETLONG(cilong, p); \
+               no.neg = 1; \
+               code \
+       }
+       
+       /*
+       * We don't care if they want to send us smaller packets than
+       * we want.  Therefore, accept any MRU less than what we asked for,
+       * but then ignore the new value when setting the MRU in the kernel.
+       * If they send us a bigger MRU than what we asked, accept it, up to
+       * the limit of the default MRU we'd get if we didn't negotiate.
+       */
+       if (go->neg_mru && go->mru != PPP_DEFMRU) {
+               NAKCISHORT(CI_MRU, neg_mru,
+                       if (cishort <= wo->mru || cishort < PPP_DEFMRU)
+                               try.mru = cishort;
+               );
+       }
+       
+       /*
+       * Add any characters they want to our (receive-side) asyncmap.
+       */
+       if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) {
+               NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+                       try.asyncmap = go->asyncmap | cilong;
+               );
+       }
+       
+       /*
+       * If they've nak'd our authentication-protocol, check whether
+       * they are proposing a different protocol, or a different
+       * hash algorithm for CHAP.
+       */
+       if ((go->neg_chap || go->neg_upap)
+                       && len >= CILEN_SHORT
+                       && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
+               cilen = p[1];
+       len -= cilen;
+       no.neg_chap = go->neg_chap;
+       no.neg_upap = go->neg_upap;
+       INCPTR(2, p);
+       GETSHORT(cishort, p);
+       if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
+               /*
+                * If we were asking for CHAP, they obviously don't want to do it.
+                * If we weren't asking for CHAP, then we were asking for PAP,
+                * in which case this Nak is bad.
+                */
+               if (!go->neg_chap)
+                       goto bad;
+               try.neg_chap = 0;
+       
+       } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
+               GETCHAR(cichar, p);
+               if (go->neg_chap) {
+                       /*
+                        * We were asking for CHAP/MD5; they must want a different
+                        * algorithm.  If they can't do MD5, we'll have to stop
+                        * asking for CHAP.
+                        */
+                       if (cichar != go->chap_mdtype)
+                               try.neg_chap = 0;
+               } else {
+                       /*
+                        * Stop asking for PAP if we were asking for it.
+                        */
+                       try.neg_upap = 0;
+               }
+       
+       } else {
+               /*
+                * We don't recognize what they're suggesting.
+                * Stop asking for what we were asking for.
+                */
+               if (go->neg_chap)
+                       try.neg_chap = 0;
+               else
+                       try.neg_upap = 0;
+               p += cilen - CILEN_SHORT;
+       }
+       }
+       
+       /*
+       * If they can't cope with our link quality protocol, we'll have
+       * to stop asking for LQR.  We haven't got any other protocol.
+       * If they Nak the reporting period, take their value XXX ?
+       */
+       NAKCILQR(CI_QUALITY, neg_lqr,
+               if (cishort != PPP_LQR)
+                       try.neg_lqr = 0;
+               else
+                       try.lqr_period = cilong;
+       );
+       
+       /*
+       * Only implementing CBCP...not the rest of the callback options
+       */
+       NAKCICHAR(CI_CALLBACK, neg_cbcp,
+               try.neg_cbcp = 0;
+       );
+       
+       /*
+       * Check for a looped-back line.
+       */
+       NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+               try.magicnumber = magic();
+               looped_back = 1;
+       );
+       
+       /*
+       * Peer shouldn't send Nak for protocol compression or
+       * address/control compression requests; they should send
+       * a Reject instead.  If they send a Nak, treat it as a Reject.
+       */
+       NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
+               try.neg_pcompression = 0;
+       );
+       NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
+               try.neg_accompression = 0;
+       );
+       
+       /*
+       * There may be remaining CIs, if the peer is requesting negotiation
+       * on an option that we didn't include in our request packet.
+       * If we see an option that we requested, or one we've already seen
+       * in this packet, then this packet is bad.
+       * If we wanted to respond by starting to negotiate on the requested
+       * option(s), we could, but we don't, because except for the
+       * authentication type and quality protocol, if we are not negotiating
+       * an option, it is because we were told not to.
+       * For the authentication type, the Nak from the peer means
+       * `let me authenticate myself with you' which is a bit pointless.
+       * For the quality protocol, the Nak means `ask me to send you quality
+       * reports', but if we didn't ask for them, we don't want them.
+       * An option we don't recognize represents the peer asking to
+       * negotiate some option we don't support, so ignore it.
+       */
+       while (len > CILEN_VOID) {
+               GETCHAR(citype, p);
+               GETCHAR(cilen, p);
+               if (cilen < CILEN_VOID || (len -= cilen) < 0)
+                       goto bad;
+               next = p + cilen - 2;
+               
+               switch (citype) {
+               case CI_MRU:
+                       if ((go->neg_mru && go->mru != PPP_DEFMRU)
+                                       || no.neg_mru || cilen != CILEN_SHORT)
+                               goto bad;
+                       GETSHORT(cishort, p);
+                       if (cishort < PPP_DEFMRU)
+                               try.mru = cishort;
+                       break;
+               case CI_ASYNCMAP:
+                       if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl)
+                                       || no.neg_asyncmap || cilen != CILEN_LONG)
+                               goto bad;
+                       break;
+               case CI_AUTHTYPE:
+                       if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+                               goto bad;
+                       break;
+               case CI_MAGICNUMBER:
+                       if (go->neg_magicnumber || no.neg_magicnumber ||
+                                       cilen != CILEN_LONG)
+                               goto bad;
+                       break;
+               case CI_PCOMPRESSION:
+                       if (go->neg_pcompression || no.neg_pcompression
+                                       || cilen != CILEN_VOID)
+                               goto bad;
+                       break;
+               case CI_ACCOMPRESSION:
+                       if (go->neg_accompression || no.neg_accompression
+                                       || cilen != CILEN_VOID)
+                               goto bad;
+                       break;
+               case CI_QUALITY:
+                       if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+                               goto bad;
+                       break;
+               }
+               p = next;
+       }
+       
+       /* If there is still anything left, this packet is bad. */
+       if (len != 0)
+               goto bad;
+       
+       /*
+       * OK, the Nak is good.  Now we can update state.
+       */
+       if (f->state != OPENED) {
+               if (looped_back) {
+                       if (++try.numloops >= lcp_loopbackfail) {
+                               LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n"));
+                               lcp_close(f->unit, "Loopback detected");
+                       }
+               } 
+               else
+                       try.numloops = 0;
+               *go = try;
+       }
+       
+       return 1;
+       
+bad:
+       LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n"));
+       return 0;
+}
+
+
+/*
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ *     0 - Reject was bad.
+ *     1 - Reject was good.
+ */
+static int lcp_rejci(fsm *f, u_char *p, int len)
+{
+       lcp_options *go = &lcp_gotoptions[f->unit];
+       u_char cichar;
+       u_short cishort;
+       u32_t cilong;
+       lcp_options try;                /* options to request next time */
+       
+       try = *go;
+       
+       /*
+       * Any Rejected CIs must be in exactly the same order that we sent.
+       * Check packet length and CI length at each step.
+       * If we find any deviations, then this packet is bad.
+       */
+#define REJCIVOID(opt, neg) \
+       if (go->neg && \
+                       len >= CILEN_VOID && \
+                       p[1] == CILEN_VOID && \
+                       p[0] == opt) { \
+               len -= CILEN_VOID; \
+               INCPTR(CILEN_VOID, p); \
+               try.neg = 0; \
+               LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \
+       }
+#define REJCISHORT(opt, neg, val) \
+       if (go->neg && \
+                       len >= CILEN_SHORT && \
+                       p[1] == CILEN_SHORT && \
+                       p[0] == opt) { \
+               len -= CILEN_SHORT; \
+               INCPTR(2, p); \
+               GETSHORT(cishort, p); \
+               /* Check rejected value. */ \
+               if (cishort != val) \
+                       goto bad; \
+               try.neg = 0; \
+               LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \
+       }
+#define REJCICHAP(opt, neg, val, digest) \
+       if (go->neg && \
+                       len >= CILEN_CHAP && \
+                       p[1] == CILEN_CHAP && \
+                       p[0] == opt) { \
+               len -= CILEN_CHAP; \
+               INCPTR(2, p); \
+               GETSHORT(cishort, p); \
+               GETCHAR(cichar, p); \
+               /* Check rejected value. */ \
+               if (cishort != val || cichar != digest) \
+                       goto bad; \
+               try.neg = 0; \
+               try.neg_upap = 0; \
+               LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \
+       }
+#define REJCILONG(opt, neg, val) \
+       if (go->neg && \
+                       len >= CILEN_LONG && \
+                       p[1] == CILEN_LONG && \
+                       p[0] == opt) { \
+               len -= CILEN_LONG; \
+               INCPTR(2, p); \
+               GETLONG(cilong, p); \
+               /* Check rejected value. */ \
+               if (cilong != val) \
+                       goto bad; \
+               try.neg = 0; \
+               LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \
+       }
+#define REJCILQR(opt, neg, val) \
+       if (go->neg && \
+                       len >= CILEN_LQR && \
+                       p[1] == CILEN_LQR && \
+                       p[0] == opt) { \
+               len -= CILEN_LQR; \
+               INCPTR(2, p); \
+               GETSHORT(cishort, p); \
+               GETLONG(cilong, p); \
+               /* Check rejected value. */ \
+               if (cishort != PPP_LQR || cilong != val) \
+                       goto bad; \
+               try.neg = 0; \
+               LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \
+       }
+#define REJCICBCP(opt, neg, val) \
+       if (go->neg && \
+                       len >= CILEN_CBCP && \
+                       p[1] == CILEN_CBCP && \
+                       p[0] == opt) { \
+               len -= CILEN_CBCP; \
+               INCPTR(2, p); \
+               GETCHAR(cichar, p); \
+               /* Check rejected value. */ \
+               if (cichar != val) \
+                       goto bad; \
+               try.neg = 0; \
+               LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \
+       }
+       
+       REJCISHORT(CI_MRU, neg_mru, go->mru);
+       REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+       REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
+       if (!go->neg_chap) {
+               REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
+       }
+       REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+       REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
+       REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+       REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+       REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
+       
+       /*
+       * If there are any remaining CIs, then this packet is bad.
+       */
+       if (len != 0)
+               goto bad;
+       /*
+       * Now we can update state.
+       */
+       if (f->state != OPENED)
+               *go = try;
+       return 1;
+       
+bad:
+       LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n"));
+       return 0;
+}
+
+
+/*
+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int lcp_reqci(fsm *f, 
+                                               u_char *inp,            /* Requested CIs */
+                                               int *lenp,                      /* Length of requested CIs */
+                                               int reject_if_disagree)
+{
+       lcp_options *go = &lcp_gotoptions[f->unit];
+       lcp_options *ho = &lcp_hisoptions[f->unit];
+       lcp_options *ao = &lcp_allowoptions[f->unit];
+       u_char *cip, *next;                     /* Pointer to current and next CIs */
+       int cilen, citype, cichar;      /* Parsed len, type, char value */
+       u_short cishort;                        /* Parsed short value */
+       u32_t cilong;                   /* Parse long value */
+       int rc = CONFACK;                       /* Final packet return code */
+       int orc;                                        /* Individual option return code */
+       u_char *p;                                      /* Pointer to next char to parse */
+       u_char *rejp;                           /* Pointer to next char in reject frame */
+       u_char *nakp;                           /* Pointer to next char in Nak frame */
+       int l = *lenp;                          /* Length left */
+#if TRACELCP > 0
+       char traceBuf[80];
+       int traceNdx = 0;
+#endif
+       
+       /*
+        * Reset all his options.
+        */
+       BZERO(ho, sizeof(*ho));
+       
+       /*
+        * Process all his options.
+        */
+       next = inp;
+       nakp = nak_buffer;
+       rejp = inp;
+       while (l) {
+               orc = CONFACK;                  /* Assume success */
+               cip = p = next;                 /* Remember begining of CI */
+               if (l < 2 ||                    /* Not enough data for CI header or */
+                               p[1] < 2 ||                     /*  CI length too small or */
+                               p[1] > l) {                     /*  CI length too big? */
+                       LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n"));
+                       orc = CONFREJ;          /* Reject bad CI */
+                       cilen = l;                      /* Reject till end of packet */
+                       l = 0;                  /* Don't loop again */
+                       citype = 0;
+                       goto endswitch;
+               }
+               GETCHAR(citype, p);             /* Parse CI type */
+               GETCHAR(cilen, p);              /* Parse CI length */
+               l -= cilen;                     /* Adjust remaining length */
+               next += cilen;                  /* Step to next CI */
+               
+               switch (citype) {               /* Check CI type */
+               case CI_MRU:
+                       if (!ao->neg_mru) {             /* Allow option? */
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n"));
+                               orc = CONFREJ;          /* Reject CI */
+                               break;
+                       } else if (cilen != CILEN_SHORT) {      /* Check CI length */
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n"));
+                               orc = CONFREJ;          /* Reject CI */
+                               break;
+                       }
+                       GETSHORT(cishort, p);   /* Parse MRU */
+                       
+                       /*
+                        * He must be able to receive at least our minimum.
+                        * No need to check a maximum.  If he sends a large number,
+                        * we'll just ignore it.
+                        */
+                       if (cishort < PPP_MINMRU) {
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n"));
+                               orc = CONFNAK;          /* Nak CI */
+                               PUTCHAR(CI_MRU, nakp);
+                               PUTCHAR(CILEN_SHORT, nakp);
+                               PUTSHORT(PPP_MINMRU, nakp);     /* Give him a hint */
+                               break;
+                       }
+                       ho->neg_mru = 1;                /* Remember he sent MRU */
+                       ho->mru = cishort;              /* And remember value */
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort);
+                       traceNdx = strlen(traceBuf);
+#endif
+                       break;
+               
+               case CI_ASYNCMAP:
+                       if (!ao->neg_asyncmap) {
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n"));
+                               orc = CONFREJ;
+                               break;
+                       } else if (cilen != CILEN_LONG) {
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n"));
+                               orc = CONFREJ;
+                               break;
+                       }
+                       GETLONG(cilong, p);
+                       
+                       /*
+                        * Asyncmap must have set at least the bits
+                        * which are set in lcp_allowoptions[unit].asyncmap.
+                        */
+                       if ((ao->asyncmap & ~cilong) != 0) {
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", 
+                                                       cilong, ao->asyncmap));
+                               orc = CONFNAK;
+                               PUTCHAR(CI_ASYNCMAP, nakp);
+                               PUTCHAR(CILEN_LONG, nakp);
+                               PUTLONG(ao->asyncmap | cilong, nakp);
+                               break;
+                       }
+                       ho->neg_asyncmap = 1;
+                       ho->asyncmap = cilong;
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong);
+                       traceNdx = strlen(traceBuf);
+#endif
+                       break;
+               
+               case CI_AUTHTYPE:
+                       if (cilen < CILEN_SHORT) {
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n"));
+                               orc = CONFREJ;
+                               break;
+                       } else if (!(ao->neg_upap || ao->neg_chap)) {
+                               /*
+                                * Reject the option if we're not willing to authenticate.
+                                */
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n"));
+                               orc = CONFREJ;
+                               break;
+                       }
+                       GETSHORT(cishort, p);
+                       
+                       /*
+                        * Authtype must be UPAP or CHAP.
+                        *
+                        * Note: if both ao->neg_upap and ao->neg_chap are set,
+                        * and the peer sends a Configure-Request with two
+                        * authenticate-protocol requests, one for CHAP and one
+                        * for UPAP, then we will reject the second request.
+                        * Whether we end up doing CHAP or UPAP depends then on
+                        * the ordering of the CIs in the peer's Configure-Request.
+                        */
+                       
+                       if (cishort == PPP_PAP) {
+                               if (ho->neg_chap) {     /* we've already accepted CHAP */
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n"));
+                                       orc = CONFREJ;
+                                       break;
+                               } else if (cilen != CILEN_SHORT) {
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n"));
+                                       orc = CONFREJ;
+                                       break;
+                               }
+                               if (!ao->neg_upap) {    /* we don't want to do PAP */
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n"));
+                                       orc = CONFNAK;  /* NAK it and suggest CHAP */
+                                       PUTCHAR(CI_AUTHTYPE, nakp);
+                                       PUTCHAR(CILEN_CHAP, nakp);
+                                       PUTSHORT(PPP_CHAP, nakp);
+                                       PUTCHAR(ao->chap_mdtype, nakp);
+                                       break;
+                               }
+                               ho->neg_upap = 1;
+#if TRACELCP > 0
+                               snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort);
+                               traceNdx = strlen(traceBuf);
+#endif
+                               break;
+                       }
+                       if (cishort == PPP_CHAP) {
+                               if (ho->neg_upap) {     /* we've already accepted PAP */
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n"));
+                                       orc = CONFREJ;
+                                       break;
+                               } else if (cilen != CILEN_CHAP) {
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n"));
+                                       orc = CONFREJ;
+                                       break;
+                               }
+                               if (!ao->neg_chap) {    /* we don't want to do CHAP */
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n"));
+                                       orc = CONFNAK;  /* NAK it and suggest PAP */
+                                       PUTCHAR(CI_AUTHTYPE, nakp);
+                                       PUTCHAR(CILEN_SHORT, nakp);
+                                       PUTSHORT(PPP_PAP, nakp);
+                                       break;
+                               }
+                               GETCHAR(cichar, p);     /* get digest type*/
+                               if (cichar != CHAP_DIGEST_MD5
+#ifdef CHAPMS
+                                               && cichar != CHAP_MICROSOFT
+#endif
+                               ) {
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar));
+                                       orc = CONFNAK;
+                                       PUTCHAR(CI_AUTHTYPE, nakp);
+                                       PUTCHAR(CILEN_CHAP, nakp);
+                                       PUTSHORT(PPP_CHAP, nakp);
+                                       PUTCHAR(ao->chap_mdtype, nakp);
+                                       break;
+                               }
+#if TRACELCP > 0
+                               snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar);
+                               traceNdx = strlen(traceBuf);
+#endif
+                               ho->chap_mdtype = cichar; /* save md type */
+                               ho->neg_chap = 1;
+                               break;
+                       }
+                       
+                       /*
+                        * We don't recognize the protocol they're asking for.
+                        * Nak it with something we're willing to do.
+                        * (At this point we know ao->neg_upap || ao->neg_chap.)
+                        */
+                       orc = CONFNAK;
+                       PUTCHAR(CI_AUTHTYPE, nakp);
+                       if (ao->neg_chap) {
+                               LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort));
+                               PUTCHAR(CILEN_CHAP, nakp);
+                               PUTSHORT(PPP_CHAP, nakp);
+                               PUTCHAR(ao->chap_mdtype, nakp);
+                       } 
+                       else {
+                               LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort));
+                               PUTCHAR(CILEN_SHORT, nakp);
+                               PUTSHORT(PPP_PAP, nakp);
+                       }
+                       break;
+               
+               case CI_QUALITY:
+                       GETSHORT(cishort, p);
+                       GETLONG(cilong, p);
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong);
+                       traceNdx = strlen(traceBuf);
+#endif
+
+                       if (!ao->neg_lqr ||
+                                       cilen != CILEN_LQR) {
+                               orc = CONFREJ;
+                               break;
+                       }
+                       
+                       /*
+                        * Check the protocol and the reporting period.
+                        * XXX When should we Nak this, and what with?
+                        */
+                       if (cishort != PPP_LQR) {
+                               orc = CONFNAK;
+                               PUTCHAR(CI_QUALITY, nakp);
+                               PUTCHAR(CILEN_LQR, nakp);
+                               PUTSHORT(PPP_LQR, nakp);
+                               PUTLONG(ao->lqr_period, nakp);
+                               break;
+                       }
+                       break;
+               
+               case CI_MAGICNUMBER:
+                       if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+                                       cilen != CILEN_LONG) {
+                               orc = CONFREJ;
+                               break;
+                       }
+                       GETLONG(cilong, p);
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong);
+                       traceNdx = strlen(traceBuf);
+#endif
+
+                       /*
+                        * He must have a different magic number.
+                        */
+                       if (go->neg_magicnumber &&
+                                       cilong == go->magicnumber) {
+                               cilong = magic();       /* Don't put magic() inside macro! */
+                               orc = CONFNAK;
+                               PUTCHAR(CI_MAGICNUMBER, nakp);
+                               PUTCHAR(CILEN_LONG, nakp);
+                               PUTLONG(cilong, nakp);
+                               break;
+                       }
+                       ho->neg_magicnumber = 1;
+                       ho->magicnumber = cilong;
+                       break;
+               
+               
+               case CI_PCOMPRESSION:
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION");
+                       traceNdx = strlen(traceBuf);
+#endif
+                       if (!ao->neg_pcompression ||
+                                       cilen != CILEN_VOID) {
+                               orc = CONFREJ;
+                               break;
+                       }
+                       ho->neg_pcompression = 1;
+                       break;
+               
+               case CI_ACCOMPRESSION:
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION");
+                       traceNdx = strlen(traceBuf);
+#endif
+                       if (!ao->neg_accompression ||
+                                       cilen != CILEN_VOID) {
+                               orc = CONFREJ;
+                               break;
+                       }
+                       ho->neg_accompression = 1;
+                       break;
+               
+               case CI_MRRU:
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU");
+                       traceNdx = strlen(traceBuf);
+#endif
+                       orc = CONFREJ;
+                       break;
+               
+               case CI_SSNHF:
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF");
+                       traceNdx = strlen(traceBuf);
+#endif
+                       orc = CONFREJ;
+                       break;
+               
+               case CI_EPDISC:
+#if TRACELCP > 0
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC");
+                       traceNdx = strlen(traceBuf);
+#endif
+                       orc = CONFREJ;
+                       break;
+               
+               default:
+#if TRACELCP
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype);
+                       traceNdx = strlen(traceBuf);
+#endif
+                       orc = CONFREJ;
+                       break;
+               }
+               
+       endswitch:
+#if TRACELCP
+               if (traceNdx >= 80 - 32) {
+                       LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf));
+                       traceNdx = 0;
+               }
+#endif
+               if (orc == CONFACK &&           /* Good CI */
+                               rc != CONFACK)          /*  but prior CI wasnt? */
+                       continue;                       /* Don't send this one */
+               
+               if (orc == CONFNAK) {           /* Nak this CI? */
+                       if (reject_if_disagree  /* Getting fed up with sending NAKs? */
+                                       && citype != CI_MAGICNUMBER) {
+                               orc = CONFREJ;          /* Get tough if so */
+                       } 
+                       else {
+                               if (rc == CONFREJ)      /* Rejecting prior CI? */
+                                       continue;               /* Don't send this one */
+                               rc = CONFNAK;
+                       }
+               }
+               if (orc == CONFREJ) {           /* Reject this CI */
+                       rc = CONFREJ;
+                       if (cip != rejp)                /* Need to move rejected CI? */
+                               BCOPY(cip, rejp, cilen); /* Move it */
+                       INCPTR(cilen, rejp);    /* Update output pointer */
+               }
+       }
+       
+       /*
+        * If we wanted to send additional NAKs (for unsent CIs), the
+        * code would go here.  The extra NAKs would go at *nakp.
+        * At present there are no cases where we want to ask the
+        * peer to negotiate an option.
+        */
+       
+       switch (rc) {
+       case CONFACK:
+               *lenp = (int)(next - inp);
+               break;
+       case CONFNAK:
+               /*
+                * Copy the Nak'd options from the nak_buffer to the caller's buffer.
+                */
+               *lenp = (int)(nakp - nak_buffer);
+               BCOPY(nak_buffer, inp, *lenp);
+               break;
+       case CONFREJ:
+               *lenp = (int)(rejp - inp);
+               break;
+       }
+       
+#if TRACELCP > 0
+       if (traceNdx > 0) {
+               LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf));
+       }
+#endif
+       LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc)));
+       return (rc);                    /* Return final code */
+}
+
+
+/*
+ * lcp_up - LCP has come UP.
+ */
+static void lcp_up(fsm *f)
+{
+       lcp_options *wo = &lcp_wantoptions[f->unit];
+       lcp_options *ho = &lcp_hisoptions[f->unit];
+       lcp_options *go = &lcp_gotoptions[f->unit];
+       lcp_options *ao = &lcp_allowoptions[f->unit];
+       
+       if (!go->neg_magicnumber)
+               go->magicnumber = 0;
+       if (!ho->neg_magicnumber)
+               ho->magicnumber = 0;
+       
+       /*
+       * Set our MTU to the smaller of the MTU we wanted and
+       * the MRU our peer wanted.  If we negotiated an MRU,
+       * set our MRU to the larger of value we wanted and
+       * the value we got in the negotiation.
+       */
+       ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),
+                               (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl),
+                               ho->neg_pcompression, ho->neg_accompression);
+       /*
+       * If the asyncmap hasn't been negotiated, we really should
+       * set the receive asyncmap to ffffffff, but we set it to 0
+       * for backwards contemptibility.
+       */
+       ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU),
+                               (go->neg_asyncmap? go->asyncmap: 0x00000000),
+                               go->neg_pcompression, go->neg_accompression);
+       
+       if (ho->neg_mru)
+               peer_mru[f->unit] = ho->mru;
+       
+       lcp_echo_lowerup(f->unit);  /* Enable echo messages */
+       
+       link_established(f->unit);
+}
+
+
+/*
+ * lcp_down - LCP has gone DOWN.
+ *
+ * Alert other protocols.
+ */
+static void lcp_down(fsm *f)
+{
+       lcp_options *go = &lcp_gotoptions[f->unit];
+       
+       lcp_echo_lowerdown(f->unit);
+       
+       link_down(f->unit);
+       
+       ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0);
+       ppp_recv_config(f->unit, PPP_MRU,
+                               (go->neg_asyncmap? go->asyncmap: 0x00000000),
+                               go->neg_pcompression, go->neg_accompression);
+       peer_mru[f->unit] = PPP_MRU;
+}
+
+
+/*
+ * lcp_starting - LCP needs the lower layer up.
+ */
+static void lcp_starting(fsm *f)
+{
+       link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void lcp_finished(fsm *f)
+{
+       link_terminated(f->unit);
+}
+
+
+#if 0
+/*
+ * print_string - print a readable representation of a string using
+ * printer.
+ */
+static void print_string(
+    char *p,
+    int len,
+    void (*printer) (void *, char *, ...),
+    void *arg
+)
+{
+    int c;
+    
+    printer(arg, "\"");
+    for (; len > 0; --len) {
+        c = *p++;
+        if (' ' <= c && c <= '~') {
+            if (c == '\\' || c == '"')
+                printer(arg, "\\");
+            printer(arg, "%c", c);
+        } else {
+            switch (c) {
+            case '\n':
+                printer(arg, "\\n");
+                break;
+            case '\r':
+                printer(arg, "\\r");
+                break;
+            case '\t':
+                printer(arg, "\\t");
+                break;
+            default:
+                printer(arg, "\\%.3o", c);
+            }
+        }
+    }
+    printer(arg, "\"");
+}
+
+
+/*
+ * lcp_printpkt - print the contents of an LCP packet.
+ */
+static char *lcp_codenames[] = {
+       "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+       "TermReq", "TermAck", "CodeRej", "ProtRej",
+       "EchoReq", "EchoRep", "DiscReq"
+};
+
+static int lcp_printpkt(
+       u_char *p,
+       int plen,
+       void (*printer) (void *, char *, ...),
+       void *arg
+)
+{
+       int code, id, len, olen;
+       u_char *pstart, *optend;
+       u_short cishort;
+       u32_t cilong;
+       
+       if (plen < HEADERLEN)
+               return 0;
+       pstart = p;
+       GETCHAR(code, p);
+       GETCHAR(id, p);
+       GETSHORT(len, p);
+       if (len < HEADERLEN || len > plen)
+               return 0;
+       
+       if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *))
+               printer(arg, " %s", lcp_codenames[code-1]);
+       else
+               printer(arg, " code=0x%x", code);
+       printer(arg, " id=0x%x", id);
+       len -= HEADERLEN;
+       switch (code) {
+       case CONFREQ:
+       case CONFACK:
+       case CONFNAK:
+       case CONFREJ:
+               /* print option list */
+               while (len >= 2) {
+                       GETCHAR(code, p);
+                       GETCHAR(olen, p);
+                       p -= 2;
+                       if (olen < 2 || olen > len) {
+                               break;
+                       }
+                       printer(arg, " <");
+                       len -= olen;
+                       optend = p + olen;
+                       switch (code) {
+                       case CI_MRU:
+                               if (olen == CILEN_SHORT) {
+                                       p += 2;
+                                       GETSHORT(cishort, p);
+                                       printer(arg, "mru %d", cishort);
+                               }
+                               break;
+                       case CI_ASYNCMAP:
+                               if (olen == CILEN_LONG) {
+                                       p += 2;
+                                       GETLONG(cilong, p);
+                                       printer(arg, "asyncmap 0x%lx", cilong);
+                               }
+                               break;
+                       case CI_AUTHTYPE:
+                               if (olen >= CILEN_SHORT) {
+                                       p += 2;
+                                       printer(arg, "auth ");
+                                       GETSHORT(cishort, p);
+                                       switch (cishort) {
+                                       case PPP_PAP:
+                                               printer(arg, "pap");
+                                               break;
+                                       case PPP_CHAP:
+                                               printer(arg, "chap");
+                                               break;
+                                       default:
+                                               printer(arg, "0x%x", cishort);
+                                       }
+                               }
+                               break;
+                       case CI_QUALITY:
+                               if (olen >= CILEN_SHORT) {
+                                       p += 2;
+                                       printer(arg, "quality ");
+                                       GETSHORT(cishort, p);
+                                       switch (cishort) {
+                                       case PPP_LQR:
+                                               printer(arg, "lqr");
+                                               break;
+                                       default:
+                                               printer(arg, "0x%x", cishort);
+                                       }
+                               }
+                               break;
+                       case CI_CALLBACK:
+                               if (olen >= CILEN_CHAR) {
+                                       p += 2;
+                                       printer(arg, "callback ");
+                                       GETSHORT(cishort, p);
+                                       switch (cishort) {
+                                       case CBCP_OPT:
+                                               printer(arg, "CBCP");
+                                               break;
+                                       default:
+                                               printer(arg, "0x%x", cishort);
+                                       }
+                               }
+                               break;
+                       case CI_MAGICNUMBER:
+                               if (olen == CILEN_LONG) {
+                                       p += 2;
+                                       GETLONG(cilong, p);
+                                       printer(arg, "magic 0x%x", cilong);
+                               }
+                               break;
+                       case CI_PCOMPRESSION:
+                               if (olen == CILEN_VOID) {
+                                       p += 2;
+                                       printer(arg, "pcomp");
+                               }
+                               break;
+                       case CI_ACCOMPRESSION:
+                               if (olen == CILEN_VOID) {
+                                       p += 2;
+                                       printer(arg, "accomp");
+                               }
+                               break;
+                       }
+                       while (p < optend) {
+                               GETCHAR(code, p);
+                               printer(arg, " %.2x", code);
+                       }
+                       printer(arg, ">");
+               }
+               break;
+       
+       case TERMACK:
+       case TERMREQ:
+               if (len > 0 && *p >= ' ' && *p < 0x7f) {
+                       printer(arg, " ");
+                       print_string((char*)p, len, printer, arg);
+                       p += len;
+                       len = 0;
+               }
+               break;
+       
+       case ECHOREQ:
+       case ECHOREP:
+       case DISCREQ:
+               if (len >= 4) {
+                       GETLONG(cilong, p);
+                       printer(arg, " magic=0x%x", cilong);
+                       p += 4;
+                       len -= 4;
+               }
+               break;
+       }
+       
+       /* print the rest of the bytes in the packet */
+       for (; len > 0; --len) {
+               GETCHAR(code, p);
+               printer(arg, " %.2x", code);
+       }
+       
+       return (int)(p - pstart);
+}
+#endif
+
+/*
+ * Time to shut down the link because there is nothing out there.
+ */
+
+static void LcpLinkFailure (fsm *f)
+{
+       if (f->state == OPENED) {
+               LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending));
+               LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n"));
+               lcp_close(f->unit, "Peer not responding");
+       }
+}
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+
+static void LcpEchoCheck (fsm *f)
+{
+       LcpSendEchoRequest (f);
+       
+       /*
+        * Start the timer for the next interval.
+        */
+       LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0);
+
+       TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
+       lcp_echo_timer_running = 1;
+}
+
+/*
+ * LcpEchoTimeout - Timer expired on the LCP echo
+ */
+
+static void LcpEchoTimeout (void *arg)
+{
+       if (lcp_echo_timer_running != 0) {
+               lcp_echo_timer_running = 0;
+               LcpEchoCheck ((fsm *) arg);
+       }
+}
+
+/*
+ * LcpEchoReply - LCP has received a reply to the echo
+ */
+static void lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len)
+{
+       u32_t magic;
+       
+       (void)id;
+
+       /* Check the magic number - don't count replies from ourselves. */
+       if (len < 4) {
+               LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len));
+               return;
+       }
+       GETLONG(magic, inp);
+       if (lcp_gotoptions[f->unit].neg_magicnumber
+                       && magic == lcp_gotoptions[f->unit].magicnumber) {
+               LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n"));
+               return;
+       }
+       
+       /* Reset the number of outstanding echo frames */
+       lcp_echos_pending = 0;
+}
+
+/*
+ * LcpSendEchoRequest - Send an echo request frame to the peer
+ */
+
+static void LcpSendEchoRequest (fsm *f)
+{
+       u32_t lcp_magic;
+       u_char pkt[4], *pktp;
+       
+       /*
+       * Detect the failure of the peer at this point.
+       */
+       if (lcp_echo_fails != 0) {
+               if (lcp_echos_pending++ >= lcp_echo_fails) {
+                       LcpLinkFailure(f);
+                       lcp_echos_pending = 0;
+               }
+       }
+       
+       /*
+       * Make and send the echo request frame.
+       */
+       if (f->state == OPENED) {
+               lcp_magic = lcp_gotoptions[f->unit].magicnumber;
+               pktp = pkt;
+               PUTLONG(lcp_magic, pktp);
+               fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt));
+       }
+}
+
+/*
+ * lcp_echo_lowerup - Start the timer for the LCP frame
+ */
+
+static void lcp_echo_lowerup (int unit)
+{
+       fsm *f = &lcp_fsm[unit];
+       
+       /* Clear the parameters for generating echo frames */
+       lcp_echos_pending      = 0;
+       lcp_echo_number        = 0;
+       lcp_echo_timer_running = 0;
+       
+       /* If a timeout interval is specified then start the timer */
+       if (lcp_echo_interval != 0)
+               LcpEchoCheck (f);
+}
+
+/*
+ * lcp_echo_lowerdown - Stop the timer for the LCP frame
+ */
+
+static void lcp_echo_lowerdown (int unit)
+{
+       fsm *f = &lcp_fsm[unit];
+       
+       if (lcp_echo_timer_running != 0) {
+               UNTIMEOUT (LcpEchoTimeout, f);
+               lcp_echo_timer_running = 0;
+       }
+}
+
+#endif /* PPP_SUPPORT */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/lcp.h b/Demo/Common/ethernet/lwIP/netif/ppp/lcp.h
new file mode 100644 (file)
index 0000000..3876d39
--- /dev/null
@@ -0,0 +1,169 @@
+/*****************************************************************************
+* lcp.h - Network Link Control Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+*      Original derived from BSD codes.
+*****************************************************************************/
+/*
+ * lcp.h - Link Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lcp.h,v 1.1 2003/05/27 14:37:56 jani Exp $
+ */
+
+#ifndef LCP_H
+#define LCP_H
+
+
+/*************************
+*** PUBLIC DEFINITIONS ***
+*************************/
+/*
+ * Options.
+ */
+#define CI_MRU         1       /* Maximum Receive Unit */
+#define CI_ASYNCMAP    2       /* Async Control Character Map */
+#define CI_AUTHTYPE    3       /* Authentication Type */
+#define CI_QUALITY     4       /* Quality Protocol */
+#define CI_MAGICNUMBER 5       /* Magic Number */
+#define CI_PCOMPRESSION        7       /* Protocol Field Compression */
+#define CI_ACCOMPRESSION 8     /* Address/Control Field Compression */
+#define CI_CALLBACK    13      /* callback */
+#define CI_MRRU                17      /* max reconstructed receive unit; multilink */
+#define CI_SSNHF       18      /* short sequence numbers for multilink */
+#define CI_EPDISC      19      /* endpoint discriminator */
+
+/*
+ * LCP-specific packet types.
+ */
+#define PROTREJ                8       /* Protocol Reject */
+#define ECHOREQ                9       /* Echo Request */
+#define ECHOREP                10      /* Echo Reply */
+#define DISCREQ                11      /* Discard Request */
+#define CBCP_OPT       6       /* Use callback control protocol */
+
+
+/************************
+*** PUBLIC DATA TYPES ***
+************************/
+
+/*
+ * The state of options is described by an lcp_options structure.
+ */
+typedef struct lcp_options {
+    u_int passive : 1;                 /* Don't die if we don't get a response */
+    u_int silent : 1;                          /* Wait for the other end to start first */
+    u_int restart : 1;                 /* Restart vs. exit after close */
+    u_int neg_mru : 1;                 /* Negotiate the MRU? */
+    u_int neg_asyncmap : 1;            /* Negotiate the async map? */
+    u_int neg_upap : 1;                        /* Ask for UPAP authentication? */
+    u_int neg_chap : 1;                        /* Ask for CHAP authentication? */
+    u_int neg_magicnumber : 1; /* Ask for magic number? */
+    u_int neg_pcompression : 1;        /* HDLC Protocol Field Compression? */
+    u_int neg_accompression : 1;       /* HDLC Address/Control Field Compression? */
+    u_int neg_lqr : 1;                 /* Negotiate use of Link Quality Reports */
+    u_int neg_cbcp : 1;                        /* Negotiate use of CBCP */
+#ifdef PPP_MULTILINK
+    u_int neg_mrru : 1;                        /* Negotiate multilink MRRU */
+    u_int neg_ssnhf : 1;               /* Negotiate short sequence numbers */
+    u_int neg_endpoint : 1;            /* Negotiate endpoint discriminator */
+#endif
+    u_short mru;                       /* Value of MRU */
+#ifdef PPP_MULTILINK
+    u_short mrru;                      /* Value of MRRU, and multilink enable */
+#endif
+    u_char chap_mdtype;                        /* which MD type (hashing algorithm) */
+    u32_t asyncmap;                    /* Value of async map */
+    u32_t magicnumber;
+    int numloops;                              /* Number of loops during magic number neg. */
+    u32_t lqr_period;          /* Reporting period for LQR 1/100ths second */
+#ifdef PPP_MULTILINK
+    struct epdisc endpoint;    /* endpoint discriminator */
+#endif
+} lcp_options;
+
+/*
+ * Values for phase from BSD pppd.h based on RFC 1661.
+ */
+typedef enum {
+       PHASE_DEAD = 0,
+       PHASE_INITIALIZE,
+       PHASE_ESTABLISH,
+       PHASE_AUTHENTICATE,
+       PHASE_CALLBACK,
+       PHASE_NETWORK,
+       PHASE_TERMINATE
+} LinkPhase;
+
+
+/*****************************
+*** PUBLIC DATA STRUCTURES ***
+*****************************/
+
+extern LinkPhase lcp_phase[NUM_PPP];   /* Phase of link session (RFC 1661) */
+extern lcp_options lcp_wantoptions[];
+extern lcp_options lcp_gotoptions[];
+extern lcp_options lcp_allowoptions[];
+extern lcp_options lcp_hisoptions[];
+extern ext_accm xmit_accm[];
+
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+
+void lcp_init (int);
+void lcp_open (int);
+void lcp_close (int, char *);
+void lcp_lowerup (int);
+void lcp_lowerdown (int);
+void lcp_sprotrej (int, u_char *, int);        /* send protocol reject */
+
+extern struct protent lcp_protent;
+
+/* Default number of times we receive our magic number from the peer
+   before deciding the link is looped-back. */
+#define DEFLOOPBACKFAIL        10
+
+#endif /* LCP_H */
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/magic.c b/Demo/Common/ethernet/lwIP/netif/ppp/magic.c
new file mode 100644 (file)
index 0000000..4274016
--- /dev/null
@@ -0,0 +1,79 @@
+/*****************************************************************************
+* magic.c - Network Random Number Generator program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original based on BSD magic.c.
+*****************************************************************************/
+/*
+ * magic.c - PPP Magic Number routines.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "ppp.h"
+#include "randm.h"
+#include "magic.h"
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/*
+ * magicInit - Initialize the magic number generator.
+ *
+ * Since we use another random number generator that has its own
+ * initialization, we do nothing here.
+ */
+void magicInit()
+{
+       return;
+}
+
+/*
+ * magic - Returns the next magic number.
+ */
+u32_t magic()
+{
+    return avRandom();
+}
+
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/magic.h b/Demo/Common/ethernet/lwIP/netif/ppp/magic.h
new file mode 100644 (file)
index 0000000..7574f32
--- /dev/null
@@ -0,0 +1,64 @@
+/*****************************************************************************
+* magic.h - Network Random Number Generator header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+*   Original derived from BSD codes.
+*****************************************************************************/
+/*
+ * magic.h - PPP Magic Number definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: magic.h,v 1.1 2003/05/27 14:37:56 jani Exp $
+ */
+
+#ifndef MAGIC_H
+#define MAGIC_H
+
+/*****************************************************************************
+************************** PUBLIC FUNCTIONS **********************************
+*****************************************************************************/
+
+void magicInit(void);   /* Initialize the magic number generator */
+u32_t magic(void);  /* Returns the next magic number */
+
+#endif /* MAGIC_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/md5.c b/Demo/Common/ethernet/lwIP/netif/ppp/md5.c
new file mode 100644 (file)
index 0000000..e077cde
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines                         **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#include "ppp.h"
+#include "md5.h"
+#include "pppdebug.h"
+
+#if CHAP_SUPPORT > 0 || MD5_SUPPORT > 0
+
+/*
+ ***********************************************************************
+ **  Message-digest routines:                                         **
+ **  To form the message digest for a message M                       **
+ **    (1) Initialize a context buffer mdContext using MD5Init        **
+ **    (2) Call MD5Update on mdContext and M                          **
+ **    (3) Call MD5Final on mdContext                                 **
+ **  The message digest is now in mdContext->digest[0...15]           **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform (u32_t *buf, u32_t *in);
+
+static unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+  {(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) \
+  {(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) \
+  {(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) \
+  {(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+
+#ifdef __STDC__
+#define UL(x)  x##UL
+#else
+#ifdef WIN32
+#define UL(x)  x##UL
+#else
+#define UL(x)  x
+#endif
+#endif
+
+/* The routine MD5Init initializes the message-digest context
+   mdContext. All fields are set to zero.
+ */
+void MD5Init (MD5_CTX *mdContext)
+{
+  mdContext->i[0] = mdContext->i[1] = (u32_t)0;
+
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = (u32_t)0x67452301UL;
+  mdContext->buf[1] = (u32_t)0xefcdab89UL;
+  mdContext->buf[2] = (u32_t)0x98badcfeUL;
+  mdContext->buf[3] = (u32_t)0x10325476UL;
+}
+
+/* The routine MD5Update updates the message-digest context to
+   account for the presence of each of the characters inBuf[0..inLen-1]
+   in the message whose digest is being computed.
+ */
+void MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)
+{
+  u32_t in[16];
+  int mdi;
+  unsigned int i, ii;
+
+#if 0
+  ppp_trace(LOG_INFO, "MD5Update: %u:%.*H\n", inLen, MIN(inLen, 20) * 2, inBuf);
+  ppp_trace(LOG_INFO, "MD5Update: %u:%s\n", inLen, inBuf);
+#endif
+  
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((u32_t)inLen << 3);
+  mdContext->i[1] += ((u32_t)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |
+                (((u32_t)mdContext->in[ii+2]) << 16) |
+                               (((u32_t)mdContext->in[ii+1]) << 8) |
+                ((u32_t)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5Final (unsigned char hash[], MD5_CTX *mdContext)
+{
+  u32_t in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  MD5Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |
+            (((u32_t)mdContext->in[ii+2]) << 16) |
+            (((u32_t)mdContext->in[ii+1]) << 8) |
+            ((u32_t)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+       mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+  memcpy(hash, mdContext->digest, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (u32_t *buf, u32_t *in)
+{
+  u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+  /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+  /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */
+  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+  /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */
+  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+  /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+#endif
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/md5.h b/Demo/Common/ethernet/lwIP/netif/ppp/md5.h
new file mode 100644 (file)
index 0000000..0e81cdc
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5                    **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **
+ ** Revised (for MD5): RLR 4/27/91                                    **
+ **   -- G modified to have y&~z instead of y&z                       **
+ **   -- FF, GG, HH modified to add in last register done             **
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **
+ **   -- distinct additive constant for each step                     **
+ **   -- round 4 added, working mod 7                                 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+  u32_t i[2];                   /* number of _bits_ handled mod 2^64 */
+  u32_t buf[4];                                    /* scratch buffer */
+  unsigned char in[64];                              /* input buffer */
+  unsigned char digest[16];     /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init (MD5_CTX *mdContext);
+void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);
+void MD5Final (unsigned char hash[], MD5_CTX *mdContext);
+
+#endif /* MD5_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/pap.c b/Demo/Common/ethernet/lwIP/netif/ppp/pap.c
new file mode 100644 (file)
index 0000000..23e438f
--- /dev/null
@@ -0,0 +1,608 @@
+/*****************************************************************************
+* pap.c - Network Password Authentication Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original.
+*****************************************************************************/
+/*
+ * upap.c - User/Password Authentication Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "ppp.h"
+#include "auth.h"
+#include "pap.h"
+#include "pppdebug.h"
+
+
+#if PAP_SUPPORT > 0
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+/*
+ * Protocol entry points.
+ */
+static void upap_init (int);
+static void upap_lowerup (int);
+static void upap_lowerdown (int);
+static void upap_input (int, u_char *, int);
+static void upap_protrej (int);
+
+static void upap_timeout (void *);
+static void upap_reqtimeout (void *);
+static void upap_rauthreq (upap_state *, u_char *, int, int);
+static void upap_rauthack (upap_state *, u_char *, int, int);
+static void upap_rauthnak (upap_state *, u_char *, int, int);
+static void upap_sauthreq (upap_state *);
+static void upap_sresp (upap_state *, u_char, u_char, char *, int);
+
+
+
+
+/******************************/
+/*** PUBLIC DATA STRUCTURES ***/
+/******************************/
+struct protent pap_protent = {
+    PPP_PAP,
+    upap_init,
+    upap_input,
+    upap_protrej,
+    upap_lowerup,
+    upap_lowerdown,
+    NULL,
+    NULL,
+#if 0
+    upap_printpkt,
+    NULL,
+#endif
+    1,
+    "PAP",
+#if 0
+    NULL,
+    NULL,
+    NULL
+#endif
+};
+
+upap_state upap[NUM_PPP];              /* UPAP state; one for each unit */
+
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/*
+ *  Set the default login name and password for the pap sessions
+ */
+void upap_setloginpasswd(int unit, const char *luser, const char *lpassword)
+{
+       upap_state *u = &upap[unit];
+       
+       /* Save the username and password we're given */
+       u->us_user = luser;
+       u->us_userlen = strlen(luser);
+       u->us_passwd = lpassword;
+       u->us_passwdlen = strlen(lpassword);
+}
+
+
+/*
+ * upap_authwithpeer - Authenticate us with our peer (start client).
+ *
+ * Set new state and send authenticate's.
+ */
+void upap_authwithpeer(int unit, char *user, char *password)
+{
+       upap_state *u = &upap[unit];
+       
+       UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n",
+                               unit, user, password, u->us_clientstate));
+       
+       upap_setloginpasswd(unit, user, password);
+
+       u->us_transmits = 0;
+       
+       /* Lower layer up yet? */
+       if (u->us_clientstate == UPAPCS_INITIAL ||
+                       u->us_clientstate == UPAPCS_PENDING) {
+               u->us_clientstate = UPAPCS_PENDING;
+               return;
+       }
+       
+       upap_sauthreq(u);                       /* Start protocol */
+}
+
+
+/*
+ * upap_authpeer - Authenticate our peer (start server).
+ *
+ * Set new state.
+ */
+void upap_authpeer(int unit)
+{
+       upap_state *u = &upap[unit];
+       
+       /* Lower layer up yet? */
+       if (u->us_serverstate == UPAPSS_INITIAL ||
+                       u->us_serverstate == UPAPSS_PENDING) {
+               u->us_serverstate = UPAPSS_PENDING;
+               return;
+       }
+       
+       u->us_serverstate = UPAPSS_LISTEN;
+       if (u->us_reqtimeout > 0)
+               TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+}
+
+
+
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+/*
+ * upap_init - Initialize a UPAP unit.
+ */
+static void upap_init(int unit)
+{
+       upap_state *u = &upap[unit];
+
+       UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit)); 
+       u->us_unit = unit;
+       u->us_user = NULL;
+       u->us_userlen = 0;
+       u->us_passwd = NULL;
+       u->us_passwdlen = 0;
+       u->us_clientstate = UPAPCS_INITIAL;
+       u->us_serverstate = UPAPSS_INITIAL;
+       u->us_id = 0;
+       u->us_timeouttime = UPAP_DEFTIMEOUT;
+       u->us_maxtransmits = 10;
+       u->us_reqtimeout = UPAP_DEFREQTIME;
+}
+
+/*
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.
+ */
+static void upap_timeout(void *arg)
+{
+       upap_state *u = (upap_state *) arg;
+       
+       UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n", 
+                               u->us_unit, u->us_timeouttime, u->us_clientstate));
+       
+       if (u->us_clientstate != UPAPCS_AUTHREQ)
+               return;
+       
+       if (u->us_transmits >= u->us_maxtransmits) {
+               /* give up in disgust */
+               UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n"));
+               u->us_clientstate = UPAPCS_BADAUTH;
+               auth_withpeer_fail(u->us_unit, PPP_PAP);
+               return;
+       }
+       
+       upap_sauthreq(u);               /* Send Authenticate-Request */
+}
+
+
+/*
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
+ */
+static void upap_reqtimeout(void *arg)
+{
+       upap_state *u = (upap_state *) arg;
+       
+       if (u->us_serverstate != UPAPSS_LISTEN)
+               return;                 /* huh?? */
+       
+       auth_peer_fail(u->us_unit, PPP_PAP);
+       u->us_serverstate = UPAPSS_BADAUTH;
+}
+
+
+/*
+ * upap_lowerup - The lower layer is up.
+ *
+ * Start authenticating if pending.
+ */
+static void upap_lowerup(int unit)
+{
+       upap_state *u = &upap[unit];
+       
+       UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate));
+       
+       if (u->us_clientstate == UPAPCS_INITIAL)
+               u->us_clientstate = UPAPCS_CLOSED;
+       else if (u->us_clientstate == UPAPCS_PENDING) {
+               upap_sauthreq(u);       /* send an auth-request */
+       }
+       
+       if (u->us_serverstate == UPAPSS_INITIAL)
+               u->us_serverstate = UPAPSS_CLOSED;
+       else if (u->us_serverstate == UPAPSS_PENDING) {
+               u->us_serverstate = UPAPSS_LISTEN;
+               if (u->us_reqtimeout > 0)
+                       TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+       }
+}
+
+
+/*
+ * upap_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void upap_lowerdown(int unit)
+{
+       upap_state *u = &upap[unit];
+       
+       UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate));
+       
+       if (u->us_clientstate == UPAPCS_AUTHREQ)        /* Timeout pending? */
+               UNTIMEOUT(upap_timeout, u);             /* Cancel timeout */
+       if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
+               UNTIMEOUT(upap_reqtimeout, u);
+       
+       u->us_clientstate = UPAPCS_INITIAL;
+       u->us_serverstate = UPAPSS_INITIAL;
+}
+
+
+/*
+ * upap_protrej - Peer doesn't speak this protocol.
+ *
+ * This shouldn't happen.  In any case, pretend lower layer went down.
+ */
+static void upap_protrej(int unit)
+{
+       upap_state *u = &upap[unit];
+       
+       if (u->us_clientstate == UPAPCS_AUTHREQ) {
+               UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n"));
+               auth_withpeer_fail(unit, PPP_PAP);
+       }
+       if (u->us_serverstate == UPAPSS_LISTEN) {
+               UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n"));
+               auth_peer_fail(unit, PPP_PAP);
+       }
+       upap_lowerdown(unit);
+}
+
+
+/*
+ * upap_input - Input UPAP packet.
+ */
+static void upap_input(int unit, u_char *inpacket, int l)
+{
+       upap_state *u = &upap[unit];
+       u_char *inp;
+       u_char code, id;
+       int len;
+       
+       /*
+        * Parse header (code, id and length).
+        * If packet too short, drop it.
+        */
+       inp = inpacket;
+       if (l < UPAP_HEADERLEN) {
+               UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n"));
+               return;
+       }
+       GETCHAR(code, inp);
+       GETCHAR(id, inp);
+       GETSHORT(len, inp);
+       if (len < UPAP_HEADERLEN) {
+               UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n"));
+               return;
+       }
+       if (len > l) {
+               UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n"));
+               return;
+       }
+       len -= UPAP_HEADERLEN;
+       
+       /*
+        * Action depends on code.
+        */
+       switch (code) {
+       case UPAP_AUTHREQ:
+               upap_rauthreq(u, inp, id, len);
+               break;
+       
+       case UPAP_AUTHACK:
+               upap_rauthack(u, inp, id, len);
+               break;
+       
+       case UPAP_AUTHNAK:
+               upap_rauthnak(u, inp, id, len);
+               break;
+       
+       default:                                /* XXX Need code reject */
+               break;
+       }
+}
+
+
+/*
+ * upap_rauth - Receive Authenticate.
+ */
+static void upap_rauthreq(
+       upap_state *u, 
+       u_char *inp, 
+       int id,
+       int len
+)
+{
+       u_char ruserlen, rpasswdlen;
+       char *ruser, *rpasswd;
+       int retcode;
+       char *msg;
+       int msglen;
+       
+       UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id));
+       
+       if (u->us_serverstate < UPAPSS_LISTEN)
+               return;
+       
+       /*
+        * If we receive a duplicate authenticate-request, we are
+        * supposed to return the same status as for the first request.
+        */
+       if (u->us_serverstate == UPAPSS_OPEN) {
+               upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
+               return;
+       }
+       if (u->us_serverstate == UPAPSS_BADAUTH) {
+               upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
+               return;
+       }
+       
+       /*
+        * Parse user/passwd.
+        */
+       if (len < sizeof (u_char)) {
+               UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
+               return;
+       }
+       GETCHAR(ruserlen, inp);
+       len -= sizeof (u_char) + ruserlen + sizeof (u_char);
+       if (len < 0) {
+               UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
+               return;
+       }
+       ruser = (char *) inp;
+       INCPTR(ruserlen, inp);
+       GETCHAR(rpasswdlen, inp);
+       if (len < rpasswdlen) {
+               UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
+               return;
+       }
+       rpasswd = (char *) inp;
+       
+       /*
+        * Check the username and password given.
+        */
+       retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
+                          rpasswdlen, &msg, &msglen);
+       BZERO(rpasswd, rpasswdlen);
+       
+       upap_sresp(u, retcode, id, msg, msglen);
+       
+       if (retcode == UPAP_AUTHACK) {
+               u->us_serverstate = UPAPSS_OPEN;
+               auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
+       } else {
+               u->us_serverstate = UPAPSS_BADAUTH;
+               auth_peer_fail(u->us_unit, PPP_PAP);
+       }
+       
+       if (u->us_reqtimeout > 0)
+               UNTIMEOUT(upap_reqtimeout, u);
+}
+
+
+/*
+ * upap_rauthack - Receive Authenticate-Ack.
+ */
+static void upap_rauthack(
+       upap_state *u,
+       u_char *inp,
+       int id,
+       int len
+)
+{
+       u_char msglen;
+       char *msg;
+       
+       UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate));
+       
+       if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+               return;
+       
+       /*
+        * Parse message.
+        */
+       if (len < sizeof (u_char)) {
+               UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));
+               return;
+       }
+       GETCHAR(msglen, inp);
+       len -= sizeof (u_char);
+       if (len < msglen) {
+               UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));
+               return;
+       }
+       msg = (char *) inp;
+       PRINTMSG(msg, msglen);
+       
+       u->us_clientstate = UPAPCS_OPEN;
+       
+       auth_withpeer_success(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_rauthnak - Receive Authenticate-Nakk.
+ */
+static void upap_rauthnak(
+       upap_state *u,
+       u_char *inp,
+       int id,
+       int len
+)
+{
+       u_char msglen;
+       char *msg;
+       
+       UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));
+       
+       if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+               return;
+       
+       /*
+        * Parse message.
+        */
+       if (len < sizeof (u_char)) {
+               UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
+               return;
+       }
+       GETCHAR(msglen, inp);
+       len -= sizeof (u_char);
+       if (len < msglen) {
+               UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
+               return;
+       }
+       msg = (char *) inp;
+       PRINTMSG(msg, msglen);
+       
+       u->us_clientstate = UPAPCS_BADAUTH;
+       
+       UPAPDEBUG((LOG_ERR, "PAP authentication failed\n"));
+       auth_withpeer_fail(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_sauthreq - Send an Authenticate-Request.
+ */
+static void upap_sauthreq(upap_state *u)
+{
+       u_char *outp;
+       int outlen;
+       
+       outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) 
+                       + u->us_userlen + u->us_passwdlen;
+       outp = outpacket_buf[u->us_unit];
+       
+       MAKEHEADER(outp, PPP_PAP);
+       
+       PUTCHAR(UPAP_AUTHREQ, outp);
+       PUTCHAR(++u->us_id, outp);
+       PUTSHORT(outlen, outp);
+       PUTCHAR(u->us_userlen, outp);
+       BCOPY(u->us_user, outp, u->us_userlen);
+       INCPTR(u->us_userlen, outp);
+       PUTCHAR(u->us_passwdlen, outp);
+       BCOPY(u->us_passwd, outp, u->us_passwdlen);
+       
+       pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
+       
+       UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id));
+       
+       TIMEOUT(upap_timeout, u, u->us_timeouttime);
+       ++u->us_transmits;
+       u->us_clientstate = UPAPCS_AUTHREQ;
+}
+
+
+/*
+ * upap_sresp - Send a response (ack or nak).
+ */
+static void upap_sresp(
+       upap_state *u,
+       u_char code, 
+       u_char id,
+       char *msg,
+       int msglen
+)
+{
+       u_char *outp;
+       int outlen;
+       
+       outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
+       outp = outpacket_buf[u->us_unit];
+       MAKEHEADER(outp, PPP_PAP);
+       
+       PUTCHAR(code, outp);
+       PUTCHAR(id, outp);
+       PUTSHORT(outlen, outp);
+       PUTCHAR(msglen, outp);
+       BCOPY(msg, outp, msglen);
+       pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
+       
+       UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n", 
+                               code, id, u->us_clientstate));
+}
+
+#if 0
+/*
+ * upap_printpkt - print the contents of a PAP packet.
+ */
+static int upap_printpkt(
+       u_char *p,
+       int plen,
+       void (*printer) (void *, char *, ...),
+       void *arg
+)
+{
+       (void)p;
+       (void)plen;
+       (void)printer;
+       (void)arg;
+       return 0;
+}
+#endif
+
+#endif /* PAP_SUPPORT */
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/ppp.c b/Demo/Common/ethernet/lwIP/netif/ppp/ppp.c
new file mode 100644 (file)
index 0000000..5295f6a
--- /dev/null
@@ -0,0 +1,1631 @@
+/*****************************************************************************
+* ppp.c - Network Point to Point Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*   Original.
+*****************************************************************************/
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * if_pppvar.h - private structures and declarations for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+/*
+ * if_ppp.h - Point-to-Point Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <string.h>
+#include "ppp.h"
+#if PPP_SUPPORT > 0
+#include "randm.h"
+#include "fsm.h"
+#if PAP_SUPPORT > 0
+#include "pap.h"
+#endif
+#if CHAP_SUPPORT > 0
+#include "chap.h"
+#endif
+#include "ipcp.h"
+#include "lcp.h"
+#include "magic.h"
+#include "auth.h"
+#if VJ_SUPPORT > 0
+#include "vj.h"
+#endif
+
+#include "pppdebug.h"
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_ADDRESS(p)  (((u_char *)(p))[0])
+#define PPP_CONTROL(p)  (((u_char *)(p))[1])
+#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
+
+/* PPP packet parser states.  Current state indicates operation yet to be
+ * completed. */
+typedef enum {
+    PDIDLE = 0,                 /* Idle state - waiting. */
+    PDSTART,                    /* Process start flag. */
+    PDADDRESS,                  /* Process address field. */
+    PDCONTROL,                  /* Process control field. */
+    PDPROTOCOL1,                /* Process protocol field 1. */
+    PDPROTOCOL2,                /* Process protocol field 2. */
+    PDDATA                      /* Process data byte. */
+} PPPDevStates;
+
+#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
+
+/************************/
+/*** LOCAL DATA TYPES ***/
+/************************/
+/*
+ * PPP interface control block.
+ */
+typedef struct PPPControl_s {
+    char openFlag;                      /* True when in use. */
+    char oldFrame;                      /* Old framing character for fd. */
+    sio_fd_t fd;                    /* File device ID of port. */
+    int  kill_link;                     /* Shut the link down. */
+    int  sig_hup;                       /* Carrier lost. */
+    int  if_up;                         /* True when the interface is up. */
+    int  errCode;                       /* Code indicating why interface is down. */
+    struct pbuf *inHead, *inTail;       /* The input packet. */
+    PPPDevStates inState;               /* The input process state. */
+    char inEscaped;                     /* Escape next character. */
+    u16_t inProtocol;                   /* The input protocol code. */
+    u16_t inFCS;                        /* Input Frame Check Sequence value. */
+    int  mtu;                           /* Peer's mru */
+    int  pcomp;                         /* Does peer accept protocol compression? */
+    int  accomp;                        /* Does peer accept addr/ctl compression? */
+    u_long lastXMit;                    /* Time of last transmission. */
+    ext_accm inACCM;                    /* Async-Ctl-Char-Map for input. */
+    ext_accm outACCM;                   /* Async-Ctl-Char-Map for output. */
+#if VJ_SUPPORT > 0
+    int  vjEnabled;                     /* Flag indicating VJ compression enabled. */
+    struct vjcompress vjComp;           /* Van Jabobsen compression header. */
+#endif
+
+    struct netif netif;
+
+    struct ppp_addrs addrs;
+
+    void (*linkStatusCB)(void *ctx, int errCode, void *arg);
+    void *linkStatusCtx;
+
+} PPPControl;
+
+
+/*
+ * Ioctl definitions.
+ */
+
+struct npioctl {
+    int     protocol;           /* PPP procotol, e.g. PPP_IP */
+    enum NPmode mode;
+};
+
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+static void pppMain(void *pd);
+static void pppDrop(PPPControl *pc);
+static void pppInProc(int pd, u_char *s, int l);
+
+
+/******************************/
+/*** PUBLIC DATA STRUCTURES ***/
+/******************************/
+u_long subnetMask;
+
+static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */
+
+/*
+ * PPP Data Link Layer "protocol" table.
+ * One entry per supported protocol.
+ * The last entry must be NULL.
+ */
+struct protent *ppp_protocols[] = {
+    &lcp_protent,
+#if PAP_SUPPORT > 0
+    &pap_protent,
+#endif
+#if CHAP_SUPPORT > 0
+    &chap_protent,
+#endif
+#if CBCP_SUPPORT > 0
+    &cbcp_protent,
+#endif
+    &ipcp_protent,
+#if CCP_SUPPORT > 0
+    &ccp_protent,
+#endif
+    NULL
+};
+
+
+/*
+ * Buffers for outgoing packets.  This must be accessed only from the appropriate
+ * PPP task so that it doesn't need to be protected to avoid collisions.
+ */
+u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];  
+
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static const u_short fcstab[256] = {
+    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/* PPP's Asynchronous-Control-Character-Map.  The mask array is used
+ * to select the specific bit for a character. */
+static u_char pppACCMMask[] = {
+    0x01,
+    0x02,
+    0x04,
+    0x08,
+    0x10,
+    0x20,
+    0x40,
+    0x80
+};
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/* Initialize the PPP subsystem. */
+
+struct ppp_settings ppp_settings;
+
+void pppInit(void)
+{
+    struct protent *protp;
+    int i, j;
+    
+       memset(&ppp_settings, 0, sizeof(ppp_settings));
+       ppp_settings.usepeerdns = 1;
+       pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
+
+       magicInit();
+
+    for (i = 0; i < NUM_PPP; i++) {
+        pppControl[i].openFlag = 0;
+
+               subnetMask = htonl(0xffffff00);
+    
+        /*
+         * Initialize to the standard option set.
+         */
+        for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j)
+            (*protp->init)(i);
+    }
+
+#if LINK_STATS
+    /* Clear the statistics. */
+    memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));
+#endif
+}
+
+void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
+{
+    switch(authType) {
+       case PPPAUTHTYPE_NONE:
+       default:
+#ifdef LWIP_PPP_STRICT_PAP_REJECT
+           ppp_settings.refuse_pap = 1;
+#else
+           /* some providers request pap and accept an empty login/pw */
+           ppp_settings.refuse_pap = 0;
+#endif
+           ppp_settings.refuse_chap = 1;
+           break;
+       case PPPAUTHTYPE_ANY:
+/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
+ * RFC 1994 says:
+ *
+ * In practice, within or associated with each PPP server, there is a
+ * database which associates "user" names with authentication
+ * information ("secrets").  It is not anticipated that a particular
+ * named user would be authenticated by multiple methods.  This would
+ * make the user vulnerable to attacks which negotiate the least secure
+ * method from among a set (such as PAP rather than CHAP).  If the same
+ * secret was used, PAP would reveal the secret to be used later with
+ * CHAP.
+ *
+ * Instead, for each user name there should be an indication of exactly
+ * one method used to authenticate that user name.  If a user needs to
+ * make use of different authentication methods under different
+ * circumstances, then distinct user names SHOULD be employed, each of
+ * which identifies exactly one authentication method.
+ *
+ */
+           ppp_settings.refuse_pap = 0;
+           ppp_settings.refuse_chap = 0;
+           break;
+       case PPPAUTHTYPE_PAP:
+           ppp_settings.refuse_pap = 0;
+           ppp_settings.refuse_chap = 1;
+           break;
+       case PPPAUTHTYPE_CHAP:
+           ppp_settings.refuse_pap = 1;
+           ppp_settings.refuse_chap = 0;
+           break;
+    }
+
+    if(user) {
+       strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
+       ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
+    } else
+       ppp_settings.user[0] = '\0';
+
+    if(passwd) {
+       strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
+       ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
+    } else
+       ppp_settings.passwd[0] = '\0';
+}
+
+/* Open a new PPP connection using the given I/O device.
+ * This initializes the PPP control block but does not
+ * attempt to negotiate the LCP session.  If this port
+ * connects to a modem, the modem connection must be
+ * established before calling this.
+ * Return a new PPP connection descriptor on success or
+ * an error code (negative) on failure. */
+int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
+{
+    PPPControl *pc;
+    int pd;
+
+    /* Find a free PPP session descriptor. Critical region? */
+    for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
+    if (pd >= NUM_PPP)
+        pd = PPPERR_OPEN;
+    else
+        pppControl[pd].openFlag = !0;
+
+    /* Launch a deamon thread. */
+    if (pd >= 0) {
+
+        pppControl[pd].openFlag = 1;
+
+        lcp_init(pd);
+        pc = &pppControl[pd];
+        pc->fd = fd;
+        pc->kill_link = 0;
+        pc->sig_hup = 0;
+        pc->if_up = 0;
+        pc->errCode = 0;
+        pc->inState = PDIDLE;
+        pc->inHead = NULL;
+        pc->inTail = NULL;
+        pc->inEscaped = 0;
+        pc->lastXMit = 0;
+
+#if VJ_SUPPORT > 0
+        pc->vjEnabled = 0;
+        vj_compress_init(&pc->vjComp);
+#endif
+
+        /* 
+         * Default the in and out accm so that escape and flag characters
+         * are always escaped. 
+         */
+        memset(pc->inACCM, 0, sizeof(ext_accm));
+        pc->inACCM[15] = 0x60;
+        memset(pc->outACCM, 0, sizeof(ext_accm));
+        pc->outACCM[15] = 0x60;
+
+       pc->linkStatusCB = linkStatusCB;
+       pc->linkStatusCtx = linkStatusCtx;
+
+       sys_thread_new(pppMain, (void*)pd, PPP_THREAD_PRIO);
+       if(!linkStatusCB) {
+               while(pd >= 0 && !pc->if_up) {
+                       sys_msleep(500);
+                       if (lcp_phase[pd] == PHASE_DEAD) {
+                               pppClose(pd);
+                               if (pc->errCode)
+                                       pd = pc->errCode;
+                               else
+                                       pd = PPPERR_CONNECT;
+                       }
+               }
+       }
+    }
+    return pd;
+}
+
+/* Close a PPP connection and release the descriptor. 
+ * Any outstanding packets in the queues are dropped.
+ * Return 0 on success, an error code on failure. */
+int pppClose(int pd)
+{
+    PPPControl *pc = &pppControl[pd];
+    int st = 0;
+
+    /* Disconnect */
+    pc->kill_link = !0;
+    pppMainWakeup(pd);
+    
+    if(!pc->linkStatusCB) {
+           while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {
+                   sys_msleep(500);
+                   break;
+           }
+    }
+    return st;
+}
+
+/* This function is called when carrier is lost on the PPP channel. */
+void pppSigHUP(int pd)
+{
+    PPPControl *pc = &pppControl[pd];
+
+    pc->sig_hup = 1;
+    pppMainWakeup(pd);
+}
+
+static void nPut(PPPControl *pc, struct pbuf *nb)
+{
+       struct pbuf *b;
+       int c;
+
+       for(b = nb; b != NULL; b = b->next) {
+           if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
+               PPPDEBUG((LOG_WARNING,
+                           "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c));
+#if LINK_STATS
+               lwip_stats.link.err++;
+#endif /* LINK_STATS */
+               pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
+               break;
+           }
+       }
+       pbuf_free(nb);
+
+#if LINK_STATS
+       lwip_stats.link.xmit++;
+#endif /* LINK_STATS */
+}
+
+/* 
+ * pppAppend - append given character to end of given pbuf.  If outACCM
+ * is not NULL and the character needs to be escaped, do so.
+ * If pbuf is full, append another.
+ * Return the current pbuf.
+ */
+static struct pbuf *pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
+{
+    struct pbuf *tb = nb;
+    
+    /* Make sure there is room for the character and an escape code.
+     * Sure we don't quite fill the buffer if the character doesn't
+     * get escaped but is one character worth complicating this? */
+    /* Note: We assume no packet header. */
+    if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
+       tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+       if (tb) {
+           nb->next = tb;
+        }
+#if LINK_STATS
+       else {
+           lwip_stats.link.memerr++;
+       }
+#endif /* LINK_STATS */
+       nb = tb;
+    }
+    if (nb) {
+       if (outACCM && ESCAPE_P(*outACCM, c)) {
+            *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
+            *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
+        }
+        else
+            *((u_char*)nb->payload + nb->len++) = c;
+    }
+        
+    return tb;
+}
+
+/* Send a packet on the given connection. */
+static err_t pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
+{
+    int pd = (int)netif->state;
+    u_short protocol = PPP_IP;
+    PPPControl *pc = &pppControl[pd];
+    u_int fcsOut = PPP_INITFCS;
+    struct pbuf *headMB = NULL, *tailMB = NULL, *p;
+    u_char c;
+
+    (void)ipaddr;
+
+    /* Validate parameters. */
+    /* We let any protocol value go through - it can't hurt us
+     * and the peer will just drop it if it's not accepting it. */
+       if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
+        PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",
+                    pd, protocol, pb));
+#if LINK_STATS
+               lwip_stats.link.opterr++;
+               lwip_stats.link.drop++;
+#endif
+               return ERR_ARG;
+       }
+
+    /* Check that the link is up. */
+       if (lcp_phase[pd] == PHASE_DEAD) {
+        PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd));
+#if LINK_STATS
+               lwip_stats.link.rterr++;
+               lwip_stats.link.drop++;
+#endif
+               return ERR_RTE;
+       }
+
+    /* Grab an output buffer. */
+       headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+    if (headMB == NULL) {
+        PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd));
+#if LINK_STATS
+               lwip_stats.link.memerr++;
+               lwip_stats.link.drop++;
+#endif /* LINK_STATS */
+        return ERR_MEM;
+    }
+        
+#if VJ_SUPPORT > 0
+    /* 
+     * Attempt Van Jacobson header compression if VJ is configured and
+     * this is an IP packet. 
+     */
+    if (protocol == PPP_IP && pc->vjEnabled) {
+        switch (vj_compress_tcp(&pc->vjComp, pb)) {
+        case TYPE_IP:
+            /* No change...
+            protocol = PPP_IP_PROTOCOL;
+             */
+            break;
+        case TYPE_COMPRESSED_TCP:
+            protocol = PPP_VJC_COMP;
+            break;
+        case TYPE_UNCOMPRESSED_TCP:
+            protocol = PPP_VJC_UNCOMP;
+            break;
+        default:
+            PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));
+#if LINK_STATS
+                       lwip_stats.link.proterr++;
+                       lwip_stats.link.drop++;
+#endif
+               pbuf_free(headMB);
+            return ERR_VAL;
+        }
+    }
+#endif
+        
+    tailMB = headMB;
+        
+    /* Build the PPP header. */
+    if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
+        tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
+    pc->lastXMit = sys_jiffies();
+    if (!pc->accomp) {
+        fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
+        tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
+        fcsOut = PPP_FCS(fcsOut, PPP_UI);
+        tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
+    }
+    if (!pc->pcomp || protocol > 0xFF) {
+        c = (protocol >> 8) & 0xFF;
+        fcsOut = PPP_FCS(fcsOut, c);
+        tailMB = pppAppend(c, tailMB, &pc->outACCM);
+    }
+    c = protocol & 0xFF;
+    fcsOut = PPP_FCS(fcsOut, c);
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);
+    
+    /* Load packet. */
+       for(p = pb; p; p = p->next) {
+       int n;
+       u_char *sPtr;
+
+        sPtr = (u_char*)p->payload;
+        n = p->len;
+        while (n-- > 0) {
+            c = *sPtr++;
+            
+            /* Update FCS before checking for special characters. */
+            fcsOut = PPP_FCS(fcsOut, c);
+            
+            /* Copy to output buffer escaping special characters. */
+            tailMB = pppAppend(c, tailMB, &pc->outACCM);
+        }
+    }
+
+    /* Add FCS and trailing flag. */
+    c = ~fcsOut & 0xFF;
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);
+    c = (~fcsOut >> 8) & 0xFF;
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);
+    tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
+        
+    /* If we failed to complete the packet, throw it away. */
+    if (!tailMB) {
+        PPPDEBUG((LOG_WARNING,
+                    "pppifOutput[%d]: Alloc err - dropping proto=%d\n", 
+                    pd, protocol));
+        pbuf_free(headMB);
+#if LINK_STATS
+               lwip_stats.link.memerr++;
+               lwip_stats.link.drop++;
+#endif
+        return ERR_MEM;
+    }
+
+       /* Send it. */
+    PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));
+
+    nPut(pc, headMB);
+
+    return ERR_OK;
+}
+
+/* Get and set parameters for the given connection.
+ * Return 0 on success, an error code on failure. */
+int  pppIOCtl(int pd, int cmd, void *arg)
+{
+    PPPControl *pc = &pppControl[pd];
+    int st = 0;
+
+    if (pd < 0 || pd >= NUM_PPP)
+        st = PPPERR_PARAM;
+    else {
+        switch(cmd) {
+        case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */
+            if (arg) 
+                *(int *)arg = (int)(pc->if_up);
+            else
+                st = PPPERR_PARAM;
+            break;
+        case PPPCTLS_ERRCODE:       /* Set the PPP error code. */
+            if (arg) 
+                pc->errCode = *(int *)arg;
+            else
+                st = PPPERR_PARAM;
+            break;
+        case PPPCTLG_ERRCODE:       /* Get the PPP error code. */
+            if (arg) 
+                *(int *)arg = (int)(pc->errCode);
+            else
+                st = PPPERR_PARAM;
+            break;
+        case PPPCTLG_FD:
+            if (arg) 
+                *(sio_fd_t *)arg = pc->fd;
+            else
+                st = PPPERR_PARAM;
+            break;
+        default:
+            st = PPPERR_PARAM;
+            break;
+        }
+    }
+    
+    return st;
+}
+
+/*
+ * Return the Maximum Transmission Unit for the given PPP connection.
+ */
+u_int pppMTU(int pd)
+{
+    PPPControl *pc = &pppControl[pd];
+    u_int st;
+    
+    /* Validate parameters. */
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag)
+        st = 0;
+    else
+        st = pc->mtu;
+        
+    return st;
+}
+
+/*
+ * Write n characters to a ppp link.
+ *  RETURN: >= 0 Number of characters written
+ *           -1 Failed to write to device
+ */
+int pppWrite(int pd, const u_char *s, int n)
+{
+    PPPControl *pc = &pppControl[pd];
+    u_char c;
+    u_int fcsOut = PPP_INITFCS;
+    struct pbuf *headMB = NULL, *tailMB;
+       headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+    if (headMB == NULL) {
+#if LINK_STATS
+               lwip_stats.link.memerr++;
+               lwip_stats.link.proterr++;
+#endif /* LINK_STATS */
+               return PPPERR_ALLOC;
+    }
+
+    tailMB = headMB;
+        
+    /* If the link has been idle, we'll send a fresh flag character to
+     * flush any noise. */
+    if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
+        tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
+    pc->lastXMit = sys_jiffies();
+     
+    /* Load output buffer. */
+    while (n-- > 0) {
+        c = *s++;
+        
+        /* Update FCS before checking for special characters. */
+        fcsOut = PPP_FCS(fcsOut, c);
+        
+        /* Copy to output buffer escaping special characters. */
+        tailMB = pppAppend(c, tailMB, &pc->outACCM);
+    }
+    
+    /* Add FCS and trailing flag. */
+    c = ~fcsOut & 0xFF;
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);
+    c = (~fcsOut >> 8) & 0xFF;
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);
+    tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
+        
+    /* If we failed to complete the packet, throw it away.
+     * Otherwise send it. */
+    if (!tailMB) {
+               PPPDEBUG((LOG_WARNING,
+                "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
+/*                "pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
+               pbuf_free(headMB);
+#if LINK_STATS
+               lwip_stats.link.memerr++;
+               lwip_stats.link.proterr++;
+#endif /* LINK_STATS */
+               return PPPERR_ALLOC;
+       }
+
+    PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len));
+/*     "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
+    nPut(pc, headMB);
+
+    return PPPERR_NONE;
+}
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void ppp_send_config(
+    int unit, 
+    int mtu,
+    u32_t asyncmap,
+    int pcomp, 
+    int accomp
+)
+{
+    PPPControl *pc = &pppControl[unit];
+    int i;
+    
+    pc->mtu = mtu;
+    pc->pcomp = pcomp;
+    pc->accomp = accomp;
+    
+    /* Load the ACCM bits for the 32 control codes. */
+    for (i = 0; i < 32/8; i++)
+        pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
+    PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n",
+                unit,
+                pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
+}
+
+
+/*
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+void ppp_set_xaccm(int unit, ext_accm *accm)
+{
+    memcpy(pppControl[unit].outACCM, accm, sizeof(ext_accm));
+    PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
+                unit,
+                pppControl[unit].outACCM[0],
+                pppControl[unit].outACCM[1],
+                pppControl[unit].outACCM[2],
+                pppControl[unit].outACCM[3]));
+}
+
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+void ppp_recv_config(
+    int unit, 
+    int mru,
+    u32_t asyncmap,
+    int pcomp, 
+    int accomp
+)
+{
+    PPPControl *pc = &pppControl[unit];
+    int i;
+    
+       (void)accomp;
+       (void)pcomp;
+       (void)mru;
+
+    /* Load the ACCM bits for the 32 control codes. */
+    for (i = 0; i < 32 / 8; i++)
+        pc->inACCM[i] = (u_char)(asyncmap >> (i * 8));
+    PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
+                unit,
+                pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));
+}
+
+#if 0
+/*
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use.  Returns 1 if the method and parameters
+ * are OK, 0 if the method is known but the parameters are not OK
+ * (e.g. code size should be reduced), or -1 if the method is unknown.
+ */
+int ccp_test(
+    int unit, 
+    int opt_len, 
+    int for_transmit,
+    u_char *opt_ptr
+)
+{
+    return 0;   /* XXX Currently no compression. */
+}
+
+/*
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+void ccp_flags_set(int unit, int isopen, int isup)
+{
+    /* XXX */
+}
+
+/*
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise.  This is necessary because of patent nonsense.
+ */
+int ccp_fatal_error(int unit)
+{
+    /* XXX */
+    return 0;
+}
+#endif
+
+/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int get_idle_time(int u, struct ppp_idle *ip)
+{   
+    /* XXX */
+       (void)u;
+       (void)ip;
+
+    return 0;
+}
+
+
+/*
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'.  If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+u32_t GetMask(u32_t addr)
+{
+    u32_t mask, nmask;
+    
+    htonl(addr);
+    if (IN_CLASSA(addr))    /* determine network mask for address class */
+        nmask = IN_CLASSA_NET;
+    else if (IN_CLASSB(addr))
+        nmask = IN_CLASSB_NET;
+    else
+        nmask = IN_CLASSC_NET;
+    /* class D nets are disallowed by bad_ip_adrs */
+    mask = subnetMask | htonl(nmask);
+    
+    /* XXX
+     * Scan through the system's network interfaces.
+     * Get each netmask and OR them into our mask.
+     */
+    
+    return mask;
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int sifvjcomp(
+    int pd, 
+    int vjcomp, 
+    int cidcomp, 
+    int maxcid
+)
+{
+#if VJ_SUPPORT > 0
+    PPPControl *pc = &pppControl[pd];
+    
+    pc->vjEnabled = vjcomp;
+    pc->vjComp.compressSlot = cidcomp;
+    pc->vjComp.maxSlotIndex = maxcid;
+    PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
+                vjcomp, cidcomp, maxcid));
+#endif
+
+    return 0;
+}
+
+/*
+ * pppifNetifInit - netif init callback
+ */
+static err_t pppifNetifInit(struct netif *netif)
+{
+       netif->name[0] = 'p';
+       netif->name[1] = 'p';
+       netif->output = pppifOutput;
+       netif->mtu = pppMTU((int)netif->state);
+       return ERR_OK;
+}
+
+
+/*
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+int sifup(int pd)
+{
+    PPPControl *pc = &pppControl[pd];
+    int st = 1;
+    
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+        st = 0;
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
+    } else {
+               netif_remove(&pc->netif);
+               if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) {
+               
+               netif_set_up(&pc->netif);
+               pc->if_up = 1;
+               pc->errCode = PPPERR_NONE;
+
+                       PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
+                       if(pc->linkStatusCB)
+                               pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
+               } else {
+               st = 0;
+               PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));
+               }
+    }
+
+    return st;
+}
+
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int sifnpmode(int u, int proto, enum NPmode mode)
+{
+       (void)u;
+       (void)proto;
+       (void)mode;
+    return 0;
+}
+
+/*
+ * sifdown - Config the interface down and disable IP.
+ */
+int sifdown(int pd)
+{
+    PPPControl *pc = &pppControl[pd];
+    int st = 1;
+    
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+        st = 0;
+        PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));
+    } else {
+        pc->if_up = 0;
+       netif_remove(&pc->netif);
+       PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
+       if(pc->linkStatusCB)
+               pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
+       }
+    return st;
+}
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int sifaddr(
+    int pd,             /* Interface unit ??? */
+    u32_t o,        /* Our IP address ??? */
+    u32_t h,        /* His IP address ??? */
+    u32_t m,        /* IP subnet mask ??? */
+    u32_t ns1,      /* Primary DNS */
+    u32_t ns2       /* Secondary DNS */
+)
+{
+    PPPControl *pc = &pppControl[pd];
+    int st = 1;
+    
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+        st = 0;
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
+    } else {
+               memcpy(&pc->addrs.our_ipaddr, &o, sizeof(o));
+               memcpy(&pc->addrs.his_ipaddr, &h, sizeof(h));
+               memcpy(&pc->addrs.netmask, &m, sizeof(m));
+               memcpy(&pc->addrs.dns1, &ns1, sizeof(ns1));
+               memcpy(&pc->addrs.dns2, &ns2, sizeof(ns2));
+    }
+    return st;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int cifaddr(
+    int pd,         /* Interface unit ??? */
+    u32_t o,    /* Our IP address ??? */
+    u32_t h     /* IP broadcast address ??? */
+)
+{
+    PPPControl *pc = &pppControl[pd];
+    int st = 1;
+    
+       (void)o;
+       (void)h;
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+        st = 0;
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
+    } else {
+               IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
+               IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
+               IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
+               IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
+               IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
+    }
+    return st;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int sifdefaultroute(int pd, u32_t l, u32_t g)
+{
+    PPPControl *pc = &pppControl[pd];
+    int st = 1;
+    
+       (void)l;
+       (void)g;
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+        st = 0;
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
+    } else {
+               netif_set_default(&pc->netif);
+    }
+
+    /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
+
+    return st;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int cifdefaultroute(int pd, u32_t l, u32_t g)
+{
+    PPPControl *pc = &pppControl[pd];
+    int st = 1;
+    
+       (void)l;
+       (void)g;
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+        st = 0;
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
+    } else {
+               netif_set_default(NULL);
+    }
+
+    return st;
+}
+
+void
+pppMainWakeup(int pd)
+{
+       PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));
+       sio_read_abort(pppControl[pd].fd);
+}
+
+/* these callbacks are necessary because lcp_* functions
+   must be called in the same context as pppInput(),
+   namely the tcpip_thread(), essentially because
+   they manipulate timeouts which are thread-private
+*/
+
+static void
+pppStartCB(void *arg)
+{
+    int pd = (int)arg;
+
+       PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));
+    lcp_lowerup(pd);
+    lcp_open(pd);      /* Start protocol */
+}
+
+static void
+pppStopCB(void *arg)
+{
+    int pd = (int)arg;
+
+       PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));
+    lcp_close(pd, "User request");
+}
+
+static void
+pppHupCB(void *arg)
+{
+    int pd = (int)arg;
+
+       PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));
+    lcp_lowerdown(pd);
+    link_terminated(pd);
+}
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+/* The main PPP process function.  This implements the state machine according
+ * to section 4 of RFC 1661: The Point-To-Point Protocol. */
+static void pppMain(void *arg)
+{
+    int pd = (int)arg;
+    struct pbuf *p;
+    PPPControl* pc;
+
+    pc = &pppControl[pd];
+
+    p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);
+    if(!p) {
+               LWIP_ASSERT("p != NULL", p);
+               pc->errCode = PPPERR_ALLOC;
+               goto out;
+    }
+
+    /*
+     * Start the connection and handle incoming events (packet or timeout).
+     */
+       PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));
+    tcpip_callback(pppStartCB, arg);
+    while (lcp_phase[pd] != PHASE_DEAD) {
+        if (pc->kill_link) {
+               PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d kill_link -> pppStopCB\n", pd));
+               pc->errCode = PPPERR_USER;
+               /* This will leave us at PHASE_DEAD. */
+               tcpip_callback(pppStopCB, arg);
+               pc->kill_link = 0;
+        }
+        else if (pc->sig_hup) {
+               PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sig_hup -> pppHupCB\n", pd));
+               pc->sig_hup = 0;
+               tcpip_callback(pppHupCB, arg);
+        } else {
+               int c = sio_read(pc->fd, p->payload, p->len);
+               if(c > 0) {
+                       pppInProc(pd, p->payload, c);
+               } else {
+                   PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
+                   sys_msleep(1); /* give other tasks a chance to run */
+               }
+        }
+    }
+       PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));
+    pbuf_free(p);
+
+out:
+       PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
+    if(pc->linkStatusCB)
+           pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
+
+    pc->openFlag = 0;
+}
+
+static struct pbuf *pppSingleBuf(struct pbuf *p)
+{
+       struct pbuf *q, *b;
+       u_char *pl;
+
+       if(p->tot_len == p->len)
+               return p;
+
+       q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
+       if(!q) {
+               PPPDEBUG((LOG_ERR,
+                        "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
+               return p; /* live dangerously */
+       }
+
+       for(b = p, pl = q->payload; b != NULL; b = b->next) {
+               memcpy(pl, b->payload, b->len);
+               pl += b->len;
+       }
+
+       pbuf_free(p);
+
+       return q;
+}
+
+struct pppInputHeader {
+       int unit;
+       u16_t proto;
+};
+
+/*
+ * Pass the processed input packet to the appropriate handler.
+ * This function and all handlers run in the context of the tcpip_thread
+ */
+static void pppInput(void *arg)
+{
+       struct pbuf *nb = (struct pbuf *)arg;
+    u16_t protocol;
+    int pd;
+
+       pd = ((struct pppInputHeader *)nb->payload)->unit;
+       protocol = ((struct pppInputHeader *)nb->payload)->proto;
+
+    pbuf_header(nb, -(int)sizeof(struct pppInputHeader));
+
+#if LINK_STATS
+    lwip_stats.link.recv++;
+#endif /* LINK_STATS */
+
+    /*
+     * Toss all non-LCP packets unless LCP is OPEN.
+     * Until we get past the authentication phase, toss all packets
+     * except LCP, LQR and authentication packets.
+     */
+    if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
+           if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
+                       (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
+               PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd]));
+               goto drop;
+           }
+    }
+
+    switch(protocol) {
+    case PPP_VJC_COMP:      /* VJ compressed TCP */
+#if VJ_SUPPORT > 0
+        PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
+        /*
+         * Clip off the VJ header and prepend the rebuilt TCP/IP header and
+         * pass the result to IP.
+         */
+        if (vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) {
+            if (pppControl[pd].netif.input != NULL) {
+              pppControl[pd].netif.input(nb, &pppControl[pd].netif);
+            }
+                       return;
+        }
+       /* Something's wrong so drop it. */
+       PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));
+#else
+        /* No handler for this protocol so drop the packet. */
+        PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
+#endif /* VJ_SUPPORT > 0 */
+       break;
+    case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */
+#if VJ_SUPPORT > 0
+        PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
+        /*
+         * Process the TCP/IP header for VJ header compression and then pass
+         * the packet to IP.
+         */
+        if (vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) {
+            if (pppControl[pd].netif.input != NULL) {
+              pppControl[pd].netif.input(nb, &pppControl[pd].netif);
+            }
+                       return;
+        }
+       /* Something's wrong so drop it. */
+       PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));
+#else
+        /* No handler for this protocol so drop the packet. */
+        PPPDEBUG((LOG_INFO,
+                    "pppInput[%d]: drop VJ UnComp in %d:.*H\n", 
+                    pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
+#endif /* VJ_SUPPORT > 0 */
+       break;
+    case PPP_IP:            /* Internet Protocol */
+        PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
+        if (pppControl[pd].netif.input != NULL) {
+          pppControl[pd].netif.input(nb, &pppControl[pd].netif);
+        }
+               return;
+    default:
+       {
+               struct protent *protp;
+               int i;
+
+               /*
+                * Upcall the proper protocol input routine.
+                */
+               for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
+                       if (protp->protocol == protocol && protp->enabled_flag) {
+                               PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
+                               nb = pppSingleBuf(nb);
+                               (*protp->input)(pd, nb->payload, nb->len);
+                               goto out;
+                       }
+               }
+
+               /* No handler for this protocol so reject the packet. */
+               PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len));
+               pbuf_header(nb, sizeof(protocol));
+#if BYTE_ORDER == LITTLE_ENDIAN
+               protocol = htons(protocol);
+               memcpy(nb->payload, &protocol, sizeof(protocol));
+#endif
+               lcp_sprotrej(pd, nb->payload, nb->len);
+       }
+       break;
+    }
+
+drop:
+#if LINK_STATS
+    lwip_stats.link.drop++;
+#endif
+
+out:
+    pbuf_free(nb);
+    return;
+}
+
+
+/*
+ * Drop the input packet.
+ */
+static void pppDrop(PPPControl *pc)
+{
+    if (pc->inHead != NULL) {
+#if 0      
+        PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));
+#endif 
+        PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len));
+       if (pc->inTail && (pc->inTail != pc->inHead))
+           pbuf_free(pc->inTail);
+        pbuf_free(pc->inHead);
+        pc->inHead = NULL;
+        pc->inTail = NULL;
+    }
+#if VJ_SUPPORT > 0
+    vj_uncompress_err(&pc->vjComp);
+#endif
+
+#if LINK_STATS
+    lwip_stats.link.drop++;
+#endif /* LINK_STATS */
+}
+
+
+/*
+ * Process a received octet string.
+ */
+static void pppInProc(int pd, u_char *s, int l)
+{
+    PPPControl *pc = &pppControl[pd];
+    struct pbuf *nextNBuf;
+    u_char curChar;
+
+    PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));
+    while (l-- > 0) {
+        curChar = *s++;
+        
+        /* Handle special characters. */
+        if (ESCAPE_P(pc->inACCM, curChar)) {
+            /* Check for escape sequences. */
+            /* XXX Note that this does not handle an escaped 0x5d character which
+             * would appear as an escape character.  Since this is an ASCII ']'
+             * and there is no reason that I know of to escape it, I won't complicate
+             * the code to handle this case. GLL */
+            if (curChar == PPP_ESCAPE)
+                pc->inEscaped = 1;
+            /* Check for the flag character. */
+            else if (curChar == PPP_FLAG) {
+                /* If this is just an extra flag character, ignore it. */
+                if (pc->inState <= PDADDRESS)
+                    ;
+                /* If we haven't received the packet header, drop what has come in. */
+                else if (pc->inState < PDDATA) {
+                    PPPDEBUG((LOG_WARNING,
+                                "pppInProc[%d]: Dropping incomplete packet %d\n", 
+                                pd, pc->inState));
+#if LINK_STATS
+                                       lwip_stats.link.lenerr++;
+#endif
+                    pppDrop(pc);
+                }
+                /* If the fcs is invalid, drop the packet. */
+                else if (pc->inFCS != PPP_GOODFCS) {
+                    PPPDEBUG((LOG_INFO,
+                                "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n", 
+                                pd, pc->inFCS, pc->inProtocol));
+#if LINK_STATS
+                                       lwip_stats.link.chkerr++;
+#endif
+                    pppDrop(pc);
+                }
+                /* Otherwise it's a good packet so pass it on. */
+                else {
+                    
+                    /* Trim off the checksum. */
+                   if(pc->inTail->len >= 2) {
+                       pc->inTail->len -= 2;
+
+                       pc->inTail->tot_len = pc->inTail->len;
+                       if (pc->inTail != pc->inHead) {
+                           pbuf_cat(pc->inHead, pc->inTail);
+                       }
+                   } else {
+                       pc->inTail->tot_len = pc->inTail->len;
+                       if (pc->inTail != pc->inHead) {
+                           pbuf_cat(pc->inHead, pc->inTail);
+                       }
+
+                       pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);
+                   }
+
+                    /* Dispatch the packet thereby consuming it. */
+                   if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) {
+                       PPPDEBUG((LOG_ERR,
+                                   "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd));
+                       pbuf_free(pc->inHead);
+#if LINK_STATS
+                       lwip_stats.link.drop++;
+#endif
+                   }
+                    pc->inHead = NULL;
+                    pc->inTail = NULL;
+                }
+                    
+                /* Prepare for a new packet. */
+                pc->inFCS = PPP_INITFCS;
+                pc->inState = PDADDRESS;
+                pc->inEscaped = 0;
+            }
+            /* Other characters are usually control characters that may have
+             * been inserted by the physical layer so here we just drop them. */
+            else {
+                PPPDEBUG((LOG_WARNING,
+                            "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));
+            }
+        }
+        /* Process other characters. */
+        else {
+            /* Unencode escaped characters. */
+            if (pc->inEscaped) {
+                pc->inEscaped = 0;
+                curChar ^= PPP_TRANS;
+            }
+            
+            /* Process character relative to current state. */
+            switch(pc->inState) {
+            case PDIDLE:                    /* Idle state - waiting. */
+                /* Drop the character if it's not 0xff
+                 * we would have processed a flag character above. */
+                if (curChar != PPP_ALLSTATIONS) {
+                       break;
+                               }
+
+                               /* Fall through */
+            case PDSTART:                   /* Process start flag. */
+                /* Prepare for a new packet. */
+                pc->inFCS = PPP_INITFCS;
+
+                               /* Fall through */
+            case PDADDRESS:                 /* Process address field. */
+                if (curChar == PPP_ALLSTATIONS) {
+                    pc->inState = PDCONTROL;
+                    break;
+                }
+                /* Else assume compressed address and control fields so
+                 * fall through to get the protocol... */
+            case PDCONTROL:                 /* Process control field. */
+                /* If we don't get a valid control code, restart. */
+                if (curChar == PPP_UI) {
+                    pc->inState = PDPROTOCOL1;
+                       break;
+                }
+#if 0
+                else {
+                    PPPDEBUG((LOG_WARNING,
+                                "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));
+                    pc->inState = PDSTART;
+                }
+#endif
+            case PDPROTOCOL1:               /* Process protocol field 1. */
+                /* If the lower bit is set, this is the end of the protocol
+                 * field. */
+                if (curChar & 1) {
+                    pc->inProtocol = curChar;
+                    pc->inState = PDDATA;
+                }
+                else {
+                    pc->inProtocol = (u_int)curChar << 8;
+                    pc->inState = PDPROTOCOL2;
+                }
+                break;
+            case PDPROTOCOL2:               /* Process protocol field 2. */
+                pc->inProtocol |= curChar;
+                pc->inState = PDDATA;
+                break;
+            case PDDATA:                    /* Process data byte. */
+                /* Make space to receive processed data. */
+                if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) {
+                   if(pc->inTail) {
+                       pc->inTail->tot_len = pc->inTail->len;
+                       if (pc->inTail != pc->inHead) {
+                           pbuf_cat(pc->inHead, pc->inTail);
+                       }
+                   }
+                    /* If we haven't started a packet, we need a packet header. */
+                    nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+                    if (nextNBuf == NULL) {
+                        /* No free buffers.  Drop the input packet and let the
+                         * higher layers deal with it.  Continue processing
+                         * the received pbuf chain in case a new packet starts. */
+                        PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd));
+#if LINK_STATS
+                                               lwip_stats.link.memerr++;
+#endif /* LINK_STATS */
+                        pppDrop(pc);
+                        pc->inState = PDSTART;  /* Wait for flag sequence. */
+                       break;
+                    }
+                   if (pc->inHead == NULL) {
+                       struct pppInputHeader *pih = nextNBuf->payload;
+
+                       pih->unit = pd;
+                       pih->proto = pc->inProtocol;
+
+                       nextNBuf->len += sizeof(*pih);
+
+                       pc->inHead = nextNBuf;
+                   }
+                   pc->inTail = nextNBuf;
+                }
+                /* Load character into buffer. */
+                ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;
+                break;
+            }
+
+            /* update the frame check sequence number. */
+            pc->inFCS = PPP_FCS(pc->inFCS, curChar);
+        }
+    }
+       avRandomize();
+}
+
+#endif /* PPP_SUPPORT */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/ppp.h b/Demo/Common/ethernet/lwIP/netif/ppp/ppp.h
new file mode 100644 (file)
index 0000000..25cea83
--- /dev/null
@@ -0,0 +1,446 @@
+/*****************************************************************************
+* ppp.h - Network Point to Point Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+*      Original derived from BSD codes.
+*****************************************************************************/
+
+#ifndef PPP_H
+#define PPP_H
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT > 0
+#include "lwip/sio.h"
+#include "lwip/api.h"
+#include "lwip/sockets.h"
+#include "lwip/stats.h"
+#include "lwip/mem.h"
+#include "lwip/tcpip.h"
+#include "lwip/netif.h"
+
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define TIMEOUT(f, a, t)    sys_untimeout((f), (a)), sys_timeout((t)*1000, (f), (a))
+#define UNTIMEOUT(f, a)     sys_untimeout((f), (a))
+
+
+# ifndef __u_char_defined
+
+/* Type definitions for BSD code. */
+typedef unsigned long u_long;
+typedef unsigned int u_int;
+typedef unsigned short u_short;
+typedef unsigned char u_char;
+
+#endif
+
+/*
+ * Constants and structures defined by the internet system,
+ * Per RFC 790, September 1981, and numerous additions.
+ */
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN  4       /* octets for standard ppp header */
+#define PPP_FCSLEN  2       /* octets for FCS */
+
+
+/*
+ * Significant octet values.
+ */
+#define PPP_ALLSTATIONS 0xff    /* All-Stations broadcast address */
+#define PPP_UI          0x03    /* Unnumbered Information */
+#define PPP_FLAG        0x7e    /* Flag Sequence */
+#define PPP_ESCAPE      0x7d    /* Asynchronous Control Escape */
+#define PPP_TRANS       0x20    /* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP          0x21    /* Internet Protocol */
+#define PPP_AT          0x29    /* AppleTalk Protocol */
+#define PPP_VJC_COMP    0x2d    /* VJ compressed TCP */
+#define PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */
+#define PPP_COMP        0xfd    /* compressed packet */
+#define PPP_IPCP        0x8021  /* IP Control Protocol */
+#define PPP_ATCP        0x8029  /* AppleTalk Control Protocol */
+#define PPP_CCP         0x80fd  /* Compression Control Protocol */
+#define PPP_LCP         0xc021  /* Link Control Protocol */
+#define PPP_PAP         0xc023  /* Password Authentication Protocol */
+#define PPP_LQR         0xc025  /* Link Quality Report protocol */
+#define PPP_CHAP        0xc223  /* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP        0xc029  /* Callback Control Protocol */
+
+/*
+ * Values for FCS calculations.
+ */
+#define PPP_INITFCS 0xffff  /* Initial FCS value */
+#define PPP_GOODFCS 0xf0b8  /* Good final FCS value */
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+typedef u_char  ext_accm[32];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+    NPMODE_PASS,        /* pass the packet through */
+    NPMODE_DROP,        /* silently drop the packet */
+    NPMODE_ERROR,       /* return an error */
+    NPMODE_QUEUE        /* save it up for later. */
+};
+
+/*
+ * Inline versions of get/put char/short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETCHAR(c, cp) { \
+    (c) = *(cp)++; \
+}
+#define PUTCHAR(c, cp) { \
+    *(cp)++ = (u_char) (c); \
+}
+
+
+#define GETSHORT(s, cp) { \
+    (s) = *(cp); (cp)++; (s) << 8; \
+    (s) |= *(cp); (cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+    *(cp)++ = (u_char) ((s) >> 8); \
+    *(cp)++ = (u_char) (s); \
+}
+
+#define GETLONG(l, cp) { \
+    (l) = *(cp); (cp)++; (l) << 8; \
+    (l) |= *(cp); (cp)++; (l) <<= 8; \
+    (l) |= *(cp); (cp)++; (l) <<= 8; \
+    (l) |= *(cp); (cp)++; \
+}
+#define PUTLONG(l, cp) { \
+    *(cp)++ = (u_char) ((l) >> 24); \
+    *(cp)++ = (u_char) ((l) >> 16); \
+    *(cp)++ = (u_char) ((l) >> 8); \
+    *(cp)++ = (u_char) (l); \
+}
+
+
+#define INCPTR(n, cp)   ((cp) += (n))
+#define DECPTR(n, cp)   ((cp) -= (n))
+
+#define BCMP(s0, s1, l)     memcmp((u_char *)(s0), (u_char *)(s1), (l))
+#define BCOPY(s, d, l)      memcpy((d), (s), (l))
+#define BZERO(s, n)         memset(s, 0, n)
+#if PPP_DEBUG
+#define PRINTMSG(m, l)  { m[l] = '\0'; ppp_trace(LOG_INFO, "Remote message: %s\n", m); }
+#else
+#define PRINTMSG(m, l)
+#endif
+
+/*
+ * MAKEHEADER - Add PPP Header fields to a packet.
+ */
+#define MAKEHEADER(p, t) { \
+    PUTCHAR(PPP_ALLSTATIONS, p); \
+    PUTCHAR(PPP_UI, p); \
+    PUTSHORT(t, p); }
+
+/*************************
+*** PUBLIC DEFINITIONS ***
+*************************/
+
+/* Error codes. */
+#define PPPERR_NONE 0                          /* No error. */
+#define PPPERR_PARAM -1                                /* Invalid parameter. */
+#define PPPERR_OPEN -2                         /* Unable to open PPP session. */
+#define PPPERR_DEVICE -3                       /* Invalid I/O device for PPP. */
+#define PPPERR_ALLOC -4                                /* Unable to allocate resources. */
+#define PPPERR_USER -5                         /* User interrupt. */
+#define PPPERR_CONNECT -6                      /* Connection lost. */
+#define PPPERR_AUTHFAIL -7                     /* Failed authentication challenge. */
+#define PPPERR_PROTOCOL -8                     /* Failed to meet protocol. */
+
+/*
+ * PPP IOCTL commands.
+ */
+/*
+ * Get the up status - 0 for down, non-zero for up.  The argument must
+ * point to an int.
+ */
+#define PPPCTLG_UPSTATUS 100   /* Get the up status - 0 down else up */
+#define PPPCTLS_ERRCODE 101            /* Set the error code */
+#define PPPCTLG_ERRCODE 102            /* Get the error code */
+#define        PPPCTLG_FD              103             /* Get the fd associated with the ppp */
+
+/************************
+*** PUBLIC DATA TYPES ***
+************************/
+
+/*
+ * The following struct gives the addresses of procedures to call
+ * for a particular protocol.
+ */
+struct protent {
+    u_short protocol;       /* PPP protocol number */
+    /* Initialization procedure */
+    void (*init) (int unit);
+    /* Process a received packet */
+    void (*input) (int unit, u_char *pkt, int len);
+    /* Process a received protocol-reject */
+    void (*protrej) (int unit);
+    /* Lower layer has come up */
+    void (*lowerup) (int unit);
+    /* Lower layer has gone down */
+    void (*lowerdown) (int unit);
+    /* Open the protocol */
+    void (*open) (int unit);
+    /* Close the protocol */
+    void (*close) (int unit, char *reason);
+#if 0
+    /* Print a packet in readable form */
+    int  (*printpkt) (u_char *pkt, int len,
+              void (*printer) (void *, char *, ...),
+              void *arg);
+    /* Process a received data packet */
+    void (*datainput) (int unit, u_char *pkt, int len);
+#endif
+    int  enabled_flag;      /* 0 iff protocol is disabled */
+    char *name;         /* Text name of protocol */
+#if 0
+    /* Check requested options, assign defaults */
+    void (*check_options) (u_long);
+    /* Configure interface for demand-dial */
+    int  (*demand_conf) (int unit);
+    /* Say whether to bring up link for this pkt */
+    int  (*active_pkt) (u_char *pkt, int len);
+#endif
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+    u_short xmit_idle;      /* seconds since last NP packet sent */
+    u_short recv_idle;      /* seconds since last NP packet received */
+};
+
+struct ppp_settings {
+
+       u_int  disable_defaultip : 1;   /* Don't use hostname for default IP addrs */
+       u_int  auth_required : 1;      /* Peer is required to authenticate */
+       u_int  explicit_remote : 1;    /* remote_name specified with remotename opt */
+       u_int  refuse_pap : 1;         /* Don't wanna auth. ourselves with PAP */
+       u_int  refuse_chap : 1;        /* Don't wanna auth. ourselves with CHAP */
+       u_int  usehostname : 1;        /* Use hostname for our_name */
+       u_int  usepeerdns : 1;         /* Ask peer for DNS adds */
+
+       u_short idle_time_limit; /* Shut down link if idle for this long */
+       int  maxconnect;         /* Maximum connect time (seconds) */
+
+       char user[MAXNAMELEN + 1];/* Username for PAP */
+       char passwd[MAXSECRETLEN + 1];           /* Password for PAP, secret for CHAP */
+       char our_name[MAXNAMELEN + 1];         /* Our name for authentication purposes */
+       char remote_name[MAXNAMELEN + 1];      /* Peer's name for authentication */
+};
+
+struct ppp_addrs {
+    struct ip_addr our_ipaddr, his_ipaddr, netmask, dns1, dns2;
+};
+
+/*****************************
+*** PUBLIC DATA STRUCTURES ***
+*****************************/
+/* Buffers for outgoing packets. */
+extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
+
+extern struct ppp_settings ppp_settings;
+
+extern struct protent *ppp_protocols[];/* Table of pointers to supported protocols */
+
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+
+/* Initialize the PPP subsystem. */
+void pppInit(void);
+
+/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
+ * RFC 1994 says:
+ *
+ * In practice, within or associated with each PPP server, there is a
+ * database which associates "user" names with authentication
+ * information ("secrets").  It is not anticipated that a particular
+ * named user would be authenticated by multiple methods.  This would
+ * make the user vulnerable to attacks which negotiate the least secure
+ * method from among a set (such as PAP rather than CHAP).  If the same
+ * secret was used, PAP would reveal the secret to be used later with
+ * CHAP.
+ *
+ * Instead, for each user name there should be an indication of exactly
+ * one method used to authenticate that user name.  If a user needs to
+ * make use of different authentication methods under different
+ * circumstances, then distinct user names SHOULD be employed, each of
+ * which identifies exactly one authentication method.
+ *
+ */
+enum pppAuthType {
+    PPPAUTHTYPE_NONE,
+    PPPAUTHTYPE_ANY,
+    PPPAUTHTYPE_PAP,
+    PPPAUTHTYPE_CHAP
+};
+
+void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd);
+
+/*
+ * Open a new PPP connection using the given I/O device.
+ * This initializes the PPP control block but does not
+ * attempt to negotiate the LCP session.
+ * Return a new PPP connection descriptor on success or
+ * an error code (negative) on failure. 
+ */
+int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);
+
+/*
+ * Close a PPP connection and release the descriptor. 
+ * Any outstanding packets in the queues are dropped.
+ * Return 0 on success, an error code on failure. 
+ */
+int pppClose(int pd);
+
+/*
+ * Indicate to the PPP process that the line has disconnected.
+ */
+void pppSigHUP(int pd);
+
+/*
+ * Get and set parameters for the given connection.
+ * Return 0 on success, an error code on failure. 
+ */
+int  pppIOCtl(int pd, int cmd, void *arg);
+
+/*
+ * Return the Maximum Transmission Unit for the given PPP connection.
+ */
+u_int pppMTU(int pd);
+
+/*
+ * Write n characters to a ppp link.
+ *     RETURN: >= 0 Number of characters written
+ *                      -1 Failed to write to device
+ */
+int pppWrite(int pd, const u_char *s, int n);
+
+void pppMainWakeup(int pd);
+
+/* Configure i/f transmit parameters */
+void ppp_send_config (int, int, u32_t, int, int);
+/* Set extended transmit ACCM */
+void ppp_set_xaccm (int, ext_accm *);
+/* Configure i/f receive parameters */
+void ppp_recv_config (int, int, u32_t, int, int);
+/* Find out how long link has been idle */
+int  get_idle_time (int, struct ppp_idle *);
+
+/* Configure VJ TCP header compression */
+int  sifvjcomp (int, int, int, int);
+/* Configure i/f down (for IP) */
+int  sifup (int);              
+/* Set mode for handling packets for proto */
+int  sifnpmode (int u, int proto, enum NPmode mode);
+/* Configure i/f down (for IP) */
+int  sifdown (int);    
+/* Configure IP addresses for i/f */
+int  sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t);
+/* Reset i/f IP addresses */
+int  cifaddr (int, u32_t, u32_t);
+/* Create default route through i/f */
+int  sifdefaultroute (int, u32_t, u32_t);
+/* Delete default route through i/f */
+int  cifdefaultroute (int, u32_t, u32_t);
+
+/* Get appropriate netmask for address */
+u32_t GetMask (u32_t); 
+
+#endif /* PPP_SUPPORT */
+
+#endif /* PPP_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/pppdebug.h b/Demo/Common/ethernet/lwIP/netif/ppp/pppdebug.h
new file mode 100644 (file)
index 0000000..de1478c
--- /dev/null
@@ -0,0 +1,89 @@
+/*****************************************************************************
+* pppdebug.h - System debugging utilities.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1998 Global Election Systems Inc.
+* portions Copyright (c) 2001 by Cognizant Pty Ltd.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY (please don't use tabs!)
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 98-07-29 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*      Original.
+*
+*****************************************************************************
+*/
+#ifndef PPPDEBUG_H
+#define PPPDEBUG_H
+
+/************************
+*** PUBLIC DATA TYPES ***
+************************/
+/* Trace levels. */
+typedef enum {
+       LOG_CRITICAL = 0,
+       LOG_ERR = 1,
+       LOG_NOTICE = 2,
+       LOG_WARNING = 3,
+       LOG_INFO = 5,
+       LOG_DETAIL = 6,
+       LOG_DEBUG = 7
+} LogCodes;
+
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+/*
+ *     ppp_trace - a form of printf to send tracing information to stderr
+ */
+void ppp_trace(int level, const char *format,...);
+
+#if PPP_DEBUG > 0
+
+#define AUTHDEBUG(a) ppp_trace a
+#define IPCPDEBUG(a) ppp_trace a
+#define UPAPDEBUG(a) ppp_trace a
+#define LCPDEBUG(a) ppp_trace a
+#define FSMDEBUG(a) ppp_trace a
+#define CHAPDEBUG(a) ppp_trace a
+#define PPPDEBUG(a) ppp_trace a
+
+#define TRACELCP 1
+
+#else
+
+#define AUTHDEBUG(a)
+#define IPCPDEBUG(a)
+#define UPAPDEBUG(a)
+#define LCPDEBUG(a)
+#define FSMDEBUG(a)
+#define CHAPDEBUG(a)
+
+#define PPPDEBUG(a)
+
+#define TRACELCP 0
+
+#endif
+
+#endif /* PPPDEBUG_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/randm.c b/Demo/Common/ethernet/lwIP/netif/ppp/randm.c
new file mode 100644 (file)
index 0000000..05eeb44
--- /dev/null
@@ -0,0 +1,242 @@
+/*****************************************************************************
+* randm.c - Random number generator program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1998 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 98-06-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+*   Extracted from avos.
+*****************************************************************************/
+
+#include "ppp.h"
+#if PPP_SUPPORT > 0
+#include "md5.h"
+#include "randm.h"
+
+#include "pppdebug.h"
+
+
+#if MD5_SUPPORT>0   /* this module depends on MD5 */
+#define RANDPOOLSZ 16   /* Bytes stored in the pool of randomness. */
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+static char randPool[RANDPOOLSZ];   /* Pool of randomness. */
+static long randCount = 0;      /* Pseudo-random incrementer */
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/*
+ * Initialize the random number generator.
+ *
+ * Since this is to be called on power up, we don't have much
+ *  system randomess to work with.  Here all we use is the
+ *  real-time clock.  We'll accumulate more randomness as soon
+ *  as things start happening.
+ */
+void avRandomInit()
+{
+    avChurnRand(NULL, 0);
+}
+
+/*
+ * Churn the randomness pool on a random event.  Call this early and often
+ *  on random and semi-random system events to build randomness in time for
+ *  usage.  For randomly timed events, pass a null pointer and a zero length
+ *  and this will use the system timer and other sources to add randomness.
+ *  If new random data is available, pass a pointer to that and it will be
+ *  included.
+ *
+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427
+ */
+void avChurnRand(char *randData, u32_t randLen)
+{
+    MD5_CTX md5;
+
+/*  ppp_trace(LOG_INFO, "churnRand: %u@%P\n", randLen, randData); */
+    MD5Init(&md5);
+    MD5Update(&md5, (u_char *)randPool, sizeof(randPool));
+    if (randData)
+        MD5Update(&md5, (u_char *)randData, randLen);
+    else {
+        struct {
+            /* INCLUDE fields for any system sources of randomness */
+            char foobar;
+        } sysData;
+
+        /* Load sysData fields here. */
+        ;
+        MD5Update(&md5, (u_char *)&sysData, sizeof(sysData));
+    }
+    MD5Final((u_char *)randPool, &md5);
+/*  ppp_trace(LOG_INFO, "churnRand: -> 0\n"); */
+}
+
+/*
+ * Use the random pool to generate random data.  This degrades to pseudo
+ *  random when used faster than randomness is supplied using churnRand().
+ * Note: It's important that there be sufficient randomness in randPool
+ *  before this is called for otherwise the range of the result may be
+ *  narrow enough to make a search feasible.
+ *
+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427
+ *
+ * XXX Why does he not just call churnRand() for each block?  Probably
+ *  so that you don't ever publish the seed which could possibly help
+ *  predict future values.
+ * XXX Why don't we preserve md5 between blocks and just update it with
+ *  randCount each time?  Probably there is a weakness but I wish that
+ *  it was documented.
+ */
+void avGenRand(char *buf, u32_t bufLen)
+{
+    MD5_CTX md5;
+    u_char tmp[16];
+    u32_t n;
+
+    while (bufLen > 0) {
+        n = LWIP_MIN(bufLen, RANDPOOLSZ);
+        MD5Init(&md5);
+        MD5Update(&md5, (u_char *)randPool, sizeof(randPool));
+        MD5Update(&md5, (u_char *)&randCount, sizeof(randCount));
+        MD5Final(tmp, &md5);
+        randCount++;
+        memcpy(buf, tmp, n);
+        buf += n;
+        bufLen -= n;
+    }
+}
+
+/*
+ * Return a new random number.
+ */
+u32_t avRandom()
+{
+    u32_t newRand;
+
+    avGenRand((char *)&newRand, sizeof(newRand));
+
+    return newRand;
+}
+
+#else /* MD5_SUPPORT */
+
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+static int  avRandomized = 0;       /* Set when truely randomized. */
+static u32_t avRandomSeed = 0;      /* Seed used for random number generation. */
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/*
+ * Initialize the random number generator.
+ *
+ * Here we attempt to compute a random number seed but even if
+ * it isn't random, we'll randomize it later.
+ *
+ * The current method uses the fields from the real time clock,
+ * the idle process counter, the millisecond counter, and the
+ * hardware timer tick counter.  When this is invoked
+ * in startup(), then the idle counter and timer values may
+ * repeat after each boot and the real time clock may not be
+ * operational.  Thus we call it again on the first random
+ * event.
+ */
+void avRandomInit()
+{
+#if 0
+    /* Get a pointer into the last 4 bytes of clockBuf. */
+    u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]);
+
+    /*
+     * Initialize our seed using the real-time clock, the idle
+     * counter, the millisecond timer, and the hardware timer
+     * tick counter.  The real-time clock and the hardware
+     * tick counter are the best sources of randomness but
+     * since the tick counter is only 16 bit (and truncated
+     * at that), the idle counter and millisecond timer
+     * (which may be small values) are added to help
+     * randomize the lower 16 bits of the seed.
+     */
+    readClk();
+    avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr
+             + ppp_mtime() + ((u32_t)TM1 << 16) + TM1;
+#else
+    avRandomSeed += sys_jiffies(); /* XXX */
+#endif
+        
+    /* Initialize the Borland random number generator. */
+    srand((unsigned)avRandomSeed);
+}
+
+/*
+ * Randomize our random seed value.  Here we use the fact that
+ * this function is called at *truely random* times by the polling
+ * and network functions.  Here we only get 16 bits of new random
+ * value but we use the previous value to randomize the other 16
+ * bits.
+ */
+void avRandomize(void)
+{
+    static u32_t last_jiffies;
+
+    if (!avRandomized) {
+        avRandomized = !0;
+        avRandomInit();
+        /* The initialization function also updates the seed. */
+    } else {
+/*        avRandomSeed += (avRandomSeed << 16) + TM1; */
+       avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */
+    }
+    last_jiffies = sys_jiffies();
+}
+
+/*
+ * Return a new random number.
+ * Here we use the Borland rand() function to supply a pseudo random
+ * number which we make truely random by combining it with our own
+ * seed which is randomized by truely random events. 
+ * Thus the numbers will be truely random unless there have been no
+ * operator or network events in which case it will be pseudo random
+ * seeded by the real time clock.
+ */
+u32_t avRandom()
+{
+    return ((((u32_t)rand() << 16) + rand()) + avRandomSeed);
+}
+
+
+
+#endif /* MD5_SUPPORT */
+#endif /* PPP_SUPPORT */
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/randm.h b/Demo/Common/ethernet/lwIP/netif/ppp/randm.h
new file mode 100644 (file)
index 0000000..baa42f0
--- /dev/null
@@ -0,0 +1,81 @@
+/*****************************************************************************
+* randm.h - Random number generator header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1998 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any 
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+*   Ported to lwIP.
+* 98-05-29 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+*      Extracted from avos.
+*****************************************************************************/
+
+#ifndef RANDM_H
+#define RANDM_H
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+/*
+ * Initialize the random number generator.
+ */
+void avRandomInit(void);
+
+/*
+ * Churn the randomness pool on a random event.  Call this early and often
+ *     on random and semi-random system events to build randomness in time for
+ *     usage.  For randomly timed events, pass a null pointer and a zero length
+ *     and this will use the system timer and other sources to add randomness.
+ *     If new random data is available, pass a pointer to that and it will be
+ *     included.
+ */
+void avChurnRand(char *randData, u32_t randLen);
+
+/*
+ * Randomize our random seed value.  To be called for truely random events
+ * such as user operations and network traffic.
+ */
+#if MD5_SUPPORT
+#define avRandomize()  avChurnRand(NULL, 0)
+#else
+void avRandomize(void);
+#endif
+
+/*
+ * Use the random pool to generate random data.  This degrades to pseudo
+ *     random when used faster than randomness is supplied using churnRand().
+ *     Thus it's important to make sure that the results of this are not
+ *     published directly because one could predict the next result to at
+ *     least some degree.  Also, it's important to get a good seed before
+ *     the first use.
+ */
+void avGenRand(char *buf, u32_t bufLen);
+
+/*
+ * Return a new random number.
+ */
+u32_t avRandom(void);
+
+
+#endif /* RANDM_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/vj.c b/Demo/Common/ethernet/lwIP/netif/ppp/vj.c
new file mode 100644 (file)
index 0000000..0636ee1
--- /dev/null
@@ -0,0 +1,633 @@
+/*
+ * Routines to compress and uncompess tcp packets (for transmission
+ * over low speed serial lines.
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ *     - Initial distribution.
+ *
+ * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,
+ * so that the entire packet being decompressed doesn't have
+ * to be in contiguous memory (just the compressed header).
+ *
+ * Modified March 1998 by Guy Lancaster, glanca@gesn.com,
+ * for a 16 bit processor.
+ */
+
+#include <string.h>
+
+#include "ppp.h"
+#include "vj.h"
+#include "pppdebug.h"
+
+#if VJ_SUPPORT > 0
+
+#if LINK_STATS
+#define INCR(counter) ++comp->stats.counter
+#else
+#define INCR(counter)
+#endif
+
+#if defined(NO_CHAR_BITFIELDS)
+#define getip_hl(base) ((base).ip_hl_v&0xf)
+#define getth_off(base)        (((base).th_x2_off&0xf0)>>4)
+#else
+#define getip_hl(base) ((base).ip_hl)
+#define getth_off(base)        ((base).th_off)
+#endif
+
+void vj_compress_init(struct vjcompress *comp)
+{
+       register u_int i;
+       register struct cstate *tstate = comp->tstate;
+       
+#if MAX_SLOTS == 0
+       memset((char *)comp, 0, sizeof(*comp));
+#endif
+       comp->maxSlotIndex = MAX_SLOTS - 1;
+       comp->compressSlot = 0;         /* Disable slot ID compression by default. */
+       for (i = MAX_SLOTS - 1; i > 0; --i) {
+               tstate[i].cs_id = i;
+               tstate[i].cs_next = &tstate[i - 1];
+       }
+       tstate[0].cs_next = &tstate[MAX_SLOTS - 1];
+       tstate[0].cs_id = 0;
+       comp->last_cs = &tstate[0];
+       comp->last_recv = 255;
+       comp->last_xmit = 255;
+       comp->flags = VJF_TOSS;
+}
+
+
+/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
+ * checks for zero (since zero has to be encoded in the long, 3 byte
+ * form).
+ */
+#define ENCODE(n) { \
+       if ((u_short)(n) >= 256) { \
+               *cp++ = 0; \
+               cp[1] = (n); \
+               cp[0] = (n) >> 8; \
+               cp += 2; \
+       } else { \
+               *cp++ = (n); \
+       } \
+}
+#define ENCODEZ(n) { \
+       if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
+               *cp++ = 0; \
+               cp[1] = (n); \
+               cp[0] = (n) >> 8; \
+               cp += 2; \
+       } else { \
+               *cp++ = (n); \
+       } \
+}
+
+#define DECODEL(f) { \
+       if (*cp == 0) {\
+               u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \
+               (f) = htonl(tmp); \
+               cp += 3; \
+       } else { \
+               u32_t tmp = ntohl(f) + (u32_t)*cp++; \
+               (f) = htonl(tmp); \
+       } \
+}
+
+#define DECODES(f) { \
+       if (*cp == 0) {\
+               u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \
+               (f) = htons(tmp); \
+               cp += 3; \
+       } else { \
+               u_short tmp = ntohs(f) + (u_short)*cp++; \
+               (f) = htons(tmp); \
+       } \
+}
+
+#define DECODEU(f) { \
+       if (*cp == 0) {\
+               (f) = htons(((u_short)cp[1] << 8) | cp[2]); \
+               cp += 3; \
+       } else { \
+               (f) = htons((u_short)*cp++); \
+       } \
+}
+
+/*
+ * vj_compress_tcp - Attempt to do Van Jacobsen header compression on a
+ * packet.  This assumes that nb and comp are not null and that the first
+ * buffer of the chain contains a valid IP header.
+ * Return the VJ type code indicating whether or not the packet was
+ * compressed.
+ */
+u_int vj_compress_tcp(
+       struct vjcompress *comp,
+       struct pbuf *pb
+)
+{
+       register struct ip *ip = (struct ip *)pb->payload;
+       register struct cstate *cs = comp->last_cs->cs_next;
+       register u_short hlen = getip_hl(*ip);
+       register struct tcphdr *oth;
+       register struct tcphdr *th;
+       register u_short deltaS, deltaA;
+       register u_long deltaL;
+       register u_int changes = 0;
+       u_char new_seq[16];
+       register u_char *cp = new_seq;
+
+       /*      
+        * Check that the packet is IP proto TCP.
+        */
+       if (ip->ip_p != IPPROTO_TCP)
+               return (TYPE_IP);
+               
+       /*
+        * Bail if this is an IP fragment or if the TCP packet isn't
+        * `compressible' (i.e., ACK isn't set or some other control bit is
+        * set).  
+        */
+       if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40)
+               return (TYPE_IP);
+       th = (struct tcphdr *)&((long *)ip)[hlen];
+       if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK)
+               return (TYPE_IP);
+               
+       /*
+        * Packet is compressible -- we're going to send either a
+        * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
+        * to locate (or create) the connection state.  Special case the
+        * most recently used connection since it's most likely to be used
+        * again & we don't have to do any reordering if it's used.
+        */
+       INCR(vjs_packets);
+       if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr 
+                       || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr 
+                       || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {
+               /*
+                * Wasn't the first -- search for it.
+                *
+                * States are kept in a circularly linked list with
+                * last_cs pointing to the end of the list.  The
+                * list is kept in lru order by moving a state to the
+                * head of the list whenever it is referenced.  Since
+                * the list is short and, empirically, the connection
+                * we want is almost always near the front, we locate
+                * states via linear search.  If we don't find a state
+                * for the datagram, the oldest state is (re-)used.
+                */
+               register struct cstate *lcs;
+               register struct cstate *lastcs = comp->last_cs;
+               
+               do {
+                       lcs = cs; cs = cs->cs_next;
+                       INCR(vjs_searches);
+                       if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
+                                       && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
+                                       && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)])
+                               goto found;
+               } while (cs != lastcs);
+               
+               /*
+                * Didn't find it -- re-use oldest cstate.  Send an
+                * uncompressed packet that tells the other side what
+                * connection number we're using for this conversation.
+                * Note that since the state list is circular, the oldest
+                * state points to the newest and we only need to set
+                * last_cs to update the lru linkage.
+                */
+               INCR(vjs_misses);
+               comp->last_cs = lcs;
+               hlen += getth_off(*th);
+               hlen <<= 2;
+               /* Check that the IP/TCP headers are contained in the first buffer. */
+               if (hlen > pb->len)
+                       return (TYPE_IP);
+               goto uncompressed;
+               
+               found:
+               /*
+                * Found it -- move to the front on the connection list.
+                */
+               if (cs == lastcs)
+                       comp->last_cs = lcs;
+               else {
+                       lcs->cs_next = cs->cs_next;
+                       cs->cs_next = lastcs->cs_next;
+                       lastcs->cs_next = cs;
+               }
+       }
+       
+       oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen];
+       deltaS = hlen;
+       hlen += getth_off(*th);
+       hlen <<= 2;
+       /* Check that the IP/TCP headers are contained in the first buffer. */
+       if (hlen > pb->len) {
+               PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", 
+                                       hlen));
+               return (TYPE_IP);
+       }
+       
+       /*
+        * Make sure that only what we expect to change changed. The first
+        * line of the `if' checks the IP protocol version, header length &
+        * type of service.  The 2nd line checks the "Don't fragment" bit.
+        * The 3rd line checks the time-to-live and protocol (the protocol
+        * check is unnecessary but costless).  The 4th line checks the TCP
+        * header length.  The 5th line checks IP options, if any.  The 6th
+        * line checks TCP options, if any.  If any of these things are
+        * different between the previous & current datagram, we send the
+        * current datagram `uncompressed'.
+        */
+       if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] 
+                       || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] 
+                       || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] 
+                       || getth_off(*th) != getth_off(*oth) 
+                       || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) 
+                       || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2)))
+               goto uncompressed;
+       
+       /*
+        * Figure out which of the changing fields changed.  The
+        * receiver expects changes in the order: urgent, window,
+        * ack, seq (the order minimizes the number of temporaries
+        * needed in this section of code).
+        */
+       if (th->th_flags & TCP_URG) {
+               deltaS = ntohs(th->th_urp);
+               ENCODEZ(deltaS);
+               changes |= NEW_U;
+       } else if (th->th_urp != oth->th_urp)
+               /* argh! URG not set but urp changed -- a sensible
+                * implementation should never do this but RFC793
+                * doesn't prohibit the change so we have to deal
+                * with it. */
+               goto uncompressed;
+       
+       if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) {
+               ENCODE(deltaS);
+               changes |= NEW_W;
+       }
+       
+       if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) {
+               if (deltaL > 0xffff)
+                       goto uncompressed;
+               deltaA = (u_short)deltaL;
+               ENCODE(deltaA);
+               changes |= NEW_A;
+       }
+       
+       if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) {
+               if (deltaL > 0xffff)
+                       goto uncompressed;
+               deltaS = (u_short)deltaL;
+               ENCODE(deltaS);
+               changes |= NEW_S;
+       }
+       
+       switch(changes) {
+       
+       case 0:
+               /*
+                * Nothing changed. If this packet contains data and the
+                * last one didn't, this is probably a data packet following
+                * an ack (normal on an interactive connection) and we send
+                * it compressed.  Otherwise it's probably a retransmit,
+                * retransmitted ack or window probe.  Send it uncompressed
+                * in case the other side missed the compressed version.
+                */
+               if (ip->ip_len != cs->cs_ip.ip_len &&
+                       ntohs(cs->cs_ip.ip_len) == hlen)
+               break;
+       
+       /* (fall through) */
+       
+       case SPECIAL_I:
+       case SPECIAL_D:
+               /*
+                * actual changes match one of our special case encodings --
+                * send packet uncompressed.
+                */
+               goto uncompressed;
+       
+       case NEW_S|NEW_A:
+               if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+                       /* special case for echoed terminal traffic */
+                       changes = SPECIAL_I;
+                       cp = new_seq;
+               }
+               break;
+       
+       case NEW_S:
+               if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+                       /* special case for data xfer */
+                       changes = SPECIAL_D;
+                       cp = new_seq;
+               }
+               break;
+       }
+       
+       deltaS = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id));
+       if (deltaS != 1) {
+               ENCODEZ(deltaS);
+               changes |= NEW_I;
+       }
+       if (th->th_flags & TCP_PSH)
+       changes |= TCP_PUSH_BIT;
+       /*
+        * Grab the cksum before we overwrite it below.  Then update our
+        * state with this packet's header.
+        */
+       deltaA = ntohs(th->th_sum);
+       BCOPY(ip, &cs->cs_ip, hlen);
+       
+       /*
+        * We want to use the original packet as our compressed packet.
+        * (cp - new_seq) is the number of bytes we need for compressed
+        * sequence numbers.  In addition we need one byte for the change
+        * mask, one for the connection id and two for the tcp checksum.
+        * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
+        * many bytes of the original packet to toss so subtract the two to
+        * get the new packet size.
+        */
+       deltaS = (u_short)(cp - new_seq);
+       if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {
+               comp->last_xmit = cs->cs_id;
+               hlen -= deltaS + 4;
+               pbuf_header(pb, -hlen);
+               cp = (u_char *)pb->payload;
+               *cp++ = changes | NEW_C;
+               *cp++ = cs->cs_id;
+       } else {
+               hlen -= deltaS + 3;
+               pbuf_header(pb, -hlen);
+               cp = (u_char *)pb->payload;
+               *cp++ = changes;
+       }
+       *cp++ = deltaA >> 8;
+       *cp++ = deltaA;
+       BCOPY(new_seq, cp, deltaS);
+       INCR(vjs_compressed);
+       return (TYPE_COMPRESSED_TCP);
+
+       /*
+        * Update connection state cs & send uncompressed packet (that is,
+        * a regular ip/tcp packet but with the 'conversation id' we hope
+        * to use on future compressed packets in the protocol field).
+        */
+uncompressed:
+       BCOPY(ip, &cs->cs_ip, hlen);
+       ip->ip_p = cs->cs_id;
+       comp->last_xmit = cs->cs_id;
+       return (TYPE_UNCOMPRESSED_TCP);
+}
+
+/*
+ * Called when we may have missed a packet.
+ */
+void vj_uncompress_err(struct vjcompress *comp)
+{
+    comp->flags |= VJF_TOSS;
+       INCR(vjs_errorin);
+}
+
+/*
+ * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.
+ * Return 0 on success, -1 on failure.
+ */
+int vj_uncompress_uncomp(
+       struct pbuf *nb,
+       struct vjcompress *comp
+)
+{
+       register u_int hlen;
+       register struct cstate *cs;
+       register struct ip *ip;
+       
+       ip = (struct ip *)nb->payload;
+       hlen = getip_hl(*ip) << 2;
+       if (ip->ip_p >= MAX_SLOTS
+                       || hlen + sizeof(struct tcphdr) > nb->len
+                       || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2)
+                           > nb->len
+                       || hlen > MAX_HDR) {
+               PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", 
+                                       ip->ip_p, hlen, nb->len));
+               comp->flags |= VJF_TOSS;
+               INCR(vjs_errorin);
+               return -1;
+       }
+       cs = &comp->rstate[comp->last_recv = ip->ip_p];
+       comp->flags &=~ VJF_TOSS;
+       ip->ip_p = IPPROTO_TCP;
+       BCOPY(ip, &cs->cs_ip, hlen);
+       cs->cs_hlen = hlen;
+       INCR(vjs_uncompressedin);
+       return 0;
+}
+
+/*
+ * Uncompress a packet of type TYPE_COMPRESSED_TCP.
+ * The packet is composed of a buffer chain and the first buffer
+ * must contain an accurate chain length.
+ * The first buffer must include the entire compressed TCP/IP header. 
+ * This procedure replaces the compressed header with the uncompressed
+ * header and returns the length of the VJ header.
+ */
+int vj_uncompress_tcp(
+       struct pbuf **nb,
+       struct vjcompress *comp
+)
+{
+       u_char *cp;
+       struct tcphdr *th;
+       struct cstate *cs;
+       u_short *bp;
+       struct pbuf *n0 = *nb;
+       u32_t tmp;
+       u_int vjlen, hlen, changes;
+       
+       INCR(vjs_compressedin);
+       cp = (u_char *)n0->payload;
+       changes = *cp++;
+       if (changes & NEW_C) {
+               /* 
+                * Make sure the state index is in range, then grab the state.
+                * If we have a good state index, clear the 'discard' flag. 
+                */
+               if (*cp >= MAX_SLOTS) {
+                       PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: bad cid=%d\n", *cp));
+                       goto bad;
+               }
+               
+               comp->flags &=~ VJF_TOSS;
+               comp->last_recv = *cp++;
+       } else {
+               /* 
+                * this packet has an implicit state index.  If we've
+                * had a line error since the last time we got an
+                * explicit state index, we have to toss the packet. 
+                */
+               if (comp->flags & VJF_TOSS) {
+                       PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: tossing\n"));
+                       INCR(vjs_tossed);
+                       return (-1);
+               }
+       }
+       cs = &comp->rstate[comp->last_recv];
+       hlen = getip_hl(cs->cs_ip) << 2;
+       th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
+       th->th_sum = htons((*cp << 8) | cp[1]);
+       cp += 2;
+       if (changes & TCP_PUSH_BIT)
+               th->th_flags |= TCP_PSH;
+       else
+               th->th_flags &=~ TCP_PSH;
+       
+       switch (changes & SPECIALS_MASK) {
+       case SPECIAL_I:
+               {
+                       register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+                       /* some compilers can't nest inline assembler.. */
+                       tmp = ntohl(th->th_ack) + i;
+                       th->th_ack = htonl(tmp);
+                       tmp = ntohl(th->th_seq) + i;
+                       th->th_seq = htonl(tmp);
+               }
+               break;
+       
+       case SPECIAL_D:
+               /* some compilers can't nest inline assembler.. */
+               tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+               th->th_seq = htonl(tmp);
+               break;
+       
+       default:
+               if (changes & NEW_U) {
+                       th->th_flags |= TCP_URG;
+                       DECODEU(th->th_urp);
+               } else
+                       th->th_flags &=~ TCP_URG;
+               if (changes & NEW_W)
+                       DECODES(th->th_win);
+               if (changes & NEW_A)
+                       DECODEL(th->th_ack);
+               if (changes & NEW_S)
+                       DECODEL(th->th_seq);
+               break;
+       }
+       if (changes & NEW_I) {
+               DECODES(cs->cs_ip.ip_id);
+       } else {
+               cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1;
+               cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id);
+       }
+       
+       /*
+        * At this point, cp points to the first byte of data in the
+        * packet.  Fill in the IP total length and update the IP
+        * header checksum.
+        */
+       vjlen = (u_short)(cp - (u_char*)n0->payload);
+       if (n0->len < vjlen) {
+               /* 
+                * We must have dropped some characters (crc should detect
+                * this but the old slip framing won't) 
+                */
+               PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: head buffer %d too short %d\n", 
+                                 n0->len, vjlen));
+               goto bad;
+       }
+       
+#if BYTE_ORDER == LITTLE_ENDIAN
+       tmp = n0->tot_len - vjlen + cs->cs_hlen;
+       cs->cs_ip.ip_len = htons(tmp);
+#else
+       cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen);
+#endif
+       
+       /* recompute the ip header checksum */
+       bp = (u_short *) &cs->cs_ip;
+       cs->cs_ip.ip_sum = 0;
+       for (tmp = 0; hlen > 0; hlen -= 2)
+               tmp += *bp++;
+       tmp = (tmp & 0xffff) + (tmp >> 16);
+       tmp = (tmp & 0xffff) + (tmp >> 16);
+       cs->cs_ip.ip_sum = (u_short)(~tmp);
+       
+       /* Remove the compressed header and prepend the uncompressed header. */
+       pbuf_header(n0, -vjlen);
+
+       if(MEM_ALIGN(n0->payload) != n0->payload) {
+               struct pbuf *np, *q;
+               u8_t *bufptr;
+
+               np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);
+               if(!np) {
+                       PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: realign failed\n"));
+                       *nb = NULL;
+                       goto bad;
+               }
+
+               pbuf_header(np, -cs->cs_hlen);
+
+               bufptr = n0->payload;
+               for(q = np; q != NULL; q = q->next) {
+                       memcpy(q->payload, bufptr, q->len);
+                       bufptr += q->len;
+               }
+
+               if(n0->next) {
+                       pbuf_chain(np, n0->next);
+                       pbuf_dechain(n0);
+               }
+               pbuf_free(n0);
+               n0 = np;
+       }
+
+       if(pbuf_header(n0, cs->cs_hlen)) {
+               struct pbuf *np;
+
+               LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);
+               np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);
+               if(!np) {
+                       PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: prepend failed\n"));
+                       *nb = NULL;
+                       goto bad;
+               }
+               pbuf_cat(np, n0);
+               n0 = np;
+       }
+       LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);
+       memcpy(n0->payload, &cs->cs_ip, cs->cs_hlen);
+
+       *nb = n0;
+
+       return vjlen;
+       
+bad:
+       comp->flags |= VJF_TOSS;
+       INCR(vjs_errorin);
+       return (-1);
+}
+
+#endif
+
+
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/vj.h b/Demo/Common/ethernet/lwIP/netif/ppp/vj.h
new file mode 100644 (file)
index 0000000..7172081
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Id: vj.h,v 1.4 2004/02/07 00:30:03 likewise Exp $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ *     - Initial distribution.
+ */
+
+#ifndef VJ_H
+#define VJ_H
+
+#include "vjbsdhdr.h"
+
+#define MAX_SLOTS      16                      /* must be > 2 and < 256 */
+#define MAX_HDR                128
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits).  The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet.  The next two octets are the TCP checksum
+ * from the original datagram.  The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ * 
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowlegement, sequence number and IP ID.  (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.)  Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0.  (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type.  There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows.  Top
+ * three bits are actual packet type.  For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C  0x40    /* flag bits for what changed in a packet */
+#define NEW_I  0x20
+#define NEW_S  0x08
+#define NEW_A  0x04
+#define NEW_W  0x02
+#define NEW_U  0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U)          /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)    /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+
+/*
+ * "state" data for each active tcp conversation on the wire.  This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+    struct cstate *cs_next;    /* next most recently used state (xmit only) */
+    u_short cs_hlen;           /* size of hdr (receive only) */
+    u_char cs_id;                      /* connection # associated with this state */
+    u_char cs_filler;
+    union {
+               char csu_hdr[MAX_HDR];
+               struct ip csu_ip;       /* ip/tcp hdr from most recent packet */
+    } vjcs_u;
+};
+#define cs_ip vjcs_u.csu_ip
+#define cs_hdr vjcs_u.csu_hdr
+
+
+struct vjstat {
+    unsigned long vjs_packets;                 /* outbound packets */
+    unsigned long vjs_compressed;              /* outbound compressed packets */
+    unsigned long vjs_searches;                        /* searches for connection state */
+    unsigned long vjs_misses;                  /* times couldn't find conn. state */
+    unsigned long vjs_uncompressedin;  /* inbound uncompressed packets */
+    unsigned long vjs_compressedin;            /* inbound compressed packets */
+    unsigned long vjs_errorin;                 /* inbound unknown type packets */
+    unsigned long vjs_tossed;                  /* inbound packets tossed because of error */
+};
+
+/*
+ * all the state data for one serial line (we need one of these per line).
+ */
+struct vjcompress {
+    struct cstate *last_cs;    /* most recently used tstate */
+    u_char last_recv;          /* last rcvd conn. id */
+    u_char last_xmit;          /* last sent conn. id */
+    u_short flags;
+    u_char maxSlotIndex;
+    u_char compressSlot;       /* Flag indicating OK to compress slot ID. */
+#if LINK_STATS
+    struct vjstat stats;
+#endif
+    struct cstate tstate[MAX_SLOTS];   /* xmit connection states */
+    struct cstate rstate[MAX_SLOTS];   /* receive connection states */
+};
+
+/* flag values */
+#define VJF_TOSS 1U            /* tossing rcvd frames because of input err */
+
+extern void  vj_compress_init (struct vjcompress *comp);
+extern u_int vj_compress_tcp (struct vjcompress *comp, struct pbuf *pb);
+extern void  vj_uncompress_err (struct vjcompress *comp);
+extern int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp);
+extern int vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp);
+
+#endif /* VJ_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/ppp/vjbsdhdr.h b/Demo/Common/ethernet/lwIP/netif/ppp/vjbsdhdr.h
new file mode 100644 (file)
index 0000000..a089352
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef VJBSDHDR_H
+#define VJBSDHDR_H
+
+#include "lwip/tcp.h"
+
+
+/*
+ * Structure of an internet header, naked of options.
+ *
+ * We declare ip_len and ip_off to be short, rather than u_short
+ * pragmatically since otherwise unsigned comparisons can result
+ * against negative integers quite easily, and fail in subtle ways.
+ */
+PACK_STRUCT_BEGIN
+struct ip
+{
+#if defined(NO_CHAR_BITFIELDS)
+       u_char ip_hl_v; /* bug in GCC for mips means the bitfield stuff will sometimes break - so we use a char for both and get round it with macro's instead... */
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+       unsigned ip_hl:4,                               /* header length */
+               ip_v:4;                                         /* version */
+#elif BYTE_ORDER == BIG_ENDIAN 
+       unsigned ip_v:4,                                        /* version */
+               ip_hl:4;                                        /* header length */
+#else
+       COMPLAIN - NO BYTE ORDER SELECTED!
+#endif
+#endif
+       u_char  ip_tos;                                 /* type of service */
+       u_short ip_len;                                 /* total length */
+       u_short ip_id;                                  /* identification */
+       u_short ip_off;                                 /* fragment offset field */
+#define        IP_DF 0x4000                            /* dont fragment flag */
+#define        IP_MF 0x2000                            /* more fragments flag */
+#define        IP_OFFMASK 0x1fff                       /* mask for fragmenting bits */
+       u_char  ip_ttl;                                 /* time to live */
+       u_char  ip_p;                                   /* protocol */
+       u_short ip_sum;                                 /* checksum */
+       struct  in_addr ip_src,ip_dst;  /* source and dest address */
+};
+PACK_STRUCT_END
+
+typedef u32_t tcp_seq;
+
+/*
+ * TCP header.
+ * Per RFC 793, September, 1981.
+ */
+PACK_STRUCT_BEGIN
+struct tcphdr  
+{
+       u_short th_sport;               /* source port */
+       u_short th_dport;               /* destination port */
+       tcp_seq th_seq;                 /* sequence number */
+       tcp_seq th_ack;                 /* acknowledgement number */
+#if defined(NO_CHAR_BITFIELDS)
+       u_char th_x2_off;
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+       unsigned        th_x2:4,                /* (unused) */
+                       th_off:4;               /* data offset */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN 
+       unsigned        th_off:4,               /* data offset */
+                       th_x2:4;                /* (unused) */
+#endif
+#endif
+       u_char  th_flags;
+       u_short th_win;                 /* window */
+       u_short th_sum;                 /* checksum */
+       u_short th_urp;                 /* urgent pointer */
+};
+PACK_STRUCT_END
+
+#endif /* VJBSDHDR_H */
diff --git a/Demo/Common/ethernet/lwIP/netif/slipif.c b/Demo/Common/ethernet/lwIP/netif/slipif.c
new file mode 100644 (file)
index 0000000..dd8db20
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE. 
+ *
+ * This file is built upon the file: src/arch/rtxc/netif/sioslip.c
+ *
+ * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com> 
+ */
+
+/* 
+ * This is an arch independent SLIP netif. The specific serial hooks must be
+ * provided by another file. They are sio_open, sio_recv and sio_send
+ */
+
+#include "netif/slipif.h"
+#include "lwip/opt.h"
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "lwip/stats.h"
+#include "lwip/sio.h"
+
+#define SLIP_END     0300
+#define SLIP_ESC     0333
+#define SLIP_ESC_END 0334
+#define SLIP_ESC_ESC 0335
+
+#define MAX_SIZE     1500
+
+/**
+ * Send a pbuf doing the necessary SLIP encapsulation
+ *
+ * Uses the serial layer's sio_send() 
+ */
+err_t
+slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
+{
+  struct pbuf *q;
+  u16_t i;
+  u8_t c;
+
+  /* Send pbuf out on the serial I/O device. */
+  sio_send(SLIP_END, netif->state);
+
+  for (q = p; q != NULL; q = q->next) {
+    for (i = 0; i < q->len; i++) {
+      c = ((u8_t *)q->payload)[i];
+      switch (c) {
+      case SLIP_END:
+        sio_send(SLIP_ESC, netif->state);
+        sio_send(SLIP_ESC_END, netif->state);
+        break;
+      case SLIP_ESC:
+        sio_send(SLIP_ESC, netif->state);
+        sio_send(SLIP_ESC_ESC, netif->state);
+        break;
+      default:
+        sio_send(c, netif->state);
+        break;
+      }
+    }
+  }
+  sio_send(SLIP_END, netif->state);
+  return 0;
+}
+
+/**
+ * Handle the incoming SLIP stream character by character
+ *
+ * Poll the serial layer by calling sio_recv()
+ * 
+ * @return The IP packet when SLIP_END is received 
+ */
+static struct pbuf *
+slipif_input(struct netif *netif)
+{
+  u8_t c;
+  struct pbuf *p, *q;
+  u16_t recved;
+  u16_t i;
+
+  q = p = NULL;
+  recved = i = 0;
+  c = 0;
+
+  while (1) {
+    c = sio_recv(netif->state);
+    switch (c) {
+    case SLIP_END:
+      if (recved > 0) {
+        /* Received whole packet. */
+        pbuf_realloc(q, recved);
+        
+        LINK_STATS_INC(link.recv);
+        
+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
+        return q;
+      }
+      break;
+
+    case SLIP_ESC:
+      c = sio_recv(netif->state);
+      switch (c) {
+      case SLIP_ESC_END:
+        c = SLIP_END;
+        break;
+      case SLIP_ESC_ESC:
+        c = SLIP_ESC;
+        break;
+      }
+      /* FALLTHROUGH */
+
+    default:
+      if (p == NULL) {
+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
+        p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL);
+
+        if (p == NULL) {
+          LINK_STATS_INC(link.drop);
+          LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
+        }
+
+        if (q != NULL) {
+          pbuf_cat(q, p);
+        } else {
+          q = p;
+        }
+      }
+      if (p != NULL && recved < MAX_SIZE) {
+        ((u8_t *)p->payload)[i] = c;
+        recved++;
+        i++;
+        if (i >= p->len) {
+          i = 0;
+          if (p->next != NULL && p->next->len > 0)
+            p = p->next;
+          else
+            p = NULL;
+        }
+      }
+      break;
+    }
+
+  }
+  return NULL;
+}
+
+/**
+ * The SLIP input thread.
+ *
+ * Feed the IP layer with incoming packets
+ */
+static void
+slipif_loop(void *nf)
+{
+  struct pbuf *p;
+  struct netif *netif = (struct netif *)nf;
+
+  while (1) {
+    p = slipif_input(netif);
+    netif->input(p, netif);
+  }
+}
+
+/**
+ * SLIP netif initialization
+ *
+ * Call the arch specific sio_open and remember
+ * the opened device in the state field of the netif.
+ */
+err_t
+slipif_init(struct netif *netif)
+{
+
+  LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));
+
+  netif->name[0] = 's';
+  netif->name[1] = 'l';
+  netif->output = slipif_output;
+  netif->mtu = 1500;
+  netif->flags = NETIF_FLAG_POINTTOPOINT;
+
+  netif->state = sio_open(netif->num);
+  if (!netif->state)
+    return ERR_IF;
+
+  sys_thread_new(slipif_loop, netif, SLIPIF_THREAD_PRIO);
+  return ERR_OK;
+}