]> git.sur5r.net Git - freertos/commitdiff
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@82 1d2547de-c912-0410-9cb9...
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Tue, 5 Jun 2007 09:35:13 +0000 (09:35 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Tue, 5 Jun 2007 09:35:13 +0000 (09:35 +0000)
134 files changed:
Demo/Common/Full/BlockQ.c
Demo/Common/Full/PollQ.c
Demo/Common/Full/comtest.c
Demo/Common/Full/death.c
Demo/Common/Full/dynamic.c
Demo/Common/Full/events.c
Demo/Common/Full/flash.c
Demo/Common/Full/flop.c
Demo/Common/Full/integer.c
Demo/Common/Full/print.c
Demo/Common/Full/semtest.c
Demo/Common/Minimal/BlockQ.c
Demo/Common/Minimal/PollQ.c
Demo/Common/Minimal/blocktim.c
Demo/Common/Minimal/comtest.c
Demo/Common/Minimal/crflash.c
Demo/Common/Minimal/crhook.c
Demo/Common/Minimal/death.c
Demo/Common/Minimal/dynamic.c
Demo/Common/Minimal/flash.c
Demo/Common/Minimal/flop.c
Demo/Common/Minimal/integer.c
Demo/Common/Minimal/semtest.c
Demo/Common/ethernet/lwIP/api/api_lib.c
Demo/Common/ethernet/lwIP/api/api_msg.c
Demo/Common/ethernet/lwIP/api/err.c
Demo/Common/ethernet/lwIP/api/sockets.c
Demo/Common/ethernet/lwIP/api/tcpip.c
Demo/Common/ethernet/lwIP/core/dhcp.c
Demo/Common/ethernet/lwIP/core/inet.c
Demo/Common/ethernet/lwIP/core/inet6.c
Demo/Common/ethernet/lwIP/core/ipv4/icmp.c
Demo/Common/ethernet/lwIP/core/ipv4/ip.c
Demo/Common/ethernet/lwIP/core/ipv4/ip_addr.c
Demo/Common/ethernet/lwIP/core/ipv4/ip_frag.c
Demo/Common/ethernet/lwIP/core/mem.c
Demo/Common/ethernet/lwIP/core/memp.c
Demo/Common/ethernet/lwIP/core/netif.c
Demo/Common/ethernet/lwIP/core/pbuf.c
Demo/Common/ethernet/lwIP/core/raw.c
Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c
Demo/Common/ethernet/lwIP/core/snmp/asn1_enc.c
Demo/Common/ethernet/lwIP/core/snmp/mib2.c
Demo/Common/ethernet/lwIP/core/snmp/mib_structs.c
Demo/Common/ethernet/lwIP/core/snmp/msg_in.c
Demo/Common/ethernet/lwIP/core/snmp/msg_out.c
Demo/Common/ethernet/lwIP/core/stats.c
Demo/Common/ethernet/lwIP/core/sys.c
Demo/Common/ethernet/lwIP/core/tcp.c
Demo/Common/ethernet/lwIP/core/tcp_in.c
Demo/Common/ethernet/lwIP/core/tcp_out.c
Demo/Common/ethernet/lwIP/core/udp.c
Demo/Common/ethernet/lwIP/include/ipv4/lwip/icmp.h
Demo/Common/ethernet/lwIP/include/ipv4/lwip/inet.h
Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip.h
Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip_addr.h
Demo/Common/ethernet/lwIP/include/ipv4/lwip/ip_frag.h
Demo/Common/ethernet/lwIP/include/lwip/api.h
Demo/Common/ethernet/lwIP/include/lwip/api_msg.h
Demo/Common/ethernet/lwIP/include/lwip/arch.h
Demo/Common/ethernet/lwIP/include/lwip/debug.h
Demo/Common/ethernet/lwIP/include/lwip/def.h
Demo/Common/ethernet/lwIP/include/lwip/dhcp.h
Demo/Common/ethernet/lwIP/include/lwip/err.h
Demo/Common/ethernet/lwIP/include/lwip/mem.h
Demo/Common/ethernet/lwIP/include/lwip/memp.h
Demo/Common/ethernet/lwIP/include/lwip/netif.h
Demo/Common/ethernet/lwIP/include/lwip/pbuf.h
Demo/Common/ethernet/lwIP/include/lwip/raw.h
Demo/Common/ethernet/lwIP/include/lwip/sio.h
Demo/Common/ethernet/lwIP/include/lwip/snmp.h
Demo/Common/ethernet/lwIP/include/lwip/snmp_asn1.h
Demo/Common/ethernet/lwIP/include/lwip/snmp_msg.h
Demo/Common/ethernet/lwIP/include/lwip/snmp_structs.h
Demo/Common/ethernet/lwIP/include/lwip/sockets.h
Demo/Common/ethernet/lwIP/include/lwip/stats.h
Demo/Common/ethernet/lwIP/include/lwip/sys.h
Demo/Common/ethernet/lwIP/include/lwip/tcp.h
Demo/Common/ethernet/lwIP/include/lwip/tcpip.h
Demo/Common/ethernet/lwIP/include/lwip/udp.h
Demo/Common/ethernet/lwIP/include/netif/etharp.h
Demo/Common/ethernet/lwIP/include/netif/loopif.h
Demo/Common/ethernet/lwIP/include/netif/slipif.h
Demo/Common/ethernet/lwIP/netif/etharp.c
Demo/Common/ethernet/lwIP/netif/ethernetif.c
Demo/Common/ethernet/lwIP/netif/loopif.c
Demo/Common/ethernet/lwIP/netif/ppp/auth.c
Demo/Common/ethernet/lwIP/netif/ppp/auth.h
Demo/Common/ethernet/lwIP/netif/ppp/chap.c
Demo/Common/ethernet/lwIP/netif/ppp/chap.h
Demo/Common/ethernet/lwIP/netif/ppp/chpms.c
Demo/Common/ethernet/lwIP/netif/ppp/chpms.h
Demo/Common/ethernet/lwIP/netif/ppp/fsm.c
Demo/Common/ethernet/lwIP/netif/ppp/fsm.h
Demo/Common/ethernet/lwIP/netif/ppp/ipcp.c
Demo/Common/ethernet/lwIP/netif/ppp/ipcp.h
Demo/Common/ethernet/lwIP/netif/ppp/lcp.c
Demo/Common/ethernet/lwIP/netif/ppp/lcp.h
Demo/Common/ethernet/lwIP/netif/ppp/magic.c
Demo/Common/ethernet/lwIP/netif/ppp/magic.h
Demo/Common/ethernet/lwIP/netif/ppp/md5.c
Demo/Common/ethernet/lwIP/netif/ppp/md5.h
Demo/Common/ethernet/lwIP/netif/ppp/pap.c
Demo/Common/ethernet/lwIP/netif/ppp/ppp.c
Demo/Common/ethernet/lwIP/netif/ppp/ppp.h
Demo/Common/ethernet/lwIP/netif/ppp/pppdebug.h
Demo/Common/ethernet/lwIP/netif/ppp/randm.c
Demo/Common/ethernet/lwIP/netif/ppp/randm.h
Demo/Common/ethernet/lwIP/netif/ppp/vj.c
Demo/Common/ethernet/lwIP/netif/ppp/vj.h
Demo/Common/ethernet/lwIP/netif/ppp/vjbsdhdr.h
Demo/Common/ethernet/lwIP/netif/slipif.c
Demo/Common/ethernet/uIP/uip-1.0/uip/uip.c
Demo/Common/ethernet/uIP/uip-1.0/uip/uip.h
Demo/Common/ethernet/uIP/uip-1.0/uip/uip_arp.c
Demo/Common/ethernet/uIP/uip-1.0/uip/uip_arp.h
Demo/Common/include/BlockQ.h
Demo/Common/include/PollQ.h
Demo/Common/include/blocktim.h
Demo/Common/include/comtest.h
Demo/Common/include/comtest2.h
Demo/Common/include/crflash.h
Demo/Common/include/crhook.h
Demo/Common/include/death.h
Demo/Common/include/dynamic.h
Demo/Common/include/fileIO.h
Demo/Common/include/flash.h
Demo/Common/include/flop.h
Demo/Common/include/integer.h
Demo/Common/include/mevents.h
Demo/Common/include/partest.h
Demo/Common/include/print.h
Demo/Common/include/semtest.h
Demo/Common/include/serial.h

index e3c64f62f0d33e28920170a1f0ea0ca5aa85e1de..a3dd52d1d0231f46a2a3358736f14a19abc8a347 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index d10c2081f98207537d79cbc519b6c243cfcc6c8b..05ef9266ecea244b5e0024093950f3198f524c18 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 0d3643803694bc4bfe0c77cf50e175e7316b2420..82804fb98201da1c28212bfa4cf6be21abc1b899 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 274498f57e53c1d94d820a05f76cd8550fe2f693..e5dfb9be995feec497644688eb969c2e4d3efdbd 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 94446691489f712280a20d81c5030c25b988e3e1..e27b70817044fe0ec4a48cbc475706feedfbcf13 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 347c766111073cb1ea6905b5ed57b57c4c99269d..5b1c54cc4635e7d122b7401eab340c58ef942798 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 91936c8cd29914fe4b41143628307df441d1a94a..59d6d033cd7ea92731e27fed9d5864a25ab3078e 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index b9b626c3458b633f545df8d3c8b914395a39e660..a4f3565798a01e57aa06cf1192969c782b6d51c1 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 8bca3480064f5bf789d9f12995fc86bbc21c9ec2..bf1f4ea53a8f0cdc4eb67f0702b615a1dcc75441 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index c55fdc1c7b515b80f0bd499232372ee099a89c90..635de1f28c27442539c3fe42867811c2ea5767fd 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index ba31bee10f461e41d87d87b33366e215e414adb2..5e9dd0a619c9035589573a5b7b4a04633a3deeff 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 698fec31f273902856f929ffb9305396c61de261..8ab9537849adcf2bcda9ae4a69e3ffebd4313aae 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index d53e7894dd954bdbd7f3a2ff8a075e4d96fc3230..681fd7033ab1e2019b8e7292067c9f9d989fee9f 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 71b50314a646202f2497d77da2ba28d57d564d56..77b25f99010ab7a97ac45c2b0c53f0d6d242c017 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 3729ca1bf3c55d5cce65c8436e51af63d8bc66be..53c5ebf9afe9d0160c141a6887a284ef379de2ff 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 63948d56e16ac12bc8a2238fa38cbf12683a2edd..b2f15038e4b39416ac8719c87e1fb5f73966782e 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index c9eb0e72ae980e61f5cb21886ef261867cf26e5f..d9f735efa989abed11cec90116a239af88a33465 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 69c3e644ad891712c8953f7bb1e5fd374ae7c3f2..f5a680782c2c7576f2bc79167746f6f52d3fe981 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 3996ce43fce33ddf4f4f476b39f09e9f2c207b46..6ea9a7e1ed9b71a3100288071adcbc5be9e35326 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index c219d3f6fe99275f6ca38eda003bd2d6ec9b72dc..3765dd11e70e8dd32ba850ca920d851e6eeacc81 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 4e370384291501c42d9c1e7a7333ac534838f608..87d61219b658e27104c928dec930cfc6b85a4615 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 97a873bf6e8e3a306064d346f8ceecb3aecc0357..26ebff36a28814f0e181ce1644e232c2592dfd4b 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index c6a05c81a3e2c1c9adce050e3bef4fa133631601..0e9059b39008b35ad71736b0fd44605369f818eb 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 01683b0d4b2add6b6db06159c98af601ed9f6c47..917a2ecb28370eba1a553aa6f508c453165b2dbf 100644 (file)
-/*
- * 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;
-}
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/* This is the part of the API that is linked with\r
+   the application */\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/api.h"\r
+#include "lwip/api_msg.h"\r
+#include "lwip/memp.h"\r
+\r
+\r
+struct\r
+netbuf *netbuf_new(void)\r
+{\r
+  struct netbuf *buf;\r
+\r
+  buf = memp_malloc(MEMP_NETBUF);\r
+  if (buf != NULL) {\r
+    buf->p = NULL;\r
+    buf->ptr = NULL;\r
+    return buf;\r
+  } else {\r
+    return NULL;\r
+  }\r
+}\r
+\r
+void\r
+netbuf_delete(struct netbuf *buf)\r
+{\r
+  if (buf != NULL) {\r
+    if (buf->p != NULL) {\r
+      pbuf_free(buf->p);\r
+      buf->p = buf->ptr = NULL;\r
+    }\r
+    memp_free(MEMP_NETBUF, buf);\r
+  }\r
+}\r
+\r
+void *\r
+netbuf_alloc(struct netbuf *buf, u16_t size)\r
+{\r
+  /* Deallocate any previously allocated memory. */\r
+  if (buf->p != NULL) {\r
+    pbuf_free(buf->p);\r
+  }\r
+  buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);\r
+  if (buf->p == NULL) {\r
+     return NULL;\r
+  }\r
+  buf->ptr = buf->p;\r
+  return buf->p->payload;\r
+}\r
+\r
+void\r
+netbuf_free(struct netbuf *buf)\r
+{\r
+  if (buf->p != NULL) {\r
+    pbuf_free(buf->p);\r
+  }\r
+  buf->p = buf->ptr = NULL;\r
+}\r
+\r
+void\r
+netbuf_ref(struct netbuf *buf, void *dataptr, u16_t size)\r
+{\r
+  if (buf->p != NULL) {\r
+    pbuf_free(buf->p);\r
+  }\r
+  buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);\r
+  buf->p->payload = dataptr;\r
+  buf->p->len = buf->p->tot_len = size;\r
+  buf->ptr = buf->p;\r
+}\r
+\r
+void\r
+netbuf_chain(struct netbuf *head, struct netbuf *tail)\r
+{\r
+  pbuf_chain(head->p, tail->p);\r
+  head->ptr = head->p;\r
+  memp_free(MEMP_NETBUF, tail);\r
+}\r
+\r
+u16_t\r
+netbuf_len(struct netbuf *buf)\r
+{\r
+  return buf->p->tot_len;\r
+}\r
+\r
+err_t\r
+netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)\r
+{\r
+  if (buf->ptr == NULL) {\r
+    return ERR_BUF;\r
+  }\r
+  *dataptr = buf->ptr->payload;\r
+  *len = buf->ptr->len;\r
+  return ERR_OK;\r
+}\r
+\r
+s8_t\r
+netbuf_next(struct netbuf *buf)\r
+{\r
+  if (buf->ptr->next == NULL) {\r
+    return -1;\r
+  }\r
+  buf->ptr = buf->ptr->next;\r
+  if (buf->ptr->next == NULL) {\r
+    return 1;\r
+  }\r
+  return 0;\r
+}\r
+\r
+void\r
+netbuf_first(struct netbuf *buf)\r
+{\r
+  buf->ptr = buf->p;\r
+}\r
+\r
+void\r
+netbuf_copy_partial(struct netbuf *buf, void *dataptr, u16_t len, u16_t offset)\r
+{\r
+  struct pbuf *p;\r
+  u16_t i, left;\r
+\r
+  left = 0;\r
+\r
+  if(buf == NULL || dataptr == NULL) {\r
+    return;\r
+  }\r
+  \r
+  /* This implementation is bad. It should use bcopy\r
+     instead. */\r
+  for(p = buf->p; left < len && p != NULL; p = p->next) {\r
+    if (offset != 0 && offset >= p->len) {\r
+      offset -= p->len;\r
+    } else {    \r
+      for(i = offset; i < p->len; ++i) {\r
+  ((u8_t *)dataptr)[left] = ((u8_t *)p->payload)[i];\r
+  if (++left >= len) {\r
+    return;\r
+  }\r
+      }\r
+      offset = 0;\r
+    }\r
+  }\r
+}\r
+\r
+void\r
+netbuf_copy(struct netbuf *buf, void *dataptr, u16_t len)\r
+{\r
+  netbuf_copy_partial(buf, dataptr, len, 0);\r
+}\r
+\r
+struct ip_addr *\r
+netbuf_fromaddr(struct netbuf *buf)\r
+{\r
+  return buf->fromaddr;\r
+}\r
+\r
+u16_t\r
+netbuf_fromport(struct netbuf *buf)\r
+{\r
+  return buf->fromport;\r
+}\r
+\r
+struct\r
+netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,\r
+                                   void (*callback)(struct netconn *, enum netconn_evt, u16_t len))\r
+{\r
+  struct netconn *conn;\r
+  struct api_msg *msg;\r
+\r
+  conn = memp_malloc(MEMP_NETCONN);\r
+  if (conn == NULL) {\r
+    return NULL;\r
+  }\r
+  \r
+  conn->err = ERR_OK;\r
+  conn->type = t;\r
+  conn->pcb.tcp = NULL;\r
+\r
+  if ((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
+    memp_free(MEMP_NETCONN, conn);\r
+    return NULL;\r
+  }\r
+  conn->recvmbox = SYS_MBOX_NULL;\r
+  conn->acceptmbox = SYS_MBOX_NULL;\r
+  conn->sem = sys_sem_new(0);\r
+  if (conn->sem == SYS_SEM_NULL) {\r
+    memp_free(MEMP_NETCONN, conn);\r
+    return NULL;\r
+  }\r
+  conn->state = NETCONN_NONE;\r
+  conn->socket = 0;\r
+  conn->callback = callback;\r
+  conn->recv_avail = 0;\r
+\r
+  if((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    memp_free(MEMP_NETCONN, conn);\r
+    return NULL;\r
+  }\r
+  \r
+  msg->type = API_MSG_NEWCONN;\r
+  msg->msg.msg.bc.port = proto; /* misusing the port field */\r
+  msg->msg.conn = conn;\r
+  api_msg_post(msg);  \r
+  sys_mbox_fetch(conn->mbox, NULL);\r
+  memp_free(MEMP_API_MSG, msg);\r
+\r
+  if ( conn->err != ERR_OK ) {\r
+    memp_free(MEMP_NETCONN, conn);\r
+    return NULL;\r
+  }\r
+\r
+  return conn;\r
+}\r
+\r
+\r
+struct\r
+netconn *netconn_new(enum netconn_type t)\r
+{\r
+  return netconn_new_with_proto_and_callback(t,0,NULL);\r
+}\r
+\r
+struct\r
+netconn *netconn_new_with_callback(enum netconn_type t,\r
+                                   void (*callback)(struct netconn *, enum netconn_evt, u16_t len))\r
+{\r
+  return netconn_new_with_proto_and_callback(t,0,callback);\r
+}\r
+\r
+\r
+err_t\r
+netconn_delete(struct netconn *conn)\r
+{\r
+  struct api_msg *msg;\r
+  void *mem;\r
+  \r
+  if (conn == NULL) {\r
+    return ERR_OK;\r
+  }\r
+  \r
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    return ERR_MEM;\r
+  }\r
+  \r
+  msg->type = API_MSG_DELCONN;\r
+  msg->msg.conn = conn;\r
+  api_msg_post(msg);  \r
+  sys_mbox_fetch(conn->mbox, NULL);\r
+  memp_free(MEMP_API_MSG, msg);\r
+\r
+  /* Drain the recvmbox. */\r
+  if (conn->recvmbox != SYS_MBOX_NULL) {\r
+    while (sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {\r
+      if (conn->type == NETCONN_TCP) {\r
+        if(mem != NULL)\r
+          pbuf_free((struct pbuf *)mem);\r
+      } else {\r
+        netbuf_delete((struct netbuf *)mem);\r
+      }\r
+    }\r
+    sys_mbox_free(conn->recvmbox);\r
+    conn->recvmbox = SYS_MBOX_NULL;\r
+  }\r
\r
+\r
+  /* Drain the acceptmbox. */\r
+  if (conn->acceptmbox != SYS_MBOX_NULL) {\r
+    while (sys_arch_mbox_fetch(conn->acceptmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {\r
+      netconn_delete((struct netconn *)mem);\r
+    }\r
+    \r
+    sys_mbox_free(conn->acceptmbox);\r
+    conn->acceptmbox = SYS_MBOX_NULL;\r
+  }\r
+\r
+  sys_mbox_free(conn->mbox);\r
+  conn->mbox = SYS_MBOX_NULL;\r
+  if (conn->sem != SYS_SEM_NULL) {\r
+    sys_sem_free(conn->sem);\r
+  }\r
+  /*  conn->sem = SYS_SEM_NULL;*/\r
+  memp_free(MEMP_NETCONN, conn);\r
+  return ERR_OK;\r
+}\r
+\r
+enum netconn_type\r
+netconn_type(struct netconn *conn)\r
+{\r
+  return conn->type;\r
+}\r
+\r
+err_t\r
+netconn_peer(struct netconn *conn, struct ip_addr *addr,\r
+       u16_t *port)\r
+{\r
+  switch (conn->type) {\r
+  case NETCONN_RAW:\r
+    /* return an error as connecting is only a helper for upper layers */\r
+    return ERR_CONN;\r
+  case NETCONN_UDPLITE:\r
+  case NETCONN_UDPNOCHKSUM:\r
+  case NETCONN_UDP:\r
+    if (conn->pcb.udp == NULL ||\r
+  ((conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0))\r
+     return ERR_CONN;\r
+    *addr = (conn->pcb.udp->remote_ip);\r
+    *port = conn->pcb.udp->remote_port;\r
+    break;\r
+  case NETCONN_TCP:\r
+    if (conn->pcb.tcp == NULL)\r
+      return ERR_CONN;\r
+    *addr = (conn->pcb.tcp->remote_ip);\r
+    *port = conn->pcb.tcp->remote_port;\r
+    break;\r
+  }\r
+  return (conn->err = ERR_OK);\r
+}\r
+\r
+err_t\r
+netconn_addr(struct netconn *conn, struct ip_addr **addr,\r
+       u16_t *port)\r
+{\r
+  switch (conn->type) {\r
+  case NETCONN_RAW:\r
+    *addr = &(conn->pcb.raw->local_ip);\r
+    *port = conn->pcb.raw->protocol;\r
+    break;\r
+  case NETCONN_UDPLITE:\r
+  case NETCONN_UDPNOCHKSUM:\r
+  case NETCONN_UDP:\r
+    *addr = &(conn->pcb.udp->local_ip);\r
+    *port = conn->pcb.udp->local_port;\r
+    break;\r
+  case NETCONN_TCP:\r
+    *addr = &(conn->pcb.tcp->local_ip);\r
+    *port = conn->pcb.tcp->local_port;\r
+    break;\r
+  }\r
+  return (conn->err = ERR_OK);\r
+}\r
+\r
+err_t\r
+netconn_bind(struct netconn *conn, struct ip_addr *addr,\r
+      u16_t port)\r
+{\r
+  struct api_msg *msg;\r
+\r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+  if (conn->type != NETCONN_TCP &&\r
+     conn->recvmbox == SYS_MBOX_NULL) {\r
+    if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
+      return ERR_MEM;\r
+    }\r
+  }\r
+  \r
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    return (conn->err = ERR_MEM);\r
+  }\r
+  msg->type = API_MSG_BIND;\r
+  msg->msg.conn = conn;\r
+  msg->msg.msg.bc.ipaddr = addr;\r
+  msg->msg.msg.bc.port = port;\r
+  api_msg_post(msg);\r
+  sys_mbox_fetch(conn->mbox, NULL);\r
+  memp_free(MEMP_API_MSG, msg);\r
+  return conn->err;\r
+}\r
+\r
+\r
+err_t\r
+netconn_connect(struct netconn *conn, struct ip_addr *addr,\r
+       u16_t port)\r
+{\r
+  struct api_msg *msg;\r
+  \r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+\r
+  if (conn->recvmbox == SYS_MBOX_NULL) {\r
+    if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
+      return ERR_MEM;\r
+    }\r
+  }\r
+  \r
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    return ERR_MEM;\r
+  }\r
+  msg->type = API_MSG_CONNECT;\r
+  msg->msg.conn = conn;  \r
+  msg->msg.msg.bc.ipaddr = addr;\r
+  msg->msg.msg.bc.port = port;\r
+  api_msg_post(msg);\r
+  sys_mbox_fetch(conn->mbox, NULL);\r
+  memp_free(MEMP_API_MSG, msg);\r
+  return conn->err;\r
+}\r
+\r
+err_t\r
+netconn_disconnect(struct netconn *conn)\r
+{\r
+  struct api_msg *msg;\r
+  \r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    return ERR_MEM;\r
+  }\r
+  msg->type = API_MSG_DISCONNECT;\r
+  msg->msg.conn = conn;  \r
+  api_msg_post(msg);\r
+  sys_mbox_fetch(conn->mbox, NULL);\r
+  memp_free(MEMP_API_MSG, msg);\r
+  return conn->err;\r
+\r
+}\r
+\r
+err_t\r
+netconn_listen(struct netconn *conn)\r
+{\r
+  struct api_msg *msg;\r
+\r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+  if (conn->acceptmbox == SYS_MBOX_NULL) {\r
+    conn->acceptmbox = sys_mbox_new();\r
+    if (conn->acceptmbox == SYS_MBOX_NULL) {\r
+      return ERR_MEM;\r
+    }\r
+  }\r
+  \r
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    return (conn->err = ERR_MEM);\r
+  }\r
+  msg->type = API_MSG_LISTEN;\r
+  msg->msg.conn = conn;\r
+  api_msg_post(msg);\r
+  sys_mbox_fetch(conn->mbox, NULL);\r
+  memp_free(MEMP_API_MSG, msg);\r
+  return conn->err;\r
+}\r
+\r
+struct netconn *\r
+netconn_accept(struct netconn *conn)\r
+{\r
+  struct netconn *newconn;\r
+  \r
+  if (conn == NULL) {\r
+    return NULL;\r
+  }\r
+  \r
+  sys_mbox_fetch(conn->acceptmbox, (void *)&newconn);\r
+  /* Register event with callback */\r
+  if (conn->callback)\r
+      (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, 0);\r
+  \r
+  return newconn;\r
+}\r
+\r
+struct netbuf *\r
+netconn_recv(struct netconn *conn)\r
+{\r
+  struct api_msg *msg;\r
+  struct netbuf *buf;\r
+  struct pbuf *p;\r
+  u16_t len;\r
+    \r
+  if (conn == NULL) {\r
+    return NULL;\r
+  }\r
+  \r
+  if (conn->recvmbox == SYS_MBOX_NULL) {\r
+    conn->err = ERR_CONN;\r
+    return NULL;\r
+  }\r
+\r
+  if (conn->err != ERR_OK) {\r
+    return NULL;\r
+  }\r
+\r
+  if (conn->type == NETCONN_TCP) {\r
+    if (conn->pcb.tcp->state == LISTEN) {\r
+      conn->err = ERR_CONN;\r
+      return NULL;\r
+    }\r
+\r
+\r
+    buf = memp_malloc(MEMP_NETBUF);\r
+\r
+    if (buf == NULL) {\r
+      conn->err = ERR_MEM;\r
+      return NULL;\r
+    }\r
+    \r
+    sys_mbox_fetch(conn->recvmbox, (void *)&p);\r
+\r
+    if (p != NULL)\r
+    {\r
+        len = p->tot_len;\r
+        conn->recv_avail -= len;\r
+    }\r
+    else\r
+        len = 0;\r
+    \r
+    /* Register event with callback */\r
+      if (conn->callback)\r
+        (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, len);\r
+\r
+    /* If we are closed, we indicate that we no longer wish to receive\r
+       data by setting conn->recvmbox to SYS_MBOX_NULL. */\r
+    if (p == NULL) {\r
+      memp_free(MEMP_NETBUF, buf);\r
+      sys_mbox_free(conn->recvmbox);\r
+      conn->recvmbox = SYS_MBOX_NULL;\r
+      return NULL;\r
+    }\r
+\r
+    buf->p = p;\r
+    buf->ptr = p;\r
+    buf->fromport = 0;\r
+    buf->fromaddr = NULL;\r
+\r
+    /* Let the stack know that we have taken the data. */\r
+    if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+      conn->err = ERR_MEM;\r
+      return buf;\r
+    }\r
+    msg->type = API_MSG_RECV;\r
+    msg->msg.conn = conn;\r
+    if (buf != NULL) {\r
+      msg->msg.msg.len = buf->p->tot_len;\r
+    } else {\r
+      msg->msg.msg.len = 1;\r
+    }\r
+    api_msg_post(msg);\r
+\r
+    sys_mbox_fetch(conn->mbox, NULL);\r
+    memp_free(MEMP_API_MSG, msg);\r
+  } else {\r
+    sys_mbox_fetch(conn->recvmbox, (void *)&buf);\r
+  conn->recv_avail -= buf->p->tot_len;\r
+    /* Register event with callback */\r
+    if (conn->callback)\r
+        (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);\r
+  }\r
+\r
+  \r
+\r
+    \r
+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));\r
+\r
+\r
+  return buf;\r
+}\r
+\r
+err_t\r
+netconn_send(struct netconn *conn, struct netbuf *buf)\r
+{\r
+  struct api_msg *msg;\r
+\r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+  if (conn->err != ERR_OK) {\r
+    return conn->err;\r
+  }\r
+\r
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    return (conn->err = ERR_MEM);\r
+  }\r
+\r
+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));\r
+  msg->type = API_MSG_SEND;\r
+  msg->msg.conn = conn;\r
+  msg->msg.msg.p = buf->p;\r
+  api_msg_post(msg);\r
+\r
+  sys_mbox_fetch(conn->mbox, NULL);\r
+  memp_free(MEMP_API_MSG, msg);\r
+  return conn->err;\r
+}\r
+\r
+err_t\r
+netconn_write(struct netconn *conn, void *dataptr, u16_t size, u8_t copy)\r
+{\r
+  struct api_msg *msg;\r
+  u16_t len;\r
+  \r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+  if (conn->err != ERR_OK) {\r
+    return conn->err;\r
+  }\r
+\r
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    return (conn->err = ERR_MEM);\r
+  }\r
+  msg->type = API_MSG_WRITE;\r
+  msg->msg.conn = conn;\r
+        \r
+\r
+  conn->state = NETCONN_WRITE;\r
+  while (conn->err == ERR_OK && size > 0) {\r
+    msg->msg.msg.w.dataptr = dataptr;\r
+    msg->msg.msg.w.copy = copy;\r
+    \r
+    if (conn->type == NETCONN_TCP) {\r
+      if (tcp_sndbuf(conn->pcb.tcp) == 0) {\r
+  sys_sem_wait(conn->sem);\r
+  if (conn->err != ERR_OK) {\r
+    goto ret;\r
+  }\r
+      }\r
+      if (size > tcp_sndbuf(conn->pcb.tcp)) {\r
+  /* We cannot send more than one send buffer's worth of data at a\r
+     time. */\r
+  len = tcp_sndbuf(conn->pcb.tcp);\r
+      } else {\r
+  len = size;\r
+      }\r
+    } else {\r
+      len = size;\r
+    }\r
+    \r
+    LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy));\r
+    msg->msg.msg.w.len = len;\r
+    api_msg_post(msg);\r
+    sys_mbox_fetch(conn->mbox, NULL);    \r
+    if (conn->err == ERR_OK) {\r
+      dataptr = (void *)((u8_t *)dataptr + len);\r
+      size -= len;\r
+    } else if (conn->err == ERR_MEM) {\r
+      conn->err = ERR_OK;\r
+      sys_sem_wait(conn->sem);\r
+    } else {\r
+      goto ret;\r
+    }\r
+  }\r
+ ret:\r
+  memp_free(MEMP_API_MSG, msg);\r
+  conn->state = NETCONN_NONE;\r
+  \r
+  return conn->err;\r
+}\r
+\r
+err_t\r
+netconn_close(struct netconn *conn)\r
+{\r
+  struct api_msg *msg;\r
+\r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+  if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
+    return (conn->err = ERR_MEM);\r
+  }\r
+\r
+  conn->state = NETCONN_CLOSE;\r
+ again:\r
+  msg->type = API_MSG_CLOSE;\r
+  msg->msg.conn = conn;\r
+  api_msg_post(msg);\r
+  sys_mbox_fetch(conn->mbox, NULL);\r
+  if (conn->err == ERR_MEM &&\r
+     conn->sem != SYS_SEM_NULL) {\r
+    sys_sem_wait(conn->sem);\r
+    goto again;\r
+  }\r
+  conn->state = NETCONN_NONE;\r
+  memp_free(MEMP_API_MSG, msg);\r
+  return conn->err;\r
+}\r
+\r
+err_t\r
+netconn_err(struct netconn *conn)\r
+{\r
+  return conn->err;\r
+}\r
+\r
index b7cf03ba60ead5e0408880f8ab184b338f7d41b4..36a7fc1d8ee632392f88dd885974b201b56eb1e1 100644 (file)
-/*
- * 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);
-}
-
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/arch.h"\r
+#include "lwip/api_msg.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/tcpip.h"\r
+\r
+#if LWIP_RAW\r
+static u8_t\r
+recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,\r
+    struct ip_addr *addr)\r
+{\r
+  struct netbuf *buf;\r
+  struct netconn *conn;\r
+\r
+  conn = arg;\r
+  if (!conn) return 0;\r
+\r
+  if (conn->recvmbox != SYS_MBOX_NULL) {\r
+    if (!(buf = memp_malloc(MEMP_NETBUF))) {\r
+      return 0;\r
+    }\r
+    pbuf_ref(p);\r
+    buf->p = p;\r
+    buf->ptr = p;\r
+    buf->fromaddr = addr;\r
+    buf->fromport = pcb->protocol;\r
+\r
+    conn->recv_avail += p->tot_len;\r
+    /* Register event with callback */\r
+    if (conn->callback)\r
+        (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);\r
+    sys_mbox_post(conn->recvmbox, buf);\r
+  }\r
+\r
+  return 0; /* do not eat the packet */\r
+}\r
+#endif\r
+#if LWIP_UDP\r
+static void\r
+recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,\r
+   struct ip_addr *addr, u16_t port)\r
+{\r
+  struct netbuf *buf;\r
+  struct netconn *conn;\r
+\r
+  conn = arg;\r
+  \r
+  if (conn == NULL) {\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+  if (conn->recvmbox != SYS_MBOX_NULL) {\r
+    buf = memp_malloc(MEMP_NETBUF);\r
+    if (buf == NULL) {\r
+      pbuf_free(p);\r
+      return;\r
+    } else {\r
+      buf->p = p;\r
+      buf->ptr = p;\r
+      buf->fromaddr = addr;\r
+      buf->fromport = port;\r
+    }\r
+\r
+  conn->recv_avail += p->tot_len;\r
+    /* Register event with callback */\r
+    if (conn->callback)\r
+        (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);\r
+    sys_mbox_post(conn->recvmbox, buf);\r
+  }\r
+}\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+\r
+static err_t\r
+recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\r
+{\r
+  struct netconn *conn;\r
+  u16_t len;\r
+  \r
+  conn = arg;\r
+\r
+  if (conn == NULL) {\r
+    pbuf_free(p);\r
+    return ERR_VAL;\r
+  }\r
+\r
+  if (conn->recvmbox != SYS_MBOX_NULL) {\r
+        \r
+    conn->err = err;\r
+    if (p != NULL) {\r
+        len = p->tot_len;\r
+        conn->recv_avail += len;\r
+    }\r
+    else\r
+        len = 0;\r
+    /* Register event with callback */\r
+    if (conn->callback)\r
+        (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, len);\r
+    sys_mbox_post(conn->recvmbox, p);\r
+  }  \r
+  return ERR_OK;\r
+}\r
+\r
+\r
+static err_t\r
+poll_tcp(void *arg, struct tcp_pcb *pcb)\r
+{\r
+  struct netconn *conn;\r
+\r
+  conn = arg;\r
+  if (conn != NULL &&\r
+     (conn->state == NETCONN_WRITE || conn->state == NETCONN_CLOSE) &&\r
+     conn->sem != SYS_SEM_NULL) {\r
+    sys_sem_signal(conn->sem);\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+static err_t\r
+sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)\r
+{\r
+  struct netconn *conn;\r
+\r
+  conn = arg;\r
+  if (conn != NULL && conn->sem != SYS_SEM_NULL) {\r
+    sys_sem_signal(conn->sem);\r
+  }\r
+\r
+  if (conn && conn->callback)\r
+      if (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)\r
+          (*conn->callback)(conn, NETCONN_EVT_SENDPLUS, len);\r
+  \r
+  return ERR_OK;\r
+}\r
+\r
+static void\r
+err_tcp(void *arg, err_t err)\r
+{\r
+  struct netconn *conn;\r
+\r
+  conn = arg;\r
+\r
+  conn->pcb.tcp = NULL;\r
+\r
+  \r
+  conn->err = err;\r
+  if (conn->recvmbox != SYS_MBOX_NULL) {\r
+    /* Register event with callback */\r
+    if (conn->callback)\r
+      (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);\r
+    sys_mbox_post(conn->recvmbox, NULL);\r
+  }\r
+  if (conn->mbox != SYS_MBOX_NULL) {\r
+    sys_mbox_post(conn->mbox, NULL);\r
+  }\r
+  if (conn->acceptmbox != SYS_MBOX_NULL) {\r
+     /* Register event with callback */\r
+    if (conn->callback)\r
+      (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);\r
+    sys_mbox_post(conn->acceptmbox, NULL);\r
+  }\r
+  if (conn->sem != SYS_SEM_NULL) {\r
+    sys_sem_signal(conn->sem);\r
+  }\r
+}\r
+\r
+static void\r
+setup_tcp(struct netconn *conn)\r
+{\r
+  struct tcp_pcb *pcb;\r
+  \r
+  pcb = conn->pcb.tcp;\r
+  tcp_arg(pcb, conn);\r
+  tcp_recv(pcb, recv_tcp);\r
+  tcp_sent(pcb, sent_tcp);\r
+  tcp_poll(pcb, poll_tcp, 4);\r
+  tcp_err(pcb, err_tcp);\r
+}\r
+\r
+static err_t\r
+accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)\r
+{\r
+  sys_mbox_t mbox;\r
+  struct netconn *newconn;\r
+  struct netconn *conn;\r
+  \r
+#if API_MSG_DEBUG\r
+#if TCP_DEBUG\r
+  tcp_debug_print_state(newpcb->state);\r
+#endif /* TCP_DEBUG */\r
+#endif /* API_MSG_DEBUG */\r
+  conn = (struct netconn *)arg;\r
+  mbox = conn->acceptmbox;\r
+  newconn = memp_malloc(MEMP_NETCONN);\r
+  if (newconn == NULL) {\r
+    return ERR_MEM;\r
+  }\r
+  newconn->recvmbox = sys_mbox_new();\r
+  if (newconn->recvmbox == SYS_MBOX_NULL) {\r
+    memp_free(MEMP_NETCONN, newconn);\r
+    return ERR_MEM;\r
+  }\r
+  newconn->mbox = sys_mbox_new();\r
+  if (newconn->mbox == SYS_MBOX_NULL) {\r
+    sys_mbox_free(newconn->recvmbox);\r
+    memp_free(MEMP_NETCONN, newconn);\r
+    return ERR_MEM;\r
+  }\r
+  newconn->sem = sys_sem_new(0);\r
+  if (newconn->sem == SYS_SEM_NULL) {\r
+    sys_mbox_free(newconn->recvmbox);\r
+    sys_mbox_free(newconn->mbox);\r
+    memp_free(MEMP_NETCONN, newconn);\r
+    return ERR_MEM;\r
+  }\r
+  /* Allocations were OK, setup the PCB etc */\r
+  newconn->type = NETCONN_TCP;\r
+  newconn->pcb.tcp = newpcb;\r
+  setup_tcp(newconn);\r
+  newconn->acceptmbox = SYS_MBOX_NULL;\r
+  newconn->err = err;\r
+  /* Register event with callback */\r
+  if (conn->callback)\r
+  {\r
+    (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);\r
+  }\r
+  /* We have to set the callback here even though\r
+   * the new socket is unknown. Mark the socket as -1. */\r
+  newconn->callback = conn->callback;\r
+  newconn->socket = -1;\r
+  newconn->recv_avail = 0;\r
+  \r
+  sys_mbox_post(mbox, newconn);\r
+  return ERR_OK;\r
+}\r
+#endif /* LWIP_TCP */\r
+\r
+static void\r
+do_newconn(struct api_msg_msg *msg)\r
+{\r
+   if(msg->conn->pcb.tcp != NULL) {\r
+   /* This "new" connection already has a PCB allocated. */\r
+   /* Is this an error condition? Should it be deleted? \r
+      We currently just are happy and return. */\r
+     sys_mbox_post(msg->conn->mbox, NULL);\r
+     return;\r
+   }\r
+\r
+   msg->conn->err = ERR_OK;\r
+\r
+   /* Allocate a PCB for this connection */\r
+   switch(msg->conn->type) {\r
+#if LWIP_RAW\r
+   case NETCONN_RAW:\r
+      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field */\r
+      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);\r
+     break;\r
+#endif\r
+#if LWIP_UDP\r
+   case NETCONN_UDPLITE:\r
+      msg->conn->pcb.udp = udp_new();\r
+      if(msg->conn->pcb.udp == NULL) {\r
+         msg->conn->err = ERR_MEM;\r
+         break;\r
+      }\r
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+   case NETCONN_UDPNOCHKSUM:\r
+      msg->conn->pcb.udp = udp_new();\r
+      if(msg->conn->pcb.udp == NULL) {\r
+         msg->conn->err = ERR_MEM;\r
+         break;\r
+      }\r
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+   case NETCONN_UDP:\r
+      msg->conn->pcb.udp = udp_new();\r
+      if(msg->conn->pcb.udp == NULL) {\r
+         msg->conn->err = ERR_MEM;\r
+         break;\r
+      }\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+   case NETCONN_TCP:\r
+      msg->conn->pcb.tcp = tcp_new();\r
+      if(msg->conn->pcb.tcp == NULL) {\r
+         msg->conn->err = ERR_MEM;\r
+         break;\r
+      }\r
+      setup_tcp(msg->conn);\r
+      break;\r
+#endif\r
+   }\r
+   \r
+  \r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+}\r
+\r
+\r
+static void\r
+do_delconn(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.tcp != NULL) {\r
+    switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      raw_remove(msg->conn->pcb.raw);\r
+      break;\r
+#endif\r
+#if LWIP_UDP\r
+    case NETCONN_UDPLITE:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDPNOCHKSUM:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDP:\r
+      msg->conn->pcb.udp->recv_arg = NULL;\r
+      udp_remove(msg->conn->pcb.udp);\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP      \r
+    case NETCONN_TCP:\r
+      if (msg->conn->pcb.tcp->state == LISTEN) {\r
+  tcp_arg(msg->conn->pcb.tcp, NULL);\r
+  tcp_accept(msg->conn->pcb.tcp, NULL);  \r
+  tcp_close(msg->conn->pcb.tcp);\r
+      } else {\r
+  tcp_arg(msg->conn->pcb.tcp, NULL);\r
+  tcp_sent(msg->conn->pcb.tcp, NULL);\r
+  tcp_recv(msg->conn->pcb.tcp, NULL);  \r
+  tcp_poll(msg->conn->pcb.tcp, NULL, 0);\r
+  tcp_err(msg->conn->pcb.tcp, NULL);\r
+  if (tcp_close(msg->conn->pcb.tcp) != ERR_OK) {\r
+    tcp_abort(msg->conn->pcb.tcp);\r
+  }\r
+      }\r
+#endif\r
+    default:  \r
+    break;\r
+    }\r
+  }\r
+  /* Trigger select() in socket layer */\r
+  if (msg->conn->callback)\r
+  {\r
+      (*msg->conn->callback)(msg->conn, NETCONN_EVT_RCVPLUS, 0);\r
+      (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDPLUS, 0);\r
+  }\r
+  \r
+  if (msg->conn->mbox != SYS_MBOX_NULL) {\r
+    sys_mbox_post(msg->conn->mbox, NULL);\r
+  }\r
+}\r
+\r
+static void\r
+do_bind(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.tcp == NULL) {\r
+    switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */\r
+      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);\r
+      break;\r
+#endif\r
+#if LWIP_UDP\r
+    case NETCONN_UDPLITE:\r
+      msg->conn->pcb.udp = udp_new();\r
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+    case NETCONN_UDPNOCHKSUM:\r
+      msg->conn->pcb.udp = udp_new();\r
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+    case NETCONN_UDP:\r
+      msg->conn->pcb.udp = udp_new();\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP      \r
+    case NETCONN_TCP:\r
+      msg->conn->pcb.tcp = tcp_new();\r
+      setup_tcp(msg->conn);\r
+#endif /* LWIP_TCP */\r
+    default:  \r
+    break;\r
+    }\r
+  }\r
+  switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+  case NETCONN_RAW:\r
+    msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr);\r
+    break;\r
+#endif\r
+#if LWIP_UDP\r
+  case NETCONN_UDPLITE:\r
+    /* FALLTHROUGH */\r
+  case NETCONN_UDPNOCHKSUM:\r
+    /* FALLTHROUGH */\r
+  case NETCONN_UDP:\r
+    msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);\r
+    break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+  case NETCONN_TCP:\r
+    msg->conn->err = tcp_bind(msg->conn->pcb.tcp,\r
+            msg->msg.bc.ipaddr, msg->msg.bc.port);\r
+#endif /* LWIP_TCP */\r
+  default:\r
+    break;\r
+  }\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+}\r
+#if LWIP_TCP\r
+\r
+static err_t\r
+do_connected(void *arg, struct tcp_pcb *pcb, err_t err)\r
+{\r
+  struct netconn *conn;\r
+\r
+  conn = arg;\r
+\r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+  \r
+  conn->err = err;\r
+  if (conn->type == NETCONN_TCP && err == ERR_OK) {\r
+    setup_tcp(conn);\r
+  }    \r
+  sys_mbox_post(conn->mbox, NULL);\r
+  return ERR_OK;\r
+}\r
+#endif  \r
+\r
+static void\r
+do_connect(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.tcp == NULL) {\r
+    switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */\r
+      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);\r
+      break;\r
+#endif\r
+#if LWIP_UDP\r
+    case NETCONN_UDPLITE:\r
+      msg->conn->pcb.udp = udp_new();\r
+      if (msg->conn->pcb.udp == NULL) {\r
+  msg->conn->err = ERR_MEM;\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+  return;\r
+      }\r
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+    case NETCONN_UDPNOCHKSUM:\r
+      msg->conn->pcb.udp = udp_new();\r
+      if (msg->conn->pcb.udp == NULL) {\r
+  msg->conn->err = ERR_MEM;\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+  return;\r
+      }\r
+      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+    case NETCONN_UDP:\r
+      msg->conn->pcb.udp = udp_new();\r
+      if (msg->conn->pcb.udp == NULL) {\r
+  msg->conn->err = ERR_MEM;\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+  return;\r
+      }\r
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP      \r
+    case NETCONN_TCP:\r
+      msg->conn->pcb.tcp = tcp_new();      \r
+      if (msg->conn->pcb.tcp == NULL) {\r
+  msg->conn->err = ERR_MEM;\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+  return;\r
+      }\r
+#endif\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+  switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+  case NETCONN_RAW:\r
+    raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);\r
+    sys_mbox_post(msg->conn->mbox, NULL);\r
+    break;\r
+#endif\r
+#if LWIP_UDP\r
+  case NETCONN_UDPLITE:\r
+    /* FALLTHROUGH */\r
+  case NETCONN_UDPNOCHKSUM:\r
+    /* FALLTHROUGH */\r
+  case NETCONN_UDP:\r
+    udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);\r
+    sys_mbox_post(msg->conn->mbox, NULL);\r
+    break;\r
+#endif \r
+#if LWIP_TCP      \r
+  case NETCONN_TCP:\r
+    /*    tcp_arg(msg->conn->pcb.tcp, msg->conn);*/\r
+    setup_tcp(msg->conn);\r
+    tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,\r
+    do_connected);\r
+    /*tcp_output(msg->conn->pcb.tcp);*/\r
+#endif\r
+\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+static void\r
+do_disconnect(struct api_msg_msg *msg)\r
+{\r
+\r
+  switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+  case NETCONN_RAW:\r
+    /* Do nothing as connecting is only a helper for upper lwip layers */\r
+    break;\r
+#endif\r
+#if LWIP_UDP\r
+  case NETCONN_UDPLITE:\r
+    /* FALLTHROUGH */\r
+  case NETCONN_UDPNOCHKSUM:\r
+    /* FALLTHROUGH */\r
+  case NETCONN_UDP:\r
+    udp_disconnect(msg->conn->pcb.udp);\r
+    break;\r
+#endif \r
+  case NETCONN_TCP:\r
+    break;\r
+  }\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+}\r
+\r
+\r
+static void\r
+do_listen(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.tcp != NULL) {\r
+    switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen RAW: cannot listen for RAW.\n"));\r
+      break;\r
+#endif\r
+#if LWIP_UDP\r
+    case NETCONN_UDPLITE:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDPNOCHKSUM:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDP:\r
+      LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen UDP: cannot listen for UDP.\n"));\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP      \r
+    case NETCONN_TCP:\r
+      msg->conn->pcb.tcp = tcp_listen(msg->conn->pcb.tcp);\r
+      if (msg->conn->pcb.tcp == NULL) {\r
+  msg->conn->err = ERR_MEM;\r
+      } else {\r
+  if (msg->conn->acceptmbox == SYS_MBOX_NULL) {\r
+    msg->conn->acceptmbox = sys_mbox_new();\r
+    if (msg->conn->acceptmbox == SYS_MBOX_NULL) {\r
+      msg->conn->err = ERR_MEM;\r
+      break;\r
+    }\r
+  }\r
+  tcp_arg(msg->conn->pcb.tcp, msg->conn);\r
+  tcp_accept(msg->conn->pcb.tcp, accept_function);\r
+      }\r
+#endif\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+}\r
+\r
+static void\r
+do_accept(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.tcp != NULL) {\r
+    switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept RAW: cannot accept for RAW.\n"));\r
+      break;\r
+#endif\r
+#if LWIP_UDP\r
+    case NETCONN_UDPLITE:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDPNOCHKSUM:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDP:    \r
+      LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept UDP: cannot accept for UDP.\n"));\r
+      break;\r
+#endif /* LWIP_UDP */\r
+    case NETCONN_TCP:\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+static void\r
+do_send(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.tcp != NULL) {\r
+    switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      raw_send(msg->conn->pcb.raw, msg->msg.p);\r
+      break;\r
+#endif\r
+#if LWIP_UDP\r
+    case NETCONN_UDPLITE:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDPNOCHKSUM:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDP:\r
+      udp_send(msg->conn->pcb.udp, msg->msg.p);\r
+      break;\r
+#endif /* LWIP_UDP */\r
+    case NETCONN_TCP:\r
+      break;\r
+    }\r
+  }\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+}\r
+\r
+static void\r
+do_recv(struct api_msg_msg *msg)\r
+{\r
+#if LWIP_TCP\r
+  if (msg->conn->pcb.tcp != NULL) {\r
+    if (msg->conn->type == NETCONN_TCP) {\r
+      tcp_recved(msg->conn->pcb.tcp, msg->msg.len);\r
+    }\r
+  }\r
+#endif  \r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+}\r
+\r
+static void\r
+do_write(struct api_msg_msg *msg)\r
+{\r
+#if LWIP_TCP  \r
+  err_t err;\r
+#endif  \r
+  if (msg->conn->pcb.tcp != NULL) {\r
+    switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      msg->conn->err = ERR_VAL;\r
+      break;\r
+#endif\r
+#if LWIP_UDP \r
+    case NETCONN_UDPLITE:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDPNOCHKSUM:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDP:\r
+      msg->conn->err = ERR_VAL;\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP \r
+    case NETCONN_TCP:      \r
+      err = tcp_write(msg->conn->pcb.tcp, msg->msg.w.dataptr,\r
+                      msg->msg.w.len, msg->msg.w.copy);\r
+      /* This is the Nagle algorithm: inhibit the sending of new TCP\r
+   segments when new outgoing data arrives from the user if any\r
+   previously transmitted data on the connection remains\r
+   unacknowledged. */\r
+      if(err == ERR_OK && (msg->conn->pcb.tcp->unacked == NULL ||\r
+        (msg->conn->pcb.tcp->flags & TF_NODELAY) || \r
+        (msg->conn->pcb.tcp->snd_queuelen) > 1)) {\r
+          tcp_output(msg->conn->pcb.tcp);\r
+      }\r
+      msg->conn->err = err;\r
+      if (msg->conn->callback)\r
+          if (err == ERR_OK)\r
+          {\r
+              if (tcp_sndbuf(msg->conn->pcb.tcp) <= TCP_SNDLOWAT)\r
+                  (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDMINUS, msg->msg.w.len);\r
+          }\r
+#endif\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+}\r
+\r
+static void\r
+do_close(struct api_msg_msg *msg)\r
+{\r
+  err_t err;\r
+\r
+  err = ERR_OK;\r
+\r
+  if (msg->conn->pcb.tcp != NULL) {\r
+    switch (msg->conn->type) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      break;\r
+#endif\r
+#if LWIP_UDP\r
+    case NETCONN_UDPLITE:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDPNOCHKSUM:\r
+      /* FALLTHROUGH */\r
+    case NETCONN_UDP:\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+    case NETCONN_TCP:\r
+      if (msg->conn->pcb.tcp->state == LISTEN) {\r
+        err = tcp_close(msg->conn->pcb.tcp);\r
+      }\r
+      else if (msg->conn->pcb.tcp->state == CLOSE_WAIT) {\r
+        err = tcp_output(msg->conn->pcb.tcp);\r
+      }\r
+      msg->conn->err = err;      \r
+#endif\r
+    default:      \r
+      break;\r
+    }\r
+  }\r
+  sys_mbox_post(msg->conn->mbox, NULL);\r
+}\r
+\r
+typedef void (* api_msg_decode)(struct api_msg_msg *msg);\r
+static api_msg_decode decode[API_MSG_MAX] = {\r
+  do_newconn,\r
+  do_delconn,\r
+  do_bind,\r
+  do_connect,\r
+  do_disconnect,\r
+  do_listen,\r
+  do_accept,\r
+  do_send,\r
+  do_recv,\r
+  do_write,\r
+  do_close\r
+  };\r
+void\r
+api_msg_input(struct api_msg *msg)\r
+{  \r
+  decode[msg->type](&(msg->msg));\r
+}\r
+\r
+void\r
+api_msg_post(struct api_msg *msg)\r
+{\r
+  tcpip_apimsg(msg);\r
+}\r
+\r
+\r
+\r
index b582d88a2b4f6943bbdaa9fa7fca6bb91a60bb27..cc6367814734a1ebbfab543822da22dcb4006e9e 100644 (file)
@@ -1,59 +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 */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/err.h"\r
+\r
+#ifdef LWIP_DEBUG\r
+\r
+static char *err_strerr[] = {"Ok.",\r
+           "Out of memory error.",\r
+           "Buffer error.",\r
+           "Connection aborted.",\r
+           "Connection reset.",\r
+           "Connection closed.",\r
+           "Not connected.",\r
+           "Illegal value.",\r
+           "Illegal argument.",\r
+           "Routing problem.",\r
+           "Address in use."\r
+};\r
+\r
+\r
+char *\r
+lwip_strerr(err_t err)\r
+{\r
+  return err_strerr[-err];\r
+\r
+}\r
+\r
+\r
+#endif /* LWIP_DEBUG */\r
index 290a7b73755326cfbca09f572232543c80efab8a..26e6d86300c270802858d780a5781b02cfab2a47 100644 (file)
-/*
- * 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;
-  }
-}
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+#include <errno.h>\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/api.h"\r
+#include "lwip/arch.h"\r
+#include "lwip/sys.h"\r
+\r
+#include "lwip/sockets.h"\r
+\r
+#define NUM_SOCKETS MEMP_NUM_NETCONN\r
+\r
+struct lwip_socket {\r
+  struct netconn *conn;\r
+  struct netbuf *lastdata;\r
+  u16_t lastoffset;\r
+  u16_t rcvevent;\r
+  u16_t sendevent;\r
+  u16_t  flags;\r
+  int err;\r
+};\r
+\r
+struct lwip_select_cb\r
+{\r
+    struct lwip_select_cb *next;\r
+    fd_set *readset;\r
+    fd_set *writeset;\r
+    fd_set *exceptset;\r
+    int sem_signalled;\r
+    sys_sem_t sem;\r
+};\r
+\r
+static struct lwip_socket sockets[NUM_SOCKETS];\r
+static struct lwip_select_cb *select_cb_list = 0;\r
+\r
+static sys_sem_t socksem = 0;\r
+static sys_sem_t selectsem = 0;\r
+\r
+static void\r
+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);\r
+\r
+static int err_to_errno_table[11] = {\r
+    0,      /* ERR_OK    0      No error, everything OK. */\r
+    ENOMEM,    /* ERR_MEM  -1      Out of memory error.     */\r
+    ENOBUFS,    /* ERR_BUF  -2      Buffer error.            */\r
+    ECONNABORTED,  /* ERR_ABRT -3      Connection aborted.      */\r
+    ECONNRESET,    /* ERR_RST  -4      Connection reset.        */\r
+    ESHUTDOWN,    /* ERR_CLSD -5      Connection closed.       */\r
+    ENOTCONN,    /* ERR_CONN -6      Not connected.           */\r
+    EINVAL,    /* ERR_VAL  -7      Illegal value.           */\r
+    EIO,    /* ERR_ARG  -8      Illegal argument.        */\r
+    EHOSTUNREACH,  /* ERR_RTE  -9      Routing problem.         */\r
+    EADDRINUSE    /* ERR_USE  -10     Address in use.          */\r
+};\r
+\r
+#define ERR_TO_ERRNO_TABLE_SIZE \\r
+  (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))\r
+\r
+#define err_to_errno(err) \\r
+  (-(err) >= 0 && -(err) < ERR_TO_ERRNO_TABLE_SIZE ? \\r
+    err_to_errno_table[-(err)] : EIO)\r
+\r
+#ifdef ERRNO\r
+#define set_errno(err) errno = (err)\r
+#else\r
+#define set_errno(err)\r
+#endif\r
+\r
+#define sock_set_errno(sk, e) do { \\r
+      sk->err = (e); \\r
+      set_errno(sk->err); \\r
+} while (0)\r
+\r
+\r
+static struct lwip_socket *\r
+get_socket(int s)\r
+{\r
+  struct lwip_socket *sock;\r
+\r
+  if ((s < 0) || (s > NUM_SOCKETS)) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));\r
+    set_errno(EBADF);\r
+    return NULL;\r
+  }\r
+\r
+  sock = &sockets[s];\r
+\r
+  if (!sock->conn) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));\r
+    set_errno(EBADF);\r
+    return NULL;\r
+  }\r
+\r
+  return sock;\r
+}\r
+\r
+static int\r
+alloc_socket(struct netconn *newconn)\r
+{\r
+  int i;\r
+\r
+  if (!socksem)\r
+      socksem = sys_sem_new(1);\r
+\r
+  /* Protect socket array */\r
+  sys_sem_wait(socksem);\r
+\r
+  /* allocate a new socket identifier */\r
+  for(i = 0; i < NUM_SOCKETS; ++i) {\r
+    if (!sockets[i].conn) {\r
+      sockets[i].conn = newconn;\r
+      sockets[i].lastdata = NULL;\r
+      sockets[i].lastoffset = 0;\r
+      sockets[i].rcvevent = 0;\r
+      sockets[i].sendevent = 1; /* TCP send buf is empty */\r
+      sockets[i].flags = 0;\r
+      sockets[i].err = 0;\r
+      sys_sem_signal(socksem);\r
+      return i;\r
+    }\r
+  }\r
+  sys_sem_signal(socksem);\r
+  return -1;\r
+}\r
+\r
+int\r
+lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct netconn *newconn;\r
+  struct ip_addr naddr;\r
+  u16_t port;\r
+  int newsock;\r
+  struct sockaddr_in sin;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  newconn = netconn_accept(sock->conn);\r
+\r
+  /* get the IP address and port of the remote host */\r
+  netconn_peer(newconn, &naddr, &port);\r
+\r
+  memset(&sin, 0, sizeof(sin));\r
+  sin.sin_len = sizeof(sin);\r
+  sin.sin_family = AF_INET;\r
+  sin.sin_port = htons(port);\r
+  sin.sin_addr.s_addr = naddr.addr;\r
+\r
+  if (*addrlen > sizeof(sin))\r
+      *addrlen = sizeof(sin);\r
+\r
+  memcpy(addr, &sin, *addrlen);\r
+\r
+  newsock = alloc_socket(newconn);\r
+  if (newsock == -1) {\r
+    netconn_delete(newconn);\r
+  sock_set_errno(sock, ENOBUFS);\r
+  return -1;\r
+  }\r
+  newconn->callback = event_callback;\r
+  sock = get_socket(newsock);\r
+\r
+  sys_sem_wait(socksem);\r
+  sock->rcvevent += -1 - newconn->socket;\r
+  newconn->socket = newsock;\r
+  sys_sem_signal(socksem);\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));\r
+\r
+  sock_set_errno(sock, 0);\r
+  return newsock;\r
+}\r
+\r
+int\r
+lwip_bind(int s, struct sockaddr *name, socklen_t namelen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct ip_addr local_addr;\r
+  u16_t local_port;\r
+  err_t err;\r
+\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;\r
+  local_port = ((struct sockaddr_in *)name)->sin_port;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));\r
+\r
+  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));\r
+\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));\r
+    sock_set_errno(sock, err_to_errno(err));\r
+    return -1;\r
+  }\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int\r
+lwip_close(int s)\r
+{\r
+  struct lwip_socket *sock;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));\r
+  if (!socksem)\r
+      socksem = sys_sem_new(1);\r
+\r
+  /* We cannot allow multiple closes of the same socket. */\r
+  sys_sem_wait(socksem);\r
+\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+      sys_sem_signal(socksem);\r
+      set_errno(EBADF);\r
+      return -1;\r
+  }\r
+\r
+  netconn_delete(sock->conn);\r
+  if (sock->lastdata) {\r
+    netbuf_delete(sock->lastdata);\r
+  }\r
+  sock->lastdata = NULL;\r
+  sock->lastoffset = 0;\r
+  sock->conn = NULL;\r
+  sys_sem_signal(socksem);\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int\r
+lwip_connect(int s, struct sockaddr *name, socklen_t namelen)\r
+{\r
+  struct lwip_socket *sock;\r
+  err_t err;\r
+\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));\r
+    err = netconn_disconnect(sock->conn);\r
+  } else {\r
+    struct ip_addr remote_addr;\r
+    u16_t remote_port;\r
+\r
+    remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;\r
+    remote_port = ((struct sockaddr_in *)name)->sin_port;\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));\r
+    ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));\r
+\r
+    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));\r
+   }\r
+\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));\r
+    sock_set_errno(sock, err_to_errno(err));\r
+    return -1;\r
+  }\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int\r
+lwip_listen(int s, int backlog)\r
+{\r
+  struct lwip_socket *sock;\r
+  err_t err;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  err = netconn_listen(sock->conn);\r
+\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));\r
+    sock_set_errno(sock, err_to_errno(err));\r
+    return -1;\r
+  }\r
+\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int\r
+lwip_recvfrom(int s, void *mem, int len, unsigned int flags,\r
+        struct sockaddr *from, socklen_t *fromlen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct netbuf *buf;\r
+  u16_t buflen, copylen;\r
+  struct ip_addr *addr;\r
+  u16_t port;\r
+\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  /* Check if there is data left from the last recv operation. */\r
+  if (sock->lastdata) {\r
+    buf = sock->lastdata;\r
+  } else {\r
+    /* If this is non-blocking call, then check first */\r
+    if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK))\r
+  && !sock->rcvevent)\r
+    {\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));\r
+      sock_set_errno(sock, EWOULDBLOCK);\r
+      return -1;\r
+    }\r
+\r
+    /* No data was left from the previous operation, so we try to get\r
+       some from the network. */\r
+    buf = netconn_recv(sock->conn);\r
+\r
+    if (!buf) {\r
+      /* We should really do some error checking here. */\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));\r
+      sock_set_errno(sock, 0);\r
+      return 0;\r
+    }\r
+  }\r
+\r
+  buflen = netbuf_len(buf);\r
+\r
+  buflen -= sock->lastoffset;\r
+\r
+  if (len > buflen) {\r
+    copylen = buflen;\r
+  } else {\r
+    copylen = len;\r
+  }\r
+\r
+  /* copy the contents of the received buffer into\r
+     the supplied memory pointer mem */\r
+  netbuf_copy_partial(buf, mem, copylen, sock->lastoffset);\r
+\r
+  /* Check to see from where the data was. */\r
+  if (from && fromlen) {\r
+    struct sockaddr_in sin;\r
+\r
+    addr = netbuf_fromaddr(buf);\r
+    port = netbuf_fromport(buf);\r
+\r
+    memset(&sin, 0, sizeof(sin));\r
+    sin.sin_len = sizeof(sin);\r
+    sin.sin_family = AF_INET;\r
+    sin.sin_port = htons(port);\r
+    sin.sin_addr.s_addr = addr->addr;\r
+\r
+    if (*fromlen > sizeof(sin))\r
+      *fromlen = sizeof(sin);\r
+\r
+    memcpy(from, &sin, *fromlen);\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));\r
+    ip_addr_debug_print(SOCKETS_DEBUG, addr);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));\r
+  } else {\r
+#if SOCKETS_DEBUG\r
+    addr = netbuf_fromaddr(buf);\r
+    port = netbuf_fromport(buf);\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));\r
+    ip_addr_debug_print(SOCKETS_DEBUG, addr);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));\r
+#endif\r
+\r
+  }\r
+\r
+  /* If this is a TCP socket, check if there is data left in the\r
+     buffer. If so, it should be saved in the sock structure for next\r
+     time around. */\r
+  if (netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) {\r
+    sock->lastdata = buf;\r
+    sock->lastoffset += copylen;\r
+  } else {\r
+    sock->lastdata = NULL;\r
+    sock->lastoffset = 0;\r
+    netbuf_delete(buf);\r
+  }\r
+\r
+\r
+  sock_set_errno(sock, 0);\r
+  return copylen;\r
+}\r
+\r
+int\r
+lwip_read(int s, void *mem, int len)\r
+{\r
+  return lwip_recvfrom(s, mem, len, 0, NULL, NULL);\r
+}\r
+\r
+int\r
+lwip_recv(int s, void *mem, int len, unsigned int flags)\r
+{\r
+  return lwip_recvfrom(s, mem, len, flags, NULL, NULL);\r
+}\r
+\r
+int\r
+lwip_send(int s, void *data, int size, unsigned int flags)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct netbuf *buf;\r
+  err_t err;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", s, data, size, flags));\r
+\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  switch (netconn_type(sock->conn)) {\r
+  case NETCONN_RAW:\r
+  case NETCONN_UDP:\r
+  case NETCONN_UDPLITE:\r
+  case NETCONN_UDPNOCHKSUM:\r
+    /* create a buffer */\r
+    buf = netbuf_new();\r
+\r
+    if (!buf) {\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ENOBUFS\n", s));\r
+      sock_set_errno(sock, ENOBUFS);\r
+      return -1;\r
+    }\r
+\r
+    /* make the buffer point to the data that should\r
+       be sent */\r
+    netbuf_ref(buf, data, size);\r
+\r
+    /* send the data */\r
+    err = netconn_send(sock->conn, buf);\r
+\r
+    /* deallocated the buffer */\r
+    netbuf_delete(buf);\r
+    break;\r
+  case NETCONN_TCP:\r
+    err = netconn_write(sock->conn, data, size, NETCONN_COPY);\r
+    break;\r
+  default:\r
+    err = ERR_ARG;\r
+    break;\r
+  }\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d\n", s, err));\r
+    sock_set_errno(sock, err_to_errno(err));\r
+    return -1;\r
+  }\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ok size=%d\n", s, size));\r
+  sock_set_errno(sock, 0);\r
+  return size;\r
+}\r
+\r
+int\r
+lwip_sendto(int s, void *data, int size, unsigned int flags,\r
+       struct sockaddr *to, socklen_t tolen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct ip_addr remote_addr, addr;\r
+  u16_t remote_port, port;\r
+  int ret,connected;\r
+\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  /* get the peer if currently connected */\r
+  connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK);\r
+\r
+  remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;\r
+  remote_port = ((struct sockaddr_in *)to)->sin_port;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, size, flags));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port)));\r
+\r
+  netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));\r
+\r
+  ret = lwip_send(s, data, size, flags);\r
+\r
+  /* reset the remote address and port number\r
+     of the connection */\r
+  if (connected)\r
+    netconn_connect(sock->conn, &addr, port);\r
+  else\r
+  netconn_disconnect(sock->conn);\r
+  return ret;\r
+}\r
+\r
+int\r
+lwip_socket(int domain, int type, int protocol)\r
+{\r
+  struct netconn *conn;\r
+  int i;\r
+\r
+  /* create a netconn */\r
+  switch (type) {\r
+  case SOCK_RAW:\r
+    conn = netconn_new_with_proto_and_callback(NETCONN_RAW, protocol, event_callback);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));\r
+    break;\r
+  case SOCK_DGRAM:\r
+    conn = netconn_new_with_callback(NETCONN_UDP, event_callback);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));\r
+    break;\r
+  case SOCK_STREAM:\r
+    conn = netconn_new_with_callback(NETCONN_TCP, event_callback);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));\r
+    break;\r
+  default:\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", domain, type, protocol));\r
+    set_errno(EINVAL);\r
+    return -1;\r
+  }\r
+\r
+  if (!conn) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));\r
+    set_errno(ENOBUFS);\r
+    return -1;\r
+  }\r
+\r
+  i = alloc_socket(conn);\r
+\r
+  if (i == -1) {\r
+    netconn_delete(conn);\r
+  set_errno(ENOBUFS);\r
+  return -1;\r
+  }\r
+  conn->socket = i;\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));\r
+  set_errno(0);\r
+  return i;\r
+}\r
+\r
+int\r
+lwip_write(int s, void *data, int size)\r
+{\r
+   return lwip_send(s, data, size, 0);\r
+}\r
+\r
+\r
+static int\r
+lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)\r
+{\r
+    int i, nready = 0;\r
+    fd_set lreadset, lwriteset, lexceptset;\r
+    struct lwip_socket *p_sock;\r
+\r
+    FD_ZERO(&lreadset);\r
+    FD_ZERO(&lwriteset);\r
+    FD_ZERO(&lexceptset);\r
+\r
+    /* Go through each socket in each list to count number of sockets which\r
+       currently match */\r
+    for(i = 0; i < maxfdp1; i++)\r
+    {\r
+        if (FD_ISSET(i, readset))\r
+        {\r
+            /* See if netconn of this socket is ready for read */\r
+            p_sock = get_socket(i);\r
+            if (p_sock && (p_sock->lastdata || p_sock->rcvevent))\r
+            {\r
+                FD_SET(i, &lreadset);\r
+               LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));\r
+                nready++;\r
+            }\r
+        }\r
+        if (FD_ISSET(i, writeset))\r
+        {\r
+            /* See if netconn of this socket is ready for write */\r
+            p_sock = get_socket(i);\r
+            if (p_sock && p_sock->sendevent)\r
+            {\r
+                FD_SET(i, &lwriteset);\r
+               LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));\r
+                nready++;\r
+            }\r
+        }\r
+    }\r
+    *readset = lreadset;\r
+    *writeset = lwriteset;\r
+    FD_ZERO(exceptset);\r
+\r
+    return nready;\r
+}\r
+\r
+\r
+\r
+int\r
+lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,\r
+               struct timeval *timeout)\r
+{\r
+    int i;\r
+    int nready;\r
+    fd_set lreadset, lwriteset, lexceptset;\r
+    u32_t msectimeout;\r
+    struct lwip_select_cb select_cb;\r
+    struct lwip_select_cb *p_selcb;\r
+\r
+    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));\r
+\r
+    select_cb.next = 0;\r
+    select_cb.readset = readset;\r
+    select_cb.writeset = writeset;\r
+    select_cb.exceptset = exceptset;\r
+    select_cb.sem_signalled = 0;\r
+\r
+    /* Protect ourselves searching through the list */\r
+    if (!selectsem)\r
+        selectsem = sys_sem_new(1);\r
+    sys_sem_wait(selectsem);\r
+\r
+    if (readset)\r
+        lreadset = *readset;\r
+    else\r
+        FD_ZERO(&lreadset);\r
+    if (writeset)\r
+        lwriteset = *writeset;\r
+    else\r
+        FD_ZERO(&lwriteset);\r
+    if (exceptset)\r
+        lexceptset = *exceptset;\r
+    else\r
+        FD_ZERO(&lexceptset);\r
+\r
+    /* Go through each socket in each list to count number of sockets which\r
+       currently match */\r
+    nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);\r
+\r
+    /* If we don't have any current events, then suspend if we are supposed to */\r
+    if (!nready)\r
+    {\r
+        if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)\r
+        {\r
+            sys_sem_signal(selectsem);\r
+            if (readset)\r
+                FD_ZERO(readset);\r
+            if (writeset)\r
+                FD_ZERO(writeset);\r
+            if (exceptset)\r
+                FD_ZERO(exceptset);\r
+\r
+           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));\r
+           set_errno(0);\r
+\r
+            return 0;\r
+        }\r
+\r
+        /* add our semaphore to list */\r
+        /* We don't actually need any dynamic memory. Our entry on the\r
+         * list is only valid while we are in this function, so it's ok\r
+         * to use local variables */\r
+\r
+        select_cb.sem = sys_sem_new(0);\r
+        /* Note that we are still protected */\r
+        /* Put this select_cb on top of list */\r
+        select_cb.next = select_cb_list;\r
+        select_cb_list = &select_cb;\r
+\r
+        /* Now we can safely unprotect */\r
+        sys_sem_signal(selectsem);\r
+\r
+        /* Now just wait to be woken */\r
+        if (timeout == 0)\r
+            /* Wait forever */\r
+            msectimeout = 0;\r
+        else\r
+            msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));\r
+\r
+        i = sys_sem_wait_timeout(select_cb.sem, msectimeout);\r
+\r
+        /* Take us off the list */\r
+        sys_sem_wait(selectsem);\r
+        if (select_cb_list == &select_cb)\r
+            select_cb_list = select_cb.next;\r
+        else\r
+            for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next)\r
+                if (p_selcb->next == &select_cb)\r
+                {\r
+                    p_selcb->next = select_cb.next;\r
+                    break;\r
+                }\r
+\r
+        sys_sem_signal(selectsem);\r
+\r
+        sys_sem_free(select_cb.sem);\r
+        if (i == 0)             /* Timeout */\r
+        {\r
+            if (readset)\r
+                FD_ZERO(readset);\r
+            if (writeset)\r
+                FD_ZERO(writeset);\r
+            if (exceptset)\r
+                FD_ZERO(exceptset);\r
+\r
+           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));\r
+           set_errno(0);\r
+\r
+            return 0;\r
+        }\r
+\r
+        if (readset)\r
+            lreadset = *readset;\r
+        else\r
+            FD_ZERO(&lreadset);\r
+        if (writeset)\r
+            lwriteset = *writeset;\r
+        else\r
+            FD_ZERO(&lwriteset);\r
+        if (exceptset)\r
+            lexceptset = *exceptset;\r
+        else\r
+            FD_ZERO(&lexceptset);\r
+\r
+        /* See what's set */\r
+        nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);\r
+    }\r
+    else\r
+        sys_sem_signal(selectsem);\r
+\r
+    if (readset)\r
+        *readset = lreadset;\r
+    if (writeset)\r
+        *writeset = lwriteset;\r
+    if (exceptset)\r
+        *exceptset = lexceptset;\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));\r
+    set_errno(0);\r
+\r
+    return nready;\r
+}\r
+\r
+\r
+static void\r
+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)\r
+{\r
+    int s;\r
+    struct lwip_socket *sock;\r
+    struct lwip_select_cb *scb;\r
+\r
+    /* Get socket */\r
+    if (conn)\r
+    {\r
+        s = conn->socket;\r
+        if (s < 0)\r
+        {\r
+            /* Data comes in right away after an accept, even though\r
+             * the server task might not have created a new socket yet.\r
+             * Just count down (or up) if that's the case and we\r
+             * will use the data later. Note that only receive events\r
+             * can happen before the new socket is set up. */\r
+            if (evt == NETCONN_EVT_RCVPLUS)\r
+                conn->socket--;\r
+            return;\r
+        }\r
+\r
+        sock = get_socket(s);\r
+        if (!sock)\r
+            return;\r
+    }\r
+    else\r
+        return;\r
+\r
+    if (!selectsem)\r
+        selectsem = sys_sem_new(1);\r
+\r
+    sys_sem_wait(selectsem);\r
+    /* Set event as required */\r
+    switch (evt)\r
+    {\r
+      case NETCONN_EVT_RCVPLUS:\r
+        sock->rcvevent++;\r
+        break;\r
+      case NETCONN_EVT_RCVMINUS:\r
+        sock->rcvevent--;\r
+        break;\r
+      case NETCONN_EVT_SENDPLUS:\r
+        sock->sendevent = 1;\r
+        break;\r
+      case NETCONN_EVT_SENDMINUS:\r
+        sock->sendevent = 0;\r
+        break;\r
+    }\r
+    sys_sem_signal(selectsem);\r
+\r
+    /* Now decide if anyone is waiting for this socket */\r
+    /* NOTE: This code is written this way to protect the select link list\r
+       but to avoid a deadlock situation by releasing socksem before\r
+       signalling for the select. This means we need to go through the list\r
+       multiple times ONLY IF a select was actually waiting. We go through\r
+       the list the number of waiting select calls + 1. This list is\r
+       expected to be small. */\r
+    while (1)\r
+    {\r
+        sys_sem_wait(selectsem);\r
+        for (scb = select_cb_list; scb; scb = scb->next)\r
+        {\r
+            if (scb->sem_signalled == 0)\r
+            {\r
+                /* Test this select call for our socket */\r
+                if (scb->readset && FD_ISSET(s, scb->readset))\r
+                    if (sock->rcvevent)\r
+                        break;\r
+                if (scb->writeset && FD_ISSET(s, scb->writeset))\r
+                    if (sock->sendevent)\r
+                        break;\r
+            }\r
+        }\r
+        if (scb)\r
+        {\r
+            scb->sem_signalled = 1;\r
+            sys_sem_signal(selectsem);\r
+            sys_sem_signal(scb->sem);\r
+        } else {\r
+            sys_sem_signal(selectsem);\r
+            break;\r
+        }\r
+    }\r
+\r
+}\r
+\r
+\r
+\r
+\r
+int lwip_shutdown(int s, int how)\r
+{\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));\r
+  return lwip_close(s); /* XXX temporary hack until proper implementation */\r
+}\r
+\r
+int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct sockaddr_in sin;\r
+  struct ip_addr naddr;\r
+\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  memset(&sin, 0, sizeof(sin));\r
+  sin.sin_len = sizeof(sin);\r
+  sin.sin_family = AF_INET;\r
+\r
+  /* get the IP address and port of the remote host */\r
+  netconn_peer(sock->conn, &naddr, &sin.sin_port);\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getpeername(%d, addr=", s));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));\r
+\r
+  sin.sin_port = htons(sin.sin_port);\r
+  sin.sin_addr.s_addr = naddr.addr;\r
+\r
+  if (*namelen > sizeof(sin))\r
+      *namelen = sizeof(sin);\r
+\r
+  memcpy(name, &sin, *namelen);\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct sockaddr_in sin;\r
+  struct ip_addr *naddr;\r
+\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  memset(&sin, 0, sizeof(sin));\r
+  sin.sin_len = sizeof(sin);\r
+  sin.sin_family = AF_INET;\r
+\r
+  /* get the IP address and port of the remote host */\r
+  netconn_addr(sock->conn, &naddr, &sin.sin_port);\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockname(%d, addr=", s));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, naddr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));\r
+\r
+  sin.sin_port = htons(sin.sin_port);\r
+  sin.sin_addr.s_addr = naddr->addr;\r
+\r
+  if (*namelen > sizeof(sin))\r
+      *namelen = sizeof(sin);\r
+\r
+  memcpy(name, &sin, *namelen);\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)\r
+{\r
+  int err = 0;\r
+  struct lwip_socket *sock = get_socket(s);\r
+\r
+  if(!sock) {\r
+       set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  if( NULL == optval || NULL == optlen ) {\r
+    sock_set_errno( sock, EFAULT );\r
+    return -1;\r
+  }\r
+\r
+  /* Do length and type checks for the various options first, to keep it readable. */\r
+  switch( level ) {\r
+   \r
+/* Level: SOL_SOCKET */\r
+  case SOL_SOCKET:\r
+      switch(optname) {\r
+         \r
+      case SO_ACCEPTCONN:\r
+      case SO_BROADCAST:\r
+      /* UNIMPL case SO_DEBUG: */\r
+      /* UNIMPL case SO_DONTROUTE: */\r
+      case SO_ERROR:\r
+      case SO_KEEPALIVE:\r
+      /* UNIMPL case SO_OOBINLINE: */\r
+      /* UNIMPL case SO_RCVBUF: */\r
+      /* UNIMPL case SO_SNDBUF: */\r
+      /* UNIMPL case SO_RCVLOWAT: */\r
+      /* UNIMPL case SO_SNDLOWAT: */\r
+#if SO_REUSE\r
+      case SO_REUSEADDR:\r
+      case SO_REUSEPORT:\r
+#endif /* SO_REUSE */\r
+      case SO_TYPE:\r
+      /* UNIMPL case SO_USELOOPBACK: */\r
+        if( *optlen < sizeof(int) ) {\r
+          err = EINVAL;\r
+        }\r
+          break;\r
+\r
+      default:\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));\r
+        err = ENOPROTOOPT;\r
+      }  /* switch */\r
+      break;\r
+                     \r
+/* Level: IPPROTO_IP */\r
+  case IPPROTO_IP:\r
+      switch(optname) {\r
+      /* UNIMPL case IP_HDRINCL: */\r
+      /* UNIMPL case IP_RCVDSTADDR: */\r
+      /* UNIMPL case IP_RCVIF: */\r
+      case IP_TTL:\r
+      case IP_TOS:\r
+        if( *optlen < sizeof(int) ) {\r
+          err = EINVAL;\r
+        }\r
+        break;\r
+\r
+      default:\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));\r
+        err = ENOPROTOOPT;\r
+      }  /* switch */\r
+      break;\r
+         \r
+/* Level: IPPROTO_TCP */\r
+  case IPPROTO_TCP:\r
+      if( *optlen < sizeof(int) ) {\r
+        err = EINVAL;\r
+        break;\r
+    }\r
+      \r
+      /* If this is no TCP socket, ignore any options. */\r
+      if ( sock->conn->type != NETCONN_TCP ) return 0;\r
+\r
+      switch( optname ) {\r
+      case TCP_NODELAY:\r
+      case TCP_KEEPALIVE:\r
+        break;\r
+         \r
+      default:\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));\r
+        err = ENOPROTOOPT;\r
+      }  /* switch */\r
+      break;\r
+\r
+/* UNDEFINED LEVEL */\r
+  default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));\r
+      err = ENOPROTOOPT;\r
+  }  /* switch */\r
+\r
+   \r
+  if( 0 != err ) {\r
+    sock_set_errno(sock, err);\r
+    return -1;\r
+  }\r
+   \r
+\r
+\r
+  /* Now do the actual option processing */\r
+\r
+  switch(level) {\r
+   \r
+/* Level: SOL_SOCKET */\r
+  case SOL_SOCKET:\r
+    switch( optname ) {\r
+\r
+    /* The option flags */\r
+    case SO_ACCEPTCONN:\r
+    case SO_BROADCAST:\r
+    /* UNIMPL case SO_DEBUG: */\r
+    /* UNIMPL case SO_DONTROUTE: */\r
+    case SO_KEEPALIVE:\r
+    /* UNIMPL case SO_OOBINCLUDE: */\r
+#if SO_REUSE\r
+    case SO_REUSEADDR:\r
+    case SO_REUSEPORT:\r
+#endif /* SO_REUSE */\r
+    /*case SO_USELOOPBACK: UNIMPL */\r
+      *(int*)optval = sock->conn->pcb.tcp->so_options & optname;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off")));\r
+      break;\r
+\r
+    case SO_TYPE:\r
+      switch (sock->conn->type) {\r
+      case NETCONN_RAW:\r
+        *(int*)optval = SOCK_RAW;\r
+        break;\r
+      case NETCONN_TCP:\r
+        *(int*)optval = SOCK_STREAM;\r
+        break;\r
+      case NETCONN_UDP:\r
+      case NETCONN_UDPLITE:\r
+      case NETCONN_UDPNOCHKSUM:\r
+        *(int*)optval = SOCK_DGRAM;\r
+        break;\r
+      default: /* unrecognized socket type */\r
+        *(int*)optval = sock->conn->type;\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval));\r
+      }  /* switch */\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval));\r
+      break;\r
+\r
+    case SO_ERROR:\r
+      *(int *)optval = sock->err;\r
+      sock->err = 0;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval));\r
+      break;\r
+    }  /* switch */\r
+    break;\r
+\r
+/* Level: IPPROTO_IP */\r
+  case IPPROTO_IP:\r
+    switch( optname ) {\r
+    case IP_TTL:\r
+      *(int*)optval = sock->conn->pcb.tcp->ttl;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval));\r
+      break;\r
+    case IP_TOS:\r
+      *(int*)optval = sock->conn->pcb.tcp->tos;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval));\r
+      break;\r
+    }  /* switch */\r
+    break;\r
+\r
+/* Level: IPPROTO_TCP */\r
+  case IPPROTO_TCP:\r
+    switch( optname ) {\r
+    case TCP_NODELAY:\r
+      *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") );\r
+      break;\r
+    case TCP_KEEPALIVE:\r
+      *(int*)optval = (int)sock->conn->pcb.tcp->keepalive;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval));\r
+      break;\r
+    }  /* switch */\r
+    break;\r
+  }\r
+\r
+\r
+  sock_set_errno(sock, err);\r
+  return err ? -1 : 0;\r
+}\r
+\r
+int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)\r
+{\r
+  struct lwip_socket *sock = get_socket(s);\r
+  int err = 0;\r
+\r
+  if(!sock) {\r
+       set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  if( NULL == optval ) {\r
+    sock_set_errno( sock, EFAULT );\r
+    return -1;\r
+  }\r
+\r
+\r
+  /* Do length and type checks for the various options first, to keep it readable. */\r
+  switch( level ) {\r
+\r
+/* Level: SOL_SOCKET */\r
+  case SOL_SOCKET:\r
+    switch(optname) {\r
+\r
+    case SO_BROADCAST:\r
+    /* UNIMPL case SO_DEBUG: */\r
+    /* UNIMPL case SO_DONTROUTE: */\r
+    case SO_KEEPALIVE:\r
+    /* UNIMPL case SO_OOBINLINE: */\r
+    /* UNIMPL case SO_RCVBUF: */\r
+    /* UNIMPL case SO_SNDBUF: */\r
+    /* UNIMPL case SO_RCVLOWAT: */\r
+    /* UNIMPL case SO_SNDLOWAT: */\r
+#if SO_REUSE\r
+    case SO_REUSEADDR:\r
+    case SO_REUSEPORT:\r
+#endif /* SO_REUSE */\r
+    /* UNIMPL case SO_USELOOPBACK: */\r
+      if( optlen < sizeof(int) ) {\r
+        err = EINVAL;\r
+      }\r
+      break;\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch */\r
+    break;\r
+\r
+/* Level: IPPROTO_IP */\r
+  case IPPROTO_IP:\r
+    switch(optname) {\r
+    /* UNIMPL case IP_HDRINCL: */\r
+    /* UNIMPL case IP_RCVDSTADDR: */\r
+    /* UNIMPL case IP_RCVIF: */\r
+    case IP_TTL:\r
+    case IP_TOS:\r
+      if( optlen < sizeof(int) ) {\r
+        err = EINVAL;\r
+      }\r
+        break;\r
+      default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch */\r
+    break;\r
+\r
+/* Level: IPPROTO_TCP */\r
+  case IPPROTO_TCP:\r
+    if( optlen < sizeof(int) ) {\r
+      err = EINVAL;\r
+        break;\r
+    }\r
+\r
+    /* If this is no TCP socket, ignore any options. */\r
+    if ( sock->conn->type != NETCONN_TCP ) return 0;\r
+\r
+    switch( optname ) {\r
+    case TCP_NODELAY:\r
+    case TCP_KEEPALIVE:\r
+      break;\r
+\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch */\r
+    break;\r
+\r
+/* UNDEFINED LEVEL */      \r
+  default:\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));\r
+    err = ENOPROTOOPT;\r
+  }  /* switch */\r
+\r
+\r
+  if( 0 != err ) {\r
+    sock_set_errno(sock, err);\r
+    return -1;\r
+  }\r
+\r
+\r
+\r
+  /* Now do the actual option processing */\r
+\r
+  switch(level) {\r
+\r
+/* Level: SOL_SOCKET */\r
+  case SOL_SOCKET:\r
+    switch(optname) {\r
+\r
+    /* The option flags */\r
+    case SO_BROADCAST:\r
+    /* UNIMPL case SO_DEBUG: */\r
+    /* UNIMPL case SO_DONTROUTE: */\r
+    case SO_KEEPALIVE:\r
+    /* UNIMPL case SO_OOBINCLUDE: */\r
+#if SO_REUSE\r
+    case SO_REUSEADDR:\r
+    case SO_REUSEPORT:\r
+#endif /* SO_REUSE */\r
+    /* UNIMPL case SO_USELOOPBACK: */\r
+      if ( *(int*)optval ) {\r
+        sock->conn->pcb.tcp->so_options |= optname;\r
+      } else {\r
+        sock->conn->pcb.tcp->so_options &= ~optname;\r
+      }\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off")));\r
+      break;\r
+    }  /* switch */\r
+    break;\r
+\r
+/* Level: IPPROTO_IP */\r
+  case IPPROTO_IP:\r
+    switch( optname ) {\r
+    case IP_TTL:\r
+      sock->conn->pcb.tcp->ttl = (u8_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", s, sock->conn->pcb.tcp->ttl));\r
+      break;\r
+    case IP_TOS:\r
+      sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos));\r
+      break;\r
+    }  /* switch */\r
+    break;\r
+\r
+/* Level: IPPROTO_TCP */\r
+  case IPPROTO_TCP:\r
+    switch( optname ) {\r
+    case TCP_NODELAY:\r
+      if ( *(int*)optval ) {\r
+        sock->conn->pcb.tcp->flags |= TF_NODELAY;\r
+      } else {\r
+        sock->conn->pcb.tcp->flags &= ~TF_NODELAY;\r
+      }\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") );\r
+      break;\r
+    case TCP_KEEPALIVE:\r
+      sock->conn->pcb.tcp->keepalive = (u32_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n", s, sock->conn->pcb.tcp->keepalive));\r
+      break;\r
+    }  /* switch */\r
+    break;\r
+  }  /* switch */\r
+\r
+  sock_set_errno(sock, err);\r
+  return err ? -1 : 0;\r
+}\r
+\r
+int lwip_ioctl(int s, long cmd, void *argp)\r
+{\r
+  struct lwip_socket *sock = get_socket(s);\r
+\r
+  if(!sock) {\r
+       set_errno(EBADF);\r
+    return -1;\r
+  }\r
+\r
+  switch (cmd) {\r
+  case FIONREAD:\r
+    if (!argp) {\r
+      sock_set_errno(sock, EINVAL);\r
+      return -1;\r
+    }\r
+\r
+    *((u16_t*)argp) = sock->conn->recv_avail;\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));\r
+    sock_set_errno(sock, 0);\r
+    return 0;\r
+\r
+  case FIONBIO:\r
+    if (argp && *(u32_t*)argp)\r
+      sock->flags |= O_NONBLOCK;\r
+    else\r
+      sock->flags &= ~O_NONBLOCK;\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));\r
+    sock_set_errno(sock, 0);\r
+    return 0;\r
+\r
+  default:\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));\r
+    sock_set_errno(sock, ENOSYS); /* not yet implemented */\r
+    return -1;\r
+  }\r
+}\r
+\r
index ce8a2ca5d12616d4ba54de9814b30893fb2e02f6..db86cf4ca31207c24c9b86d8c62a72d79fccd35a 100644 (file)
-/*
- * 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);
-}
-
-
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/sys.h"\r
+\r
+#include "lwip/memp.h"\r
+#include "lwip/pbuf.h"\r
+\r
+#include "lwip/ip.h"\r
+#include "lwip/ip_frag.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+\r
+#include "lwip/tcpip.h"\r
+\r
+static void (* tcpip_init_done)(void *arg) = NULL;\r
+static void *tcpip_init_done_arg;\r
+static sys_mbox_t mbox;\r
+\r
+#if LWIP_TCP\r
+static int tcpip_tcp_timer_active = 0;\r
+\r
+static void\r
+tcpip_tcp_timer(void *arg)\r
+{\r
+  (void)arg;\r
+\r
+  /* call TCP timer handler */\r
+  tcp_tmr();\r
+  /* timer still needed? */\r
+  if (tcp_active_pcbs || tcp_tw_pcbs) {\r
+    /* restart timer */\r
+    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);\r
+  } else {\r
+    /* disable timer */\r
+    tcpip_tcp_timer_active = 0;\r
+  }\r
+}\r
+\r
+#if !NO_SYS\r
+void\r
+tcp_timer_needed(void)\r
+{\r
+  /* timer is off but needed again? */\r
+  if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {\r
+    /* enable and start timer */\r
+    tcpip_tcp_timer_active = 1;\r
+    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);\r
+  }\r
+}\r
+#endif /* !NO_SYS */\r
+#endif /* LWIP_TCP */\r
+\r
+#if IP_REASSEMBLY\r
+static void\r
+ip_timer(void *data)\r
+{\r
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));\r
+  ip_reass_tmr();\r
+  sys_timeout(1000, ip_timer, NULL);\r
+}\r
+#endif\r
+\r
+static void\r
+tcpip_thread(void *arg)\r
+{\r
+  struct tcpip_msg *msg;\r
+\r
+  (void)arg;\r
+\r
+  ip_init();\r
+#if LWIP_UDP  \r
+  udp_init();\r
+#endif\r
+#if LWIP_TCP\r
+  tcp_init();\r
+#endif\r
+#if IP_REASSEMBLY\r
+  sys_timeout(1000, ip_timer, NULL);\r
+#endif\r
+  if (tcpip_init_done != NULL) {\r
+    tcpip_init_done(tcpip_init_done_arg);\r
+  }\r
+\r
+  while (1) {                          /* MAIN Loop */\r
+    sys_mbox_fetch(mbox, (void *)&msg);\r
+    switch (msg->type) {\r
+    case TCPIP_MSG_API:\r
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));\r
+      api_msg_input(msg->msg.apimsg);\r
+      break;\r
+    case TCPIP_MSG_INPUT:\r
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: IP packet %p\n", (void *)msg));\r
+      ip_input(msg->msg.inp.p, msg->msg.inp.netif);\r
+      break;\r
+    case TCPIP_MSG_CALLBACK:\r
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));\r
+      msg->msg.cb.f(msg->msg.cb.ctx);\r
+      break;\r
+    default:\r
+      break;\r
+    }\r
+    memp_free(MEMP_TCPIP_MSG, msg);\r
+  }\r
+}\r
+\r
+err_t\r
+tcpip_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct tcpip_msg *msg;\r
+  \r
+  msg = memp_malloc(MEMP_TCPIP_MSG);\r
+  if (msg == NULL) {\r
+    pbuf_free(p);    \r
+    return ERR_MEM;  \r
+  }\r
+  \r
+  msg->type = TCPIP_MSG_INPUT;\r
+  msg->msg.inp.p = p;\r
+  msg->msg.inp.netif = inp;\r
+  sys_mbox_post(mbox, msg);\r
+  return ERR_OK;\r
+}\r
+\r
+err_t\r
+tcpip_callback(void (*f)(void *ctx), void *ctx)\r
+{\r
+  struct tcpip_msg *msg;\r
+  \r
+  msg = memp_malloc(MEMP_TCPIP_MSG);\r
+  if (msg == NULL) {\r
+    return ERR_MEM;  \r
+  }\r
+  \r
+  msg->type = TCPIP_MSG_CALLBACK;\r
+  msg->msg.cb.f = f;\r
+  msg->msg.cb.ctx = ctx;\r
+  sys_mbox_post(mbox, msg);\r
+  return ERR_OK;\r
+}\r
+\r
+void\r
+tcpip_apimsg(struct api_msg *apimsg)\r
+{\r
+  struct tcpip_msg *msg;\r
+  msg = memp_malloc(MEMP_TCPIP_MSG);\r
+  if (msg == NULL) {\r
+    memp_free(MEMP_API_MSG, apimsg);\r
+    return;\r
+  }\r
+  msg->type = TCPIP_MSG_API;\r
+  msg->msg.apimsg = apimsg;\r
+  sys_mbox_post(mbox, msg);\r
+}\r
+\r
+void\r
+tcpip_init(void (* initfunc)(void *), void *arg)\r
+{\r
+  tcpip_init_done = initfunc;\r
+  tcpip_init_done_arg = arg;\r
+  mbox = sys_mbox_new();\r
+  sys_thread_new(tcpip_thread, NULL, TCPIP_THREAD_PRIO);\r
+}\r
+\r
+\r
+\r
+\r
index 2dabd4f5d3493dd6cd7d9ed58e4c28137b1af66e..47f65c2e2dfcfd315eaf85a5466c1b010b99dc3c 100644 (file)
-/**
- * @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 */
+/**\r
+ * @file\r
+ *\r
+ * Dynamic Host Configuration Protocol client\r
+ */\r
+\r
+/*\r
+ *\r
+ * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+ * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is a contribution to the lwIP TCP/IP stack.\r
+ * The Swedish Institute of Computer Science and Adam Dunkels\r
+ * are specifically granted permission to redistribute this\r
+ * source code.\r
+ *\r
+ * Author: Leon Woestenberg <leon.woestenberg@gmx.net>\r
+ *\r
+ * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform\r
+ * with RFC 2131 and RFC 2132.\r
+ *\r
+ * TODO:\r
+ * - Proper parsing of DHCP messages exploiting file/sname field overloading.\r
+ * - Add JavaDoc style documentation (API, internals).\r
+ * - Support for interfaces other than Ethernet (SLIP, PPP, ...)\r
+ *\r
+ * Please coordinate changes and requests with Leon Woestenberg\r
+ * <leon.woestenberg@gmx.net>\r
+ *\r
+ * Integration with your code:\r
+ *\r
+ * In lwip/dhcp.h\r
+ * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)\r
+ * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)\r
+ *\r
+ * Then have your application call dhcp_coarse_tmr() and\r
+ * dhcp_fine_tmr() on the defined intervals.\r
+ *\r
+ * dhcp_start(struct netif *netif);\r
+ * starts a DHCP client instance which configures the interface by\r
+ * obtaining an IP address lease and maintaining it.\r
+ *\r
+ * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)\r
+ * to remove the DHCP client.\r
+ *\r
+ */\r
\r
+#include <string.h>\r
\r
+#include "lwip/stats.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/inet.h"\r
+#include "netif/etharp.h"\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/opt.h"\r
+#include "lwip/dhcp.h"\r
+\r
+#if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */\r
+\r
+/** global transaction identifier, must be\r
+ *  unique for each DHCP request. We simply increment, starting\r
+ *  with this value (easy to match with a packet analyzer) */\r
+static u32_t xid = 0xABCD0000;\r
+\r
+/** DHCP client state machine functions */\r
+static void dhcp_handle_ack(struct netif *netif);\r
+static void dhcp_handle_nak(struct netif *netif);\r
+static void dhcp_handle_offer(struct netif *netif);\r
+\r
+static err_t dhcp_discover(struct netif *netif);\r
+static err_t dhcp_select(struct netif *netif);\r
+static void dhcp_check(struct netif *netif);\r
+static void dhcp_bind(struct netif *netif);\r
+static err_t dhcp_decline(struct netif *netif);\r
+static err_t dhcp_rebind(struct netif *netif);\r
+static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);\r
+\r
+/** receive, unfold, parse and free incoming messages */\r
+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);\r
+static err_t dhcp_unfold_reply(struct dhcp *dhcp);\r
+static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);\r
+static u8_t dhcp_get_option_byte(u8_t *ptr);\r
+#if 0\r
+static u16_t dhcp_get_option_short(u8_t *ptr);\r
+#endif\r
+static u32_t dhcp_get_option_long(u8_t *ptr);\r
+static void dhcp_free_reply(struct dhcp *dhcp);\r
+\r
+/** set the DHCP timers */\r
+static void dhcp_timeout(struct netif *netif);\r
+static void dhcp_t1_timeout(struct netif *netif);\r
+static void dhcp_t2_timeout(struct netif *netif);\r
+\r
+/** build outgoing messages */\r
+/** create a DHCP request, fill in common headers */\r
+static err_t dhcp_create_request(struct netif *netif);\r
+/** free a DHCP request */\r
+static void dhcp_delete_request(struct netif *netif);\r
+/** add a DHCP option (type, then length in bytes) */\r
+static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);\r
+/** add option values */\r
+static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);\r
+static void dhcp_option_short(struct dhcp *dhcp, u16_t value);\r
+static void dhcp_option_long(struct dhcp *dhcp, u32_t value);\r
+/** always add the DHCP options trailer to end and pad */\r
+static void dhcp_option_trailer(struct dhcp *dhcp);\r
+\r
+/**\r
+ * Back-off the DHCP client (because of a received NAK response).\r
+ *\r
+ * Back-off the DHCP client because of a received NAK. Receiving a\r
+ * NAK means the client asked for something non-sensible, for\r
+ * example when it tries to renew a lease obtained on another network.\r
+ *\r
+ * We back-off and will end up restarting a fresh DHCP negotiation later.\r
+ *\r
+ * @param state pointer to DHCP state structure\r
+ */\r
+static void dhcp_handle_nak(struct netif *netif) {\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  u16_t msecs = 10 * 1000;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", \r
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_handle_nak(): set request timeout %"U16_F" msecs\n", msecs));\r
+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);\r
+}\r
+\r
+/**\r
+ * Checks if the offered IP address is already in use.\r
+ *\r
+ * It does so by sending an ARP request for the offered address and\r
+ * entering CHECKING state. If no ARP reply is received within a small\r
+ * interval, the address is assumed to be free for use by us.\r
+ */\r
+static void dhcp_check(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],\r
+    (s16_t)netif->name[1]));\r
+  /* create an ARP query for the offered IP address, expecting that no host\r
+     responds, as the IP address should not be in use. */\r
+  result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);\r
+  if (result != ERR_OK) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = 500;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));\r
+  dhcp_set_state(dhcp, DHCP_CHECKING);\r
+}\r
+\r
+/**\r
+ * Remember the configuration offered by a DHCP server.\r
+ *\r
+ * @param state pointer to DHCP state structure\r
+ */\r
+static void dhcp_handle_offer(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  /* obtain the server address */\r
+  u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",\r
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\r
+  if (option_ptr != NULL)\r
+  {\r
+    dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));\r
+    /* remember offered address */\r
+    ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));\r
+\r
+    dhcp_select(netif);\r
+  }\r
+}\r
+\r
+/**\r
+ * Select a DHCP server offer out of all offers.\r
+ *\r
+ * Simply select the first offer received.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ * @return lwIP specific error (see error.h)\r
+ */\r
+static err_t dhcp_select(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u32_t msecs;\r
+  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));\r
+\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK)\r
+  {\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_REQUEST);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+    /* MUST request the offered IP address */\r
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);\r
+\r
+    dhcp_option_trailer(dhcp);\r
+    /* shrink the pbuf to the actual content length */\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    /* TODO: we really should bind to a specific local interface here\r
+       but we cannot specify an unconfigured netif as it is addressless */\r
+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+    /* send broadcast to any DHCP server */\r
+    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
+    udp_send(dhcp->pcb, dhcp->p_out);\r
+    /* reconnect to any (or to server here?!) */\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_select: REQUESTING\n"));\r
+    dhcp_set_state(dhcp, DHCP_REQUESTING);\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_select(): set request timeout %"U32_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+\r
+/**\r
+ * The DHCP timer that checks for lease renewal/rebind timeouts.\r
+ *\r
+ */\r
+void dhcp_coarse_tmr()\r
+{\r
+  struct netif *netif = netif_list;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_coarse_tmr()\n"));\r
+  /* iterate through all network interfaces */\r
+  while (netif != NULL) {\r
+    /* only act on DHCP configured interfaces */\r
+    if (netif->dhcp != NULL) {\r
+      /* timer is active (non zero), and triggers (zeroes) now? */\r
+      if (netif->dhcp->t2_timeout-- == 1) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));\r
+        /* this clients' rebind timeout triggered */\r
+        dhcp_t2_timeout(netif);\r
+      /* timer is active (non zero), and triggers (zeroes) now */\r
+      } else if (netif->dhcp->t1_timeout-- == 1) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));\r
+        /* this clients' renewal timeout triggered */\r
+        dhcp_t1_timeout(netif);\r
+      }\r
+    }\r
+    /* proceed to next netif */\r
+    netif = netif->next;\r
+  }\r
+}\r
+\r
+/**\r
+ * DHCP transaction timeout handling\r
+ *\r
+ * A DHCP server is expected to respond within a short period of time.\r
+ * This timer checks whether an outstanding DHCP request is timed out.\r
+ * \r
+ */\r
+void dhcp_fine_tmr()\r
+{\r
+  struct netif *netif = netif_list;\r
+  /* loop through netif's */\r
+  while (netif != NULL) {\r
+    /* only act on DHCP configured interfaces */\r
+    if (netif->dhcp != NULL) {\r
+      /* timer is active (non zero), and is about to trigger now */      \r
+      if (netif->dhcp->request_timeout > 1) {\r
+        netif->dhcp->request_timeout--;\r
+      }\r
+      else if (netif->dhcp->request_timeout == 1) {\r
+        netif->dhcp->request_timeout--;\r
+        /* { netif->dhcp->request_timeout == 0 } */\r
+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));\r
+        /* this clients' request timeout triggered */\r
+        dhcp_timeout(netif);\r
+      }\r
+    }\r
+    /* proceed to next network interface */\r
+    netif = netif->next;\r
+  }\r
+}\r
+\r
+/**\r
+ * A DHCP negotiation transaction, or ARP request, has timed out.\r
+ *\r
+ * The timer that was started with the DHCP or ARP request has\r
+ * timed out, indicating no response was received in time.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ *\r
+ */\r
+static void dhcp_timeout(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_timeout()\n"));\r
+  /* back-off period has passed, or server selection timed out */\r
+  if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));\r
+    dhcp_discover(netif);\r
+  /* receiving the requested lease timed out */\r
+  } else if (dhcp->state == DHCP_REQUESTING) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));\r
+    if (dhcp->tries <= 5) {\r
+      dhcp_select(netif);\r
+    } else {\r
+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));\r
+      dhcp_release(netif);\r
+      dhcp_discover(netif);\r
+    }\r
+  /* received no ARP reply for the offered address (which is good) */\r
+  } else if (dhcp->state == DHCP_CHECKING) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));\r
+    if (dhcp->tries <= 1) {\r
+      dhcp_check(netif);\r
+    /* no ARP replies on the offered address,\r
+       looks like the IP address is indeed free */\r
+    } else {\r
+      /* bind the interface to the offered address */\r
+      dhcp_bind(netif);\r
+    }\r
+  }\r
+  /* did not get response to renew request? */\r
+  else if (dhcp->state == DHCP_RENEWING) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));\r
+    /* just retry renewal */\r
+    /* note that the rebind timer will eventually time-out if renew does not work */\r
+    dhcp_renew(netif);\r
+  /* did not get response to rebind request? */\r
+  } else if (dhcp->state == DHCP_REBINDING) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));\r
+    if (dhcp->tries <= 8) {\r
+      dhcp_rebind(netif);\r
+    } else {\r
+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));\r
+      dhcp_release(netif);\r
+      dhcp_discover(netif);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * The renewal period has timed out.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void dhcp_t1_timeout(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_t1_timeout()\n"));\r
+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {\r
+    /* just retry to renew - note that the rebind timer (t2) will\r
+     * eventually time-out if renew tries fail. */\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));\r
+    dhcp_renew(netif);\r
+  }\r
+}\r
+\r
+/**\r
+ * The rebind period has timed out.\r
+ *\r
+ */\r
+static void dhcp_t2_timeout(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout()\n"));\r
+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {\r
+    /* just retry to rebind */\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));\r
+    dhcp_rebind(netif);\r
+  }\r
+}\r
+\r
+/**\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void dhcp_handle_ack(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  u8_t *option_ptr;\r
+  /* clear options we might not get from the ACK */\r
+  dhcp->offered_sn_mask.addr = 0;\r
+  dhcp->offered_gw_addr.addr = 0;\r
+  dhcp->offered_bc_addr.addr = 0;\r
+\r
+  /* lease time given? */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);\r
+  if (option_ptr != NULL) {\r
+    /* remember offered lease time */\r
+    dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);\r
+  }\r
+  /* renewal period given? */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);\r
+  if (option_ptr != NULL) {\r
+    /* remember given renewal period */\r
+    dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);\r
+  } else {\r
+    /* calculate safe periods for renewal */\r
+    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;\r
+  }\r
+\r
+  /* renewal period given? */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);\r
+  if (option_ptr != NULL) {\r
+    /* remember given rebind period */\r
+    dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);\r
+  } else {\r
+    /* calculate safe periods for rebinding */\r
+    dhcp->offered_t2_rebind = dhcp->offered_t0_lease;\r
+  }\r
+\r
+  /* (y)our internet address */\r
+  ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);\r
+\r
+/**\r
+ * Patch #1308\r
+ * TODO: we must check if the file field is not overloaded by DHCP options!\r
+ */\r
+#if 0\r
+  /* boot server address */\r
+  ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);\r
+  /* boot file name */\r
+  if (dhcp->msg_in->file[0]) {\r
+    dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);\r
+    strcpy(dhcp->boot_file_name, dhcp->msg_in->file);\r
+  }\r
+#endif\r
+\r
+  /* subnet mask */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);\r
+  /* subnet mask given? */\r
+  if (option_ptr != NULL) {\r
+    dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
+  }\r
+\r
+  /* gateway router */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);\r
+  if (option_ptr != NULL) {\r
+    dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
+  }\r
+\r
+  /* broadcast address */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);\r
+  if (option_ptr != NULL) {\r
+    dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
+  }\r
+  \r
+  /* DNS servers */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);\r
+  if (option_ptr != NULL) {\r
+    u8_t n;\r
+    dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);\r
+    /* limit to at most DHCP_MAX_DNS DNS servers */\r
+    if (dhcp->dns_count > DHCP_MAX_DNS)\r
+      dhcp->dns_count = DHCP_MAX_DNS;\r
+    for (n = 0; n < dhcp->dns_count; n++) {\r
+      dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Start DHCP negotiation for a network interface.\r
+ *\r
+ * If no DHCP client instance was attached to this interface,\r
+ * a new client is created first. If a DHCP client instance\r
+ * was already present, it restarts negotiation.\r
+ *\r
+ * @param netif The lwIP network interface\r
+ * @return lwIP error code\r
+ * - ERR_OK - No error\r
+ * - ERR_MEM - Out of memory\r
+ *\r
+ */\r
+err_t dhcp_start(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result = ERR_OK;\r
+\r
+  LWIP_ASSERT("netif != NULL", netif != NULL);\r
+  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));\r
+  netif->flags &= ~NETIF_FLAG_DHCP;\r
+\r
+  /* no DHCP client attached yet? */\r
+  if (dhcp == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));\r
+    dhcp = mem_malloc(sizeof(struct dhcp));\r
+    if (dhcp == NULL) {\r
+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));\r
+      return ERR_MEM;\r
+    }\r
+    /* store this dhcp client in the netif */\r
+    netif->dhcp = dhcp;\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));\r
+  /* already has DHCP client attached */\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));\r
+  }\r
+    \r
+  /* clear data structure */\r
+  memset(dhcp, 0, sizeof(struct dhcp));\r
+  /* allocate UDP PCB */\r
+  dhcp->pcb = udp_new();\r
+  if (dhcp->pcb == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG  | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));\r
+    mem_free((void *)dhcp);\r
+    netif->dhcp = dhcp = NULL;\r
+    return ERR_MEM;\r
+  }\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));\r
+  /* (re)start the DHCP negotiation */\r
+  result = dhcp_discover(netif);\r
+  if (result != ERR_OK) {\r
+    /* free resources allocated above */\r
+    dhcp_stop(netif);\r
+    return ERR_MEM;\r
+  }\r
+  netif->flags |= NETIF_FLAG_DHCP;\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Inform a DHCP server of our manual configuration.\r
+ *\r
+ * This informs DHCP servers of our fixed IP address configuration\r
+ * by sending an INFORM message. It does not involve DHCP address\r
+ * configuration, it is just here to be nice to the network.\r
+ *\r
+ * @param netif The lwIP network interface\r
+ *\r
+ */\r
+void dhcp_inform(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp;\r
+  err_t result = ERR_OK;\r
+  dhcp = mem_malloc(sizeof(struct dhcp));\r
+  if (dhcp == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));\r
+    return;\r
+  }\r
+  netif->dhcp = dhcp;\r
+  memset(dhcp, 0, sizeof(struct dhcp));\r
+\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));\r
+  dhcp->pcb = udp_new();\r
+  if (dhcp->pcb == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));\r
+    mem_free((void *)dhcp);\r
+    return;\r
+  }\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_INFORM);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    /* TODO: use netif->mtu ?! */\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_inform: INFORMING\n"));\r
+    udp_send(dhcp->pcb, dhcp->p_out);\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    dhcp_delete_request(netif);\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));\r
+  }\r
+\r
+  if (dhcp != NULL)\r
+  {\r
+    if (dhcp->pcb != NULL) udp_remove(dhcp->pcb);\r
+    dhcp->pcb = NULL;\r
+    mem_free((void *)dhcp);\r
+    netif->dhcp = NULL;\r
+  }\r
+}\r
+\r
+#if DHCP_DOES_ARP_CHECK\r
+/**\r
+ * Match an ARP reply with the offered IP address.\r
+ *\r
+ * @param addr The IP address we received a reply from\r
+ *\r
+ */\r
+void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)\r
+{\r
+  LWIP_ASSERT("netif != NULL", netif != NULL);\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_arp_reply()\n"));\r
+  /* is a DHCP client doing an ARP check? */\r
+  if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));\r
+    /* did a host respond with the address we\r
+       were offered by the DHCP server? */\r
+    if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {\r
+      /* we will not accept the offered address */\r
+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));\r
+      dhcp_decline(netif);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Decline an offered lease.\r
+ *\r
+ * Tell the DHCP server we do not accept the offered address.\r
+ * One reason to decline the lease is when we find out the address\r
+ * is already in use by another host (through ARP).\r
+ */\r
+static err_t dhcp_decline(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result = ERR_OK;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_decline()\n"));\r
+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK)\r
+  {\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_DECLINE);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
+\r
+    dhcp_option_trailer(dhcp);\r
+    /* resize pbuf to reflect true size of options */\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+    /* @todo: should we really connect here? we are performing sendto() */\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    /* per section 4.4.4, broadcast DECLINE messages */\r
+    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n"));\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = 10*1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+#endif\r
+\r
+\r
+/**\r
+ * Start the DHCP process, discover a DHCP server.\r
+ *\r
+ */\r
+static err_t dhcp_discover(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result = ERR_OK;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_discover()\n"));\r
+  ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK)\r
+  {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: making request\n"));\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_DISCOVER);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);\r
+\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: realloc()ing\n"));\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    /* set receive callback function with netif as user data */\r
+    udp_recv(dhcp->pcb, dhcp_recv, netif);\r
+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));\r
+    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: deleting()ing\n"));\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover: SELECTING\n"));\r
+    dhcp_set_state(dhcp, DHCP_SELECTING);\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+\r
+\r
+/**\r
+ * Bind the interface to the offered IP address.\r
+ *\r
+ * @param netif network interface to bind to the offered address\r
+ */\r
+static void dhcp_bind(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  struct ip_addr sn_mask, gw_addr;\r
+  LWIP_ASSERT("dhcp_bind: netif != NULL", netif != NULL);\r
+  LWIP_ASSERT("dhcp_bind: dhcp != NULL", dhcp != NULL);\r
+  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));\r
+\r
+  /* temporary DHCP lease? */\r
+  if (dhcp->offered_t1_renew != 0xffffffffUL) {\r
+    /* set renewal period timer */\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));\r
+    dhcp->t1_timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;\r
+    if (dhcp->t1_timeout == 0) dhcp->t1_timeout = 1;\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));\r
+  }\r
+  /* set renewal period timer */\r
+  if (dhcp->offered_t2_rebind != 0xffffffffUL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));\r
+    dhcp->t2_timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;\r
+    if (dhcp->t2_timeout == 0) dhcp->t2_timeout = 1;\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));\r
+  }\r
+  /* copy offered network mask */\r
+  ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);\r
+\r
+  /* subnet mask not given? */\r
+  /* TODO: this is not a valid check. what if the network mask is 0? */\r
+  if (sn_mask.addr == 0) {\r
+    /* choose a safe subnet mask given the network class */\r
+    u8_t first_octet = ip4_addr1(&sn_mask);\r
+    if (first_octet <= 127) sn_mask.addr = htonl(0xff000000);\r
+    else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00);\r
+    else sn_mask.addr = htonl(0xffff0000);\r
+  }\r
+\r
+  ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);\r
+  /* gateway address not given? */\r
+  if (gw_addr.addr == 0) {\r
+    /* copy network address */\r
+    gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);\r
+    /* use first host address on network as gateway */\r
+    gw_addr.addr |= htonl(0x00000001);\r
+  }\r
+\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));\r
+  netif_set_ipaddr(netif, &dhcp->offered_ip_addr);\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));\r
+  netif_set_netmask(netif, &sn_mask);\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));\r
+  netif_set_gw(netif, &gw_addr);\r
+  /* bring the interface up */\r
+  netif_set_up(netif);\r
+  /* netif is now bound to DHCP leased address */\r
+  dhcp_set_state(dhcp, DHCP_BOUND);\r
+}\r
+\r
+/**\r
+ * Renew an existing DHCP lease at the involved DHCP server.\r
+ *\r
+ * @param netif network interface which must renew its lease\r
+ */\r
+err_t dhcp_renew(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_renew()\n"));\r
+  dhcp_set_state(dhcp, DHCP_RENEWING);\r
+\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_REQUEST);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    /* TODO: use netif->mtu in some way */\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+#if 0\r
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
+#endif\r
+\r
+#if 0\r
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
+#endif\r
+    /* append DHCP message trailer */\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);\r
+    udp_send(dhcp->pcb, dhcp->p_out);\r
+    dhcp_delete_request(netif);\r
+\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew: RENEWING\n"));\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  /* back-off on retries, but to a maximum of 20 seconds */\r
+  msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Rebind with a DHCP server for an existing DHCP lease.\r
+ *\r
+ * @param netif network interface which must rebind with a DHCP server\r
+ */\r
+static err_t dhcp_rebind(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind()\n"));\r
+  dhcp_set_state(dhcp, DHCP_REBINDING);\r
+\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK)\r
+  {\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_REQUEST);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+#if 0\r
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
+#endif\r
+\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    /* set remote IP association to any DHCP server */\r
+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    /* broadcast to server */\r
+    udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind: REBINDING\n"));\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Release a DHCP lease.\r
+ *\r
+ * @param netif network interface which must release its lease\r
+ */\r
+err_t dhcp_release(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_release()\n"));\r
+\r
+  /* idle DHCP client */\r
+  dhcp_set_state(dhcp, DHCP_OFF);\r
+  /* clean old DHCP offer */\r
+  dhcp->server_ip_addr.addr = 0;\r
+  dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;\r
+  dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;\r
+  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;\r
+  dhcp->dns_count = 0;\r
+  \r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_RELEASE);\r
+\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);\r
+    udp_send(dhcp->pcb, dhcp->p_out);\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));\r
+  /* bring the interface down */\r
+  netif_set_down(netif);\r
+  /* remove IP address from interface */\r
+  netif_set_ipaddr(netif, IP_ADDR_ANY);\r
+  netif_set_gw(netif, IP_ADDR_ANY);\r
+  netif_set_netmask(netif, IP_ADDR_ANY);\r
+  \r
+  /* TODO: netif_down(netif); */\r
+  return result;\r
+}\r
+/**\r
+ * Remove the DHCP client from the interface.\r
+ *\r
+ * @param netif The network interface to stop DHCP on\r
+ */\r
+void dhcp_stop(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_ASSERT("dhcp_stop: netif != NULL", netif != NULL);\r
+\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_stop()\n"));\r
+  /* netif is DHCP configured? */\r
+  if (dhcp != NULL)\r
+  {\r
+    if (dhcp->pcb != NULL)\r
+    {\r
+      udp_remove(dhcp->pcb);\r
+      dhcp->pcb = NULL;\r
+    }\r
+    if (dhcp->p != NULL)\r
+    {\r
+      pbuf_free(dhcp->p);\r
+      dhcp->p = NULL;\r
+    }\r
+    /* free unfolded reply */\r
+    dhcp_free_reply(dhcp);\r
+    mem_free((void *)dhcp);\r
+    netif->dhcp = NULL;\r
+  }\r
+}\r
+\r
+/*\r
+ * Set the DHCP state of a DHCP client.\r
+ *\r
+ * If the state changed, reset the number of tries.\r
+ *\r
+ * TODO: we might also want to reset the timeout here?\r
+ */\r
+static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state)\r
+{\r
+  if (new_state != dhcp->state)\r
+  {\r
+    dhcp->state = new_state;\r
+    dhcp->tries = 0;\r
+  }\r
+}\r
+\r
+/*\r
+ * Concatenate an option type and length field to the outgoing\r
+ * DHCP message.\r
+ *\r
+ */\r
+static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)\r
+{\r
+  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);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = option_type;\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = option_len;\r
+}\r
+/*\r
+ * Concatenate a single byte to the outgoing DHCP message.\r
+ *\r
+ */\r
+static void dhcp_option_byte(struct dhcp *dhcp, u8_t value)\r
+{\r
+  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = value;\r
+}\r
+static void dhcp_option_short(struct dhcp *dhcp, u16_t value)\r
+{\r
+  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff00U) >> 8;\r
+  dhcp->msg_out->options[dhcp->options_out_len++] =  value & 0x00ffU;\r
+}\r
+static void dhcp_option_long(struct dhcp *dhcp, u32_t value)\r
+{\r
+  LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff000000UL) >> 24;\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x00ff0000UL) >> 16;\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x0000ff00UL) >> 8;\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x000000ffUL);\r
+}\r
+\r
+/**\r
+ * Extract the DHCP message and the DHCP options.\r
+ *\r
+ * Extract the DHCP message and the DHCP options, each into a contiguous\r
+ * piece of memory. As a DHCP message is variable sized by its options,\r
+ * and also allows overriding some fields for options, the easy approach\r
+ * is to first unfold the options into a conitguous piece of memory, and\r
+ * use that further on.\r
+ *\r
+ */\r
+static err_t dhcp_unfold_reply(struct dhcp *dhcp)\r
+{\r
+  struct pbuf *p = dhcp->p;\r
+  u8_t *ptr;\r
+  u16_t i;\r
+  u16_t j = 0;\r
+  LWIP_ASSERT("dhcp->p != NULL", dhcp->p != NULL);\r
+  /* free any left-overs from previous unfolds */\r
+  dhcp_free_reply(dhcp);\r
+  /* options present? */\r
+  if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN))\r
+  {\r
+    dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);\r
+    dhcp->options_in = mem_malloc(dhcp->options_in_len);\r
+    if (dhcp->options_in == NULL)\r
+    {\r
+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));\r
+      return ERR_MEM;\r
+    }\r
+  }\r
+  dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);\r
+  if (dhcp->msg_in == NULL)\r
+  {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));\r
+    mem_free((void *)dhcp->options_in);\r
+    dhcp->options_in = NULL;\r
+    return ERR_MEM;\r
+  }\r
+\r
+  ptr = (u8_t *)dhcp->msg_in;\r
+  /* proceed through struct dhcp_msg */\r
+  for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++)\r
+  {\r
+    *ptr++ = ((u8_t *)p->payload)[j++];\r
+    /* reached end of pbuf? */\r
+    if (j == p->len)\r
+    {\r
+      /* proceed to next pbuf in chain */\r
+      p = p->next;\r
+      j = 0;\r
+    }\r
+  }\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", i));\r
+  if (dhcp->options_in != NULL) {\r
+    ptr = (u8_t *)dhcp->options_in;\r
+    /* proceed through options */\r
+    for (i = 0; i < dhcp->options_in_len; i++) {\r
+      *ptr++ = ((u8_t *)p->payload)[j++];\r
+      /* reached end of pbuf? */\r
+      if (j == p->len) {\r
+        /* proceed to next pbuf in chain */\r
+        p = p->next;\r
+        j = 0;\r
+      }\r
+    }\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", i));\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Free the incoming DHCP message including contiguous copy of\r
+ * its DHCP options.\r
+ *\r
+ */\r
+static void dhcp_free_reply(struct dhcp *dhcp)\r
+{\r
+  if (dhcp->msg_in != NULL) {\r
+    mem_free((void *)dhcp->msg_in);\r
+    dhcp->msg_in = NULL;\r
+  }\r
+  if (dhcp->options_in) {\r
+    mem_free((void *)dhcp->options_in);\r
+    dhcp->options_in = NULL;\r
+    dhcp->options_in_len = 0;\r
+  }\r
+  LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));\r
+}\r
+\r
+\r
+/**\r
+ * If an incoming DHCP message is in response to us, then trigger the state machine\r
+ */\r
+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)\r
+{\r
+  struct netif *netif = (struct netif *)arg;\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;\r
+  u8_t *options_ptr;\r
+  u8_t msg_type;\r
+  u8_t i;\r
+  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,\r
+    (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),\r
+    (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));\r
+  /* prevent warnings about unused arguments */\r
+  (void)pcb; (void)addr; (void)port;\r
+  dhcp->p = p;\r
+  /* TODO: check packet length before reading them */\r
+  if (reply_msg->op != DHCP_BOOTREPLY) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));\r
+    pbuf_free(p);\r
+    dhcp->p = NULL;\r
+    return;\r
+  }\r
+  /* iterate through hardware address and match against DHCP message */\r
+  for (i = 0; i < netif->hwaddr_len; i++) {\r
+    if (netif->hwaddr[i] != reply_msg->chaddr[i]) {\r
+      LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",\r
+        (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));\r
+      pbuf_free(p);\r
+      dhcp->p = NULL;\r
+      return;\r
+    }\r
+  }\r
+  /* match transaction ID against what we expected */\r
+  if (ntohl(reply_msg->xid) != dhcp->xid) {\r
+    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));\r
+    pbuf_free(p);\r
+    dhcp->p = NULL;\r
+    return;\r
+  }\r
+  /* option fields could be unfold? */\r
+  if (dhcp_unfold_reply(dhcp) != ERR_OK) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));\r
+    pbuf_free(p);\r
+    dhcp->p = NULL;\r
+    return;\r
+  }\r
+\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));\r
+  /* obtain pointer to DHCP message type */\r
+  options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);\r
+  if (options_ptr == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));\r
+    pbuf_free(p);\r
+    dhcp->p = NULL;\r
+    return;\r
+  }\r
+\r
+  /* read DHCP message type */\r
+  msg_type = dhcp_get_option_byte(options_ptr + 2);\r
+  /* message type is DHCP ACK? */\r
+  if (msg_type == DHCP_ACK) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_ACK received\n"));\r
+    /* in requesting state? */\r
+    if (dhcp->state == DHCP_REQUESTING) {\r
+      dhcp_handle_ack(netif);\r
+      dhcp->request_timeout = 0;\r
+#if DHCP_DOES_ARP_CHECK\r
+      /* check if the acknowledged lease address is already in use */\r
+      dhcp_check(netif);\r
+#else\r
+      /* bind interface to the acknowledged lease address */\r
+      dhcp_bind(netif);\r
+#endif\r
+    }\r
+    /* already bound to the given lease address? */\r
+    else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {\r
+      dhcp->request_timeout = 0;\r
+      dhcp_bind(netif);\r
+    }\r
+  }\r
+  /* received a DHCP_NAK in appropriate state? */\r
+  else if ((msg_type == DHCP_NAK) &&\r
+    ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||\r
+     (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_NAK received\n"));\r
+    dhcp->request_timeout = 0;\r
+    dhcp_handle_nak(netif);\r
+  }\r
+  /* received a DHCP_OFFER in DHCP_SELECTING state? */\r
+  else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));\r
+    dhcp->request_timeout = 0;\r
+    /* remember offered lease */\r
+    dhcp_handle_offer(netif);\r
+  }\r
+  pbuf_free(p);\r
+  dhcp->p = NULL;\r
+}\r
+\r
+\r
+static err_t dhcp_create_request(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  u16_t i;\r
+  LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);\r
+  LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);\r
+  dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);\r
+  if (dhcp->p_out == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));\r
+    return ERR_MEM;\r
+  }\r
+  /* give unique transaction identifier to this request */\r
+  dhcp->xid = xid++;\r
+  LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));\r
+\r
+  dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;\r
+\r
+  dhcp->msg_out->op = DHCP_BOOTREQUEST;\r
+  /* TODO: make link layer independent */\r
+  dhcp->msg_out->htype = DHCP_HTYPE_ETH;\r
+  /* TODO: make link layer independent */\r
+  dhcp->msg_out->hlen = DHCP_HLEN_ETH;\r
+  dhcp->msg_out->hops = 0;\r
+  dhcp->msg_out->xid = htonl(dhcp->xid);\r
+  dhcp->msg_out->secs = 0;\r
+  dhcp->msg_out->flags = 0;\r
+  dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;\r
+  dhcp->msg_out->yiaddr.addr = 0;\r
+  dhcp->msg_out->siaddr.addr = 0;\r
+  dhcp->msg_out->giaddr.addr = 0;\r
+  for (i = 0; i < DHCP_CHADDR_LEN; i++) {\r
+    /* copy netif hardware address, pad with zeroes */\r
+    dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;\r
+  }\r
+  for (i = 0; i < DHCP_SNAME_LEN; i++) dhcp->msg_out->sname[i] = 0;\r
+  for (i = 0; i < DHCP_FILE_LEN; i++) dhcp->msg_out->file[i] = 0;\r
+  dhcp->msg_out->cookie = htonl(0x63825363UL);\r
+  dhcp->options_out_len = 0;\r
+  /* fill options field with an incrementing array (for debugging purposes) */\r
+  for (i = 0; i < DHCP_OPTIONS_LEN; i++) dhcp->msg_out->options[i] = i;\r
+  return ERR_OK;\r
+}\r
+\r
+static void dhcp_delete_request(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);\r
+  LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);\r
+  pbuf_free(dhcp->p_out);\r
+  dhcp->p_out = NULL;\r
+  dhcp->msg_out = NULL;\r
+}\r
+\r
+/**\r
+ * Add a DHCP message trailer\r
+ *\r
+ * Adds the END option to the DHCP message, and if\r
+ * necessary, up to three padding bytes.\r
+ */\r
+\r
+static void dhcp_option_trailer(struct dhcp *dhcp)\r
+{\r
+  LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);\r
+  LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;\r
+  /* packet is too small, or not 4 byte aligned? */\r
+  while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {\r
+    /* 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)); */\r
+    LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
+    /* add a fill/padding byte */\r
+    dhcp->msg_out->options[dhcp->options_out_len++] = 0;\r
+  }\r
+}\r
+\r
+/**\r
+ * Find the offset of a DHCP option inside the DHCP message.\r
+ *\r
+ * @param client DHCP client\r
+ * @param option_type\r
+ *\r
+ * @return a byte offset into the UDP message where the option was found, or\r
+ * zero if the given option was not found.\r
+ */\r
+static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)\r
+{\r
+  u8_t overload = DHCP_OVERLOAD_NONE;\r
+\r
+  /* options available? */\r
+  if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {\r
+    /* start with options field */\r
+    u8_t *options = (u8_t *)dhcp->options_in;\r
+    u16_t offset = 0;\r
+    /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */\r
+    while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {\r
+      /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */\r
+      /* are the sname and/or file field overloaded with options? */\r
+      if (options[offset] == DHCP_OPTION_OVERLOAD) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("overloaded message detected\n"));\r
+        /* skip option type and length */\r
+        offset += 2;\r
+        overload = options[offset++];\r
+      }\r
+      /* requested option found */\r
+      else if (options[offset] == option_type) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));\r
+        return &options[offset];\r
+      /* skip option */\r
+      } else {\r
+         LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));\r
+        /* skip option type */\r
+        offset++;\r
+        /* skip option length, and then length bytes */\r
+        offset += 1 + options[offset];\r
+      }\r
+    }\r
+    /* is this an overloaded message? */\r
+    if (overload != DHCP_OVERLOAD_NONE) {\r
+      u16_t field_len;\r
+      if (overload == DHCP_OVERLOAD_FILE) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded file field\n"));\r
+        options = (u8_t *)&dhcp->msg_in->file;\r
+        field_len = DHCP_FILE_LEN;\r
+      } else if (overload == DHCP_OVERLOAD_SNAME) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname field\n"));\r
+        options = (u8_t *)&dhcp->msg_in->sname;\r
+        field_len = DHCP_SNAME_LEN;\r
+      /* TODO: check if else if () is necessary */\r
+      } else {\r
+        LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname and file field\n"));\r
+        options = (u8_t *)&dhcp->msg_in->sname;\r
+        field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;\r
+      }\r
+      offset = 0;\r
+\r
+      /* at least 1 byte to read and no end marker */\r
+      while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {\r
+        if (options[offset] == option_type) {\r
+           LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));\r
+          return &options[offset];\r
+        /* skip option */\r
+        } else {\r
+          LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));\r
+          /* skip option type */\r
+          offset++;\r
+          offset += 1 + options[offset];\r
+        }\r
+      }\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * Return the byte of DHCP option data.\r
+ *\r
+ * @param client DHCP client.\r
+ * @param ptr pointer obtained by dhcp_get_option_ptr().\r
+ *\r
+ * @return byte value at the given address.\r
+ */\r
+static u8_t dhcp_get_option_byte(u8_t *ptr)\r
+{\r
+  LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));\r
+  return *ptr;\r
+}\r
+\r
+#if 0\r
+/**\r
+ * Return the 16-bit value of DHCP option data.\r
+ *\r
+ * @param client DHCP client.\r
+ * @param ptr pointer obtained by dhcp_get_option_ptr().\r
+ *\r
+ * @return byte value at the given address.\r
+ */\r
+static u16_t dhcp_get_option_short(u8_t *ptr)\r
+{\r
+  u16_t value;\r
+  value = *ptr++ << 8;\r
+  value |= *ptr;\r
+  LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));\r
+  return value;\r
+}\r
+#endif\r
+\r
+/**\r
+ * Return the 32-bit value of DHCP option data.\r
+ *\r
+ * @param client DHCP client.\r
+ * @param ptr pointer obtained by dhcp_get_option_ptr().\r
+ *\r
+ * @return byte value at the given address.\r
+ */\r
+static u32_t dhcp_get_option_long(u8_t *ptr)\r
+{\r
+  u32_t value;\r
+  value = (u32_t)(*ptr++) << 24;\r
+  value |= (u32_t)(*ptr++) << 16;\r
+  value |= (u32_t)(*ptr++) << 8;\r
+  value |= (u32_t)(*ptr++);\r
+  LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));\r
+  return value;\r
+}\r
+\r
+#endif /* LWIP_DHCP */\r
index 2c54389e223484abc22c654887e0a01c0fbb1eb8..d9d52c54326082736554c5a9b90e771def43644c 100644 (file)
-/*
- * 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) */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+\r
+/* inet.c\r
+ *\r
+ * Functions common to all TCP/IP modules, such as the Internet checksum and the\r
+ * byte order functions.\r
+ *\r
+ */\r
+\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/arch.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/inet.h"\r
+\r
+#include "lwip/sys.h"\r
+\r
+/* These are some reference implementations of the checksum algorithm, with the\r
+ * aim of being simple, correct and fully portable. Checksumming is the\r
+ * first thing you would want to optimize for your platform. If you create\r
+ * your own version, link it in and in your sys_arch.h put:\r
+ * \r
+ * #define LWIP_CHKSUM <your_checksum_routine> \r
+*/\r
+#ifndef LWIP_CHKSUM\r
+#define LWIP_CHKSUM lwip_standard_chksum\r
+\r
+#if 1 /* Version A */\r
+/**\r
+ * lwip checksum\r
+ *\r
+ * @param dataptr points to start of data to be summed at any boundary\r
+ * @param len length of data to be summed\r
+ * @return host order (!) lwip checksum (non-inverted Internet sum) \r
+ *\r
+ * @note accumulator size limits summable length to 64k\r
+ * @note host endianess is irrelevant (p3 RFC1071)\r
+ */\r
+static u16_t\r
+lwip_standard_chksum(void *dataptr, u16_t len)\r
+{\r
+  u32_t acc;\r
+  u16_t src;\r
+  u8_t *octetptr;\r
+\r
+  acc = 0;\r
+  /* dataptr may be at odd or even addresses */\r
+  octetptr = (u8_t*)dataptr;\r
+  while (len > 1)\r
+  {\r
+    /* declare first octet as most significant\r
+       thus assume network order, ignoring host order */\r
+    src = (*octetptr) << 8;\r
+    octetptr++;\r
+    /* declare second octet as least significant */\r
+    src |= (*octetptr);\r
+    octetptr++;\r
+    acc += src;\r
+    len -= 2;\r
+  }\r
+  if (len > 0)\r
+  {\r
+    /* accumulate remaining octet */\r
+    src = (*octetptr) << 8;\r
+    acc += src;\r
+  }\r
+  /* add deferred carry bits */\r
+  acc = (acc >> 16) + (acc & 0x0000ffffUL);\r
+  if ((acc & 0xffff0000) != 0) {\r
+    acc = (acc >> 16) + (acc & 0x0000ffffUL);\r
+  }\r
+  /* This maybe a little confusing: reorder sum using htons()\r
+     instead of ntohs() since it has a little less call overhead.\r
+     The caller must invert bits for Internet sum ! */\r
+  return htons((u16_t)acc);\r
+}\r
+#endif\r
+\r
+#if 0 /* Version B */\r
+/*\r
+ * Curt McDowell\r
+ * Broadcom Corp.\r
+ * csm@broadcom.com\r
+ *\r
+ * IP checksum two bytes at a time with support for\r
+ * unaligned buffer.\r
+ * Works for len up to and including 0x20000.\r
+ * by Curt McDowell, Broadcom Corp. 12/08/2005\r
+ */\r
+\r
+static u16_t\r
+lwip_standard_chksum(void *dataptr, int len)\r
+{\r
+  u8_t *pb = dataptr;\r
+  u16_t *ps, t = 0;\r
+  u32_t sum = 0;\r
+  int odd = ((u32_t)pb & 1);\r
+\r
+  /* Get aligned to u16_t */\r
+  if (odd && len > 0) {\r
+    ((u8_t *)&t)[1] = *pb++;\r
+    len--;\r
+  }\r
+\r
+  /* Add the bulk of the data */\r
+  ps = (u16_t *)pb;\r
+  while (len > 1) {\r
+    sum += *ps++;\r
+    len -= 2;\r
+  }\r
+\r
+  /* Consume left-over byte, if any */\r
+  if (len > 0)\r
+    ((u8_t *)&t)[0] = *(u8_t *)ps;;\r
+\r
+  /* Add end bytes */\r
+  sum += t;\r
+\r
+  /*  Fold 32-bit sum to 16 bits */\r
+  while (sum >> 16)\r
+    sum = (sum & 0xffff) + (sum >> 16);\r
+\r
+  /* Swap if alignment was odd */\r
+  if (odd)\r
+    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);\r
+\r
+  return sum;\r
+}\r
+#endif\r
+\r
+#if 0 /* Version C */\r
+/**\r
+ * An optimized checksum routine. Basically, it uses loop-unrolling on\r
+ * the checksum loop, treating the head and tail bytes specially, whereas\r
+ * the inner loop acts on 8 bytes at a time. \r
+ *\r
+ * @arg start of buffer to be checksummed. May be an odd byte address.\r
+ * @len number of bytes in the buffer to be checksummed.\r
+ * \r
+ * by Curt McDowell, Broadcom Corp. December 8th, 2005\r
+ */\r
+\r
+static u16_t\r
+lwip_standard_chksum(void *dataptr, int len)\r
+{\r
+  u8_t *pb = dataptr;\r
+  u16_t *ps, t = 0;\r
+  u32_t *pl;\r
+  u32_t sum = 0, tmp;\r
+  /* starts at odd byte address? */\r
+  int odd = ((u32_t)pb & 1);\r
+\r
+  if (odd && len > 0) {\r
+    ((u8_t *)&t)[1] = *pb++;\r
+    len--;\r
+  }\r
+\r
+  ps = (u16_t *)pb;\r
+\r
+  if (((u32_t)ps & 3) && len > 1) {\r
+    sum += *ps++;\r
+    len -= 2;\r
+  }\r
+\r
+  pl = (u32_t *)ps;\r
+\r
+  while (len > 7)  {\r
+    tmp = sum + *pl++;          /* ping */\r
+    if (tmp < sum)\r
+      tmp++;                    /* add back carry */\r
+\r
+    sum = tmp + *pl++;          /* pong */\r
+    if (sum < tmp)\r
+      sum++;                    /* add back carry */\r
+\r
+    len -= 8;\r
+  }\r
+\r
+  /* make room in upper bits */\r
+  sum = (sum >> 16) + (sum & 0xffff);\r
+\r
+  ps = (u16_t *)pl;\r
+\r
+  /* 16-bit aligned word remaining? */\r
+  while (len > 1) {\r
+    sum += *ps++;\r
+    len -= 2;\r
+  }\r
+\r
+  /* dangling tail byte remaining? */\r
+  if (len > 0)                  /* include odd byte */\r
+    ((u8_t *)&t)[0] = *(u8_t *)ps;\r
+\r
+  sum += t;                     /* add end bytes */\r
+\r
+  while (sum >> 16)             /* combine halves */\r
+    sum = (sum >> 16) + (sum & 0xffff);\r
+\r
+  if (odd)\r
+    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);\r
+\r
+  return sum;\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_CHKSUM */\r
+\r
+/* inet_chksum_pseudo:\r
+ *\r
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.\r
+ */\r
+\r
+u16_t\r
+inet_chksum_pseudo(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u16_t proto_len)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped;\r
+\r
+  acc = 0;\r
+  swapped = 0;\r
+  /* iterate through all pbuf in chain */\r
+  for(q = p; q != NULL; q = q->next) {\r
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",\r
+      (void *)q, (void *)q->next));\r
+    acc += LWIP_CHKSUM(q->payload, q->len);\r
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/\r
+    while (acc >> 16) {\r
+      acc = (acc & 0xffffUL) + (acc >> 16);\r
+    }\r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);\r
+    }\r
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/\r
+  }\r
+\r
+  if (swapped) {\r
+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);\r
+  }\r
+  acc += (src->addr & 0xffffUL);\r
+  acc += ((src->addr >> 16) & 0xffffUL);\r
+  acc += (dest->addr & 0xffffUL);\r
+  acc += ((dest->addr >> 16) & 0xffffUL);\r
+  acc += (u32_t)htons((u16_t)proto);\r
+  acc += (u32_t)htons(proto_len);\r
+\r
+  while (acc >> 16) {\r
+    acc = (acc & 0xffffUL) + (acc >> 16);\r
+  }\r
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));\r
+  return (u16_t)~(acc & 0xffffUL);\r
+}\r
+\r
+/* inet_chksum:\r
+ *\r
+ * Calculates the Internet checksum over a portion of memory. Used primarily for IP\r
+ * and ICMP.\r
+ */\r
+\r
+u16_t\r
+inet_chksum(void *dataptr, u16_t len)\r
+{\r
+  u32_t acc;\r
+\r
+  acc = LWIP_CHKSUM(dataptr, len);\r
+  while (acc >> 16) {\r
+    acc = (acc & 0xffff) + (acc >> 16);\r
+  }\r
+  return (u16_t)~(acc & 0xffff);\r
+}\r
+\r
+u16_t\r
+inet_chksum_pbuf(struct pbuf *p)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped;\r
+\r
+  acc = 0;\r
+  swapped = 0;\r
+  for(q = p; q != NULL; q = q->next) {\r
+    acc += LWIP_CHKSUM(q->payload, q->len);\r
+    while (acc >> 16) {\r
+      acc = (acc & 0xffffUL) + (acc >> 16);\r
+    }\r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);\r
+    }\r
+  }\r
+\r
+  if (swapped) {\r
+    acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);\r
+  }\r
+  return (u16_t)~(acc & 0xffffUL);\r
+}\r
+\r
+/* Here for now until needed in other places in lwIP */\r
+#ifndef isprint\r
+#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)\r
+#define isprint(c)           in_range(c, 0x20, 0x7f)\r
+#define isdigit(c)           in_range(c, '0', '9')\r
+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))\r
+#define islower(c)           in_range(c, 'a', 'z')\r
+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')\r
+#endif    \r
+    \r
+/*\r
+ * Ascii internet address interpretation routine.\r
+ * The value returned is in network order.\r
+ */\r
+\r
+u32_t\r
+inet_addr(const char *cp)\r
+{\r
+  struct in_addr val;\r
+\r
+  if (inet_aton(cp, &val)) {\r
+    return (val.s_addr);\r
+  }\r
+  return (INADDR_NONE);\r
+}\r
+\r
+/*\r
+ * Check whether "cp" is a valid ascii representation\r
+ * of an Internet address and convert to a binary address.\r
+ * Returns 1 if the address is valid, 0 if not.\r
+ * This replaces inet_addr, the return value from which\r
+ * cannot distinguish between failure and a local broadcast address.\r
+ */\r
+int\r
+inet_aton(const char *cp, struct in_addr *addr)\r
+{\r
+  u32_t val;\r
+  int base, n, c;\r
+  u32_t parts[4];\r
+  u32_t *pp = parts;\r
+\r
+  c = *cp;\r
+  for (;;) {\r
+    /*\r
+     * Collect number up to ``.''.\r
+     * Values are specified as for C:\r
+     * 0x=hex, 0=octal, 1-9=decimal.\r
+     */\r
+    if (!isdigit(c))\r
+      return (0);\r
+    val = 0;\r
+    base = 10;\r
+    if (c == '0') {\r
+      c = *++cp;\r
+      if (c == 'x' || c == 'X') {\r
+        base = 16;\r
+        c = *++cp;\r
+      } else\r
+        base = 8;\r
+    }\r
+    for (;;) {\r
+      if (isdigit(c)) {\r
+        val = (val * base) + (int)(c - '0');\r
+        c = *++cp;\r
+      } else if (base == 16 && isxdigit(c)) {\r
+        val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));\r
+        c = *++cp;\r
+      } else\r
+        break;\r
+    }\r
+    if (c == '.') {\r
+      /*\r
+       * Internet format:\r
+       *  a.b.c.d\r
+       *  a.b.c   (with c treated as 16 bits)\r
+       *  a.b (with b treated as 24 bits)\r
+       */\r
+      if (pp >= parts + 3)\r
+        return (0);\r
+      *pp++ = val;\r
+      c = *++cp;\r
+    } else\r
+      break;\r
+  }\r
+  /*\r
+   * Check for trailing characters.\r
+   */\r
+  if (c != '\0' && (!isprint(c) || !isspace(c)))\r
+    return (0);\r
+  /*\r
+   * Concoct the address according to\r
+   * the number of parts specified.\r
+   */\r
+  n = pp - parts + 1;\r
+  switch (n) {\r
+\r
+  case 0:\r
+    return (0);       /* initial nondigit */\r
+\r
+  case 1:             /* a -- 32 bits */\r
+    break;\r
+\r
+  case 2:             /* a.b -- 8.24 bits */\r
+    if (val > 0xffffff)\r
+      return (0);\r
+    val |= parts[0] << 24;\r
+    break;\r
+\r
+  case 3:             /* a.b.c -- 8.8.16 bits */\r
+    if (val > 0xffff)\r
+      return (0);\r
+    val |= (parts[0] << 24) | (parts[1] << 16);\r
+    break;\r
+\r
+  case 4:             /* a.b.c.d -- 8.8.8.8 bits */\r
+    if (val > 0xff)\r
+      return (0);\r
+    val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);\r
+    break;\r
+  }\r
+  if (addr)\r
+    addr->s_addr = htonl(val);\r
+  return (1);\r
+}\r
+\r
+/* Convert numeric IP address into decimal dotted ASCII representation.\r
+ * returns ptr to static buffer; not reentrant!\r
+ */\r
+char *\r
+inet_ntoa(struct in_addr addr)\r
+{\r
+  static char str[16];\r
+  u32_t s_addr = addr.s_addr;\r
+  char inv[3];\r
+  char *rp;\r
+  u8_t *ap;\r
+  u8_t rem;\r
+  u8_t n;\r
+  u8_t i;\r
+\r
+  rp = str;\r
+  ap = (u8_t *)&s_addr;\r
+  for(n = 0; n < 4; n++) {\r
+    i = 0;\r
+    do {\r
+      rem = *ap % (u8_t)10;\r
+      *ap /= (u8_t)10;\r
+      inv[i++] = '0' + rem;\r
+    } while(*ap);\r
+    while(i--)\r
+      *rp++ = inv[i];\r
+    *rp++ = '.';\r
+    ap++;\r
+  }\r
+  *--rp = 0;\r
+  return str;\r
+}\r
+\r
+/*\r
+ * These are reference implementations of the byte swapping functions.\r
+ * Again with the aim of being simple, correct and fully portable.\r
+ * Byte swapping is the second thing you would want to optimize. You will\r
+ * need to port it to your architecture and in your cc.h:\r
+ * \r
+ * #define LWIP_PLATFORM_BYTESWAP 1\r
+ * #define LWIP_PLATFORM_HTONS(x) <your_htons>\r
+ * #define LWIP_PLATFORM_HTONL(x) <your_htonl>\r
+ *\r
+ * Note ntohs() and ntohl() are merely references to the htonx counterparts.\r
+ */\r
+\r
+#ifndef BYTE_ORDER\r
+#error BYTE_ORDER is not defined\r
+#endif\r
+#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)\r
+\r
+u16_t\r
+htons(u16_t n)\r
+{\r
+  return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);\r
+}\r
+\r
+u16_t\r
+ntohs(u16_t n)\r
+{\r
+  return htons(n);\r
+}\r
+\r
+u32_t\r
+htonl(u32_t n)\r
+{\r
+  return ((n & 0xff) << 24) |\r
+    ((n & 0xff00) << 8) |\r
+    ((n & 0xff0000) >> 8) |\r
+    ((n & 0xff000000) >> 24);\r
+}\r
+\r
+u32_t\r
+ntohl(u32_t n)\r
+{\r
+  return htonl(n);\r
+}\r
+\r
+#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */\r
index c04915b73d009a6e9be6050231fb60b2b984e5d3..aebc6f381e670a728968465889df3f363d70af12 100644 (file)
-/*
- * 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);
-}
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+\r
+/* inet6.c\r
+ *\r
+ * Functions common to all TCP/IP modules, such as the Internet checksum and the\r
+ * byte order functions.\r
+ *\r
+ */\r
+\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/inet.h"\r
+\r
+\r
+\r
+/* chksum:\r
+ *\r
+ * Sums up all 16 bit words in a memory portion. Also includes any odd byte.\r
+ * This function is used by the other checksum functions.\r
+ *\r
+ * For now, this is not optimized. Must be optimized for the particular processor\r
+ * arcitecture on which it is to run. Preferebly coded in assembler.\r
+ */\r
+\r
+static u32_t\r
+chksum(void *dataptr, u16_t len)\r
+{\r
+  u16_t *sdataptr = dataptr;\r
+  u32_t acc;\r
+  \r
+  \r
+  for(acc = 0; len > 1; len -= 2) {\r
+    acc += *sdataptr++;\r
+  }\r
+\r
+  /* add up any odd byte */\r
+  if (len == 1) {\r
+    acc += htons((u16_t)(*(u8_t *)dataptr) << 8);\r
+  }\r
+\r
+  return acc;\r
+\r
+}\r
+\r
+/* inet_chksum_pseudo:\r
+ *\r
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.\r
+ */\r
+\r
+u16_t\r
+inet_chksum_pseudo(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u32_t proto_len)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped, i;\r
+\r
+  acc = 0;\r
+  swapped = 0;\r
+  for(q = p; q != NULL; q = q->next) {    \r
+    acc += chksum(q->payload, q->len);\r
+    while (acc >> 16) {\r
+      acc = (acc & 0xffff) + (acc >> 16);\r
+    }\r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);\r
+    }\r
+  }\r
+\r
+  if (swapped) {\r
+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);\r
+  }\r
+  \r
+  for(i = 0; i < 8; i++) {\r
+    acc += ((u16_t *)src->addr)[i] & 0xffff;\r
+    acc += ((u16_t *)dest->addr)[i] & 0xffff;\r
+    while (acc >> 16) {\r
+      acc = (acc & 0xffff) + (acc >> 16);\r
+    }\r
+  }\r
+  acc += (u16_t)htons((u16_t)proto);\r
+  acc += ((u16_t *)&proto_len)[0] & 0xffff;\r
+  acc += ((u16_t *)&proto_len)[1] & 0xffff;\r
+\r
+  while (acc >> 16) {\r
+    acc = (acc & 0xffff) + (acc >> 16);\r
+  }\r
+  return ~(acc & 0xffff);\r
+}\r
+\r
+/* inet_chksum:\r
+ *\r
+ * Calculates the Internet checksum over a portion of memory. Used primarely for IP\r
+ * and ICMP.\r
+ */\r
+\r
+u16_t\r
+inet_chksum(void *dataptr, u16_t len)\r
+{\r
+  u32_t acc, sum;\r
+\r
+  acc = chksum(dataptr, len);\r
+  sum = (acc & 0xffff) + (acc >> 16);\r
+  sum += (sum >> 16);\r
+  return ~(sum & 0xffff);\r
+}\r
+\r
+u16_t\r
+inet_chksum_pbuf(struct pbuf *p)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped;\r
+  \r
+  acc = 0;\r
+  swapped = 0;\r
+  for(q = p; q != NULL; q = q->next) {\r
+    acc += chksum(q->payload, q->len);\r
+    while (acc >> 16) {\r
+      acc = (acc & 0xffff) + (acc >> 16);\r
+    }    \r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);\r
+    }\r
+  }\r
\r
+  if (swapped) {\r
+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);\r
+  }\r
+  return ~(acc & 0xffff);\r
+}\r
+\r
index 248f2c6b02722c50ee114a1e9fcdcea53b523839..e4028b18f1f07ca633597d2239eb033ac57b995b 100644 (file)
-/*
- * 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 */
-
-
-
-
-
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/* Some ICMP messages should be passed to the transport protocols. This\r
+   is not implemented. */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/icmp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/def.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+\r
+void\r
+icmp_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  u8_t type;\r
+  u8_t code;\r
+  struct icmp_echo_hdr *iecho;\r
+  struct ip_hdr *iphdr;\r
+  struct ip_addr tmpaddr;\r
+  u16_t hlen;\r
+\r
+  ICMP_STATS_INC(icmp.recv);\r
+  snmp_inc_icmpinmsgs();\r
+\r
+\r
+  iphdr = p->payload;\r
+  hlen = IPH_HL(iphdr) * 4;\r
+  if (pbuf_header(p, -((s16_t)hlen)) || (p->tot_len < sizeof(u16_t)*2)) {\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));\r
+    pbuf_free(p);\r
+    ICMP_STATS_INC(icmp.lenerr);\r
+    snmp_inc_icmpinerrors();\r
+    return;\r
+  }\r
+\r
+  type = *((u8_t *)p->payload);\r
+  code = *(((u8_t *)p->payload)+1);\r
+  switch (type) {\r
+  case ICMP_ECHO:\r
+    /* broadcast or multicast destination address? */\r
+    if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {\r
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));\r
+      ICMP_STATS_INC(icmp.err);\r
+      pbuf_free(p);\r
+      return;\r
+    }\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));\r
+    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {\r
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));\r
+      pbuf_free(p);\r
+      ICMP_STATS_INC(icmp.lenerr);\r
+      snmp_inc_icmpinerrors();\r
+\r
+      return;\r
+    }\r
+    iecho = p->payload;\r
+    if (inet_chksum_pbuf(p) != 0) {\r
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));\r
+      pbuf_free(p);\r
+      ICMP_STATS_INC(icmp.chkerr);\r
+      snmp_inc_icmpinerrors();\r
+      return;\r
+    }\r
+    tmpaddr.addr = iphdr->src.addr;\r
+    iphdr->src.addr = iphdr->dest.addr;\r
+    iphdr->dest.addr = tmpaddr.addr;\r
+    ICMPH_TYPE_SET(iecho, ICMP_ER);\r
+    /* adjust the checksum */\r
+    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {\r
+      iecho->chksum += htons(ICMP_ECHO << 8) + 1;\r
+    } else {\r
+      iecho->chksum += htons(ICMP_ECHO << 8);\r
+    }\r
+    ICMP_STATS_INC(icmp.xmit);\r
+    /* increase number of messages attempted to send */\r
+    snmp_inc_icmpoutmsgs();\r
+    /* increase number of echo replies attempted to send */\r
+    snmp_inc_icmpoutechoreps();\r
+\r
+    pbuf_header(p, hlen);\r
+    ip_output_if(p, &(iphdr->src), IP_HDRINCL,\r
+     IPH_TTL(iphdr), 0, IP_PROTO_ICMP, inp);\r
+    break;\r
+  default:\r
+  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", (s16_t)type, (s16_t)code));\r
+    ICMP_STATS_INC(icmp.proterr);\r
+    ICMP_STATS_INC(icmp.drop);\r
+  }\r
+  pbuf_free(p);\r
+}\r
+\r
+void\r
+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)\r
+{\r
+  struct pbuf *q;\r
+  struct ip_hdr *iphdr;\r
+  struct icmp_dur_hdr *idur;\r
+\r
+  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);\r
+  /* ICMP header + IP header + 8 bytes of data */\r
+\r
+  iphdr = p->payload;\r
+\r
+  idur = q->payload;\r
+  ICMPH_TYPE_SET(idur, ICMP_DUR);\r
+  ICMPH_CODE_SET(idur, t);\r
+\r
+  memcpy((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);\r
+\r
+  /* calculate checksum */\r
+  idur->chksum = 0;\r
+  idur->chksum = inet_chksum(idur, q->len);\r
+  ICMP_STATS_INC(icmp.xmit);\r
+  /* increase number of messages attempted to send */\r
+  snmp_inc_icmpoutmsgs();\r
+  /* increase number of destination unreachable messages attempted to send */\r
+  snmp_inc_icmpoutdestunreachs();\r
+\r
+  ip_output(q, NULL, &(iphdr->src),\r
+      ICMP_TTL, 0, IP_PROTO_ICMP);\r
+  pbuf_free(q);\r
+}\r
+\r
+#if IP_FORWARD\r
+void\r
+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)\r
+{\r
+  struct pbuf *q;\r
+  struct ip_hdr *iphdr;\r
+  struct icmp_te_hdr *tehdr;\r
+\r
+  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);\r
+\r
+  iphdr = p->payload;\r
+  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));\r
+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));\r
+  LWIP_DEBUGF(ICMP_DEBUG, (" to "));\r
+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));\r
+  LWIP_DEBUGF(ICMP_DEBUG, ("\n"));\r
+\r
+  tehdr = q->payload;\r
+  ICMPH_TYPE_SET(tehdr, ICMP_TE);\r
+  ICMPH_CODE_SET(tehdr, t);\r
+\r
+  /* copy fields from original packet */\r
+  memcpy((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);\r
+\r
+  /* calculate checksum */\r
+  tehdr->chksum = 0;\r
+  tehdr->chksum = inet_chksum(tehdr, q->len);\r
+  ICMP_STATS_INC(icmp.xmit);\r
+  /* increase number of messages attempted to send */\r
+  snmp_inc_icmpoutmsgs();\r
+  /* increase number of destination unreachable messages attempted to send */\r
+  snmp_inc_icmpouttimeexcds();\r
+  ip_output(q, NULL, &(iphdr->src),\r
+      ICMP_TTL, 0, IP_PROTO_ICMP);\r
+  pbuf_free(q);\r
+}\r
+\r
+#endif /* IP_FORWARD */\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
index 496d76efdcbc357c29e5595c92c10f57bf2b469a..31d29a98ccf874f3dfeff9c943c645b922834ab3 100644 (file)
-/* @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) {
+/* @file\r
+ *\r
+ * This is the IP layer implementation for incoming and outgoing IP traffic.\r
+ * \r
+ * @see ip_frag.c\r
+ *\r
+ */\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/ip_frag.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/icmp.h"\r
+#include "lwip/raw.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+\r
+#include "lwip/stats.h"\r
+\r
+#include "arch/perf.h"\r
+\r
+#include "lwip/snmp.h"\r
+#if LWIP_DHCP\r
+#  include "lwip/dhcp.h"\r
+#endif /* LWIP_DHCP */\r
+\r
+/**\r
+ * Initializes the IP layer.\r
+ */\r
+\r
+void\r
+ip_init(void)\r
+{\r
+#if IP_FRAG\r
+  ip_frag_init();\r
+#endif\r
+}\r
+\r
+/**\r
+ * Finds the appropriate network interface for a given IP address. It\r
+ * searches the list of network interfaces linearly. A match is found\r
+ * if the masked IP address of the network interface equals the masked\r
+ * IP address given to the function.\r
+ */\r
+\r
+struct netif *\r
+ip_route(struct ip_addr *dest)\r
+{\r
+  struct netif *netif;\r
+\r
+  /* iterate through netifs */\r
+  for(netif = netif_list; netif != NULL; netif = netif->next) {\r
+    /* network mask matches? */\r
+    if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {\r
+      /* return netif on which to forward IP packet */\r
+      return netif;\r
+    }\r
+  }\r
+  /* no matching netif found, use default netif */\r
+  return netif_default;\r
+}\r
+#if IP_FORWARD\r
+\r
+/**\r
+ * Forwards an IP packet. It finds an appropriate route for the\r
+ * packet, decrements the TTL value of the packet, adjusts the\r
+ * checksum and outputs the packet on the appropriate interface.\r
+ */\r
+\r
+static struct netif *\r
+ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)\r
+{\r
+  struct netif *netif;\r
+\r
+  PERF_START;\r
+  /* Find network interface where to forward this IP packet to. */\r
+  netif = ip_route((struct ip_addr *)&(iphdr->dest));\r
+  if (netif == NULL) {\r
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",\r
+                      iphdr->dest.addr));\r
+    snmp_inc_ipoutnoroutes();\r
+    return (struct netif *)NULL;\r
+  }\r
+  /* Do not forward packets onto the same network interface on which\r
+   * they arrived. */\r
+  if (netif == inp) {\r
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));\r
+    snmp_inc_ipoutnoroutes();\r
+    return (struct netif *)NULL;\r
+  }\r
+\r
+  /* decrement TTL */\r
+  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);\r
+  /* send ICMP if TTL == 0 */\r
+  if (IPH_TTL(iphdr) == 0) {\r
+    snmp_inc_ipinhdrerrors();\r
+    /* Don't send ICMP messages in response to ICMP messages */\r
+    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {\r
+      icmp_time_exceeded(p, ICMP_TE_TTL);\r
+    }\r
+    return (struct netif *)NULL;\r
+  }\r
+\r
+  /* Incrementally update the IP checksum. */\r
+  if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {\r
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);\r
+  } else {\r
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));\r
+  }\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",\r
+                    iphdr->dest.addr));\r
+\r
+  IP_STATS_INC(ip.fw);\r
+  IP_STATS_INC(ip.xmit);\r
+  snmp_inc_ipforwdatagrams();\r
+\r
+  PERF_STOP("ip_forward");\r
+  /* transmit pbuf on chosen interface */\r
+  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));\r
+  return netif;\r
+}\r
+#endif /* IP_FORWARD */\r
+\r
+/**\r
+ * This function is called by the network interface device driver when\r
+ * an IP packet is received. The function does the basic checks of the\r
+ * IP header such as packet size being at least larger than the header\r
+ * size etc. If the packet was not destined for us, the packet is\r
+ * forwarded (using ip_forward). The IP checksum is always checked.\r
+ *\r
+ * Finally, the packet is sent to the upper layer protocol input function.\r
+ * \r
+ * \r
+ * \r
+ */\r
+\r
+err_t\r
+ip_input(struct pbuf *p, struct netif *inp) {\r
+  struct ip_hdr *iphdr;\r
+  struct netif *netif;\r
+  u16_t iphdrlen;\r
+\r
+  IP_STATS_INC(ip.recv);\r
+  snmp_inc_ipinreceives();\r
+\r
+  /* identify the IP header */\r
+  iphdr = p->payload;\r
+  if (IPH_V(iphdr) != 4) {\r
     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
-
-
-
-
-
+    ip_debug_print(p);\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.err);\r
+    IP_STATS_INC(ip.drop);\r
+    snmp_inc_ipinhdrerrors();\r
+    return ERR_OK;\r
+  }\r
+  /* obtain IP header length in number of 32-bit words */\r
+  iphdrlen = IPH_HL(iphdr);\r
+  /* calculate IP header length in bytes */\r
+  iphdrlen *= 4;\r
+\r
+  /* header length exceeds first pbuf length? */\r
+  if (iphdrlen > p->len) {\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet droppped.\n",\r
+      iphdrlen, p->len));\r
+    /* free (drop) packet pbufs */\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.lenerr);\r
+    IP_STATS_INC(ip.drop);\r
+    snmp_inc_ipindiscards();\r
+    return ERR_OK;\r
+  }\r
+\r
+  /* verify checksum */\r
+#if CHECKSUM_CHECK_IP\r
+  if (inet_chksum(iphdr, iphdrlen) != 0) {\r
+\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen)));\r
+    ip_debug_print(p);\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.chkerr);\r
+    IP_STATS_INC(ip.drop);\r
+    snmp_inc_ipinhdrerrors();\r
+    return ERR_OK;\r
+  }\r
+#endif\r
+\r
+  /* Trim pbuf. This should have been done at the netif layer,\r
+   * but we'll do it anyway just to be sure that its done. */\r
+  pbuf_realloc(p, ntohs(IPH_LEN(iphdr)));\r
+\r
+  /* match packet against an interface, i.e. is this packet for us? */\r
+  for (netif = netif_list; netif != NULL; netif = netif->next) {\r
+\r
+    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",\r
+      iphdr->dest.addr, netif->ip_addr.addr,\r
+      iphdr->dest.addr & netif->netmask.addr,\r
+      netif->ip_addr.addr & netif->netmask.addr,\r
+      iphdr->dest.addr & ~(netif->netmask.addr)));\r
+\r
+    /* interface is up and configured? */\r
+    if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr))))\r
+    {\r
+      /* unicast to this interface address? */\r
+      if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||\r
+         /* or broadcast on this interface network address? */\r
+         ip_addr_isbroadcast(&(iphdr->dest), netif)) {\r
+        LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",\r
+          netif->name[0], netif->name[1]));\r
+        /* break out of for loop */\r
+        break;\r
+      }\r
+    }\r
+  }\r
+#if LWIP_DHCP\r
+  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed\r
+   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.\r
+   * According to RFC 1542 section 3.1.1, referred by RFC 2131).\r
+   */\r
+  if (netif == NULL) {\r
+    /* remote port is DHCP server? */\r
+    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {\r
+      LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",\r
+        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest)));\r
+      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) {\r
+        LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));\r
+        netif = inp;\r
+      }\r
+    }\r
+  }\r
+#endif /* LWIP_DHCP */\r
+  /* packet not for us? */\r
+  if (netif == NULL) {\r
+    /* packet not for us, route or discard */\r
+    LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n"));\r
+#if IP_FORWARD\r
+    /* non-broadcast packet? */\r
+    if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {\r
+      /* try to forward IP packet on (other) interfaces */\r
+      ip_forward(p, iphdr, inp);\r
+    }\r
+    else\r
+#endif /* IP_FORWARD */\r
+    {\r
+      snmp_inc_ipinaddrerrors();\r
+      snmp_inc_ipindiscards();\r
+    }\r
+    pbuf_free(p);\r
+    return ERR_OK;\r
+  }\r
+  /* packet consists of multiple fragments? */\r
+  if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {\r
+#if IP_REASSEMBLY /* packet fragment reassembly code present? */\r
+    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",\r
+      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));\r
+    /* reassemble the packet*/\r
+    p = ip_reass(p);\r
+    /* packet not fully reassembled yet? */\r
+    if (p == NULL) {\r
+      return ERR_OK;\r
+    }\r
+    iphdr = p->payload;\r
+#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */\r
+    pbuf_free(p);\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",\r
+      ntohs(IPH_OFFSET(iphdr))));\r
+    IP_STATS_INC(ip.opterr);\r
+    IP_STATS_INC(ip.drop);\r
+    /* unsupported protocol feature */\r
+    snmp_inc_ipinunknownprotos();\r
+    return ERR_OK;\r
+#endif /* IP_REASSEMBLY */\r
+  }\r
+\r
+#if IP_OPTIONS == 0 /* no support for IP options in the IP header? */\r
+  if (iphdrlen > IP_HLEN) {\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n"));\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.opterr);\r
+    IP_STATS_INC(ip.drop);\r
+    /* unsupported protocol feature */\r
+    snmp_inc_ipinunknownprotos();\r
+    return ERR_OK;\r
+  }\r
+#endif /* IP_OPTIONS == 0 */\r
+\r
+  /* send to upper layers */\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));\r
+  ip_debug_print(p);\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));\r
+\r
+#if LWIP_RAW\r
+  /* raw input did not eat the packet? */\r
+  if (raw_input(p, inp) == 0) {\r
+#endif /* LWIP_RAW */\r
+\r
+  switch (IPH_PROTO(iphdr)) {\r
+#if LWIP_UDP\r
+  case IP_PROTO_UDP:\r
+  case IP_PROTO_UDPLITE:\r
+    snmp_inc_ipindelivers();\r
+    udp_input(p, inp);\r
+    break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+  case IP_PROTO_TCP:\r
+    snmp_inc_ipindelivers();\r
+    tcp_input(p, inp);\r
+    break;\r
+#endif /* LWIP_TCP */\r
+  case IP_PROTO_ICMP:\r
+    snmp_inc_ipindelivers();\r
+    icmp_input(p, inp);\r
+    break;\r
+  default:\r
+    /* send ICMP destination protocol unreachable unless is was a broadcast */\r
+    if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&\r
+        !ip_addr_ismulticast(&(iphdr->dest))) {\r
+      p->payload = iphdr;\r
+      icmp_dest_unreach(p, ICMP_DUR_PROTO);\r
+    }\r
+    pbuf_free(p);\r
+\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));\r
+\r
+    IP_STATS_INC(ip.proterr);\r
+    IP_STATS_INC(ip.drop);\r
+    snmp_inc_ipinunknownprotos();\r
+  }\r
+#if LWIP_RAW\r
+  } /* LWIP_RAW */\r
+#endif\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Sends an IP packet on a network interface. This function constructs\r
+ * the IP header and calculates the IP header checksum. If the source\r
+ * IP address is NULL, the IP address of the outgoing network\r
+ * interface is filled in as source address.\r
+ *\r
+ * @note ip_id: RFC791 "some host may be able to simply use\r
+ *  unique identifiers independent of destination"\r
+ */\r
+\r
+err_t\r
+ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+             u8_t ttl, u8_t tos,\r
+             u8_t proto, struct netif *netif)\r
+{\r
+  struct ip_hdr *iphdr;\r
+  static u16_t ip_id = 0;\r
+\r
+  snmp_inc_ipoutrequests();\r
+\r
+  if (dest != IP_HDRINCL) {\r
+    if (pbuf_header(p, IP_HLEN)) {\r
+      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));\r
+\r
+      IP_STATS_INC(ip.err);\r
+      snmp_inc_ipoutdiscards();\r
+      return ERR_BUF;\r
+    }\r
+\r
+    iphdr = p->payload;\r
+\r
+    IPH_TTL_SET(iphdr, ttl);\r
+    IPH_PROTO_SET(iphdr, proto);\r
+\r
+    ip_addr_set(&(iphdr->dest), dest);\r
+\r
+    IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);\r
+    IPH_LEN_SET(iphdr, htons(p->tot_len));\r
+    IPH_OFFSET_SET(iphdr, htons(IP_DF));\r
+    IPH_ID_SET(iphdr, htons(ip_id));\r
+    ++ip_id;\r
+\r
+    if (ip_addr_isany(src)) {\r
+      ip_addr_set(&(iphdr->src), &(netif->ip_addr));\r
+    } else {\r
+      ip_addr_set(&(iphdr->src), src);\r
+    }\r
+\r
+    IPH_CHKSUM_SET(iphdr, 0);\r
+#if CHECKSUM_GEN_IP\r
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\r
+#endif\r
+  } else {\r
+    iphdr = p->payload;\r
+    dest = &(iphdr->dest);\r
+  }\r
+\r
+#if IP_FRAG\r
+  /* don't fragment if interface has mtu set to 0 [loopif] */\r
+  if (netif->mtu && (p->tot_len > netif->mtu))\r
+    return ip_frag(p,netif,dest);\r
+#endif\r
+\r
+  IP_STATS_INC(ip.xmit);\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));\r
+  ip_debug_print(p);\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));\r
+\r
+  return netif->output(netif, p, dest);\r
+}\r
+\r
+/**\r
+ * Simple interface to ip_output_if. It finds the outgoing network\r
+ * interface and calls upon ip_output_if to do the actual work.\r
+ */\r
+\r
+err_t\r
+ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+          u8_t ttl, u8_t tos, u8_t proto)\r
+{\r
+  struct netif *netif;\r
+\r
+  if ((netif = ip_route(dest)) == NULL) {\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));\r
+\r
+    IP_STATS_INC(ip.rterr);\r
+    snmp_inc_ipoutnoroutes();\r
+    return ERR_RTE;\r
+  }\r
+\r
+  return ip_output_if(p, src, dest, ttl, tos, proto, netif);\r
+}\r
+\r
+#if IP_DEBUG\r
+void\r
+ip_debug_print(struct pbuf *p)\r
+{\r
+  struct ip_hdr *iphdr = p->payload;\r
+  u8_t *payload;\r
+\r
+  payload = (u8_t *)iphdr + IP_HLEN;\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",\r
+                    IPH_V(iphdr),\r
+                    IPH_HL(iphdr),\r
+                    IPH_TOS(iphdr),\r
+                    ntohs(IPH_LEN(iphdr))));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",\r
+                    ntohs(IPH_ID(iphdr)),\r
+                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,\r
+                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,\r
+                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,\r
+                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",\r
+                    IPH_TTL(iphdr),\r
+                    IPH_PROTO(iphdr),\r
+                    ntohs(IPH_CHKSUM(iphdr))));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",\r
+                    ip4_addr1(&iphdr->src),\r
+                    ip4_addr2(&iphdr->src),\r
+                    ip4_addr3(&iphdr->src),\r
+                    ip4_addr4(&iphdr->src)));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",\r
+                    ip4_addr1(&iphdr->dest),\r
+                    ip4_addr2(&iphdr->dest),\r
+                    ip4_addr3(&iphdr->dest),\r
+                    ip4_addr4(&iphdr->dest)));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+}\r
+#endif /* IP_DEBUG */\r
+\r
+\r
+\r
+\r
+\r
+\r
index 70be286d5139119408beb8caf9d847e3fac08a13..56b1cd7c4b72014a59383bfeb12be5f4134d6ffc 100644 (file)
@@ -1,78 +1,78 @@
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved. 
- * 
- * Redistribution and use in source and binary forms, with or without modification, 
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission. 
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- * 
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/ip_addr.h"
-#include "lwip/inet.h"
-#include "lwip/netif.h"
-
-#define IP_ADDR_ANY_VALUE 0x00000000UL
-#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL
-
-/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
-const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };
-const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };
-
-/* Determine if an address is a broadcast address on a network interface 
- * 
- * @param addr address to be checked
- * @param netif the network interface against which the address is checked
- * @return returns non-zero if the address is a broadcast address
- *
- */
-
-u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
-{
-  u32_t addr2test;
-
-  addr2test = addr->addr;
-  /* all ones (broadcast) or all zeroes (old skool broadcast) */
-  if ((~addr2test == IP_ADDR_ANY_VALUE) ||
-      (addr2test == IP_ADDR_ANY_VALUE))
-    return 1;
-  /* no broadcast support on this network interface? */
-  else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)
-    /* the given address cannot be a broadcast address
-     * nor can we check against any broadcast addresses */
-    return 0;
-  /* address matches network interface address exactly? => no broadcast */
-  else if (addr2test == netif->ip_addr.addr)
-    return 0;
-  /*  on the same (sub) network... */
-  else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
-         /* ...and host identifier bits are all ones? =>... */
-          && ((addr2test & ~netif->netmask.addr) ==
-           (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))
-    /* => network broadcast address */
-    return 1;
-  else
-    return 0;
-}
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/netif.h"\r
+\r
+#define IP_ADDR_ANY_VALUE 0x00000000UL\r
+#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL\r
+\r
+/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */\r
+const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };\r
+const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };\r
+\r
+/* Determine if an address is a broadcast address on a network interface \r
+ * \r
+ * @param addr address to be checked\r
+ * @param netif the network interface against which the address is checked\r
+ * @return returns non-zero if the address is a broadcast address\r
+ *\r
+ */\r
+\r
+u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)\r
+{\r
+  u32_t addr2test;\r
+\r
+  addr2test = addr->addr;\r
+  /* all ones (broadcast) or all zeroes (old skool broadcast) */\r
+  if ((~addr2test == IP_ADDR_ANY_VALUE) ||\r
+      (addr2test == IP_ADDR_ANY_VALUE))\r
+    return 1;\r
+  /* no broadcast support on this network interface? */\r
+  else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)\r
+    /* the given address cannot be a broadcast address\r
+     * nor can we check against any broadcast addresses */\r
+    return 0;\r
+  /* address matches network interface address exactly? => no broadcast */\r
+  else if (addr2test == netif->ip_addr.addr)\r
+    return 0;\r
+  /*  on the same (sub) network... */\r
+  else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))\r
+         /* ...and host identifier bits are all ones? =>... */\r
+          && ((addr2test & ~netif->netmask.addr) ==\r
+           (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))\r
+    /* => network broadcast address */\r
+    return 1;\r
+  else\r
+    return 0;\r
+}\r
index c43422ca413186eb7ce50c7132ef49c8e167efad..0256a5020a52507e5f93201f151dae8f11e2cc96 100644 (file)
-/* @file
- * 
- * This is the IP packet segmentation and reassembly implementation.
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved. 
- * 
- * Redistribution and use in source and binary forms, with or without modification, 
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission. 
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- * 
- * Author: Jani Monoses <jani@iv.ro> 
- * original reassembly code by Adam Dunkels <adam@sics.se>
- * 
- */
-
-#include <string.h>
-
-#include "lwip/opt.h"
-#include "lwip/ip.h"
-#include "lwip/ip_frag.h"
-#include "lwip/netif.h"
-#include "lwip/snmp.h"
-#include "lwip/stats.h"
-
-static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];
-static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8) + 1];
-static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,
-  0x0f, 0x07, 0x03, 0x01
-};
-static u16_t ip_reasslen;
-static u8_t ip_reassflags;
-#define IP_REASS_FLAG_LASTFRAG 0x01
-
-static u8_t ip_reasstmr;
-
-/*
- * Copy len bytes from offset in pbuf to buffer 
- *
- * helper used by both ip_reass and ip_frag
- */
-static struct pbuf *
-copy_from_pbuf(struct pbuf *p, u16_t * offset,
-           u8_t * buffer, u16_t len)
-{
-  u16_t l;
-
-  p->payload = (u8_t *)p->payload + *offset;
-  p->len -= *offset;
-  while (len) {
-    l = len < p->len ? len : p->len;
-    memcpy(buffer, p->payload, l);
-    buffer += l;
-    len -= l;
-    if (len)
-      p = p->next;
-    else
-      *offset = l;
-  }
-  return p;
-}
-
-
-/**
- * Initializes IP reassembly and fragmentation states.
- */
-void
-ip_frag_init(void)
-{
-  ip_reasstmr = 0;
-  ip_reassflags = 0;
-  ip_reasslen = 0;
-  memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
-}
-
-/**
- * Reassembly timer base function
- * for both NO_SYS == 0 and 1 (!).
- *
- * Should be called every 1000 msec.
- */
-void
-ip_reass_tmr(void)
-{
-  if (ip_reasstmr > 0) {
-    ip_reasstmr--;
-    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)ip_reasstmr));
-    if (ip_reasstmr == 0) {
-      /* reassembly timed out */
-      snmp_inc_ipreasmfails();
-    }
-  }
-}
-
-/**
- * Reassembles incoming IP fragments into an IP datagram.
- *
- * @param p points to a pbuf chain of the fragment
- * @return NULL if reassembly is incomplete, ? otherwise
- */
-struct pbuf *
-ip_reass(struct pbuf *p)
-{
-  struct pbuf *q;
-  struct ip_hdr *fraghdr, *iphdr;
-  u16_t offset, len;
-  u16_t i;
-
-  IPFRAG_STATS_INC(ip_frag.recv);
-  snmp_inc_ipreasmreqds();
-
-  iphdr = (struct ip_hdr *) ip_reassbuf;
-  fraghdr = (struct ip_hdr *) p->payload;
-  /* If ip_reasstmr is zero, no packet is present in the buffer, so we
-     write the IP header of the fragment into the reassembly
-     buffer. The timer is updated with the maximum age. */
-  if (ip_reasstmr == 0) {
-    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));
-    memcpy(iphdr, fraghdr, IP_HLEN);
-    ip_reasstmr = IP_REASS_MAXAGE;
-    ip_reassflags = 0;
-    /* Clear the bitmap. */
-    memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
-  }
-
-  /* Check if the incoming fragment matches the one currently present
-     in the reasembly buffer. If so, we proceed with copying the
-     fragment into the buffer. */
-  if (ip_addr_cmp(&iphdr->src, &fraghdr->src) &&
-      ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&
-      IPH_ID(iphdr) == IPH_ID(fraghdr)) {
-    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
-      ntohs(IPH_ID(fraghdr))));
-    IPFRAG_STATS_INC(ip_frag.cachehit);
-    /* Find out the offset in the reassembly buffer where we should
-       copy the fragment. */
-    len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
-    offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
-
-    /* If the offset or the offset + fragment length overflows the
-       reassembly buffer, we discard the entire packet. */
-    if ((offset > IP_REASS_BUFSIZE) || ((offset + len) > IP_REASS_BUFSIZE)) {
-      LWIP_DEBUGF(IP_REASS_DEBUG,
-       ("ip_reass: fragment outside of buffer (%"S16_F":%"S16_F"/%"S16_F").\n", offset,
-        offset + len, IP_REASS_BUFSIZE));
-      ip_reasstmr = 0;
-      snmp_inc_ipreasmfails();
-      goto nullreturn;
-    }
-
-    /* Copy the fragment into the reassembly buffer, at the right
-       offset. */
-    LWIP_DEBUGF(IP_REASS_DEBUG,
-     ("ip_reass: copying with offset %"S16_F" into %"S16_F":%"S16_F"\n", offset,
-      IP_HLEN + offset, IP_HLEN + offset + len));
-    i = IPH_HL(fraghdr) * 4;
-    copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);
-
-    /* Update the bitmap. */
-    if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
-      LWIP_DEBUGF(IP_REASS_DEBUG,
-       ("ip_reass: updating single byte in bitmap.\n"));
-      /* If the two endpoints are in the same byte, we only update that byte. */
-      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",
-                   offset / (8 * 8) < sizeof(ip_reassbitmap));
-      ip_reassbitmap[offset / (8 * 8)] |=
-        bitmap_bits[(offset / 8) & 7] &
-        ~bitmap_bits[((offset + len) / 8) & 7];
-    } else {
-      /* If the two endpoints are in different bytes, we update the
-         bytes in the endpoints and fill the stuff inbetween with
-         0xff. */
-      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",
-                   offset / (8 * 8) < sizeof(ip_reassbitmap));
-      ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];
-      LWIP_DEBUGF(IP_REASS_DEBUG,
-       ("ip_reass: updating many bytes in bitmap (%"S16_F":%"S16_F").\n",
-        1 + offset / (8 * 8), (offset + len) / (8 * 8)));
-      for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
-        ip_reassbitmap[i] = 0xff;
-      }
-      LWIP_ASSERT("(offset + len) / (8 * 8) < sizeof(ip_reassbitmap)",
-                   (offset + len) / (8 * 8) < sizeof(ip_reassbitmap));
-      ip_reassbitmap[(offset + len) / (8 * 8)] |=
-        ~bitmap_bits[((offset + len) / 8) & 7];
-    }
-
-    /* If this fragment has the More Fragments flag set to zero, we
-       know that this is the last fragment, so we can calculate the
-       size of the entire packet. We also set the
-       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
-       the final fragment. */
-
-    if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
-      ip_reassflags |= IP_REASS_FLAG_LASTFRAG;
-      ip_reasslen = offset + len;
-      LWIP_DEBUGF(IP_REASS_DEBUG,
-       ("ip_reass: last fragment seen, total len %"S16_F"\n",
-        ip_reasslen));
-    }
-
-    /* Finally, we check if we have a full packet in the buffer. We do
-       this by checking if we have the last fragment and if all bits
-       in the bitmap are set. */
-    if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
-      /* Check all bytes up to and including all but the last byte in
-         the bitmap. */
-      LWIP_ASSERT("ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)",
-                   ip_reasslen / (8 * 8) - 1 < ((u16_t) sizeof(ip_reassbitmap)));
-      for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
-        if (ip_reassbitmap[i] != 0xff) {
-          LWIP_DEBUGF(IP_REASS_DEBUG,
-           ("ip_reass: last fragment seen, bitmap %"S16_F"/%"S16_F" failed (%"X16_F")\n",
-            i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));
-          goto nullreturn;
-        }
-      }
-      /* Check the last byte in the bitmap. It should contain just the
-         right amount of bits. */
-      LWIP_ASSERT("ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)",
-                   ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap));
-      if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=
-        (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {
-         LWIP_DEBUGF(IP_REASS_DEBUG,
-          ("ip_reass: last fragment seen, bitmap %"S16_F" didn't contain %"X16_F" (%"X16_F")\n",
-        ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],
-        ip_reassbitmap[ip_reasslen / (8 * 8)]));
-        goto nullreturn;
-      }
-
-      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
-         from now on. */
-      ip_reasslen += IP_HLEN;
-
-      IPH_LEN_SET(iphdr, htons(ip_reasslen));
-      IPH_OFFSET_SET(iphdr, 0);
-      IPH_CHKSUM_SET(iphdr, 0);
-      IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
-
-      /* If we have come this far, we have a full packet in the
-         buffer, so we allocate a pbuf and copy the packet into it. We
-         also reset the timer. */
-      ip_reasstmr = 0;
-      pbuf_free(p);
-      p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);
-      if (p != NULL) {
-        i = 0;
-        for (q = p; q != NULL; q = q->next) {
-          /* Copy enough bytes to fill this pbuf in the chain. The
-             available data in the pbuf is given by the q->len variable. */
-          LWIP_DEBUGF(IP_REASS_DEBUG,
-           ("ip_reass: memcpy from %p (%"S16_F") to %p, %"S16_F" bytes\n",
-            (void *)&ip_reassbuf[i], i, q->payload,
-            q->len > ip_reasslen - i ? ip_reasslen - i : q->len));
-          memcpy(q->payload, &ip_reassbuf[i],
-            q->len > ip_reasslen - i ? ip_reasslen - i : q->len);
-          i += q->len;
-        }
-        IPFRAG_STATS_INC(ip_frag.fw);
-        snmp_inc_ipreasmoks();
-      } else {
-        LWIP_DEBUGF(IP_REASS_DEBUG,
-          ("ip_reass: pbuf_alloc(PBUF_LINK, ip_reasslen=%"U16_F", PBUF_POOL) failed\n", ip_reasslen));
-        IPFRAG_STATS_INC(ip_frag.memerr);
-        snmp_inc_ipreasmfails();
-      }
-      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p));
-      return p;
-    }
-  }
-
-nullreturn:
-  IPFRAG_STATS_INC(ip_frag.drop);
-  pbuf_free(p);
-  return NULL;
-}
-
-static u8_t buf[MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];
-
-/**
- * Fragment an IP datagram if too large for the netif.
- *
- * Chop the datagram in MTU sized chunks and send them in order
- * by using a fixed size static memory buffer (PBUF_ROM)
- */
-err_t 
-ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
-{
-  struct pbuf *rambuf;
-  struct pbuf *header;
-  struct ip_hdr *iphdr;
-  u16_t nfb = 0;
-  u16_t left, cop;
-  u16_t mtu = netif->mtu;
-  u16_t ofo, omf;
-  u16_t last;
-  u16_t poff = IP_HLEN;
-  u16_t tmp;
-
-  /* Get a RAM based MTU sized pbuf */
-  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
-  if (rambuf == NULL) {
-    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
-    return ERR_MEM;
-  }
-  rambuf->tot_len = rambuf->len = mtu;
-  rambuf->payload = MEM_ALIGN((void *)buf);
-
-  /* Copy the IP header in it */
-  iphdr = rambuf->payload;
-  memcpy(iphdr, p->payload, IP_HLEN);
-
-  /* Save original offset */
-  tmp = ntohs(IPH_OFFSET(iphdr));
-  ofo = tmp & IP_OFFMASK;
-  omf = tmp & IP_MF;
-
-  left = p->tot_len - IP_HLEN;
-
-  while (left) {
-    last = (left <= mtu - IP_HLEN);
-
-    /* Set new offset and MF flag */
-    ofo += nfb;
-    tmp = omf | (IP_OFFMASK & (ofo));
-    if (!last)
-      tmp = tmp | IP_MF;
-    IPH_OFFSET_SET(iphdr, htons(tmp));
-
-    /* Fill this fragment */
-    nfb = (mtu - IP_HLEN) / 8;
-    cop = last ? left : nfb * 8;
-
-    p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);
-
-    /* Correct header */
-    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
-    IPH_CHKSUM_SET(iphdr, 0);
-    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
-
-    if (last)
-      pbuf_realloc(rambuf, left + IP_HLEN);
-    /* This part is ugly: we alloc a RAM based pbuf for 
-     * the link level header for each chunk and then 
-     * free it.A PBUF_ROM style pbuf for which pbuf_header
-     * worked would make things simpler.
-     */
-    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
-    if (header != NULL) {
-      pbuf_chain(header, rambuf);
-      netif->output(netif, header, dest);
-      IPFRAG_STATS_INC(ip_frag.xmit);
-      snmp_inc_ipfragcreates();
-      pbuf_free(header);
-    } else {
-      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
-      pbuf_free(rambuf);      
-      return ERR_MEM;    
-    }
-    left -= cop;
-  }
-  pbuf_free(rambuf);
-  snmp_inc_ipfragoks();
-  return ERR_OK;
-}
+/* @file\r
+ * \r
+ * This is the IP packet segmentation and reassembly implementation.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Jani Monoses <jani@iv.ro> \r
+ * original reassembly code by Adam Dunkels <adam@sics.se>\r
+ * \r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/ip_frag.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/stats.h"\r
+\r
+static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];\r
+static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8) + 1];\r
+static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,\r
+  0x0f, 0x07, 0x03, 0x01\r
+};\r
+static u16_t ip_reasslen;\r
+static u8_t ip_reassflags;\r
+#define IP_REASS_FLAG_LASTFRAG 0x01\r
+\r
+static u8_t ip_reasstmr;\r
+\r
+/*\r
+ * Copy len bytes from offset in pbuf to buffer \r
+ *\r
+ * helper used by both ip_reass and ip_frag\r
+ */\r
+static struct pbuf *\r
+copy_from_pbuf(struct pbuf *p, u16_t * offset,\r
+           u8_t * buffer, u16_t len)\r
+{\r
+  u16_t l;\r
+\r
+  p->payload = (u8_t *)p->payload + *offset;\r
+  p->len -= *offset;\r
+  while (len) {\r
+    l = len < p->len ? len : p->len;\r
+    memcpy(buffer, p->payload, l);\r
+    buffer += l;\r
+    len -= l;\r
+    if (len)\r
+      p = p->next;\r
+    else\r
+      *offset = l;\r
+  }\r
+  return p;\r
+}\r
+\r
+\r
+/**\r
+ * Initializes IP reassembly and fragmentation states.\r
+ */\r
+void\r
+ip_frag_init(void)\r
+{\r
+  ip_reasstmr = 0;\r
+  ip_reassflags = 0;\r
+  ip_reasslen = 0;\r
+  memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));\r
+}\r
+\r
+/**\r
+ * Reassembly timer base function\r
+ * for both NO_SYS == 0 and 1 (!).\r
+ *\r
+ * Should be called every 1000 msec.\r
+ */\r
+void\r
+ip_reass_tmr(void)\r
+{\r
+  if (ip_reasstmr > 0) {\r
+    ip_reasstmr--;\r
+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)ip_reasstmr));\r
+    if (ip_reasstmr == 0) {\r
+      /* reassembly timed out */\r
+      snmp_inc_ipreasmfails();\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Reassembles incoming IP fragments into an IP datagram.\r
+ *\r
+ * @param p points to a pbuf chain of the fragment\r
+ * @return NULL if reassembly is incomplete, ? otherwise\r
+ */\r
+struct pbuf *\r
+ip_reass(struct pbuf *p)\r
+{\r
+  struct pbuf *q;\r
+  struct ip_hdr *fraghdr, *iphdr;\r
+  u16_t offset, len;\r
+  u16_t i;\r
+\r
+  IPFRAG_STATS_INC(ip_frag.recv);\r
+  snmp_inc_ipreasmreqds();\r
+\r
+  iphdr = (struct ip_hdr *) ip_reassbuf;\r
+  fraghdr = (struct ip_hdr *) p->payload;\r
+  /* If ip_reasstmr is zero, no packet is present in the buffer, so we\r
+     write the IP header of the fragment into the reassembly\r
+     buffer. The timer is updated with the maximum age. */\r
+  if (ip_reasstmr == 0) {\r
+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));\r
+    memcpy(iphdr, fraghdr, IP_HLEN);\r
+    ip_reasstmr = IP_REASS_MAXAGE;\r
+    ip_reassflags = 0;\r
+    /* Clear the bitmap. */\r
+    memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));\r
+  }\r
+\r
+  /* Check if the incoming fragment matches the one currently present\r
+     in the reasembly buffer. If so, we proceed with copying the\r
+     fragment into the buffer. */\r
+  if (ip_addr_cmp(&iphdr->src, &fraghdr->src) &&\r
+      ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&\r
+      IPH_ID(iphdr) == IPH_ID(fraghdr)) {\r
+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",\r
+      ntohs(IPH_ID(fraghdr))));\r
+    IPFRAG_STATS_INC(ip_frag.cachehit);\r
+    /* Find out the offset in the reassembly buffer where we should\r
+       copy the fragment. */\r
+    len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;\r
+    offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;\r
+\r
+    /* If the offset or the offset + fragment length overflows the\r
+       reassembly buffer, we discard the entire packet. */\r
+    if ((offset > IP_REASS_BUFSIZE) || ((offset + len) > IP_REASS_BUFSIZE)) {\r
+      LWIP_DEBUGF(IP_REASS_DEBUG,\r
+       ("ip_reass: fragment outside of buffer (%"S16_F":%"S16_F"/%"S16_F").\n", offset,\r
+        offset + len, IP_REASS_BUFSIZE));\r
+      ip_reasstmr = 0;\r
+      snmp_inc_ipreasmfails();\r
+      goto nullreturn;\r
+    }\r
+\r
+    /* Copy the fragment into the reassembly buffer, at the right\r
+       offset. */\r
+    LWIP_DEBUGF(IP_REASS_DEBUG,\r
+     ("ip_reass: copying with offset %"S16_F" into %"S16_F":%"S16_F"\n", offset,\r
+      IP_HLEN + offset, IP_HLEN + offset + len));\r
+    i = IPH_HL(fraghdr) * 4;\r
+    copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);\r
+\r
+    /* Update the bitmap. */\r
+    if (offset / (8 * 8) == (offset + len) / (8 * 8)) {\r
+      LWIP_DEBUGF(IP_REASS_DEBUG,\r
+       ("ip_reass: updating single byte in bitmap.\n"));\r
+      /* If the two endpoints are in the same byte, we only update that byte. */\r
+      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",\r
+                   offset / (8 * 8) < sizeof(ip_reassbitmap));\r
+      ip_reassbitmap[offset / (8 * 8)] |=\r
+        bitmap_bits[(offset / 8) & 7] &\r
+        ~bitmap_bits[((offset + len) / 8) & 7];\r
+    } else {\r
+      /* If the two endpoints are in different bytes, we update the\r
+         bytes in the endpoints and fill the stuff inbetween with\r
+         0xff. */\r
+      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",\r
+                   offset / (8 * 8) < sizeof(ip_reassbitmap));\r
+      ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];\r
+      LWIP_DEBUGF(IP_REASS_DEBUG,\r
+       ("ip_reass: updating many bytes in bitmap (%"S16_F":%"S16_F").\n",\r
+        1 + offset / (8 * 8), (offset + len) / (8 * 8)));\r
+      for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {\r
+        ip_reassbitmap[i] = 0xff;\r
+      }\r
+      LWIP_ASSERT("(offset + len) / (8 * 8) < sizeof(ip_reassbitmap)",\r
+                   (offset + len) / (8 * 8) < sizeof(ip_reassbitmap));\r
+      ip_reassbitmap[(offset + len) / (8 * 8)] |=\r
+        ~bitmap_bits[((offset + len) / 8) & 7];\r
+    }\r
+\r
+    /* If this fragment has the More Fragments flag set to zero, we\r
+       know that this is the last fragment, so we can calculate the\r
+       size of the entire packet. We also set the\r
+       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received\r
+       the final fragment. */\r
+\r
+    if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {\r
+      ip_reassflags |= IP_REASS_FLAG_LASTFRAG;\r
+      ip_reasslen = offset + len;\r
+      LWIP_DEBUGF(IP_REASS_DEBUG,\r
+       ("ip_reass: last fragment seen, total len %"S16_F"\n",\r
+        ip_reasslen));\r
+    }\r
+\r
+    /* Finally, we check if we have a full packet in the buffer. We do\r
+       this by checking if we have the last fragment and if all bits\r
+       in the bitmap are set. */\r
+    if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {\r
+      /* Check all bytes up to and including all but the last byte in\r
+         the bitmap. */\r
+      LWIP_ASSERT("ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)",\r
+                   ip_reasslen / (8 * 8) - 1 < ((u16_t) sizeof(ip_reassbitmap)));\r
+      for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {\r
+        if (ip_reassbitmap[i] != 0xff) {\r
+          LWIP_DEBUGF(IP_REASS_DEBUG,\r
+           ("ip_reass: last fragment seen, bitmap %"S16_F"/%"S16_F" failed (%"X16_F")\n",\r
+            i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));\r
+          goto nullreturn;\r
+        }\r
+      }\r
+      /* Check the last byte in the bitmap. It should contain just the\r
+         right amount of bits. */\r
+      LWIP_ASSERT("ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)",\r
+                   ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap));\r
+      if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=\r
+        (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {\r
+         LWIP_DEBUGF(IP_REASS_DEBUG,\r
+          ("ip_reass: last fragment seen, bitmap %"S16_F" didn't contain %"X16_F" (%"X16_F")\n",\r
+        ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],\r
+        ip_reassbitmap[ip_reasslen / (8 * 8)]));\r
+        goto nullreturn;\r
+      }\r
+\r
+      /* Pretend to be a "normal" (i.e., not fragmented) IP packet\r
+         from now on. */\r
+      ip_reasslen += IP_HLEN;\r
+\r
+      IPH_LEN_SET(iphdr, htons(ip_reasslen));\r
+      IPH_OFFSET_SET(iphdr, 0);\r
+      IPH_CHKSUM_SET(iphdr, 0);\r
+      IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\r
+\r
+      /* If we have come this far, we have a full packet in the\r
+         buffer, so we allocate a pbuf and copy the packet into it. We\r
+         also reset the timer. */\r
+      ip_reasstmr = 0;\r
+      pbuf_free(p);\r
+      p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);\r
+      if (p != NULL) {\r
+        i = 0;\r
+        for (q = p; q != NULL; q = q->next) {\r
+          /* Copy enough bytes to fill this pbuf in the chain. The\r
+             available data in the pbuf is given by the q->len variable. */\r
+          LWIP_DEBUGF(IP_REASS_DEBUG,\r
+           ("ip_reass: memcpy from %p (%"S16_F") to %p, %"S16_F" bytes\n",\r
+            (void *)&ip_reassbuf[i], i, q->payload,\r
+            q->len > ip_reasslen - i ? ip_reasslen - i : q->len));\r
+          memcpy(q->payload, &ip_reassbuf[i],\r
+            q->len > ip_reasslen - i ? ip_reasslen - i : q->len);\r
+          i += q->len;\r
+        }\r
+        IPFRAG_STATS_INC(ip_frag.fw);\r
+        snmp_inc_ipreasmoks();\r
+      } else {\r
+        LWIP_DEBUGF(IP_REASS_DEBUG,\r
+          ("ip_reass: pbuf_alloc(PBUF_LINK, ip_reasslen=%"U16_F", PBUF_POOL) failed\n", ip_reasslen));\r
+        IPFRAG_STATS_INC(ip_frag.memerr);\r
+        snmp_inc_ipreasmfails();\r
+      }\r
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p));\r
+      return p;\r
+    }\r
+  }\r
+\r
+nullreturn:\r
+  IPFRAG_STATS_INC(ip_frag.drop);\r
+  pbuf_free(p);\r
+  return NULL;\r
+}\r
+\r
+static u8_t buf[MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];\r
+\r
+/**\r
+ * Fragment an IP datagram if too large for the netif.\r
+ *\r
+ * Chop the datagram in MTU sized chunks and send them in order\r
+ * by using a fixed size static memory buffer (PBUF_ROM)\r
+ */\r
+err_t \r
+ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)\r
+{\r
+  struct pbuf *rambuf;\r
+  struct pbuf *header;\r
+  struct ip_hdr *iphdr;\r
+  u16_t nfb = 0;\r
+  u16_t left, cop;\r
+  u16_t mtu = netif->mtu;\r
+  u16_t ofo, omf;\r
+  u16_t last;\r
+  u16_t poff = IP_HLEN;\r
+  u16_t tmp;\r
+\r
+  /* Get a RAM based MTU sized pbuf */\r
+  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);\r
+  if (rambuf == NULL) {\r
+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));\r
+    return ERR_MEM;\r
+  }\r
+  rambuf->tot_len = rambuf->len = mtu;\r
+  rambuf->payload = MEM_ALIGN((void *)buf);\r
+\r
+  /* Copy the IP header in it */\r
+  iphdr = rambuf->payload;\r
+  memcpy(iphdr, p->payload, IP_HLEN);\r
+\r
+  /* Save original offset */\r
+  tmp = ntohs(IPH_OFFSET(iphdr));\r
+  ofo = tmp & IP_OFFMASK;\r
+  omf = tmp & IP_MF;\r
+\r
+  left = p->tot_len - IP_HLEN;\r
+\r
+  while (left) {\r
+    last = (left <= mtu - IP_HLEN);\r
+\r
+    /* Set new offset and MF flag */\r
+    ofo += nfb;\r
+    tmp = omf | (IP_OFFMASK & (ofo));\r
+    if (!last)\r
+      tmp = tmp | IP_MF;\r
+    IPH_OFFSET_SET(iphdr, htons(tmp));\r
+\r
+    /* Fill this fragment */\r
+    nfb = (mtu - IP_HLEN) / 8;\r
+    cop = last ? left : nfb * 8;\r
+\r
+    p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);\r
+\r
+    /* Correct header */\r
+    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));\r
+    IPH_CHKSUM_SET(iphdr, 0);\r
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\r
+\r
+    if (last)\r
+      pbuf_realloc(rambuf, left + IP_HLEN);\r
+    /* This part is ugly: we alloc a RAM based pbuf for \r
+     * the link level header for each chunk and then \r
+     * free it.A PBUF_ROM style pbuf for which pbuf_header\r
+     * worked would make things simpler.\r
+     */\r
+    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);\r
+    if (header != NULL) {\r
+      pbuf_chain(header, rambuf);\r
+      netif->output(netif, header, dest);\r
+      IPFRAG_STATS_INC(ip_frag.xmit);\r
+      snmp_inc_ipfragcreates();\r
+      pbuf_free(header);\r
+    } else {\r
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));\r
+      pbuf_free(rambuf);      \r
+      return ERR_MEM;    \r
+    }\r
+    left -= cop;\r
+  }\r
+  pbuf_free(rambuf);\r
+  snmp_inc_ipfragoks();\r
+  return ERR_OK;\r
+}\r
index 6ef311d698bbf197780c55b031c27905f8ed848f..4d4cb1d6a83a483fc4756da1ad9063ae283c4c38 100644 (file)
-/** @file
- *
- * Dynamic memory manager
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include <string.h>
-
-#include "lwip/arch.h"
-#include "lwip/opt.h"
-#include "lwip/def.h"
-#include "lwip/mem.h"
-
-#include "lwip/sys.h"
-
-#include "lwip/stats.h"
-
-#if (MEM_LIBC_MALLOC == 0)
-/* lwIP replacement for your libc malloc() */
-
-struct mem {
-  mem_size_t next, prev;
-#if MEM_ALIGNMENT == 1
-  u8_t used;
-#elif MEM_ALIGNMENT == 2
-  u16_t used;
-#elif MEM_ALIGNMENT == 4
-  u32_t used;
-#elif MEM_ALIGNMENT == 8
-  u64_t used;
-#else
-#error "unhandled MEM_ALIGNMENT size"
-#endif /* MEM_ALIGNMENT */
-};
-
-static struct mem *ram_end;
-#if 1
-/* Adam original */
-static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT];
-#else
-/* Christiaan alignment fix */
-static u8_t *ram;
-static struct mem ram_heap[1 + ( (MEM_SIZE + sizeof(struct mem) - 1) / sizeof(struct mem))];
-#endif
-
-#define MIN_SIZE 12
-#if 0 /* this one does not align correctly for some, resulting in crashes */
-#define SIZEOF_STRUCT_MEM (unsigned int)MEM_ALIGN_SIZE(sizeof(struct mem))
-#else
-#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \
-                          (((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \
-                          (4 - (sizeof(struct mem) % MEM_ALIGNMENT))))
-#endif
-
-static struct mem *lfree;   /* pointer to the lowest free block */
-
-static sys_sem_t mem_sem;
-
-static void
-plug_holes(struct mem *mem)
-{
-  struct mem *nmem;
-  struct mem *pmem;
-
-  LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
-  LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
-  LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
-
-  /* plug hole forward */
-  LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE", mem->next <= MEM_SIZE);
-
-  nmem = (struct mem *)&ram[mem->next];
-  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
-    if (lfree == nmem) {
-      lfree = mem;
-    }
-    mem->next = nmem->next;
-    ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
-  }
-
-  /* plug hole backward */
-  pmem = (struct mem *)&ram[mem->prev];
-  if (pmem != mem && pmem->used == 0) {
-    if (lfree == mem) {
-      lfree = pmem;
-    }
-    pmem->next = mem->next;
-    ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
-  }
-}
-
-void
-mem_init(void)
-{
-  struct mem *mem;
-
-#if 1
-  /* Adam original */
-#else
-  /* Christiaan alignment fix */
-  ram = (u8_t*)ram_heap;
-#endif
-  memset(ram, 0, MEM_SIZE);
-  mem = (struct mem *)ram;
-  mem->next = MEM_SIZE;
-  mem->prev = 0;
-  mem->used = 0;
-  ram_end = (struct mem *)&ram[MEM_SIZE];
-  ram_end->used = 1;
-  ram_end->next = MEM_SIZE;
-  ram_end->prev = MEM_SIZE;
-
-  mem_sem = sys_sem_new(1);
-
-  lfree = (struct mem *)ram;
-
-#if MEM_STATS
-  lwip_stats.mem.avail = MEM_SIZE;
-#endif /* MEM_STATS */
-}
-
-void
-mem_free(void *rmem)
-{
-  struct mem *mem;
-
-  if (rmem == NULL) {
-    LWIP_DEBUGF(MEM_DEBUG | DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
-    return;
-  }
-
-  sys_sem_wait(mem_sem);
-
-  LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
-    (u8_t *)rmem < (u8_t *)ram_end);
-
-  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
-    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
-#if MEM_STATS
-    ++lwip_stats.mem.err;
-#endif /* MEM_STATS */
-    sys_sem_signal(mem_sem);
-    return;
-  }
-  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
-
-  LWIP_ASSERT("mem_free: mem->used", mem->used);
-
-  mem->used = 0;
-
-  if (mem < lfree) {
-    lfree = mem;
-  }
-
-#if MEM_STATS
-  lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);
-
-#endif /* MEM_STATS */
-  plug_holes(mem);
-  sys_sem_signal(mem_sem);
-}
-
-void *
-mem_realloc(void *rmem, mem_size_t newsize)
-{
-  mem_size_t size;
-  mem_size_t ptr, ptr2;
-  struct mem *mem, *mem2;
-
-  /* Expand the size of the allocated memory region so that we can
-     adjust for alignment. */
-  if ((newsize % MEM_ALIGNMENT) != 0) {
-   newsize += MEM_ALIGNMENT - ((newsize + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
-  }
-
-  if (newsize > MEM_SIZE) {
-    return NULL;
-  }
-
-  sys_sem_wait(mem_sem);
-
-  LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
-   (u8_t *)rmem < (u8_t *)ram_end);
-
-  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
-    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
-    return rmem;
-  }
-  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
-
-  ptr = (u8_t *)mem - ram;
-
-  size = mem->next - ptr - SIZEOF_STRUCT_MEM;
-#if MEM_STATS
-  lwip_stats.mem.used -= (size - newsize);
-#endif /* MEM_STATS */
-
-  if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) {
-    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
-    mem2 = (struct mem *)&ram[ptr2];
-    mem2->used = 0;
-    mem2->next = mem->next;
-    mem2->prev = ptr;
-    mem->next = ptr2;
-    if (mem2->next != MEM_SIZE) {
-      ((struct mem *)&ram[mem2->next])->prev = ptr2;
-    }
-
-    plug_holes(mem2);
-  }
-  sys_sem_signal(mem_sem);
-  return rmem;
-}
-
-#if 1
-/**
- * Adam's mem_malloc(), suffers from bug #17922
- * Set if to 0 for alternative mem_malloc().
- */
-void *
-mem_malloc(mem_size_t size)
-{
-  mem_size_t ptr, ptr2;
-  struct mem *mem, *mem2;
-
-  if (size == 0) {
-    return NULL;
-  }
-
-  /* Expand the size of the allocated memory region so that we can
-     adjust for alignment. */
-  if ((size % MEM_ALIGNMENT) != 0) {
-    size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
-  }
-
-  if (size > MEM_SIZE) {
-    return NULL;
-  }
-
-  sys_sem_wait(mem_sem);
-
-  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE; ptr = ((struct mem *)&ram[ptr])->next) {
-    mem = (struct mem *)&ram[ptr];
-    if (!mem->used &&
-       mem->next - (ptr + SIZEOF_STRUCT_MEM) >= size + SIZEOF_STRUCT_MEM) {
-      ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
-      mem2 = (struct mem *)&ram[ptr2];
-
-      mem2->prev = ptr;
-      mem2->next = mem->next;
-      mem->next = ptr2;
-      if (mem2->next != MEM_SIZE) {
-        ((struct mem *)&ram[mem2->next])->prev = ptr2;
-      }
-
-      mem2->used = 0;
-      mem->used = 1;
-#if MEM_STATS
-      lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);
-      /*      if (lwip_stats.mem.max < lwip_stats.mem.used) {
-        lwip_stats.mem.max = lwip_stats.mem.used;
-        } */
-      if (lwip_stats.mem.max < ptr2) {
-        lwip_stats.mem.max = ptr2;
-      }
-#endif /* MEM_STATS */
-
-      if (mem == lfree) {
-        /* Find next free block after mem */
-        while (lfree->used && lfree != ram_end) {
-          lfree = (struct mem *)&ram[lfree->next];
-        }
-        LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);
-      }
-      sys_sem_signal(mem_sem);
-      LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
-       (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
-      LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
-       (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
-      return (u8_t *)mem + SIZEOF_STRUCT_MEM;
-    }
-  }
-  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
-#if MEM_STATS
-  ++lwip_stats.mem.err;
-#endif /* MEM_STATS */
-  sys_sem_signal(mem_sem);
-  return NULL;
-}
-#else
-/**
- * Adam's mem_malloc() plus solution for bug #17922
- */
-void *
-mem_malloc(mem_size_t size)
-{
-  mem_size_t ptr, ptr2;
-  struct mem *mem, *mem2;
-
-  if (size == 0) {
-    return NULL;
-  }
-
-  /* Expand the size of the allocated memory region so that we can
-     adjust for alignment. */
-  if ((size % MEM_ALIGNMENT) != 0) {
-    size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
-  }
-
-  if (size > MEM_SIZE) {
-    return NULL;
-  }
-
-  sys_sem_wait(mem_sem);
-
-  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE - size; ptr = ((struct mem *)&ram[ptr])->next) {
-    mem = (struct mem *)&ram[ptr];
-
-    if (!mem->used) {
-
-      ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
-
-      if (mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) >= size) {
-        /* split large block, create empty remainder */
-        mem->next = ptr2;
-        mem->used = 1;
-        /* create mem2 struct */
-        mem2 = (struct mem *)&ram[ptr2];
-        mem2->used = 0;
-        mem2->next = mem->next;
-        mem2->prev = ptr;
-
-        if (mem2->next != MEM_SIZE) {
-          ((struct mem *)&ram[mem2->next])->prev = ptr2;
-        }
-      }
-      else if (mem->next - (ptr + SIZEOF_STRUCT_MEM) > size) {
-        /* near fit, no split, no mem2 creation,
-           round up to mem->next */
-        ptr2 = mem->next;
-        mem->used = 1;
-      }
-      else if (mem->next - (ptr + SIZEOF_STRUCT_MEM) == size) {
-        /* exact fit, do not split, no mem2 creation */
-        mem->next = ptr2;
-        mem->used = 1;
-      }
-
-      if (mem->used) {
-#if MEM_STATS
-        lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);
-        if (lwip_stats.mem.max < ptr2) {
-          lwip_stats.mem.max = ptr2;
-        }
-#endif /* MEM_STATS */
-        if (mem == lfree) {
-          /* Find next free block after mem */
-          while (lfree->used && lfree != ram_end) {
-            lfree = (struct mem *)&ram[lfree->next];
-          }
-          LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);
-        }
-        sys_sem_signal(mem_sem);
-        LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
-         (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
-        LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
-         (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
-        return (u8_t *)mem + SIZEOF_STRUCT_MEM;
-      }
-    }
-  }
-  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
-#if MEM_STATS
-  ++lwip_stats.mem.err;
-#endif /* MEM_STATS */
-  sys_sem_signal(mem_sem);
-  return NULL;
-}
-#endif
-
-#endif /* MEM_LIBC_MALLOC == 0 */
-
+/** @file\r
+ *\r
+ * Dynamic memory manager\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/arch.h"\r
+#include "lwip/opt.h"\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+\r
+#include "lwip/sys.h"\r
+\r
+#include "lwip/stats.h"\r
+\r
+#if (MEM_LIBC_MALLOC == 0)\r
+/* lwIP replacement for your libc malloc() */\r
+\r
+struct mem {\r
+  mem_size_t next, prev;\r
+#if MEM_ALIGNMENT == 1\r
+  u8_t used;\r
+#elif MEM_ALIGNMENT == 2\r
+  u16_t used;\r
+#elif MEM_ALIGNMENT == 4\r
+  u32_t used;\r
+#elif MEM_ALIGNMENT == 8\r
+  u64_t used;\r
+#else\r
+#error "unhandled MEM_ALIGNMENT size"\r
+#endif /* MEM_ALIGNMENT */\r
+};\r
+\r
+static struct mem *ram_end;\r
+#if 1\r
+/* Adam original */\r
+static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT];\r
+#else\r
+/* Christiaan alignment fix */\r
+static u8_t *ram;\r
+static struct mem ram_heap[1 + ( (MEM_SIZE + sizeof(struct mem) - 1) / sizeof(struct mem))];\r
+#endif\r
+\r
+#define MIN_SIZE 12\r
+#if 0 /* this one does not align correctly for some, resulting in crashes */\r
+#define SIZEOF_STRUCT_MEM (unsigned int)MEM_ALIGN_SIZE(sizeof(struct mem))\r
+#else\r
+#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \\r
+                          (((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \\r
+                          (4 - (sizeof(struct mem) % MEM_ALIGNMENT))))\r
+#endif\r
+\r
+static struct mem *lfree;   /* pointer to the lowest free block */\r
+\r
+static sys_sem_t mem_sem;\r
+\r
+static void\r
+plug_holes(struct mem *mem)\r
+{\r
+  struct mem *nmem;\r
+  struct mem *pmem;\r
+\r
+  LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);\r
+  LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);\r
+  LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);\r
+\r
+  /* plug hole forward */\r
+  LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE", mem->next <= MEM_SIZE);\r
+\r
+  nmem = (struct mem *)&ram[mem->next];\r
+  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {\r
+    if (lfree == nmem) {\r
+      lfree = mem;\r
+    }\r
+    mem->next = nmem->next;\r
+    ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;\r
+  }\r
+\r
+  /* plug hole backward */\r
+  pmem = (struct mem *)&ram[mem->prev];\r
+  if (pmem != mem && pmem->used == 0) {\r
+    if (lfree == mem) {\r
+      lfree = pmem;\r
+    }\r
+    pmem->next = mem->next;\r
+    ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;\r
+  }\r
+}\r
+\r
+void\r
+mem_init(void)\r
+{\r
+  struct mem *mem;\r
+\r
+#if 1\r
+  /* Adam original */\r
+#else\r
+  /* Christiaan alignment fix */\r
+  ram = (u8_t*)ram_heap;\r
+#endif\r
+  memset(ram, 0, MEM_SIZE);\r
+  mem = (struct mem *)ram;\r
+  mem->next = MEM_SIZE;\r
+  mem->prev = 0;\r
+  mem->used = 0;\r
+  ram_end = (struct mem *)&ram[MEM_SIZE];\r
+  ram_end->used = 1;\r
+  ram_end->next = MEM_SIZE;\r
+  ram_end->prev = MEM_SIZE;\r
+\r
+  mem_sem = sys_sem_new(1);\r
+\r
+  lfree = (struct mem *)ram;\r
+\r
+#if MEM_STATS\r
+  lwip_stats.mem.avail = MEM_SIZE;\r
+#endif /* MEM_STATS */\r
+}\r
+\r
+void\r
+mem_free(void *rmem)\r
+{\r
+  struct mem *mem;\r
+\r
+  if (rmem == NULL) {\r
+    LWIP_DEBUGF(MEM_DEBUG | DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));\r
+    return;\r
+  }\r
+\r
+  sys_sem_wait(mem_sem);\r
+\r
+  LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&\r
+    (u8_t *)rmem < (u8_t *)ram_end);\r
+\r
+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {\r
+    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));\r
+#if MEM_STATS\r
+    ++lwip_stats.mem.err;\r
+#endif /* MEM_STATS */\r
+    sys_sem_signal(mem_sem);\r
+    return;\r
+  }\r
+  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);\r
+\r
+  LWIP_ASSERT("mem_free: mem->used", mem->used);\r
+\r
+  mem->used = 0;\r
+\r
+  if (mem < lfree) {\r
+    lfree = mem;\r
+  }\r
+\r
+#if MEM_STATS\r
+  lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);\r
+\r
+#endif /* MEM_STATS */\r
+  plug_holes(mem);\r
+  sys_sem_signal(mem_sem);\r
+}\r
+\r
+void *\r
+mem_realloc(void *rmem, mem_size_t newsize)\r
+{\r
+  mem_size_t size;\r
+  mem_size_t ptr, ptr2;\r
+  struct mem *mem, *mem2;\r
+\r
+  /* Expand the size of the allocated memory region so that we can\r
+     adjust for alignment. */\r
+  if ((newsize % MEM_ALIGNMENT) != 0) {\r
+   newsize += MEM_ALIGNMENT - ((newsize + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);\r
+  }\r
+\r
+  if (newsize > MEM_SIZE) {\r
+    return NULL;\r
+  }\r
+\r
+  sys_sem_wait(mem_sem);\r
+\r
+  LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&\r
+   (u8_t *)rmem < (u8_t *)ram_end);\r
+\r
+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {\r
+    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));\r
+    return rmem;\r
+  }\r
+  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);\r
+\r
+  ptr = (u8_t *)mem - ram;\r
+\r
+  size = mem->next - ptr - SIZEOF_STRUCT_MEM;\r
+#if MEM_STATS\r
+  lwip_stats.mem.used -= (size - newsize);\r
+#endif /* MEM_STATS */\r
+\r
+  if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) {\r
+    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;\r
+    mem2 = (struct mem *)&ram[ptr2];\r
+    mem2->used = 0;\r
+    mem2->next = mem->next;\r
+    mem2->prev = ptr;\r
+    mem->next = ptr2;\r
+    if (mem2->next != MEM_SIZE) {\r
+      ((struct mem *)&ram[mem2->next])->prev = ptr2;\r
+    }\r
+\r
+    plug_holes(mem2);\r
+  }\r
+  sys_sem_signal(mem_sem);\r
+  return rmem;\r
+}\r
+\r
+#if 1\r
+/**\r
+ * Adam's mem_malloc(), suffers from bug #17922\r
+ * Set if to 0 for alternative mem_malloc().\r
+ */\r
+void *\r
+mem_malloc(mem_size_t size)\r
+{\r
+  mem_size_t ptr, ptr2;\r
+  struct mem *mem, *mem2;\r
+\r
+  if (size == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  /* Expand the size of the allocated memory region so that we can\r
+     adjust for alignment. */\r
+  if ((size % MEM_ALIGNMENT) != 0) {\r
+    size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);\r
+  }\r
+\r
+  if (size > MEM_SIZE) {\r
+    return NULL;\r
+  }\r
+\r
+  sys_sem_wait(mem_sem);\r
+\r
+  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE; ptr = ((struct mem *)&ram[ptr])->next) {\r
+    mem = (struct mem *)&ram[ptr];\r
+    if (!mem->used &&\r
+       mem->next - (ptr + SIZEOF_STRUCT_MEM) >= size + SIZEOF_STRUCT_MEM) {\r
+      ptr2 = ptr + SIZEOF_STRUCT_MEM + size;\r
+      mem2 = (struct mem *)&ram[ptr2];\r
+\r
+      mem2->prev = ptr;\r
+      mem2->next = mem->next;\r
+      mem->next = ptr2;\r
+      if (mem2->next != MEM_SIZE) {\r
+        ((struct mem *)&ram[mem2->next])->prev = ptr2;\r
+      }\r
+\r
+      mem2->used = 0;\r
+      mem->used = 1;\r
+#if MEM_STATS\r
+      lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);\r
+      /*      if (lwip_stats.mem.max < lwip_stats.mem.used) {\r
+        lwip_stats.mem.max = lwip_stats.mem.used;\r
+        } */\r
+      if (lwip_stats.mem.max < ptr2) {\r
+        lwip_stats.mem.max = ptr2;\r
+      }\r
+#endif /* MEM_STATS */\r
+\r
+      if (mem == lfree) {\r
+        /* Find next free block after mem */\r
+        while (lfree->used && lfree != ram_end) {\r
+          lfree = (struct mem *)&ram[lfree->next];\r
+        }\r
+        LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);\r
+      }\r
+      sys_sem_signal(mem_sem);\r
+      LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",\r
+       (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);\r
+      LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",\r
+       (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);\r
+      return (u8_t *)mem + SIZEOF_STRUCT_MEM;\r
+    }\r
+  }\r
+  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));\r
+#if MEM_STATS\r
+  ++lwip_stats.mem.err;\r
+#endif /* MEM_STATS */\r
+  sys_sem_signal(mem_sem);\r
+  return NULL;\r
+}\r
+#else\r
+/**\r
+ * Adam's mem_malloc() plus solution for bug #17922\r
+ */\r
+void *\r
+mem_malloc(mem_size_t size)\r
+{\r
+  mem_size_t ptr, ptr2;\r
+  struct mem *mem, *mem2;\r
+\r
+  if (size == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  /* Expand the size of the allocated memory region so that we can\r
+     adjust for alignment. */\r
+  if ((size % MEM_ALIGNMENT) != 0) {\r
+    size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);\r
+  }\r
+\r
+  if (size > MEM_SIZE) {\r
+    return NULL;\r
+  }\r
+\r
+  sys_sem_wait(mem_sem);\r
+\r
+  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE - size; ptr = ((struct mem *)&ram[ptr])->next) {\r
+    mem = (struct mem *)&ram[ptr];\r
+\r
+    if (!mem->used) {\r
+\r
+      ptr2 = ptr + SIZEOF_STRUCT_MEM + size;\r
+\r
+      if (mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) >= size) {\r
+        /* split large block, create empty remainder */\r
+        mem->next = ptr2;\r
+        mem->used = 1;\r
+        /* create mem2 struct */\r
+        mem2 = (struct mem *)&ram[ptr2];\r
+        mem2->used = 0;\r
+        mem2->next = mem->next;\r
+        mem2->prev = ptr;\r
+\r
+        if (mem2->next != MEM_SIZE) {\r
+          ((struct mem *)&ram[mem2->next])->prev = ptr2;\r
+        }\r
+      }\r
+      else if (mem->next - (ptr + SIZEOF_STRUCT_MEM) > size) {\r
+        /* near fit, no split, no mem2 creation,\r
+           round up to mem->next */\r
+        ptr2 = mem->next;\r
+        mem->used = 1;\r
+      }\r
+      else if (mem->next - (ptr + SIZEOF_STRUCT_MEM) == size) {\r
+        /* exact fit, do not split, no mem2 creation */\r
+        mem->next = ptr2;\r
+        mem->used = 1;\r
+      }\r
+\r
+      if (mem->used) {\r
+#if MEM_STATS\r
+        lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);\r
+        if (lwip_stats.mem.max < ptr2) {\r
+          lwip_stats.mem.max = ptr2;\r
+        }\r
+#endif /* MEM_STATS */\r
+        if (mem == lfree) {\r
+          /* Find next free block after mem */\r
+          while (lfree->used && lfree != ram_end) {\r
+            lfree = (struct mem *)&ram[lfree->next];\r
+          }\r
+          LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);\r
+        }\r
+        sys_sem_signal(mem_sem);\r
+        LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",\r
+         (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);\r
+        LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",\r
+         (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);\r
+        return (u8_t *)mem + SIZEOF_STRUCT_MEM;\r
+      }\r
+    }\r
+  }\r
+  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));\r
+#if MEM_STATS\r
+  ++lwip_stats.mem.err;\r
+#endif /* MEM_STATS */\r
+  sys_sem_signal(mem_sem);\r
+  return NULL;\r
+}\r
+#endif\r
+\r
+#endif /* MEM_LIBC_MALLOC == 0 */\r
+\r
index b31812d7089b51a4c5be3941572f9a9a65a5eac7..3912009573d0b8ea93be88b98202243823bf3773 100644 (file)
-/*
- * 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 */  
-}
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/memp.h"\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/raw.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/api.h"\r
+#include "lwip/api_msg.h"\r
+#include "lwip/tcpip.h"\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/stats.h"\r
+\r
+struct memp {\r
+  struct memp *next;\r
+};\r
+\r
+#define MEMP_SIZE MEM_ALIGN_SIZE(sizeof(struct memp))\r
+\r
+static struct memp *memp_tab[MEMP_MAX];\r
+\r
+static const u16_t memp_sizes[MEMP_MAX] = {\r
+  MEM_ALIGN_SIZE(sizeof(struct pbuf)),\r
+  MEM_ALIGN_SIZE(sizeof(struct raw_pcb)),\r
+  MEM_ALIGN_SIZE(sizeof(struct udp_pcb)),\r
+  MEM_ALIGN_SIZE(sizeof(struct tcp_pcb)),\r
+  MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen)),\r
+  MEM_ALIGN_SIZE(sizeof(struct tcp_seg)),\r
+  MEM_ALIGN_SIZE(sizeof(struct netbuf)),\r
+  MEM_ALIGN_SIZE(sizeof(struct netconn)),\r
+  MEM_ALIGN_SIZE(sizeof(struct api_msg)),\r
+  MEM_ALIGN_SIZE(sizeof(struct tcpip_msg)),\r
+  MEM_ALIGN_SIZE(sizeof(struct sys_timeo))\r
+};\r
+\r
+static const u16_t memp_num[MEMP_MAX] = {\r
+  MEMP_NUM_PBUF,\r
+  MEMP_NUM_RAW_PCB,\r
+  MEMP_NUM_UDP_PCB,\r
+  MEMP_NUM_TCP_PCB,\r
+  MEMP_NUM_TCP_PCB_LISTEN,\r
+  MEMP_NUM_TCP_SEG,\r
+  MEMP_NUM_NETBUF,\r
+  MEMP_NUM_NETCONN,\r
+  MEMP_NUM_API_MSG,\r
+  MEMP_NUM_TCPIP_MSG,\r
+  MEMP_NUM_SYS_TIMEOUT\r
+};\r
+\r
+#define MEMP_TYPE_SIZE(qty, type) \\r
+  ((qty) * (MEMP_SIZE + MEM_ALIGN_SIZE(sizeof(type))))\r
+\r
+static u8_t memp_memory[MEM_ALIGNMENT - 1 + \r
+  MEMP_TYPE_SIZE(MEMP_NUM_PBUF, struct pbuf) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_RAW_PCB, struct raw_pcb) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_UDP_PCB, struct udp_pcb) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_TCP_PCB, struct tcp_pcb) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_TCP_PCB_LISTEN, struct tcp_pcb_listen) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_TCP_SEG, struct tcp_seg) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_NETBUF, struct netbuf) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_NETCONN, struct netconn) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_API_MSG, struct api_msg) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_TCPIP_MSG, struct tcpip_msg) +\r
+  MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)];\r
+\r
+#if !SYS_LIGHTWEIGHT_PROT\r
+static sys_sem_t mutex;\r
+#endif\r
+\r
+#if MEMP_SANITY_CHECK\r
+static int\r
+memp_sanity(void)\r
+{\r
+  s16_t i, c;\r
+  struct memp *m, *n;\r
+\r
+  for (i = 0; i < MEMP_MAX; i++) {\r
+    for (m = memp_tab[i]; m != NULL; m = m->next) {\r
+      c = 1;\r
+      for (n = memp_tab[i]; n != NULL; n = n->next) {\r
+        if (n == m && --c < 0) {\r
+          return 0; /* LW was: abort(); */\r
+        }\r
+      }\r
+    }\r
+  }\r
+  return 1;\r
+}\r
+#endif /* MEMP_SANITY_CHECK*/\r
+\r
+void\r
+memp_init(void)\r
+{\r
+  struct memp *memp;\r
+  u16_t i, j;\r
+\r
+#if MEMP_STATS\r
+  for (i = 0; i < MEMP_MAX; ++i) {\r
+    lwip_stats.memp[i].used = lwip_stats.memp[i].max =\r
+      lwip_stats.memp[i].err = 0;\r
+    lwip_stats.memp[i].avail = memp_num[i];\r
+  }\r
+#endif /* MEMP_STATS */\r
+\r
+  memp = MEM_ALIGN(memp_memory);\r
+  for (i = 0; i < MEMP_MAX; ++i) {\r
+    memp_tab[i] = NULL;\r
+    for (j = 0; j < memp_num[i]; ++j) {\r
+      memp->next = memp_tab[i];\r
+      memp_tab[i] = memp;\r
+      memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);\r
+    }\r
+  }\r
+\r
+#if !SYS_LIGHTWEIGHT_PROT\r
+  mutex = sys_sem_new(1);\r
+#endif\r
+}\r
+\r
+void *\r
+memp_malloc(memp_t type)\r
+{\r
+  struct memp *memp;\r
+  void *mem;\r
+#if SYS_LIGHTWEIGHT_PROT\r
+  SYS_ARCH_DECL_PROTECT(old_level);\r
+#endif\r
\r
+  LWIP_ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX);\r
+\r
+#if SYS_LIGHTWEIGHT_PROT\r
+  SYS_ARCH_PROTECT(old_level);\r
+#else /* SYS_LIGHTWEIGHT_PROT */  \r
+  sys_sem_wait(mutex);\r
+#endif /* SYS_LIGHTWEIGHT_PROT */  \r
+\r
+  memp = memp_tab[type];\r
+  \r
+  if (memp != NULL) {    \r
+    memp_tab[type] = memp->next;    \r
+    memp->next = NULL;\r
+#if MEMP_STATS\r
+    ++lwip_stats.memp[type].used;\r
+    if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {\r
+      lwip_stats.memp[type].max = lwip_stats.memp[type].used;\r
+    }\r
+#endif /* MEMP_STATS */\r
+    mem = (u8_t *)memp + MEMP_SIZE;\r
+    LWIP_ASSERT("memp_malloc: memp properly aligned",\r
+                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);\r
+  } else {\r
+    LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %"S16_F"\n", type));\r
+#if MEMP_STATS\r
+    ++lwip_stats.memp[type].err;\r
+#endif /* MEMP_STATS */\r
+    mem = NULL;\r
+  }\r
+\r
+#if SYS_LIGHTWEIGHT_PROT\r
+  SYS_ARCH_UNPROTECT(old_level);\r
+#else /* SYS_LIGHTWEIGHT_PROT */\r
+  sys_sem_signal(mutex);\r
+#endif /* SYS_LIGHTWEIGHT_PROT */  \r
+\r
+  return mem;\r
+}\r
+\r
+void\r
+memp_free(memp_t type, void *mem)\r
+{\r
+  struct memp *memp;\r
+#if SYS_LIGHTWEIGHT_PROT\r
+  SYS_ARCH_DECL_PROTECT(old_level);\r
+#endif /* SYS_LIGHTWEIGHT_PROT */  \r
+\r
+  if (mem == NULL) {\r
+    return;\r
+  }\r
+\r
+  memp = (struct memp *)((u8_t *)mem - MEMP_SIZE);\r
+\r
+#if SYS_LIGHTWEIGHT_PROT\r
+  SYS_ARCH_PROTECT(old_level);\r
+#else /* SYS_LIGHTWEIGHT_PROT */  \r
+  sys_sem_wait(mutex);\r
+#endif /* SYS_LIGHTWEIGHT_PROT */  \r
+\r
+#if MEMP_STATS\r
+  lwip_stats.memp[type].used--; \r
+#endif /* MEMP_STATS */\r
+  \r
+  memp->next = memp_tab[type]; \r
+  memp_tab[type] = memp;\r
+\r
+#if MEMP_SANITY_CHECK\r
+  LWIP_ASSERT("memp sanity", memp_sanity());\r
+#endif  \r
+\r
+#if SYS_LIGHTWEIGHT_PROT\r
+  SYS_ARCH_UNPROTECT(old_level);\r
+#else /* SYS_LIGHTWEIGHT_PROT */\r
+  sys_sem_signal(mutex);\r
+#endif /* SYS_LIGHTWEIGHT_PROT */  \r
+}\r
index b1e2bc187acbf182bd0c3a482f4ccda7b8dfb7ae..0a7866167e7452cfd32d09595c954d7fd6bd2bb9 100644 (file)
-/**
- * @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;
-}
-
+/**\r
+ * @file\r
+ *\r
+ * lwIP network interface abstraction\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/snmp.h"\r
+\r
+struct netif *netif_list = NULL;\r
+struct netif *netif_default = NULL;\r
+\r
+/**\r
+ * Add a network interface to the list of lwIP netifs.\r
+ *\r
+ * @param netif a pre-allocated netif structure\r
+ * @param ipaddr IP address for the new netif\r
+ * @param netmask network mask for the new netif\r
+ * @param gw default gateway IP address for the new netif\r
+ * @param state opaque data passed to the new netif\r
+ * @param init callback function that initializes the interface\r
+ * @param input callback function that is called to pass\r
+ * ingress packets up in the protocol layer stack.\r
+ *\r
+ * @return netif, or NULL if failed.\r
+ */\r
+struct netif *\r
+netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,\r
+  struct ip_addr *gw,\r
+  void *state,\r
+  err_t (* init)(struct netif *netif),\r
+  err_t (* input)(struct pbuf *p, struct netif *netif))\r
+{\r
+  static s16_t netifnum = 0;\r
+\r
+  /* reset new interface configuration state */\r
+  netif->ip_addr.addr = 0;\r
+  netif->netmask.addr = 0;\r
+  netif->gw.addr = 0;\r
+  netif->flags = 0;\r
+#if LWIP_DHCP\r
+  /* netif not under DHCP control by default */\r
+  netif->dhcp = NULL;\r
+#endif\r
+  /* remember netif specific state information data */\r
+  netif->state = state;\r
+  netif->num = netifnum++;\r
+  netif->input = input;\r
+\r
+  netif_set_addr(netif, ipaddr, netmask, gw);\r
+\r
+  /* call user specified initialization function for netif */\r
+  if (init(netif) != ERR_OK) {\r
+    return NULL;\r
+  }\r
+\r
+  /* add this netif to the list */\r
+  netif->next = netif_list;\r
+  netif_list = netif;\r
+  snmp_inc_iflist();\r
+\r
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",\r
+    netif->name[0], netif->name[1]));\r
+  ip_addr_debug_print(NETIF_DEBUG, ipaddr);\r
+  LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));\r
+  ip_addr_debug_print(NETIF_DEBUG, netmask);\r
+  LWIP_DEBUGF(NETIF_DEBUG, (" gw "));\r
+  ip_addr_debug_print(NETIF_DEBUG, gw);\r
+  LWIP_DEBUGF(NETIF_DEBUG, ("\n"));\r
+  return netif;\r
+}\r
+\r
+void\r
+netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,\r
+    struct ip_addr *gw)\r
+{\r
+  netif_set_ipaddr(netif, ipaddr);\r
+  netif_set_netmask(netif, netmask);\r
+  netif_set_gw(netif, gw);\r
+}\r
+\r
+void netif_remove(struct netif * netif)\r
+{\r
+  if ( netif == NULL ) return;\r
+\r
+  snmp_delete_ipaddridx_tree(netif);\r
+\r
+  /*  is it the first netif? */\r
+  if (netif_list == netif) {\r
+    netif_list = netif->next;\r
+    snmp_dec_iflist();\r
+  }\r
+  else {\r
+    /*  look for netif further down the list */\r
+    struct netif * tmpNetif;\r
+    for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {\r
+      if (tmpNetif->next == netif) {\r
+        tmpNetif->next = netif->next;\r
+        snmp_dec_iflist();\r
+        break;\r
+      }\r
+    }\r
+    if (tmpNetif == NULL)\r
+      return; /*  we didn't find any netif today */\r
+  }\r
+  /* this netif is default? */\r
+  if (netif_default == netif)\r
+    /* reset default netif */\r
+    netif_default = NULL;\r
+  LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );\r
+}\r
+\r
+struct netif *\r
+netif_find(char *name)\r
+{\r
+  struct netif *netif;\r
+  u8_t num;\r
+\r
+  if (name == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  num = name[2] - '0';\r
+\r
+  for(netif = netif_list; netif != NULL; netif = netif->next) {\r
+    if (num == netif->num &&\r
+       name[0] == netif->name[0] &&\r
+       name[1] == netif->name[1]) {\r
+      LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));\r
+      return netif;\r
+    }\r
+  }\r
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));\r
+  return NULL;\r
+}\r
+\r
+void\r
+netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)\r
+{\r
+  /* TODO: Handling of obsolete pcbs */\r
+  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */\r
+#if LWIP_TCP\r
+  struct tcp_pcb *pcb;\r
+  struct tcp_pcb_listen *lpcb;\r
+\r
+  /* address is actually being changed? */\r
+  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)\r
+  {\r
+    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */\r
+    LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));\r
+    pcb = tcp_active_pcbs;\r
+    while (pcb != NULL) {\r
+      /* PCB bound to current local interface address? */\r
+      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {\r
+        /* this connection must be aborted */\r
+        struct tcp_pcb *next = pcb->next;\r
+        LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));\r
+        tcp_abort(pcb);\r
+        pcb = next;\r
+      } else {\r
+        pcb = pcb->next;\r
+      }\r
+    }\r
+    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {\r
+      /* PCB bound to current local interface address? */\r
+      if (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr))) {\r
+        /* The PCB is listening to the old ipaddr and\r
+         * is set to listen to the new one instead */\r
+        ip_addr_set(&(lpcb->local_ip), ipaddr);\r
+      }\r
+    }\r
+  }\r
+#endif\r
+  snmp_delete_ipaddridx_tree(netif);\r
+  snmp_delete_iprteidx_tree(0,netif);\r
+  /* set new IP address to netif */\r
+  ip_addr_set(&(netif->ip_addr), ipaddr);\r
+  snmp_insert_ipaddridx_tree(netif);\r
+  snmp_insert_iprteidx_tree(0,netif);\r
+\r
+#if 0 /* only allowed for Ethernet interfaces TODO: how can we check? */\r
+  /** For Ethernet network interfaces, we would like to send a\r
+   *  "gratuitous ARP"; this is an ARP packet sent by a node in order\r
+   *  to spontaneously cause other nodes to update an entry in their\r
+   *  ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.\r
+   */ \r
+  etharp_query(netif, ipaddr, NULL);\r
+#endif\r
+  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",\r
+    netif->name[0], netif->name[1],\r
+    ip4_addr1(&netif->ip_addr),\r
+    ip4_addr2(&netif->ip_addr),\r
+    ip4_addr3(&netif->ip_addr),\r
+    ip4_addr4(&netif->ip_addr)));\r
+}\r
+\r
+void\r
+netif_set_gw(struct netif *netif, struct ip_addr *gw)\r
+{\r
+  ip_addr_set(&(netif->gw), gw);\r
+  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",\r
+    netif->name[0], netif->name[1],\r
+    ip4_addr1(&netif->gw),\r
+    ip4_addr2(&netif->gw),\r
+    ip4_addr3(&netif->gw),\r
+    ip4_addr4(&netif->gw)));\r
+}\r
+\r
+void\r
+netif_set_netmask(struct netif *netif, struct ip_addr *netmask)\r
+{\r
+  snmp_delete_iprteidx_tree(0, netif);\r
+  /* set new netmask to netif */\r
+  ip_addr_set(&(netif->netmask), netmask);\r
+  snmp_insert_iprteidx_tree(0, netif);\r
+  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",\r
+    netif->name[0], netif->name[1],\r
+    ip4_addr1(&netif->netmask),\r
+    ip4_addr2(&netif->netmask),\r
+    ip4_addr3(&netif->netmask),\r
+    ip4_addr4(&netif->netmask)));\r
+}\r
+\r
+void\r
+netif_set_default(struct netif *netif)\r
+{\r
+  if (netif == NULL)\r
+  {\r
+    /* remove default route */\r
+    snmp_delete_iprteidx_tree(1, netif);\r
+  }\r
+  else\r
+  {\r
+    /* install default route */\r
+    snmp_insert_iprteidx_tree(1, netif);\r
+  }\r
+  netif_default = netif;\r
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",\r
+           netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));\r
+}\r
+\r
+/**\r
+ * Bring an interface up, available for processing\r
+ * traffic.\r
+ * \r
+ * @note: Enabling DHCP on a down interface will make it come\r
+ * up once configured.\r
+ * \r
+ * @see dhcp_start()\r
+ */ \r
+void netif_set_up(struct netif *netif)\r
+{\r
+  netif->flags |= NETIF_FLAG_UP;\r
+#if LWIP_SNMP\r
+  snmp_get_sysuptime(&netif->ts);\r
+#endif\r
+}\r
+\r
+/**\r
+ * Ask if an interface is up\r
+ */ \r
+u8_t netif_is_up(struct netif *netif)\r
+{\r
+  return (netif->flags & NETIF_FLAG_UP)?1:0;\r
+}\r
+\r
+/**\r
+ * Bring an interface down, disabling any traffic processing.\r
+ *\r
+ * @note: Enabling DHCP on a down interface will make it come\r
+ * up once configured.\r
+ * \r
+ * @see dhcp_start()\r
+ */ \r
+void netif_set_down(struct netif *netif)\r
+{\r
+  netif->flags &= ~NETIF_FLAG_UP;\r
+#if LWIP_SNMP\r
+  snmp_get_sysuptime(&netif->ts);\r
+#endif\r
+}\r
+\r
+void\r
+netif_init(void)\r
+{\r
+  netif_list = netif_default = NULL;\r
+}\r
+\r
index bca0725ec559e94dc55702db7f282dbb3a63f642..1f6516d98d16471304bb63fe280f10ccff07eee9 100644 (file)
-/**
- * @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:
+/**\r
+ * @file\r
+ * Packet buffer management\r
+ *\r
+ * Packets are built from the pbuf data structure. It supports dynamic\r
+ * memory allocation for packet contents or can reference externally\r
+ * managed packet contents both in RAM and ROM. Quick allocation for\r
+ * incoming packets is provided through pools with fixed sized pbufs.\r
+ *\r
+ * A packet may span over multiple pbufs, chained as a singly linked\r
+ * list. This is called a "pbuf chain".\r
+ *\r
+ * Multiple packets may be queued, also using this singly linked list.\r
+ * This is called a "packet queue".\r
+ * \r
+ * So, a packet queue consists of one or more pbuf chains, each of\r
+ * which consist of one or more pbufs. Currently, queues are only\r
+ * supported in a limited section of lwIP, this is the etharp queueing\r
+ * code. Outside of this section no packet queues are supported yet.\r
+ * \r
+ * The differences between a pbuf chain and a packet queue are very\r
+ * precise but subtle. \r
+ *\r
+ * The last pbuf of a packet has a ->tot_len field that equals the\r
+ * ->len field. It can be found by traversing the list. If the last\r
+ * pbuf of a packet has a ->next field other than NULL, more packets\r
+ * are on the queue.\r
+ *\r
+ * Therefore, looping through a pbuf of a single packet, has an\r
+ * loop end condition (tot_len == p->len), NOT (next == NULL).\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+#include "arch/perf.h"\r
+\r
+static u8_t pbuf_pool_memory[MEM_ALIGNMENT - 1 + PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf))];\r
+\r
+#if !SYS_LIGHTWEIGHT_PROT\r
+static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;\r
+static sys_sem_t pbuf_pool_free_sem;\r
+#endif\r
+\r
+static struct pbuf *pbuf_pool = NULL;\r
+\r
+/**\r
+ * Initializes the pbuf module.\r
+ *\r
+ * A large part of memory is allocated for holding the pool of pbufs.\r
+ * The size of the individual pbufs in the pool is given by the size\r
+ * parameter, and the number of pbufs in the pool by the num parameter.\r
+ *\r
+ * After the memory has been allocated, the pbufs are set up. The\r
+ * ->next pointer in each pbuf is set up to point to the next pbuf in\r
+ * the pool.\r
+ *\r
+ */\r
+void\r
+pbuf_init(void)\r
+{\r
+  struct pbuf *p, *q = NULL;\r
+  u16_t i;\r
+\r
+  pbuf_pool = (struct pbuf *)MEM_ALIGN(pbuf_pool_memory);\r
+\r
+#if PBUF_STATS\r
+  lwip_stats.pbuf.avail = PBUF_POOL_SIZE;\r
+#endif /* PBUF_STATS */\r
+\r
+  /* Set up ->next pointers to link the pbufs of the pool together */\r
+  p = pbuf_pool;\r
+\r
+  for(i = 0; i < PBUF_POOL_SIZE; ++i) {\r
+    p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));\r
+    p->len = p->tot_len = PBUF_POOL_BUFSIZE;\r
+    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));\r
+    p->flags = PBUF_FLAG_POOL;\r
+    q = p;\r
+    p = p->next;\r
+  }\r
+\r
+  /* The ->next pointer of last pbuf is NULL to indicate that there\r
+     are no more pbufs in the pool */\r
+  q->next = NULL;\r
+\r
+#if !SYS_LIGHTWEIGHT_PROT\r
+  pbuf_pool_alloc_lock = 0;\r
+  pbuf_pool_free_lock = 0;\r
+  pbuf_pool_free_sem = sys_sem_new(1);\r
+#endif\r
+}\r
+\r
+/**\r
+ * @internal only called from pbuf_alloc()\r
+ */\r
+static struct pbuf *\r
+pbuf_pool_alloc(void)\r
+{\r
+  struct pbuf *p = NULL;\r
+\r
+  SYS_ARCH_DECL_PROTECT(old_level);\r
+  SYS_ARCH_PROTECT(old_level);\r
+\r
+#if !SYS_LIGHTWEIGHT_PROT\r
+  /* Next, check the actual pbuf pool, but if the pool is locked, we\r
+     pretend to be out of buffers and return NULL. */\r
+  if (pbuf_pool_free_lock) {\r
+#if PBUF_STATS\r
+    ++lwip_stats.pbuf.alloc_locked;\r
+#endif /* PBUF_STATS */\r
+    return NULL;\r
+  }\r
+  pbuf_pool_alloc_lock = 1;\r
+  if (!pbuf_pool_free_lock) {\r
+#endif /* SYS_LIGHTWEIGHT_PROT */\r
+    p = pbuf_pool;\r
+    if (p) {\r
+      pbuf_pool = p->next;\r
+    }\r
+#if !SYS_LIGHTWEIGHT_PROT\r
+#if PBUF_STATS\r
+  } else {\r
+    ++lwip_stats.pbuf.alloc_locked;\r
+#endif /* PBUF_STATS */\r
+  }\r
+  pbuf_pool_alloc_lock = 0;\r
+#endif /* SYS_LIGHTWEIGHT_PROT */\r
+\r
+#if PBUF_STATS\r
+  if (p != NULL) {\r
+    ++lwip_stats.pbuf.used;\r
+    if (lwip_stats.pbuf.used > lwip_stats.pbuf.max) {\r
+      lwip_stats.pbuf.max = lwip_stats.pbuf.used;\r
+    }\r
+  }\r
+#endif /* PBUF_STATS */\r
+\r
+  SYS_ARCH_UNPROTECT(old_level);\r
+  return p;\r
+}\r
+\r
+\r
+/**\r
+ * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).\r
+ *\r
+ * The actual memory allocated for the pbuf is determined by the\r
+ * layer at which the pbuf is allocated and the requested size\r
+ * (from the size parameter).\r
+ *\r
+ * @param flag this parameter decides how and where the pbuf\r
+ * should be allocated as follows:\r
+ *\r
+ * - PBUF_RAM: buffer memory for pbuf is allocated as one large\r
+ *             chunk. This includes protocol headers as well.\r
+ * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for\r
+ *             protocol headers. Additional headers must be prepended\r
+ *             by allocating another pbuf and chain in to the front of\r
+ *             the ROM pbuf. It is assumed that the memory used is really\r
+ *             similar to ROM in that it is immutable and will not be\r
+ *             changed. Memory which is dynamic should generally not\r
+ *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.\r
+ * - PBUF_REF: no buffer memory is allocated for the pbuf, even for\r
+ *             protocol headers. It is assumed that the pbuf is only\r
+ *             being used in a single thread. If the pbuf gets queued,\r
+ *             then pbuf_take should be called to copy the buffer.\r
+ * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from\r
+ *              the pbuf pool that is allocated during pbuf_init().\r
+ *\r
+ * @return the allocated pbuf. If multiple pbufs where allocated, this\r
+ * is the first pbuf of a pbuf chain.\r
+ */\r
+struct pbuf *\r
+pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)\r
+{\r
+  struct pbuf *p, *q, *r;\r
+  u16_t offset;\r
+  s32_t rem_len; /* remaining length */\r
+  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));\r
+\r
+  /* determine header offset */\r
+  offset = 0;\r
+  switch (l) {\r
+  case PBUF_TRANSPORT:\r
+    /* add room for transport (often TCP) layer header */\r
+    offset += PBUF_TRANSPORT_HLEN;\r
+    /* FALLTHROUGH */\r
+  case PBUF_IP:\r
+    /* add room for IP layer header */\r
+    offset += PBUF_IP_HLEN;\r
+    /* FALLTHROUGH */\r
+  case PBUF_LINK:\r
+    /* add room for link layer header */\r
+    offset += PBUF_LINK_HLEN;\r
+    break;\r
+  case PBUF_RAW:\r
+    break;\r
+  default:\r
     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;
+    return NULL;\r
+  }\r
+\r
+  switch (flag) {\r
+  case PBUF_POOL:\r
+    /* allocate head of pbuf chain into p */\r
+    p = pbuf_pool_alloc();\r
+    LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));\r
+    if (p == NULL) {\r
+#if PBUF_STATS\r
+      ++lwip_stats.pbuf.err;\r
 #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);
+      return NULL;\r
+    }\r
+    p->next = NULL;\r
+\r
+    /* make the payload pointer point 'offset' bytes into pbuf data memory */\r
+    p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));\r
+    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",\r
+            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);\r
+    /* the total length of the pbuf chain is the requested size */\r
+    p->tot_len = length;\r
+    /* set the length of the first pbuf in the chain */\r
+    p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;\r
+    /* set reference count (needed here in case we fail) */\r
+    p->ref = 1;\r
+\r
+    /* now allocate the tail of the pbuf chain */\r
+\r
+    /* remember first pbuf for linkage in next iteration */\r
+    r = p;\r
+    /* remaining length to be allocated */\r
+    rem_len = length - p->len;\r
+    /* any remaining pbufs to be allocated? */\r
+    while (rem_len > 0) {\r
+      q = pbuf_pool_alloc();\r
+      if (q == NULL) {\r
+       LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));\r
+#if PBUF_STATS\r
+        ++lwip_stats.pbuf.err;\r
+#endif /* PBUF_STATS */\r
+        /* free chain so far allocated */\r
+        pbuf_free(p);\r
         /* 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));
+        return NULL;\r
+      }\r
+      q->next = NULL;\r
+      /* make previous pbuf point to this pbuf */\r
+      r->next = q;\r
+      /* set total length of this pbuf and next in chain */\r
+      q->tot_len = rem_len;\r
+      /* this pbuf length is pool size, unless smaller sized tail */\r
+      q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;\r
+      q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));\r
+      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",\r
+              ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);\r
+      q->ref = 1;\r
+      /* calculate remaining length to be allocated */\r
+      rem_len -= q->len;\r
+      /* remember this pbuf for linkage in next iteration */\r
+      r = q;\r
+    }\r
+    /* end of chain */\r
+    /*r->next = NULL;*/\r
+\r
+    break;\r
+  case PBUF_RAM:\r
+    /* If pbuf is to be allocated in RAM, allocate memory for it. */\r
+    p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + offset) + MEM_ALIGN_SIZE(length));\r
+    if (p == NULL) {\r
+      return NULL;\r
+    }\r
+    /* Set up internal structure of the pbuf. */\r
+    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));\r
+    p->len = p->tot_len = length;\r
+    p->next = NULL;\r
+    p->flags = PBUF_FLAG_RAM;\r
+\r
+    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",\r
+           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);\r
+    break;\r
+  /* pbuf references existing (non-volatile static constant) ROM payload? */\r
+  case PBUF_ROM:\r
+  /* pbuf references existing (externally allocated) RAM payload? */\r
+  case PBUF_REF:\r
+    /* only allocate memory for the pbuf structure */\r
+    p = memp_malloc(MEMP_PBUF);\r
     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:
+\r
+      return NULL;\r
+    }\r
+    /* caller must set this field properly, afterwards */\r
+    p->payload = NULL;\r
+    p->len = p->tot_len = length;\r
+    p->next = NULL;\r
+    p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);\r
+    break;\r
+  default:\r
     LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);\r
-    return NULL;
-  }
-  /* set reference count */
-  p->ref = 1;
+    return NULL;\r
+  }\r
+  /* set reference count */\r
+  p->ref = 1;\r
   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);
-
+  return p;\r
+}\r
+\r
+\r
+#if PBUF_STATS\r
+#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)\r
+#else /* PBUF_STATS */\r
+#define DEC_PBUF_STATS\r
+#endif /* PBUF_STATS */\r
+\r
+#define PBUF_POOL_FAST_FREE(p)  do {                                    \\r
+                                  p->next = pbuf_pool;                  \\r
+                                  pbuf_pool = p;                        \\r
+                                  DEC_PBUF_STATS;                       \\r
+                                } while (0)\r
+\r
+#if SYS_LIGHTWEIGHT_PROT\r
+#define PBUF_POOL_FREE(p)  do {                                         \\r
+                                SYS_ARCH_DECL_PROTECT(old_level);       \\r
+                                SYS_ARCH_PROTECT(old_level);            \\r
+                                PBUF_POOL_FAST_FREE(p);                 \\r
+                                SYS_ARCH_UNPROTECT(old_level);          \\r
+                               } while (0)\r
+#else /* SYS_LIGHTWEIGHT_PROT */\r
+#define PBUF_POOL_FREE(p)  do {                                         \\r
+                             sys_sem_wait(pbuf_pool_free_sem);          \\r
+                             PBUF_POOL_FAST_FREE(p);                    \\r
+                             sys_sem_signal(pbuf_pool_free_sem);        \\r
+                           } while (0)\r
+#endif /* SYS_LIGHTWEIGHT_PROT */\r
+\r
+/**\r
+ * Shrink a pbuf chain to a desired length.\r
+ *\r
+ * @param p pbuf to shrink.\r
+ * @param new_len desired new length of pbuf chain\r
+ *\r
+ * Depending on the desired length, the first few pbufs in a chain might\r
+ * be skipped and left unchanged. The new last pbuf in the chain will be\r
+ * resized, and any remaining pbufs will be freed.\r
+ *\r
+ * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.\r
+ * @note May not be called on a packet queue.\r
+ *\r
+ * @bug Cannot grow the size of a pbuf (chain) (yet).\r
+ */\r
+void\r
+pbuf_realloc(struct pbuf *p, u16_t new_len)\r
+{\r
+  struct pbuf *q;\r
+  u16_t rem_len; /* remaining length */\r
+  s16_t grow;\r
+\r
+  LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||\r
+              p->flags == PBUF_FLAG_ROM ||\r
+              p->flags == PBUF_FLAG_RAM ||\r
+              p->flags == PBUF_FLAG_REF);\r
+\r
+  /* desired length larger than current length? */\r
+  if (new_len >= p->tot_len) {\r
+    /* enlarging not yet supported */\r
+    return;\r
+  }\r
+\r
+  /* the pbuf chain grows by (new_len - p->tot_len) bytes\r
+   * (which may be negative in case of shrinking) */\r
+  grow = new_len - p->tot_len;\r
+\r
+  /* first, step over any pbufs that should remain in the chain */\r
+  rem_len = new_len;\r
+  q = p;\r
+  /* should this pbuf be kept? */\r
+  while (rem_len > q->len) {\r
+    /* decrease remaining length by pbuf length */\r
+    rem_len -= q->len;\r
+    /* decrease total length indicator */\r
+    q->tot_len += grow;\r
+    /* proceed to next pbuf in chain */\r
+    q = q->next;\r
+  }\r
+  /* we have now reached the new last pbuf (in q) */\r
+  /* rem_len == desired length for pbuf q */\r
+\r
+  /* shrink allocated memory for PBUF_RAM */\r
+  /* (other types merely adjust their length fields */\r
+  if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {\r
+    /* reallocate and adjust the length of the pbuf that will be split */\r
+    mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);\r
+  }\r
+  /* adjust length fields for new last pbuf */\r
+  q->len = rem_len;\r
+  q->tot_len = q->len;\r
+\r
+  /* any remaining pbufs in chain? */\r
+  if (q->next != NULL) {\r
+    /* free remaining pbufs in chain */\r
+    pbuf_free(q->next);\r
+  }\r
+  /* q is last packet in chain */\r
+  q->next = NULL;\r
+\r
+}\r
+\r
+/**\r
+ * Adjusts the payload pointer to hide or reveal headers in the payload.\r
+ *\r
+ * Adjusts the ->payload pointer so that space for a header\r
+ * (dis)appears in the pbuf payload.\r
+ *\r
+ * The ->payload, ->tot_len and ->len fields are adjusted.\r
+ *\r
+ * @param hdr_size_inc Number of bytes to increment header size which\r
+ * increases the size of the pbuf. New space is on the front.\r
+ * (Using a negative value decreases the header size.)\r
+ * If hdr_size_inc is 0, this function does nothing and returns succesful.\r
+ *\r
+ * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so\r
+ * the call will fail. A check is made that the increase in header size does\r
+ * not move the payload pointer in front of the start of the buffer.\r
+ * @return non-zero on failure, zero on success.\r
+ *\r
+ */\r
+u8_t\r
+pbuf_header(struct pbuf *p, s16_t header_size_increment)\r
+{\r
+  u16_t flags;\r
+  void *payload;\r
+\r
+  LWIP_ASSERT("p != NULL", p != NULL);\r
+  if ((header_size_increment == 0) || (p == NULL)) return 0;\r
\r
+  flags = p->flags;\r
+  /* remember current payload pointer */\r
+  payload = p->payload;\r
+\r
+  /* pbuf types containing payloads? */\r
+  if (flags == PBUF_FLAG_RAM || flags == PBUF_FLAG_POOL) {\r
+    /* set new payload pointer */\r
+    p->payload = (u8_t *)p->payload - header_size_increment;\r
+    /* boundary check fails? */\r
+    if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {\r
+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",\r
+        (void *)p->payload,\r
+        (void *)(p + 1)));\\r
+      /* restore old payload pointer */\r
+      p->payload = payload;\r
+      /* bail out unsuccesfully */\r
+      return 1;\r
+    }\r
+  /* pbuf types refering to external payloads? */\r
+  } else if (flags == PBUF_FLAG_REF || flags == PBUF_FLAG_ROM) {\r
+    /* hide a header in the payload? */\r
+    if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) {\r
+      /* increase payload pointer */\r
+      p->payload = (u8_t *)p->payload - header_size_increment;\r
+    } else {\r
+      /* cannot expand payload to front (yet!)\r
+       * bail out unsuccesfully */\r
+      return 1;\r
+    }\r
+  }\r
+  /* modify pbuf length fields */\r
+  p->len += header_size_increment;\r
+  p->tot_len += header_size_increment;\r
+\r
+  LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",\r
+    (void *)payload, (void *)p->payload, header_size_increment));\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+ * Dereference a pbuf chain or queue and deallocate any no-longer-used\r
+ * pbufs at the head of this chain or queue.\r
+ *\r
+ * Decrements the pbuf reference count. If it reaches zero, the pbuf is\r
+ * deallocated.\r
+ *\r
+ * For a pbuf chain, this is repeated for each pbuf in the chain,\r
+ * up to the first pbuf which has a non-zero reference count after\r
+ * decrementing. So, when all reference counts are one, the whole\r
+ * chain is free'd.\r
+ *\r
+ * @param pbuf The pbuf (chain) to be dereferenced.\r
+ *\r
+ * @return the number of pbufs that were de-allocated\r
+ * from the head of the chain.\r
+ *\r
+ * @note MUST NOT be called on a packet queue (Not verified to work yet).\r
+ * @note the reference counter of a pbuf equals the number of pointers\r
+ * that refer to the pbuf (or into the pbuf).\r
+ *\r
+ * @internal examples:\r
+ *\r
+ * Assuming existing chains a->b->c with the following reference\r
+ * counts, calling pbuf_free(a) results in:\r
+ * \r
+ * 1->2->3 becomes ...1->3\r
+ * 3->3->3 becomes 2->3->3\r
+ * 1->1->2 becomes ......1\r
+ * 2->1->1 becomes 1->1->1\r
+ * 1->1->1 becomes .......\r
+ *\r
+ */\r
+u8_t\r
+pbuf_free(struct pbuf *p)\r
+{\r
+  u16_t flags;\r
+  struct pbuf *q;\r
+  u8_t count;\r
+  SYS_ARCH_DECL_PROTECT(old_level);\r
+\r
   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");
+\r
+  /* if assertions are disabled, proceed with debug output */\r
+  if (p == NULL) {\r
+    LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));\r
+    return 0;\r
+  }\r
+  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));\r
+\r
+  PERF_START;\r
+\r
+  LWIP_ASSERT("pbuf_free: sane flags",\r
+    p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM ||\r
+    p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL);\r
+\r
+  count = 0;\r
+  /* Since decrementing ref cannot be guaranteed to be a single machine operation\r
+   * we must protect it. Also, the later test of ref must be protected.\r
+   */\r
+  SYS_ARCH_PROTECT(old_level);\r
+  /* de-allocate all consecutive pbufs from the head of the chain that\r
+   * obtain a zero reference count after decrementing*/\r
+  while (p != NULL) {\r
+    /* all pbufs in a chain are referenced at least once */\r
+    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);\r
+    /* decrease reference count (number of pointers to pbuf) */\r
+    p->ref--;\r
+    /* this pbuf is no longer referenced to? */\r
+    if (p->ref == 0) {\r
+      /* remember next pbuf in chain for next iteration */\r
+      q = p->next;\r
+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));\r
+      flags = p->flags;\r
+      /* is this a pbuf from the pool? */\r
+      if (flags == PBUF_FLAG_POOL) {\r
+        p->len = p->tot_len = PBUF_POOL_BUFSIZE;\r
+        p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));\r
+        PBUF_POOL_FREE(p);\r
+      /* is this a ROM or RAM referencing pbuf? */\r
+      } else if (flags == PBUF_FLAG_ROM || flags == PBUF_FLAG_REF) {\r
+        memp_free(MEMP_PBUF, p);\r
+      /* flags == PBUF_FLAG_RAM */\r
+      } else {\r
+        mem_free(p);\r
+      }\r
+      count++;\r
+      /* proceed to next pbuf */\r
+      p = q;\r
+    /* p->ref > 0, this pbuf is still referenced to */\r
+    /* (and so the remaining pbufs in chain as well) */\r
+    } else {\r
+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)p->ref));\r
+      /* stop walking through the chain */\r
+      p = NULL;\r
+    }\r
+  }\r
+  SYS_ARCH_UNPROTECT(old_level);\r
+  PERF_STOP("pbuf_free");\r
   /* 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);
-}
+  return count;\r
+}\r
+\r
+/**\r
+ * Count number of pbufs in a chain\r
+ *\r
+ * @param p first pbuf of chain\r
+ * @return the number of pbufs in a chain\r
+ */\r
+\r
+u8_t\r
+pbuf_clen(struct pbuf *p)\r
+{\r
+  u8_t len;\r
+\r
+  len = 0;\r
+  while (p != NULL) {\r
+    ++len;\r
+    p = p->next;\r
+  }\r
+  return len;\r
+}\r
+\r
+/**\r
+ * Increment the reference count of the pbuf.\r
+ *\r
+ * @param p pbuf to increase reference counter of\r
+ *\r
+ */\r
+void\r
+pbuf_ref(struct pbuf *p)\r
+{\r
+  SYS_ARCH_DECL_PROTECT(old_level);\r
+  /* pbuf given? */\r
+  if (p != NULL) {\r
+    SYS_ARCH_PROTECT(old_level);\r
+    ++(p->ref);\r
+    SYS_ARCH_UNPROTECT(old_level);\r
+  }\r
+}\r
+\r
+/**\r
+ * Concatenate two pbufs (each may be a pbuf chain) and take over\r
+ * the caller's reference of the tail pbuf.\r
+ * \r
+ * @note The caller MAY NOT reference the tail pbuf afterwards.\r
+ * Use pbuf_chain() for that purpose.\r
+ * \r
+ * @see pbuf_chain()\r
+ */\r
+\r
+void\r
+pbuf_cat(struct pbuf *h, struct pbuf *t)\r
+{\r
+  struct pbuf *p;\r
+\r
+  LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);\r
+  LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL);\r
+  if ((h == NULL) || (t == NULL)) return;\r
+\r
+  /* proceed to last pbuf of chain */\r
+  for (p = h; p->next != NULL; p = p->next) {\r
+    /* add total length of second chain to all totals of first chain */\r
+    p->tot_len += t->tot_len;\r
+  }\r
+  /* { p is last pbuf of first h chain, p->next == NULL } */\r
+  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);\r
+  LWIP_ASSERT("p->next == NULL", p->next == NULL);\r
+  /* add total length of second chain to last pbuf total of first chain */\r
+  p->tot_len += t->tot_len;\r
+  /* chain last pbuf of head (p) with first of tail (t) */\r
+  p->next = t;\r
+  /* p->next now references t, but the caller will drop its reference to t,\r
+   * so netto there is no change to the reference count of t.\r
+   */\r
+}\r
+\r
+/**\r
+ * Chain two pbufs (or pbuf chains) together.\r
+ * \r
+ * The caller MUST call pbuf_free(t) once it has stopped\r
+ * using it. Use pbuf_cat() instead if you no longer use t.\r
+ * \r
+ * @param h head pbuf (chain)\r
+ * @param t tail pbuf (chain)\r
+ * @note The pbufs MUST belong to the same packet.\r
+ * @note MAY NOT be called on a packet queue.\r
+ *\r
+ * The ->tot_len fields of all pbufs of the head chain are adjusted.\r
+ * The ->next field of the last pbuf of the head chain is adjusted.\r
+ * The ->ref field of the first pbuf of the tail chain is adjusted.\r
+ *\r
+ */\r
+void\r
+pbuf_chain(struct pbuf *h, struct pbuf *t)\r
+{\r
+  pbuf_cat(h, t);\r
+  /* t is now referenced by h */\r
+  pbuf_ref(t);\r
+  LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));\r
+}\r
+\r
+/* For packet queueing. Note that queued packets MUST be dequeued first\r
+ * using pbuf_dequeue() before calling other pbuf_() functions. */\r
+#if ARP_QUEUEING\r
+/**\r
+ * Add a packet to the end of a queue.\r
+ *\r
+ * @param q pointer to first packet on the queue\r
+ * @param n packet to be queued\r
+ *\r
+ * Both packets MUST be given, and must be different.\r
+ */\r
+void\r
+pbuf_queue(struct pbuf *p, struct pbuf *n)\r
+{\r
+#if PBUF_DEBUG /* remember head of queue */\r
+  struct pbuf *q = p;\r
+#endif\r
+  /* programmer stupidity checks */\r
+  LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);\r
+  LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);\r
+  LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);\r
+  if ((p == NULL) || (n == NULL) || (p == n)){\r
+    LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"));\r
+    return;\r
+  }\r
+\r
+  /* iterate through all packets on queue */\r
+  while (p->next != NULL) {\r
+/* be very picky about pbuf chain correctness */\r
+#if PBUF_DEBUG\r
+    /* iterate through all pbufs in packet */\r
+    while (p->tot_len != p->len) {\r
+      /* make sure invariant condition holds */\r
+      LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);\r
+      /* make sure each packet is complete */\r
+      LWIP_ASSERT("p->next != NULL", p->next != NULL);\r
+      p = p->next;\r
+      /* { p->tot_len == p->len => p is last pbuf of a packet } */\r
+    }\r
+    /* { p is last pbuf of a packet } */\r
+    /* proceed to next packet on queue */\r
+#endif\r
+    /* proceed to next pbuf */\r
+    if (p->next != NULL) p = p->next;\r
+  }\r
+  /* { p->tot_len == p->len and p->next == NULL } ==>\r
+   * { p is last pbuf of last packet on queue } */\r
+  /* chain last pbuf of queue with n */\r
+  p->next = n;\r
+  /* n is now referenced to by the (packet p in the) queue */\r
+  pbuf_ref(n);\r
+#if PBUF_DEBUG\r
+  LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2,\r
+    ("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n",\r
+    (void *)n, (void *)p, (void *)q));\r
+#endif\r
+}\r
+\r
+/**\r
+ * Remove a packet from the head of a queue.\r
+ *\r
+ * The caller MUST reference the remainder of the queue (as returned). The\r
+ * caller MUST NOT call pbuf_ref() as it implicitly takes over the reference\r
+ * from p.\r
+ * \r
+ * @param p pointer to first packet on the queue which will be dequeued.\r
+ * @return first packet on the remaining queue (NULL if no further packets).\r
+ *\r
+ */\r
+struct pbuf *\r
+pbuf_dequeue(struct pbuf *p)\r
+{\r
+  struct pbuf *q;\r
+  LWIP_ASSERT("p != NULL", p != NULL);\r
+\r
+  /* iterate through all pbufs in packet p */\r
+  while (p->tot_len != p->len) {\r
+    /* make sure invariant condition holds */\r
+    LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);\r
+    /* make sure each packet is complete */\r
+    LWIP_ASSERT("p->next != NULL", p->next != NULL);\r
+    p = p->next;\r
+  }\r
+  /* { p->tot_len == p->len } => p is the last pbuf of the first packet */\r
+  /* remember next packet on queue in q */\r
+  q = p->next;\r
+  /* dequeue packet p from queue */\r
+  p->next = NULL;\r
+  /* any next packet on queue? */\r
+  if (q != NULL) {\r
+    /* although q is no longer referenced by p, it MUST be referenced by\r
+     * the caller, who is maintaining this packet queue. So, we do not call\r
+     * pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */\r
+    LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q));\r
+  } else {\r
+    LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n"));\r
+  }\r
+  return q;\r
+}\r
+#endif\r
+\r
+/**\r
+ *\r
+ * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.\r
+ *\r
+ * Used to queue packets on behalf of the lwIP stack, such as\r
+ * ARP based queueing.\r
+ *\r
+ * Go through a pbuf chain and replace any PBUF_REF buffers\r
+ * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of\r
+ * the referenced data.\r
+ *\r
+ * @note You MUST explicitly use p = pbuf_take(p);\r
+ * The pbuf you give as argument, may have been replaced\r
+ * by a (differently located) copy through pbuf_take()!\r
+ *\r
+ * @note Any replaced pbufs will be freed through pbuf_free().\r
+ * This may deallocate them if they become no longer referenced.\r
+ *\r
+ * @param p Head of pbuf chain to process\r
+ *\r
+ * @return Pointer to head of pbuf chain\r
+ */\r
+struct pbuf *\r
+pbuf_take(struct pbuf *p)\r
+{\r
+  struct pbuf *q , *prev, *head;\r
+  LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);\r
+  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));\r
+\r
+  prev = NULL;\r
+  head = p;\r
+  /* iterate through pbuf chain */\r
+  do\r
+  {\r
+    /* pbuf is of type PBUF_REF? */\r
+    if (p->flags == PBUF_FLAG_REF) {\r
+      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));\r
+      /* allocate a pbuf (w/ payload) fully in RAM */\r
+      /* PBUF_POOL buffers are faster if we can use them */\r
+      if (p->len <= PBUF_POOL_BUFSIZE) {\r
+        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);\r
+        if (q == NULL) {\r
+          LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));\r
+        }\r
+      } else {\r
+        /* no replacement pbuf yet */\r
+        q = NULL;\r
+        LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));\r
+      }\r
+      /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */\r
+      if (q == NULL) {\r
+        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);\r
+        if (q == NULL) {\r
+          LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));\r
+        }\r
+      }\r
+      /* replacement pbuf could be allocated? */\r
+      if (q != NULL)\r
+      {\r
+        /* copy p to q */\r
+        /* copy successor */\r
+        q->next = p->next;\r
+        /* remove linkage from original pbuf */\r
+        p->next = NULL;\r
+        /* remove linkage to original pbuf */\r
+        if (prev != NULL) {\r
+          /* prev->next == p at this point */\r
+          LWIP_ASSERT("prev->next == p", prev->next == p);\r
+          /* break chain and insert new pbuf instead */\r
+          prev->next = q;\r
+        /* prev == NULL, so we replaced the head pbuf of the chain */\r
+        } else {\r
+          head = q;\r
+        }\r
+        /* copy pbuf payload */\r
+        memcpy(q->payload, p->payload, p->len);\r
+        q->tot_len = p->tot_len;\r
+        q->len = p->len;\r
+        /* in case p was the first pbuf, it is no longer refered to by\r
+         * our caller, as the caller MUST do p = pbuf_take(p);\r
+         * in case p was not the first pbuf, it is no longer refered to\r
+         * by prev. we can safely free the pbuf here.\r
+         * (note that we have set p->next to NULL already so that\r
+         * we will not free the rest of the chain by accident.)\r
+         */\r
+        pbuf_free(p);\r
+        /* do not copy ref, since someone else might be using the old buffer */\r
+        LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));\r
+        p = q;\r
+      } else {\r
+        /* deallocate chain */\r
+        pbuf_free(head);\r
+        LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));\r
+        return NULL;\r
+      }\r
+    /* p->flags != PBUF_FLAG_REF */\r
+    } else {\r
+      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));\r
+    }\r
+    /* remember this pbuf */\r
+    prev = p;\r
+    /* proceed to next pbuf in original chain */\r
+    p = p->next;\r
+  } while (p);\r
+  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));\r
+\r
+  return head;\r
+}\r
+\r
+/**\r
+ * Dechains the first pbuf from its succeeding pbufs in the chain.\r
+ *\r
+ * Makes p->tot_len field equal to p->len.\r
+ * @param p pbuf to dechain\r
+ * @return remainder of the pbuf chain, or NULL if it was de-allocated.\r
+ * @note May not be called on a packet queue.\r
+ */\r
+struct pbuf *\r
+pbuf_dechain(struct pbuf *p)\r
+{\r
+  struct pbuf *q;\r
+  u8_t tail_gone = 1;\r
+  /* tail */\r
+  q = p->next;\r
+  /* pbuf has successor in chain? */\r
+  if (q != NULL) {\r
+    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\r
+    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);\r
+    /* enforce invariant if assertion is disabled */\r
+    q->tot_len = p->tot_len - p->len;\r
+    /* decouple pbuf from remainder */\r
+    p->next = NULL;\r
+    /* total length of pbuf p is its own length only */\r
+    p->tot_len = p->len;\r
+    /* q is no longer referenced by p, free it */\r
+    LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));\r
+    tail_gone = pbuf_free(q);\r
+    if (tail_gone > 0) {\r
+      LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE,\r
+                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));\r
+    }\r
+    /* return remaining tail or NULL if deallocated */\r
+  }\r
+  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\r
+  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);\r
+  return (tail_gone > 0? NULL: q);\r
+}\r
index 30199804dc1015feb65caf175dda97f99e5f0f63..b0e18b015229c5e6d035ecd0c2b195a15ba34945 100644 (file)
-/**
- * @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 */
+/**\r
+ * @file\r
+ * \r
+ * Implementation of raw protocol PCBs for low-level handling of\r
+ * different types of protocols besides (or overriding) those\r
+ * already available in lwIP.\r
+ *\r
+ */\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/raw.h"\r
+\r
+#include "lwip/stats.h"\r
+\r
+#include "arch/perf.h"\r
+#include "lwip/snmp.h"\r
+\r
+#if LWIP_RAW\r
+\r
+/** The list of RAW PCBs */\r
+static struct raw_pcb *raw_pcbs = NULL;\r
+\r
+void\r
+raw_init(void)\r
+{\r
+  raw_pcbs = NULL;\r
+}\r
+\r
+/**\r
+ * Determine if in incoming IP packet is covered by a RAW PCB\r
+ * and if so, pass it to a user-provided receive callback function.\r
+ *\r
+ * Given an incoming IP datagram (as a chain of pbufs) this function\r
+ * finds a corresponding RAW PCB and calls the corresponding receive\r
+ * callback function.\r
+ *\r
+ * @param pbuf pbuf to be demultiplexed to a RAW PCB.\r
+ * @param netif network interface on which the datagram was received.\r
+ * @Return - 1 if the packet has been eaten by a RAW PCB receive\r
+ *           callback function. The caller MAY NOT not reference the\r
+ *           packet any longer, and MAY NOT call pbuf_free().\r
+ * @return - 0 if packet is not eaten (pbuf is still referenced by the\r
+ *           caller).\r
+ *\r
+ */\r
+u8_t\r
+raw_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct raw_pcb *pcb;\r
+  struct ip_hdr *iphdr;\r
+  s16_t proto;\r
+  u8_t eaten = 0;\r
+\r
+  iphdr = p->payload;\r
+  proto = IPH_PROTO(iphdr);\r
+\r
+  pcb = raw_pcbs;\r
+  /* loop through all raw pcbs until the packet is eaten by one */\r
+  /* this allows multiple pcbs to match against the packet by design */\r
+  while ((eaten == 0) && (pcb != NULL)) {\r
+    if (pcb->protocol == proto) {\r
+      /* receive callback function available? */\r
+      if (pcb->recv != NULL) {\r
+        /* the receive callback function did not eat the packet? */\r
+        if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)\r
+        {\r
+          /* receive function ate the packet */\r
+          p = NULL;\r
+          eaten = 1;\r
+        }\r
+      }\r
+      /* no receive callback function was set for this raw PCB */\r
+      /* drop the packet */\r
+    }\r
+    pcb = pcb->next;\r
+  }\r
+  return eaten;\r
+}\r
+\r
+/**\r
+ * Bind a RAW PCB.\r
+ *\r
+ * @param pcb RAW PCB to be bound with a local address ipaddr.\r
+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to\r
+ * bind to all local interfaces.\r
+ *\r
+ * @return lwIP error code.\r
+ * - ERR_OK. Successful. No error occured.\r
+ * - ERR_USE. The specified IP address is already bound to by\r
+ * another RAW PCB.\r
+ *\r
+ * @see raw_disconnect()\r
+ */\r
+err_t\r
+raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)\r
+{\r
+  ip_addr_set(&pcb->local_ip, ipaddr);\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Connect an RAW PCB. This function is required by upper layers\r
+ * of lwip. Using the raw api you could use raw_sendto() instead\r
+ *\r
+ * This will associate the RAW PCB with the remote address.\r
+ *\r
+ * @param pcb RAW PCB to be connected with remote address ipaddr and port.\r
+ * @param ipaddr remote IP address to connect with.\r
+ *\r
+ * @return lwIP error code\r
+ *\r
+ * @see raw_disconnect() and raw_sendto()\r
+ */\r
+err_t\r
+raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)\r
+{\r
+  ip_addr_set(&pcb->remote_ip, ipaddr);\r
+  return ERR_OK;\r
+}\r
+\r
+\r
+/**\r
+ * Set the callback function for received packets that match the\r
+ * raw PCB's protocol and binding. \r
+ * \r
+ * The callback function MUST either\r
+ * - eat the packet by calling pbuf_free() and returning non-zero. The\r
+ *   packet will not be passed to other raw PCBs or other protocol layers.\r
+ * - not free the packet, and return zero. The packet will be matched\r
+ *   against further PCBs and/or forwarded to another protocol layers.\r
+ * \r
+ * @return non-zero if the packet was free()d, zero if the packet remains\r
+ * available for others.\r
+ */\r
+void\r
+raw_recv(struct raw_pcb *pcb,\r
+         u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,\r
+                      struct ip_addr *addr),\r
+         void *recv_arg)\r
+{\r
+  /* remember recv() callback and user data */\r
+  pcb->recv = recv;\r
+  pcb->recv_arg = recv_arg;\r
+}\r
+\r
+/**\r
+ * Send the raw IP packet to the given address. Note that actually you cannot\r
+ * modify the IP headers (this is inconsistent with the receive callback where\r
+ * you actually get the IP headers), you can only specify the IP payload here.\r
+ * It requires some more changes in lwIP. (there will be a raw_send() function\r
+ * then.)\r
+ *\r
+ * @param pcb the raw pcb which to send\r
+ * @param p the IP payload to send\r
+ * @param ipaddr the destination address of the IP packet\r
+ *\r
+ */\r
+err_t\r
+raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)\r
+{\r
+  err_t err;\r
+  struct netif *netif;\r
+  struct ip_addr *src_ip;\r
+  struct pbuf *q; /* q will be sent down the stack */\r
+  \r
+  LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_sendto\n"));\r
+  \r
+  /* not enough space to add an IP header to first pbuf in given p chain? */\r
+  if (pbuf_header(p, IP_HLEN)) {\r
+    /* allocate header in new pbuf */\r
+    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);\r
+    /* new header pbuf could not be allocated? */\r
+    if (q == NULL) {\r
+      LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));\r
+      return ERR_MEM;\r
+    }\r
+    /* chain header q in front of given pbuf p */\r
+    pbuf_chain(q, p);\r
+    /* { first pbuf q points to header pbuf } */\r
+    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));\r
+  }  else {\r
+    /* first pbuf q equals given pbuf */\r
+    q = p;\r
+    pbuf_header(q, -IP_HLEN);\r
+  }\r
+  \r
+  if ((netif = ip_route(ipaddr)) == NULL) {\r
+    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));\r
+#if RAW_STATS\r
+    /*    ++lwip_stats.raw.rterr;*/\r
+#endif /* RAW_STATS */\r
+    /* free any temporary header pbuf allocated by pbuf_header() */\r
+    if (q != p) {\r
+      pbuf_free(q);\r
+    }\r
+    return ERR_RTE;\r
+  }\r
+\r
+  if (ip_addr_isany(&pcb->local_ip)) {\r
+    /* use outgoing network interface IP address as source address */\r
+    src_ip = &(netif->ip_addr);\r
+  } else {\r
+    /* use RAW PCB local IP address as source address */\r
+    src_ip = &(pcb->local_ip);\r
+  }\r
+\r
+  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);\r
+\r
+  /* did we chain a header earlier? */\r
+  if (q != p) {\r
+    /* free the header */\r
+    pbuf_free(q);\r
+  }\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Send the raw IP packet to the address given by raw_connect()\r
+ *\r
+ * @param pcb the raw pcb which to send\r
+ * @param p the IP payload to send\r
+ * @param ipaddr the destination address of the IP packet\r
+ *\r
+ */\r
+err_t\r
+raw_send(struct raw_pcb *pcb, struct pbuf *p)\r
+{\r
+  return raw_sendto(pcb, p, &pcb->remote_ip);\r
+}\r
+\r
+/**\r
+ * Remove an RAW PCB.\r
+ *\r
+ * @param pcb RAW PCB to be removed. The PCB is removed from the list of\r
+ * RAW PCB's and the data structure is freed from memory.\r
+ *\r
+ * @see raw_new()\r
+ */\r
+void\r
+raw_remove(struct raw_pcb *pcb)\r
+{\r
+  struct raw_pcb *pcb2;\r
+  /* pcb to be removed is first in list? */\r
+  if (raw_pcbs == pcb) {\r
+    /* make list start at 2nd pcb */\r
+    raw_pcbs = raw_pcbs->next;\r
+    /* pcb not 1st in list */\r
+  } else for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {\r
+    /* find pcb in raw_pcbs list */\r
+    if (pcb2->next != NULL && pcb2->next == pcb) {\r
+      /* remove pcb from list */\r
+      pcb2->next = pcb->next;\r
+    }\r
+  }\r
+  memp_free(MEMP_RAW_PCB, pcb);\r
+}\r
+\r
+/**\r
+ * Create a RAW PCB.\r
+ *\r
+ * @return The RAW PCB which was created. NULL if the PCB data structure\r
+ * could not be allocated.\r
+ *\r
+ * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)\r
+ *\r
+ * @see raw_remove()\r
+ */\r
+struct raw_pcb *\r
+raw_new(u16_t proto) {\r
+  struct raw_pcb *pcb;\r
+\r
+  LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_new\n"));\r
+\r
+  pcb = memp_malloc(MEMP_RAW_PCB);\r
+  /* could allocate RAW PCB? */\r
+  if (pcb != NULL) {\r
+    /* initialize PCB to all zeroes */\r
+    memset(pcb, 0, sizeof(struct raw_pcb));\r
+    pcb->protocol = proto;\r
+    pcb->ttl = RAW_TTL;\r
+    pcb->next = raw_pcbs;\r
+    raw_pcbs = pcb;\r
+  }\r
+  return pcb;\r
+}\r
+\r
+#endif /* LWIP_RAW */\r
index 5e04b38e0dbbe84d41b8a06eb67bf3224e0485c6..a556eddd0052707517441a352dfc7785aeebe7f1 100644 (file)
-/**
- * @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 */
-
+/**\r
+ * @file\r
+ * Abstract Syntax Notation One (ISO 8824, 8825) decoding\r
+ *\r
+ * @todo not optimised (yet), favor correctness over speed, favor speed over size\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP\r
+#include "lwip/snmp_asn1.h"\r
+\r
+/**\r
+ * Retrieves type field from incoming pbuf chain.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded type field\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field\r
+ * @param type return ASN1 type\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ */\r
+err_t\r
+snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+      *type = *msg_ptr;\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes length field from incoming pbuf chain into host length.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded length\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded length\r
+ * @param octets_used returns number of octets used by the length code\r
+ * @param length return host order length, upto 64k\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ */\r
+err_t\r
+snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      if (*msg_ptr < 0x80)\r
+      {\r
+        /* primitive definite length format */\r
+        *octets_used = 1;\r
+        *length = *msg_ptr;\r
+        return ERR_OK;\r
+      }\r
+      else if (*msg_ptr == 0x80)\r
+      {\r
+        /* constructed indefinite length format, termination with two zero octets */\r
+        u8_t zeros;\r
+        u8_t i;\r
+\r
+        *length = 0;\r
+        zeros = 0;\r
+        while (zeros != 2)\r
+        {\r
+          i = 2;\r
+          while (i > 0)\r
+          {\r
+            i--;\r
+            (*length) += 1;\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+            if (*msg_ptr == 0)\r
+            {\r
+              zeros++;\r
+              if (zeros == 2)\r
+              {\r
+                /* stop while (i > 0) */\r
+                i = 0;\r
+              }\r
+            }\r
+            else\r
+            {\r
+              zeros = 0;\r
+            }\r
+          }\r
+        }\r
+        *octets_used = 1;\r
+        return ERR_OK;\r
+      }\r
+      else if (*msg_ptr == 0x81)\r
+      {\r
+        /* constructed definite length format, one octet */\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+        *length = *msg_ptr;\r
+        *octets_used = 2;\r
+        return ERR_OK;\r
+      }\r
+      else if (*msg_ptr == 0x82)\r
+      {\r
+        u8_t i;\r
+\r
+        /* constructed definite length format, two octets */\r
+        i = 2;\r
+        while (i > 0)\r
+        {\r
+          i--;\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+          if (i == 0)\r
+          {\r
+            /* least significant length octet */\r
+            *length |= *msg_ptr;\r
+          }\r
+          else\r
+          {\r
+            /* most significant length octet */\r
+            *length = (*msg_ptr) << 8;\r
+          }\r
+        }\r
+        *octets_used = 3;\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        /* constructed definite length format 3..127 octets, this is too big (>64k) */\r
+        /**  @todo: do we need to accept inefficient codings with many leading zero's? */\r
+        *octets_used = 1 + ((*msg_ptr) & 0x7f);\r
+        return ERR_ARG;\r
+      }\r
+    }\r
+    p = p->next;\r
+  }\r
+\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes positive integer (counter, gauge, timeticks) into u32_t.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded integer\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer\r
+ * @param len length of the coded integer field\r
+ * @param value return host order integer\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ *\r
+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded\r
+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value\r
+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!\r
+ */\r
+err_t\r
+snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+      if ((len > 0) && (len < 6))\r
+      {\r
+        /* start from zero */\r
+        *value = 0;\r
+        if (*msg_ptr & 0x80)\r
+        {\r
+          /* negative, expecting zero sign bit! */\r
+          return ERR_ARG;\r
+        }\r
+        else\r
+        {\r
+          /* positive */\r
+          if ((len > 1) && (*msg_ptr == 0))\r
+          {\r
+            /* skip leading "sign byte" octet 0x00 */\r
+            len--;\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+          }\r
+        }\r
+        /* OR octets with value */\r
+        while (len > 1)\r
+        {\r
+          len--;\r
+          *value |= *msg_ptr;\r
+          *value <<= 8;\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+        }\r
+        *value |= *msg_ptr;\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        return ERR_ARG;\r
+      }\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes integer into s32_t.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded integer\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer\r
+ * @param len length of the coded integer field\r
+ * @param value return host order integer\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ *\r
+ * @note ASN coded integers are _always_ signed!\r
+ */\r
+err_t\r
+snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+  u8_t *lsb_ptr = (u8_t*)value;\r
+  u8_t sign;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+      if ((len > 0) && (len < 5))\r
+      {\r
+        if (*msg_ptr & 0x80)\r
+        {\r
+          /* negative, start from -1 */\r
+          *value = -1;\r
+          sign = 1;\r
+        }\r
+        else\r
+        {\r
+          /* positive, start from 0 */\r
+          *value = 0;\r
+          sign = 0;\r
+        }\r
+        /* OR/AND octets with value */\r
+        while (len > 1)\r
+        {\r
+          len--;\r
+          if (sign)\r
+          {\r
+            *lsb_ptr &= *msg_ptr;\r
+            *value <<= 8;\r
+            *lsb_ptr |= 255;\r
+          }\r
+          else\r
+          {\r
+            *lsb_ptr |= *msg_ptr;\r
+            *value <<= 8;\r
+          }\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+        }\r
+        if (sign)\r
+        {\r
+          *lsb_ptr &= *msg_ptr;\r
+        }\r
+        else\r
+        {\r
+          *lsb_ptr |= *msg_ptr;\r
+        }\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        return ERR_ARG;\r
+      }\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes object identifier from incoming message into array of s32_t.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded object identifier\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier\r
+ * @param len length of the coded object identifier\r
+ * @param oid return object identifier struct\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ */\r
+err_t\r
+snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+  s32_t *oid_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      oid->len = 0;\r
+      oid_ptr = &oid->id[0];\r
+      if (len > 0)\r
+      {\r
+        /* first compressed octet */\r
+        if (*msg_ptr == 0x2B)\r
+        {\r
+          /* (most) common case 1.3 (iso.org) */\r
+          *oid_ptr = 1;\r
+          oid_ptr++;\r
+          *oid_ptr = 3;\r
+          oid_ptr++;\r
+        }\r
+        else if (*msg_ptr < 40)\r
+        {\r
+          *oid_ptr = 0;\r
+          oid_ptr++;\r
+          *oid_ptr = *msg_ptr;\r
+          oid_ptr++;\r
+        }\r
+        else if (*msg_ptr < 80)\r
+        {\r
+          *oid_ptr = 1;\r
+          oid_ptr++;\r
+          *oid_ptr = (*msg_ptr) - 40;\r
+          oid_ptr++;\r
+        }\r
+        else\r
+        {\r
+          *oid_ptr = 2;\r
+          oid_ptr++;\r
+          *oid_ptr = (*msg_ptr) - 80;\r
+          oid_ptr++;\r
+        }\r
+        oid->len = 2;\r
+      }\r
+      else\r
+      {\r
+        /* accepting zero length identifiers e.g. for\r
+           getnext operation. uncommon but valid */\r
+        return ERR_OK;\r
+      }\r
+      len--;\r
+      if (len > 0)\r
+      {\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))\r
+      {\r
+        /* sub-identifier uses multiple octets */\r
+        if (*msg_ptr & 0x80)\r
+        {\r
+          s32_t sub_id = 0;\r
+\r
+          while ((*msg_ptr & 0x80) && (len > 1))\r
+          {\r
+            len--;\r
+            sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+          }\r
+          if (!(*msg_ptr & 0x80) && (len > 0))\r
+          {\r
+            /* last octet sub-identifier */\r
+            len--;\r
+            sub_id = (sub_id << 7) + *msg_ptr;\r
+            *oid_ptr = sub_id;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* !(*msg_ptr & 0x80) sub-identifier uses single octet */\r
+          len--;\r
+          *oid_ptr = *msg_ptr;\r
+        }\r
+        if (len > 0)\r
+        {\r
+          /* remaining oid bytes available ... */\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+        }\r
+        oid_ptr++;\r
+        oid->len++;\r
+      }\r
+      if (len == 0)\r
+      {\r
+        /* len == 0, end of oid */\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */\r
+        return ERR_ARG;\r
+      }\r
+\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)\r
+ * from incoming message into array.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded raw data\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data\r
+ * @param len length of the coded raw data (zero is valid, e.g. empty string!)\r
+ * @param raw_len length of the raw return value\r
+ * @param raw return raw bytes\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ */\r
+err_t\r
+snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  if (len > 0)\r
+  {\r
+    plen = 0;\r
+    while (p != NULL)\r
+    {\r
+      base = plen;\r
+      plen += p->len;\r
+      if (ofs < plen)\r
+      {\r
+        msg_ptr = p->payload;\r
+        msg_ptr += ofs - base;\r
+        if (raw_len >= len)\r
+        {\r
+          while (len > 1)\r
+          {\r
+            /* copy len - 1 octets */\r
+            len--;\r
+            *raw = *msg_ptr;\r
+            raw++;\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+          }\r
+          /* copy last octet */\r
+          *raw = *msg_ptr;\r
+          return ERR_OK;\r
+        }\r
+        else\r
+        {\r
+          /* raw_len < len, not enough dst space */\r
+          return ERR_ARG;\r
+        }\r
+      }\r
+      p = p->next;\r
+    }\r
+    /* p == NULL, ofs >= plen */\r
+    return ERR_ARG;\r
+  }\r
+  else\r
+  {\r
+    /* len == 0, empty string */\r
+    return ERR_OK;\r
+  }\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
+\r
index 4d04f28543200af94e512f02eee4f4b6bb887a1d..80f8d3768b81a072699d707a7f53ae0908b2ad27 100644 (file)
-/**
- * @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 */
+/**\r
+ * @file\r
+ * Abstract Syntax Notation One (ISO 8824, 8825) encoding\r
+ *\r
+ * @todo not optimised (yet), favor correctness over speed, favor speed over size\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP\r
+#include "lwip/snmp_asn1.h"\r
+\r
+/**\r
+ * Returns octet count for length.\r
+ *\r
+ * @param length\r
+ * @param octets_needed points to the return value\r
+ */\r
+void\r
+snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)\r
+{\r
+  if (length < 0x80U)\r
+  {\r
+    *octets_needed = 1;\r
+  }\r
+  else if (length < 0x100U)\r
+  {\r
+    *octets_needed = 2;\r
+  }\r
+  else\r
+  {\r
+    *octets_needed = 3;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns octet count for an u32_t.\r
+ *\r
+ * @param value\r
+ * @param octets_needed points to the return value\r
+ *\r
+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded\r
+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value\r
+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!\r
+ */\r
+void\r
+snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)\r
+{\r
+  if (value < 0x80UL)\r
+  {\r
+    *octets_needed = 1;\r
+  }\r
+  else if (value < 0x8000UL)\r
+  {\r
+    *octets_needed = 2;\r
+  }\r
+  else if (value < 0x800000UL)\r
+  {\r
+    *octets_needed = 3;\r
+  }\r
+  else if (value < 0x80000000UL)\r
+  {\r
+    *octets_needed = 4;\r
+  }\r
+  else\r
+  {\r
+    *octets_needed = 5;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns octet count for an s32_t.\r
+ *\r
+ * @param value\r
+ * @param octets_needed points to the return value\r
+ *\r
+ * @note ASN coded integers are _always_ signed.\r
+ */\r
+void\r
+snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)\r
+{\r
+  if (value < 0)\r
+  {\r
+    value = ~value;\r
+  }\r
+  if (value < 0x80L)\r
+  {\r
+    *octets_needed = 1;\r
+  }\r
+  else if (value < 0x8000L)\r
+  {\r
+    *octets_needed = 2;\r
+  }\r
+  else if (value < 0x800000L)\r
+  {\r
+    *octets_needed = 3;\r
+  }\r
+  else\r
+  {\r
+    *octets_needed = 4;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns octet count for an object identifier.\r
+ *\r
+ * @param ident_len object identifier array length\r
+ * @param ident points to object identifier array\r
+ * @param octets_needed points to the return value\r
+ */\r
+void\r
+snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)\r
+{\r
+  s32_t sub_id;\r
+  u8_t cnt;\r
+\r
+  cnt = 0;\r
+  if (ident_len > 1)\r
+  {\r
+    /* compressed prefix in one octet */\r
+    cnt++;\r
+    ident_len -= 2;\r
+    ident += 2;\r
+  }\r
+  while(ident_len > 0)\r
+  {\r
+    ident_len--;\r
+    sub_id = *ident;\r
+\r
+    sub_id >>= 7;\r
+    cnt++;\r
+    while(sub_id > 0)\r
+    {\r
+      sub_id >>= 7;\r
+      cnt++;\r
+    }\r
+    ident++;\r
+  }\r
+  *octets_needed = cnt;\r
+}\r
+\r
+/**\r
+ * Encodes ASN type field into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode value into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param type input ASN1 type\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ */\r
+err_t\r
+snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+      *msg_ptr = type;\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes host order length field into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode length into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param length is the host order length to be encoded\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ */\r
+err_t\r
+snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      if (length < 0x80)\r
+      {\r
+        *msg_ptr = length;\r
+        return ERR_OK;\r
+      }\r
+      else if (length < 0x100)\r
+      {\r
+        *msg_ptr = 0x81;\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+        *msg_ptr = length;\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        u8_t i;\r
+\r
+        /* length >= 0x100 && length <= 0xFFFF */\r
+        *msg_ptr = 0x82;\r
+        i = 2;\r
+        while (i > 0)\r
+        {\r
+          i--;\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+          if (i == 0)\r
+          {\r
+            /* least significant length octet */\r
+            *msg_ptr = length;\r
+          }\r
+          else\r
+          {\r
+            /* most significant length octet */\r
+            *msg_ptr = length >> 8;\r
+          }\r
+        }\r
+        return ERR_OK;\r
+      }\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode value into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())\r
+ * @param value is the host order u32_t value to be encoded\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ *\r
+ * @see snmp_asn1_enc_u32t_cnt()\r
+ */\r
+err_t\r
+snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      if (octets_needed == 5)\r
+      {\r
+        /* not enough bits in 'value' add leading 0x00 */\r
+        octets_needed--;\r
+        *msg_ptr = 0x00;\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      while (octets_needed > 1)\r
+      {\r
+        octets_needed--;\r
+        *msg_ptr = value >> (octets_needed << 3);\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      /* (only) one least significant octet */\r
+      *msg_ptr = value;\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes s32_t integer into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode value into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())\r
+ * @param value is the host order s32_t value to be encoded\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ *\r
+ * @see snmp_asn1_enc_s32t_cnt()\r
+ */\r
+err_t\r
+snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      while (octets_needed > 1)\r
+      {\r
+        octets_needed--;\r
+        *msg_ptr = value >> (octets_needed << 3);\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      /* (only) one least significant octet */\r
+      *msg_ptr = value;\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes object identifier into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode oid into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param ident_len object identifier array length\r
+ * @param ident points to object identifier array\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ */\r
+err_t\r
+snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      if (ident_len > 1)\r
+      {\r
+        if ((ident[0] == 1) && (ident[1] == 3))\r
+        {\r
+          /* compressed (most common) prefix .iso.org */\r
+          *msg_ptr = 0x2b;\r
+        }\r
+        else\r
+        {\r
+          /* calculate prefix */\r
+          *msg_ptr = (ident[0] * 40) + ident[1];\r
+        }\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+        ident_len -= 2;\r
+        ident += 2;\r
+      }\r
+      else\r
+      {\r
+/* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression??  */\r
+        /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */\r
+        return ERR_ARG;\r
+      }\r
+      while (ident_len > 0)\r
+      {\r
+        s32_t sub_id;\r
+        u8_t shift, tail;\r
+\r
+        ident_len--;\r
+        sub_id = *ident;\r
+        tail = 0;\r
+        shift = 28;\r
+        while(shift > 0)\r
+        {\r
+          u8_t code;\r
+\r
+          code = sub_id >> shift;\r
+          if ((code != 0) || (tail != 0))\r
+          {\r
+            tail = 1;\r
+            *msg_ptr = code | 0x80;\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+          }\r
+          shift -= 7;\r
+        }\r
+        *msg_ptr = (u8_t)sub_id & 0x7F;\r
+        if (ident_len > 0)\r
+        {\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+        }\r
+        /* proceed to next sub-identifier */\r
+        ident++;\r
+      }\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode raw data into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param raw_len raw data length\r
+ * @param raw points raw data\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ */\r
+err_t\r
+snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      while (raw_len > 1)\r
+      {\r
+        /* copy raw_len - 1 octets */\r
+        raw_len--;\r
+        *msg_ptr = *raw;\r
+        raw++;\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      if (raw_len > 0)\r
+      {\r
+        /* copy last or single octet */\r
+        *msg_ptr = *raw;\r
+      }\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
index 3e478aba6e233e955b1b0a95ac33c0ad28dd0ef8..035c8b1b4da0b491c9c528ae3f511f3ea9aaddca 100644 (file)
-/**
- * @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 */
+/**\r
+ * @file\r
+ * Management Information Base II (RFC1213) objects and functions.\r
+ *\r
+ * @note the object identifiers for this MIB-2 and private MIB tree\r
+ * must be kept in sorted ascending order. This to ensure correct getnext operation.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "arch/cc.h"\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP\r
+#include "lwip/snmp.h"\r
+#include "lwip/netif.h"\r
+#include "netif/etharp.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/ip_frag.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/snmp_asn1.h"\r
+#include "lwip/snmp_structs.h"\r
+\r
+/**\r
+ * IANA assigned enterprise ID for lwIP is 26381\r
+ * @see http://www.iana.org/assignments/enterprise-numbers\r
+ *\r
+ * @note this enterprise ID is assigned to the lwIP project,\r
+ * all object identifiers living under this ID are assigned\r
+ * by the lwIP maintainers (contact Christiaan Simons)!\r
+ * @note don't change this define, use snmp_set_sysobjid()\r
+ *\r
+ * If you need to create your own private MIB you'll need\r
+ * to apply for your own enterprise ID with IANA:\r
+ * http://www.iana.org/numbers.html\r
+ */\r
+#define SNMP_ENTERPRISE_ID 26381\r
+#define SNMP_SYSOBJID_LEN 7\r
+#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID}\r
+\r
+#ifndef SNMP_SYSSERVICES\r
+#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2))\r
+#endif\r
+\r
+static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void system_get_value(struct obj_def *od, u16_t len, void *value);\r
+static u8_t system_set_test(struct obj_def *od, u16_t len, void *value);\r
+static void system_set_value(struct obj_def *od, u16_t len, void *value);\r
+static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void interfaces_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ifentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void atentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ip_get_value(struct obj_def *od, u16_t len, void *value);\r
+static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value);\r
+static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void icmp_get_value(struct obj_def *od, u16_t len, void *value);\r
+#if LWIP_TCP\r
+static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void tcp_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+#endif\r
+static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void udp_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void udpentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void snmp_get_value(struct obj_def *od, u16_t len, void *value);\r
+static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value);\r
+static void snmp_set_value(struct obj_def *od, u16_t len, void *value);\r
+\r
+\r
+/* snmp .1.3.6.1.2.1.11 */\r
+const mib_scalar_node snmp_scalar = {\r
+  &snmp_get_object_def,\r
+  &snmp_get_value,\r
+  &snmp_set_test,\r
+  &snmp_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t snmp_ids[28] = {\r
+  1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16,\r
+  17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30\r
+};\r
+struct mib_node* const snmp_nodes[28] = {\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar\r
+};\r
+const struct mib_array_node snmp = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  28,\r
+  snmp_ids,\r
+  snmp_nodes\r
+};\r
+\r
+/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */\r
+/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */\r
+/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */\r
+\r
+/* udp .1.3.6.1.2.1.7 */\r
+/** index root node for udpTable */\r
+struct mib_list_rootnode udp_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t udpentry_ids[2] = { 1, 2 };\r
+struct mib_node* const udpentry_nodes[2] = {\r
+  (struct mib_node* const)&udp_root, (struct mib_node* const)&udp_root,\r
+};\r
+const struct mib_array_node udpentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  2,\r
+  udpentry_ids,\r
+  udpentry_nodes\r
+};\r
+\r
+s32_t udptable_id = 1;\r
+struct mib_node* udptable_node = (struct mib_node* const)&udpentry;\r
+struct mib_ram_array_node udptable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &udptable_id,\r
+  &udptable_node\r
+};\r
+\r
+const mib_scalar_node udp_scalar = {\r
+  &udp_get_object_def,\r
+  &udp_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 };\r
+struct mib_node* const udp_nodes[5] = {\r
+  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,\r
+  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,\r
+  (struct mib_node* const)&udptable\r
+};\r
+const struct mib_array_node udp = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  5,\r
+  udp_ids,\r
+  udp_nodes\r
+};\r
+\r
+/* tcp .1.3.6.1.2.1.6 */\r
+#if LWIP_TCP\r
+/* only if the TCP protocol is available may implement this group */\r
+/** index root node for tcpConnTable */\r
+struct mib_list_rootnode tcpconntree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 };\r
+struct mib_node* const tcpconnentry_nodes[5] = {\r
+  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,\r
+  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,\r
+  (struct mib_node* const)&tcpconntree_root\r
+};\r
+const struct mib_array_node tcpconnentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  5,\r
+  tcpconnentry_ids,\r
+  tcpconnentry_nodes\r
+};\r
+\r
+s32_t tcpconntable_id = 1;\r
+struct mib_node* tcpconntable_node = (struct mib_node* const)&tcpconnentry;\r
+struct mib_ram_array_node tcpconntable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+/** @todo update maxlength when inserting / deleting from table\r
+   0 when table is empty, 1 when more than one entry */\r
+  0,\r
+  &tcpconntable_id,\r
+  &tcpconntable_node\r
+};\r
+\r
+const mib_scalar_node tcp_scalar = {\r
+  &tcp_get_object_def,\r
+  &tcp_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };\r
+struct mib_node* const tcp_nodes[15] = {\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcpconntable, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar\r
+};\r
+const struct mib_array_node tcp = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  15,\r
+  tcp_ids,\r
+  tcp_nodes\r
+};\r
+#endif\r
+\r
+/* icmp .1.3.6.1.2.1.5 */\r
+const mib_scalar_node icmp_scalar = {\r
+  &icmp_get_object_def,\r
+  &icmp_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+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 };\r
+struct mib_node* const icmp_nodes[26] = {\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar\r
+};\r
+const struct mib_array_node icmp = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  26,\r
+  icmp_ids,\r
+  icmp_nodes\r
+};\r
+\r
+/** index root node for ipNetToMediaTable */\r
+struct mib_list_rootnode ipntomtree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 };\r
+struct mib_node* const ipntomentry_nodes[4] = {\r
+  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root,\r
+  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root\r
+};\r
+const struct mib_array_node ipntomentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  4,\r
+  ipntomentry_ids,\r
+  ipntomentry_nodes\r
+};\r
+\r
+s32_t ipntomtable_id = 1;\r
+struct mib_node* ipntomtable_node = (struct mib_node* const)&ipntomentry;\r
+struct mib_ram_array_node ipntomtable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &ipntomtable_id,\r
+  &ipntomtable_node\r
+};\r
+\r
+/** index root node for ipRouteTable */\r
+struct mib_list_rootnode iprtetree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };\r
+struct mib_node* const iprteentry_nodes[13] = {\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root\r
+};\r
+const struct mib_array_node iprteentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  13,\r
+  iprteentry_ids,\r
+  iprteentry_nodes\r
+};\r
+\r
+s32_t iprtetable_id = 1;\r
+struct mib_node* iprtetable_node = (struct mib_node* const)&iprteentry;\r
+struct mib_ram_array_node iprtetable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &iprtetable_id,\r
+  &iprtetable_node\r
+};\r
+\r
+/** index root node for ipAddrTable */\r
+struct mib_list_rootnode ipaddrtree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 };\r
+struct mib_node* const ipaddrentry_nodes[5] = {\r
+  (struct mib_node* const)&ipaddrtree_root,\r
+  (struct mib_node* const)&ipaddrtree_root,\r
+  (struct mib_node* const)&ipaddrtree_root,\r
+  (struct mib_node* const)&ipaddrtree_root,\r
+  (struct mib_node* const)&ipaddrtree_root\r
+};\r
+const struct mib_array_node ipaddrentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  5,\r
+  ipaddrentry_ids,\r
+  ipaddrentry_nodes\r
+};\r
+\r
+s32_t ipaddrtable_id = 1;\r
+struct mib_node* ipaddrtable_node = (struct mib_node* const)&ipaddrentry;\r
+struct mib_ram_array_node ipaddrtable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &ipaddrtable_id,\r
+  &ipaddrtable_node\r
+};\r
+\r
+/* ip .1.3.6.1.2.1.4 */\r
+const mib_scalar_node ip_scalar = {\r
+  &ip_get_object_def,\r
+  &ip_get_value,\r
+  &ip_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+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 };\r
+struct mib_node* const ip_nodes[23] = {\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ipaddrtable,\r
+  (struct mib_node* const)&iprtetable, (struct mib_node* const)&ipntomtable,\r
+  (struct mib_node* const)&ip_scalar\r
+};\r
+const struct mib_array_node ip = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  23,\r
+  ip_ids,\r
+  ip_nodes\r
+};\r
+\r
+/** index root node for atTable */\r
+struct mib_list_rootnode arptree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t atentry_ids[3] = { 1, 2, 3 };\r
+struct mib_node* const atentry_nodes[3] = {\r
+  (struct mib_node* const)&arptree_root,\r
+  (struct mib_node* const)&arptree_root,\r
+  (struct mib_node* const)&arptree_root\r
+};\r
+const struct mib_array_node atentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  3,\r
+  atentry_ids,\r
+  atentry_nodes\r
+};\r
+\r
+const s32_t attable_id = 1;\r
+struct mib_node* const attable_node = (struct mib_node* const)&atentry;\r
+const struct mib_array_node attable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  1,\r
+  &attable_id,\r
+  &attable_node\r
+};\r
+\r
+/* at .1.3.6.1.2.1.3 */\r
+s32_t at_id = 1;\r
+struct mib_node* at_node = (struct mib_node* const)&attable;\r
+struct mib_ram_array_node at = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &at_id,\r
+  &at_node\r
+};\r
+\r
+/** index root node for ifTable */\r
+struct mib_list_rootnode iflist_root = {\r
+  &ifentry_get_object_def,\r
+  &ifentry_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+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 };\r
+struct mib_node* const ifentry_nodes[22] = {\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root\r
+};\r
+const struct mib_array_node ifentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  22,\r
+  ifentry_ids,\r
+  ifentry_nodes\r
+};\r
+\r
+s32_t iftable_id = 1;\r
+struct mib_node* iftable_node = (struct mib_node* const)&ifentry;\r
+struct mib_ram_array_node iftable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &iftable_id,\r
+  &iftable_node\r
+};\r
+\r
+/* interfaces .1.3.6.1.2.1.2 */\r
+const mib_scalar_node interfaces_scalar = {\r
+  &interfaces_get_object_def,\r
+  &interfaces_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t interfaces_ids[2] = { 1, 2 };\r
+struct mib_node* const interfaces_nodes[2] = {\r
+  (struct mib_node* const)&interfaces_scalar, (struct mib_node* const)&iftable\r
+};\r
+const struct mib_array_node interfaces = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  2,\r
+  interfaces_ids,\r
+  interfaces_nodes\r
+};\r
+\r
+\r
+/*             0 1 2 3 4 5 6 */\r
+/* system .1.3.6.1.2.1.1 */\r
+const mib_scalar_node sys_tem_scalar = {\r
+  &system_get_object_def,\r
+  &system_get_value,\r
+  &system_set_test,\r
+  &system_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 };\r
+struct mib_node* const sys_tem_nodes[7] = {\r
+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,\r
+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,\r
+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,\r
+  (struct mib_node* const)&sys_tem_scalar\r
+};\r
+/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */\r
+const struct mib_array_node sys_tem = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  7,\r
+  sys_tem_ids,\r
+  sys_tem_nodes\r
+};\r
+\r
+/* mib-2 .1.3.6.1.2.1 */\r
+#if LWIP_TCP\r
+#define MIB2_GROUPS 8\r
+#else\r
+#define MIB2_GROUPS 7\r
+#endif\r
+const s32_t mib2_ids[MIB2_GROUPS] =\r
+{\r
+  1,\r
+  2,\r
+  3,\r
+  4,\r
+  5,\r
+#if LWIP_TCP\r
+  6,\r
+#endif\r
+  7,\r
+  11\r
+};\r
+struct mib_node* const mib2_nodes[MIB2_GROUPS] = {\r
+  (struct mib_node* const)&sys_tem,\r
+  (struct mib_node* const)&interfaces,\r
+  (struct mib_node* const)&at,\r
+  (struct mib_node* const)&ip,\r
+  (struct mib_node* const)&icmp,\r
+#if LWIP_TCP\r
+  (struct mib_node* const)&tcp,\r
+#endif\r
+  (struct mib_node* const)&udp,\r
+  (struct mib_node* const)&snmp\r
+};\r
+\r
+const struct mib_array_node mib2 = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  MIB2_GROUPS,\r
+  mib2_ids,\r
+  mib2_nodes\r
+};\r
+\r
+/* mgmt .1.3.6.1.2 */\r
+const s32_t mgmt_ids[1] = { 1 };\r
+struct mib_node* const mgmt_nodes[1] = { (struct mib_node* const)&mib2 };\r
+const struct mib_array_node mgmt = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  1,\r
+  mgmt_ids,\r
+  mgmt_nodes\r
+};\r
+\r
+/* internet .1.3.6.1 */\r
+#if SNMP_PRIVATE_MIB\r
+s32_t internet_ids[2] = { 2, 4 };\r
+struct mib_node* const internet_nodes[2] = { (struct mib_node* const)&mgmt, (struct mib_node* const)&private };\r
+const struct mib_array_node internet = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  2,\r
+  internet_ids,\r
+  internet_nodes\r
+};\r
+#else\r
+const s32_t internet_ids[1] = { 2 };\r
+struct mib_node* const internet_nodes[1] = { (struct mib_node* const)&mgmt };\r
+const struct mib_array_node internet = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  1,\r
+  internet_ids,\r
+  internet_nodes\r
+};\r
+#endif\r
+\r
+/** mib-2.system.sysObjectID  */\r
+static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID};\r
+/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */\r
+static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}};\r
+/** mib-2.system.sysServices */\r
+static const s32_t sysservices = SNMP_SYSSERVICES;\r
+\r
+/** mib-2.system.sysDescr */\r
+static const u8_t sysdescr_len_default = 4;\r
+static const u8_t sysdescr_default[] = "lwIP";\r
+static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default;\r
+static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0];\r
+/** mib-2.system.sysContact */\r
+static const u8_t syscontact_len_default = 0;\r
+static const u8_t syscontact_default[] = "";\r
+static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default;\r
+static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0];\r
+/** mib-2.system.sysName */\r
+static const u8_t sysname_len_default = 8;\r
+static const u8_t sysname_default[] = "FQDN-unk";\r
+static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default;\r
+static u8_t* sysname_ptr = (u8_t*)&sysname_default[0];\r
+/** mib-2.system.sysLocation */\r
+static const u8_t syslocation_len_default = 0;\r
+static const u8_t syslocation_default[] = "";\r
+static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default;\r
+static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0];\r
+/** mib-2.snmp.snmpEnableAuthenTraps */\r
+static const u8_t snmpenableauthentraps_default = 2; /* disabled */\r
+static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default;\r
+\r
+/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */\r
+static const struct snmp_obj_id ifspecific = {2, {0, 0}};\r
+/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */\r
+static const struct snmp_obj_id iprouteinfo = {2, {0, 0}};\r
+\r
+\r
+\r
+/* mib-2.system counter(s) */\r
+static u32_t sysuptime = 0;\r
+\r
+/* mib-2.ip counter(s) */\r
+static u32_t ipinreceives = 0,\r
+             ipinhdrerrors = 0,\r
+             ipinaddrerrors = 0,\r
+             ipforwdatagrams = 0,\r
+             ipinunknownprotos = 0,\r
+             ipindiscards = 0,\r
+             ipindelivers = 0,\r
+             ipoutrequests = 0,\r
+             ipoutdiscards = 0,\r
+             ipoutnoroutes = 0,\r
+             ipreasmreqds = 0,\r
+             ipreasmoks = 0,\r
+             ipreasmfails = 0,\r
+             ipfragoks = 0,\r
+             ipfragfails = 0,\r
+             ipfragcreates = 0,\r
+             iproutingdiscards = 0;\r
+/* mib-2.icmp counter(s) */\r
+static u32_t icmpinmsgs = 0,\r
+             icmpinerrors = 0,\r
+             icmpindestunreachs = 0,\r
+             icmpintimeexcds = 0,\r
+             icmpinparmprobs = 0,\r
+             icmpinsrcquenchs = 0,\r
+             icmpinredirects = 0,\r
+             icmpinechos = 0,\r
+             icmpinechoreps = 0,\r
+             icmpintimestamps = 0,\r
+             icmpintimestampreps = 0,\r
+             icmpinaddrmasks = 0,\r
+             icmpinaddrmaskreps = 0,\r
+             icmpoutmsgs = 0,\r
+             icmpouterrors = 0,\r
+             icmpoutdestunreachs = 0,\r
+             icmpouttimeexcds = 0,\r
+             icmpoutparmprobs = 0,\r
+             icmpoutsrcquenchs = 0,\r
+             icmpoutredirects = 0,\r
+             icmpoutechos = 0,\r
+             icmpoutechoreps = 0,\r
+             icmpouttimestamps = 0,\r
+             icmpouttimestampreps = 0,\r
+             icmpoutaddrmasks = 0,\r
+             icmpoutaddrmaskreps = 0;\r
+/* mib-2.tcp counter(s) */\r
+static u32_t tcpactiveopens = 0,\r
+             tcppassiveopens = 0,\r
+             tcpattemptfails = 0,\r
+             tcpestabresets = 0,\r
+             tcpinsegs = 0,\r
+             tcpoutsegs = 0,\r
+             tcpretranssegs = 0,\r
+             tcpinerrs = 0,\r
+             tcpoutrsts = 0;\r
+/* mib-2.udp counter(s) */\r
+static u32_t udpindatagrams = 0,\r
+             udpnoports = 0,\r
+             udpinerrors = 0,\r
+             udpoutdatagrams = 0;\r
+/* mib-2.snmp counter(s) */\r
+static u32_t snmpinpkts = 0,\r
+             snmpoutpkts = 0,\r
+             snmpinbadversions = 0,\r
+             snmpinbadcommunitynames = 0,\r
+             snmpinbadcommunityuses = 0,\r
+             snmpinasnparseerrs = 0,\r
+             snmpintoobigs = 0,\r
+             snmpinnosuchnames = 0,\r
+             snmpinbadvalues = 0,\r
+             snmpinreadonlys = 0,\r
+             snmpingenerrs = 0,\r
+             snmpintotalreqvars = 0,\r
+             snmpintotalsetvars = 0,\r
+             snmpingetrequests = 0,\r
+             snmpingetnexts = 0,\r
+             snmpinsetrequests = 0,\r
+             snmpingetresponses = 0,\r
+             snmpintraps = 0,\r
+             snmpouttoobigs = 0,\r
+             snmpoutnosuchnames = 0,\r
+             snmpoutbadvalues = 0,\r
+             snmpoutgenerrs = 0,\r
+             snmpoutgetrequests = 0,\r
+             snmpoutgetnexts = 0,\r
+             snmpoutsetrequests = 0,\r
+             snmpoutgetresponses = 0,\r
+             snmpouttraps = 0;\r
+\r
+\r
+\r
+/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */\r
+/**\r
+ * Copy octet string.\r
+ *\r
+ * @param dst points to destination\r
+ * @param src points to source\r
+ * @param n number of octets to copy.\r
+ */\r
+void ocstrncpy(u8_t *dst, u8_t *src, u8_t n)\r
+{\r
+  while (n > 0)\r
+  {\r
+    n--;\r
+    *dst++ = *src++;\r
+  }\r
+}\r
+\r
+/**\r
+ * Copy object identifier (s32_t) array.\r
+ *\r
+ * @param dst points to destination\r
+ * @param src points to source\r
+ * @param n number of sub identifiers to copy.\r
+ */\r
+void objectidncpy(s32_t *dst, s32_t *src, u8_t n)\r
+{\r
+  while(n > 0)\r
+  {\r
+    n--;\r
+    *dst++ = *src++;\r
+  }\r
+}\r
+\r
+/**\r
+ * Initializes sysDescr pointers.\r
+ *\r
+ * @param str if non-NULL then copy str pointer\r
+ * @param strlen points to string length, excluding zero terminator\r
+ */\r
+void snmp_set_sysdesr(u8_t *str, u8_t *strlen)\r
+{\r
+  if (str != NULL)\r
+  {\r
+    sysdescr_ptr = str;\r
+    sysdescr_len_ptr = strlen;\r
+  }\r
+}\r
+\r
+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid)\r
+{\r
+  *oid = &sysobjid;\r
+}\r
+\r
+/**\r
+ * Initializes sysObjectID value.\r
+ *\r
+ * @param oid points to stuct snmp_obj_id to copy\r
+ */\r
+void snmp_set_sysobjid(struct snmp_obj_id *oid)\r
+{\r
+  sysobjid = *oid;\r
+}\r
+\r
+/**\r
+ * Must be called at regular 10 msec interval from a timer interrupt\r
+ * or signal handler depending on your runtime environment.\r
+ */\r
+void snmp_inc_sysuptime(void)\r
+{\r
+  sysuptime++;\r
+}\r
+\r
+void snmp_get_sysuptime(u32_t *value)\r
+{\r
+  *value = sysuptime;\r
+}\r
+\r
+/**\r
+ * Initializes sysContact pointers,\r
+ * e.g. ptrs to non-volatile memory external to lwIP.\r
+ *\r
+ * @param str if non-NULL then copy str pointer\r
+ * @param strlen points to string length, excluding zero terminator\r
+ */\r
+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen)\r
+{\r
+  if (ocstr != NULL)\r
+  {\r
+    syscontact_ptr = ocstr;\r
+    syscontact_len_ptr = ocstrlen;\r
+  }\r
+}\r
+\r
+/**\r
+ * Initializes sysName pointers,\r
+ * e.g. ptrs to non-volatile memory external to lwIP.\r
+ *\r
+ * @param str if non-NULL then copy str pointer\r
+ * @param strlen points to string length, excluding zero terminator\r
+ */\r
+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen)\r
+{\r
+  if (ocstr != NULL)\r
+  {\r
+    sysname_ptr = ocstr;\r
+    sysname_len_ptr = ocstrlen;\r
+  }\r
+}\r
+\r
+/**\r
+ * Initializes sysLocation pointers,\r
+ * e.g. ptrs to non-volatile memory external to lwIP.\r
+ *\r
+ * @param str if non-NULL then copy str pointer\r
+ * @param strlen points to string length, excluding zero terminator\r
+ */\r
+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen)\r
+{\r
+  if (ocstr != NULL)\r
+  {\r
+    syslocation_ptr = ocstr;\r
+    syslocation_len_ptr = ocstrlen;\r
+  }\r
+}\r
+\r
+\r
+void snmp_add_ifinoctets(struct netif *ni, u32_t value)\r
+{\r
+  ni->ifinoctets += value;\r
+}\r
+\r
+void snmp_inc_ifinucastpkts(struct netif *ni)\r
+{\r
+  (ni->ifinucastpkts)++;\r
+}\r
+\r
+void snmp_inc_ifinnucastpkts(struct netif *ni)\r
+{\r
+  (ni->ifinnucastpkts)++;\r
+}\r
+\r
+void snmp_inc_ifindiscards(struct netif *ni)\r
+{\r
+  (ni->ifindiscards)++;\r
+}\r
+\r
+void snmp_add_ifoutoctets(struct netif *ni, u32_t value)\r
+{\r
+  ni->ifoutoctets += value;\r
+}\r
+\r
+void snmp_inc_ifoutucastpkts(struct netif *ni)\r
+{\r
+  (ni->ifoutucastpkts)++;\r
+}\r
+\r
+void snmp_inc_ifoutnucastpkts(struct netif *ni)\r
+{\r
+  (ni->ifoutnucastpkts)++;\r
+}\r
+\r
+void snmp_inc_ifoutdiscards(struct netif *ni)\r
+{\r
+  (ni->ifoutdiscards)++;\r
+}\r
+\r
+void snmp_inc_iflist(void)\r
+{\r
+  struct mib_list_node *if_node = NULL;\r
+\r
+  snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node);\r
+  /* enable getnext traversal on filled table */\r
+  iftable.maxlength = 1;\r
+}\r
+\r
+void snmp_dec_iflist(void)\r
+{\r
+  snmp_mib_node_delete(&iflist_root, iflist_root.tail);\r
+  /* disable getnext traversal on empty table */\r
+  if(iflist_root.count == 0) iftable.maxlength = 0;\r
+}\r
+\r
+/**\r
+ * Inserts ARP table indexes (.xIfIndex.xNetAddress)\r
+ * into arp table index trees (both atTable and ipNetToMediaTable).\r
+ */\r
+void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip)\r
+{\r
+  struct mib_list_rootnode *at_rn;\r
+  struct mib_list_node *at_node;\r
+  struct ip_addr hip;\r
+  s32_t arpidx[5];\r
+  u8_t level, tree;\r
+\r
+  LWIP_ASSERT("ni != NULL", ni != NULL);\r
+  snmp_netiftoifindex(ni, &arpidx[0]);\r
+  hip.addr = ntohl(ip->addr);\r
+  snmp_iptooid(&hip, &arpidx[1]);\r
+\r
+  for (tree = 0; tree < 2; tree++)\r
+  {\r
+    if (tree == 0)\r
+    {\r
+      at_rn = &arptree_root;\r
+    }\r
+    else\r
+    {\r
+      at_rn = &ipntomtree_root;\r
+    }\r
+    for (level = 0; level < 5; level++)\r
+    {\r
+      at_node = NULL;\r
+      snmp_mib_node_insert(at_rn, arpidx[level], &at_node);\r
+      if ((level != 4) && (at_node != NULL))\r
+      {\r
+        if (at_node->nptr == NULL)\r
+        {\r
+          at_rn = snmp_mib_lrn_alloc();\r
+          at_node->nptr = (struct mib_node*)at_rn;\r
+          if (at_rn != NULL)\r
+          {\r
+            if (level == 3)\r
+            {\r
+              if (tree == 0)\r
+              {\r
+                at_rn->get_object_def = atentry_get_object_def;\r
+                at_rn->get_value = atentry_get_value;\r
+              }\r
+              else\r
+              {\r
+                at_rn->get_object_def = ip_ntomentry_get_object_def;\r
+                at_rn->get_value = ip_ntomentry_get_value;\r
+              }\r
+              at_rn->set_test = noleafs_set_test;\r
+              at_rn->set_value = noleafs_set_value;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            /* at_rn == NULL, malloc failure */\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full"));\r
+            break;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          at_rn = (struct mib_list_rootnode*)at_node->nptr;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  /* enable getnext traversal on filled tables */\r
+  at.maxlength = 1;\r
+  ipntomtable.maxlength = 1;\r
+}\r
+\r
+/**\r
+ * Removes ARP table indexes (.xIfIndex.xNetAddress)\r
+ * from arp table index trees.\r
+ */\r
+void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip)\r
+{\r
+  struct mib_list_rootnode *at_rn, *next, *del_rn[5];\r
+  struct mib_list_node *at_n, *del_n[5];\r
+  struct ip_addr hip;\r
+  s32_t arpidx[5];\r
+  u8_t fc, tree, level, del_cnt;\r
+\r
+  snmp_netiftoifindex(ni, &arpidx[0]);\r
+  hip.addr = ntohl(ip->addr);\r
+  snmp_iptooid(&hip, &arpidx[1]);\r
+\r
+  for (tree = 0; tree < 2; tree++)\r
+  {\r
+    /* mark nodes for deletion */\r
+    if (tree == 0)\r
+    {\r
+      at_rn = &arptree_root;\r
+    }\r
+    else\r
+    {\r
+      at_rn = &ipntomtree_root;\r
+    }\r
+    level = 0;\r
+    del_cnt = 0;\r
+    while ((level < 5) && (at_rn != NULL))\r
+    {\r
+      fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n);\r
+      if (fc == 0)\r
+      {\r
+        /* arpidx[level] does not exist */\r
+        del_cnt = 0;\r
+        at_rn = NULL;\r
+      }\r
+      else if (fc == 1)\r
+      {\r
+        del_rn[del_cnt] = at_rn;\r
+        del_n[del_cnt] = at_n;\r
+        del_cnt++;\r
+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);\r
+      }\r
+      else if (fc == 2)\r
+      {\r
+        /* reset delete (2 or more childs) */\r
+        del_cnt = 0;\r
+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);\r
+      }\r
+      level++;\r
+    }\r
+    /* delete marked index nodes */\r
+    while (del_cnt > 0)\r
+    {\r
+      del_cnt--;\r
+\r
+      at_rn = del_rn[del_cnt];\r
+      at_n = del_n[del_cnt];\r
+\r
+      next = snmp_mib_node_delete(at_rn, at_n);\r
+      if (next != NULL)\r
+      {\r
+        LWIP_ASSERT("next_count == 0",next->count == 0);\r
+        snmp_mib_lrn_free(next);\r
+      }\r
+    }\r
+  }\r
+  /* disable getnext traversal on empty tables */\r
+  if(arptree_root.count == 0) at.maxlength = 0;\r
+  if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0;\r
+}\r
+\r
+void snmp_inc_ipinreceives(void)\r
+{\r
+  ipinreceives++;\r
+}\r
+\r
+void snmp_inc_ipinhdrerrors(void)\r
+{\r
+  ipinhdrerrors++;\r
+}\r
+\r
+void snmp_inc_ipinaddrerrors(void)\r
+{\r
+  ipinaddrerrors++;\r
+}\r
+\r
+void snmp_inc_ipforwdatagrams(void)\r
+{\r
+  ipforwdatagrams++;\r
+}\r
+\r
+void snmp_inc_ipinunknownprotos(void)\r
+{\r
+  ipinunknownprotos++;\r
+}\r
+\r
+void snmp_inc_ipindiscards(void)\r
+{\r
+  ipindiscards++;\r
+}\r
+\r
+void snmp_inc_ipindelivers(void)\r
+{\r
+  ipindelivers++;\r
+}\r
+\r
+void snmp_inc_ipoutrequests(void)\r
+{\r
+  ipoutrequests++;\r
+}\r
+\r
+void snmp_inc_ipoutdiscards(void)\r
+{\r
+  ipoutdiscards++;\r
+}\r
+\r
+void snmp_inc_ipoutnoroutes(void)\r
+{\r
+  ipoutnoroutes++;\r
+}\r
+\r
+void snmp_inc_ipreasmreqds(void)\r
+{\r
+  ipreasmreqds++;\r
+}\r
+\r
+void snmp_inc_ipreasmoks(void)\r
+{\r
+  ipreasmoks++;\r
+}\r
+\r
+void snmp_inc_ipreasmfails(void)\r
+{\r
+  ipreasmfails++;\r
+}\r
+\r
+void snmp_inc_ipfragoks(void)\r
+{\r
+  ipfragoks++;\r
+}\r
+\r
+void snmp_inc_ipfragfails(void)\r
+{\r
+  ipfragfails++;\r
+}\r
+\r
+void snmp_inc_ipfragcreates(void)\r
+{\r
+  ipfragcreates++;\r
+}\r
+\r
+void snmp_inc_iproutingdiscards(void)\r
+{\r
+  iproutingdiscards++;\r
+}\r
+\r
+/**\r
+ * Inserts ipAddrTable indexes (.ipAdEntAddr)\r
+ * into index tree.\r
+ */\r
+void snmp_insert_ipaddridx_tree(struct netif *ni)\r
+{\r
+  struct mib_list_rootnode *ipa_rn;\r
+  struct mib_list_node *ipa_node;\r
+  struct ip_addr ip;\r
+  s32_t ipaddridx[4];\r
+  u8_t level;\r
+\r
+  LWIP_ASSERT("ni != NULL", ni != NULL);\r
+  ip.addr = ntohl(ni->ip_addr.addr);\r
+  snmp_iptooid(&ip, &ipaddridx[0]);\r
+\r
+  level = 0;\r
+  ipa_rn = &ipaddrtree_root;\r
+  while (level < 4)\r
+  {\r
+    ipa_node = NULL;\r
+    snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node);\r
+    if ((level != 3) && (ipa_node != NULL))\r
+    {\r
+      if (ipa_node->nptr == NULL)\r
+      {\r
+        ipa_rn = snmp_mib_lrn_alloc();\r
+        ipa_node->nptr = (struct mib_node*)ipa_rn;\r
+        if (ipa_rn != NULL)\r
+        {\r
+          if (level == 2)\r
+          {\r
+            ipa_rn->get_object_def = ip_addrentry_get_object_def;\r
+            ipa_rn->get_value = ip_addrentry_get_value;\r
+            ipa_rn->set_test = noleafs_set_test;\r
+            ipa_rn->set_value = noleafs_set_value;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* ipa_rn == NULL, malloc failure */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full"));\r
+          break;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr;\r
+      }\r
+    }\r
+    level++;\r
+  }\r
+  /* enable getnext traversal on filled table */\r
+  ipaddrtable.maxlength = 1;\r
+}\r
+\r
+/**\r
+ * Removes ipAddrTable indexes (.ipAdEntAddr)\r
+ * from index tree.\r
+ */\r
+void snmp_delete_ipaddridx_tree(struct netif *ni)\r
+{\r
+  struct mib_list_rootnode *ipa_rn, *next, *del_rn[4];\r
+  struct mib_list_node *ipa_n, *del_n[4];\r
+  struct ip_addr ip;\r
+  s32_t ipaddridx[4];\r
+  u8_t fc, level, del_cnt;\r
+\r
+  LWIP_ASSERT("ni != NULL", ni != NULL);\r
+  ip.addr = ntohl(ni->ip_addr.addr);\r
+  snmp_iptooid(&ip, &ipaddridx[0]);\r
+\r
+  /* mark nodes for deletion */\r
+  level = 0;\r
+  del_cnt = 0;\r
+  ipa_rn = &ipaddrtree_root;\r
+  while ((level < 4) && (ipa_rn != NULL))\r
+  {\r
+    fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n);\r
+    if (fc == 0)\r
+    {\r
+      /* ipaddridx[level] does not exist */\r
+      del_cnt = 0;\r
+      ipa_rn = NULL;\r
+    }\r
+    else if (fc == 1)\r
+    {\r
+      del_rn[del_cnt] = ipa_rn;\r
+      del_n[del_cnt] = ipa_n;\r
+      del_cnt++;\r
+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);\r
+    }\r
+    else if (fc == 2)\r
+    {\r
+      /* reset delete (2 or more childs) */\r
+      del_cnt = 0;\r
+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);\r
+    }\r
+    level++;\r
+  }\r
+  /* delete marked index nodes */\r
+  while (del_cnt > 0)\r
+  {\r
+    del_cnt--;\r
+\r
+    ipa_rn = del_rn[del_cnt];\r
+    ipa_n = del_n[del_cnt];\r
+\r
+    next = snmp_mib_node_delete(ipa_rn, ipa_n);\r
+    if (next != NULL)\r
+    {\r
+      LWIP_ASSERT("next_count == 0",next->count == 0);\r
+      snmp_mib_lrn_free(next);\r
+    }\r
+  }\r
+  /* disable getnext traversal on empty table */\r
+  if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0;\r
+}\r
+\r
+/**\r
+ * Inserts ipRouteTable indexes (.ipRouteDest)\r
+ * into index tree.\r
+ *\r
+ * @param dflt non-zero for the default rte, zero for network rte\r
+ * @param netif points to network interface for this rte\r
+ *\r
+ * @todo record sysuptime for _this_ route when it is installed\r
+ *   (needed for ipRouteAge) in the netif.\r
+ */\r
+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni)\r
+{\r
+  u8_t insert = 0;\r
+  struct ip_addr dst;\r
+\r
+  if (dflt != 0)\r
+  {\r
+    /* the default route 0.0.0.0 */\r
+    dst.addr = 0;\r
+    insert = 1;\r
+  }\r
+  else\r
+  {\r
+    /* route to the network address */\r
+    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);\r
+    /* exclude 0.0.0.0 network (reserved for default rte) */\r
+    if (dst.addr != 0) insert = 1;\r
+  }\r
+  if (insert)\r
+  {\r
+    struct mib_list_rootnode *iprte_rn;\r
+    struct mib_list_node *iprte_node;\r
+    s32_t iprteidx[4];\r
+    u8_t level;\r
+\r
+    snmp_iptooid(&dst, &iprteidx[0]);\r
+    level = 0;\r
+    iprte_rn = &iprtetree_root;\r
+    while (level < 4)\r
+    {\r
+      iprte_node = NULL;\r
+      snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node);\r
+      if ((level != 3) && (iprte_node != NULL))\r
+      {\r
+        if (iprte_node->nptr == NULL)\r
+        {\r
+          iprte_rn = snmp_mib_lrn_alloc();\r
+          iprte_node->nptr = (struct mib_node*)iprte_rn;\r
+          if (iprte_rn != NULL)\r
+          {\r
+            if (level == 2)\r
+            {\r
+              iprte_rn->get_object_def = ip_rteentry_get_object_def;\r
+              iprte_rn->get_value = ip_rteentry_get_value;\r
+              iprte_rn->set_test = noleafs_set_test;\r
+              iprte_rn->set_value = noleafs_set_value;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            /* iprte_rn == NULL, malloc failure */\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full"));\r
+            break;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr;\r
+        }\r
+      }\r
+      level++;\r
+    }\r
+  }\r
+  /* enable getnext traversal on filled table */\r
+  iprtetable.maxlength = 1;\r
+}\r
+\r
+/**\r
+ * Removes ipRouteTable indexes (.ipRouteDest)\r
+ * from index tree.\r
+ *\r
+ * @param dflt non-zero for the default rte, zero for network rte\r
+ * @param netif points to network interface for this rte or NULL\r
+ *   for default route to be removed.\r
+ */\r
+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni)\r
+{\r
+  u8_t delete = 0;\r
+  struct ip_addr dst;\r
+\r
+  if (dflt != 0)\r
+  {\r
+    /* the default route 0.0.0.0 */\r
+    dst.addr = 0;\r
+    delete = 1;\r
+  }\r
+  else\r
+  {\r
+    /* route to the network address */\r
+    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);\r
+    /* exclude 0.0.0.0 network (reserved for default rte) */\r
+    if (dst.addr != 0) delete = 1;\r
+  }\r
+  if (delete)\r
+  {\r
+    struct mib_list_rootnode *iprte_rn, *next, *del_rn[4];\r
+    struct mib_list_node *iprte_n, *del_n[4];\r
+    s32_t iprteidx[4];\r
+    u8_t fc, level, del_cnt;\r
+\r
+    snmp_iptooid(&dst, &iprteidx[0]);\r
+    /* mark nodes for deletion */\r
+    level = 0;\r
+    del_cnt = 0;\r
+    iprte_rn = &iprtetree_root;\r
+    while ((level < 4) && (iprte_rn != NULL))\r
+    {\r
+      fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n);\r
+      if (fc == 0)\r
+      {\r
+        /* iprteidx[level] does not exist */\r
+        del_cnt = 0;\r
+        iprte_rn = NULL;\r
+      }\r
+      else if (fc == 1)\r
+      {\r
+        del_rn[del_cnt] = iprte_rn;\r
+        del_n[del_cnt] = iprte_n;\r
+        del_cnt++;\r
+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);\r
+      }\r
+      else if (fc == 2)\r
+      {\r
+        /* reset delete (2 or more childs) */\r
+        del_cnt = 0;\r
+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);\r
+      }\r
+      level++;\r
+    }\r
+    /* delete marked index nodes */\r
+    while (del_cnt > 0)\r
+    {\r
+      del_cnt--;\r
+\r
+      iprte_rn = del_rn[del_cnt];\r
+      iprte_n = del_n[del_cnt];\r
+\r
+      next = snmp_mib_node_delete(iprte_rn, iprte_n);\r
+      if (next != NULL)\r
+      {\r
+        LWIP_ASSERT("next_count == 0",next->count == 0);\r
+        snmp_mib_lrn_free(next);\r
+      }\r
+    }\r
+  }\r
+  /* disable getnext traversal on empty table */\r
+  if (iprtetree_root.count == 0) iprtetable.maxlength = 0;\r
+}\r
+\r
+\r
+void snmp_inc_icmpinmsgs(void)\r
+{\r
+  icmpinmsgs++;\r
+}\r
+\r
+void snmp_inc_icmpinerrors(void)\r
+{\r
+  icmpinerrors++;\r
+}\r
+\r
+void snmp_inc_icmpindestunreachs(void)\r
+{\r
+  icmpindestunreachs++;\r
+}\r
+\r
+void snmp_inc_icmpintimeexcds(void)\r
+{\r
+  icmpintimeexcds++;\r
+}\r
+\r
+void snmp_inc_icmpinparmprobs(void)\r
+{\r
+  icmpinparmprobs++;\r
+}\r
+\r
+void snmp_inc_icmpinsrcquenchs(void)\r
+{\r
+  icmpinsrcquenchs++;\r
+}\r
+\r
+void snmp_inc_icmpinredirects(void)\r
+{\r
+  icmpinredirects++;\r
+}\r
+\r
+void snmp_inc_icmpinechos(void)\r
+{\r
+  icmpinechos++;\r
+}\r
+\r
+void snmp_inc_icmpinechoreps(void)\r
+{\r
+  icmpinechoreps++;\r
+}\r
+\r
+void snmp_inc_icmpintimestamps(void)\r
+{\r
+  icmpintimestamps++;\r
+}\r
+\r
+void snmp_inc_icmpintimestampreps(void)\r
+{\r
+  icmpintimestampreps++;\r
+}\r
+\r
+void snmp_inc_icmpinaddrmasks(void)\r
+{\r
+  icmpinaddrmasks++;\r
+}\r
+\r
+void snmp_inc_icmpinaddrmaskreps(void)\r
+{\r
+  icmpinaddrmaskreps++;\r
+}\r
+\r
+void snmp_inc_icmpoutmsgs(void)\r
+{\r
+  icmpoutmsgs++;\r
+}\r
+\r
+void snmp_inc_icmpouterrors(void)\r
+{\r
+  icmpouterrors++;\r
+}\r
+\r
+void snmp_inc_icmpoutdestunreachs(void)\r
+{\r
+  icmpoutdestunreachs++;\r
+}\r
+\r
+void snmp_inc_icmpouttimeexcds(void)\r
+{\r
+  icmpouttimeexcds++;\r
+}\r
+\r
+void snmp_inc_icmpoutparmprobs(void)\r
+{\r
+  icmpoutparmprobs++;\r
+}\r
+\r
+void snmp_inc_icmpoutsrcquenchs(void)\r
+{\r
+  icmpoutsrcquenchs++;\r
+}\r
+\r
+void snmp_inc_icmpoutredirects(void)\r
+{\r
+  icmpoutredirects++;\r
+}\r
+\r
+void snmp_inc_icmpoutechos(void)\r
+{\r
+  icmpoutechos++;\r
+}\r
+\r
+void snmp_inc_icmpoutechoreps(void)\r
+{\r
+  icmpoutechoreps++;\r
+}\r
+\r
+void snmp_inc_icmpouttimestamps(void)\r
+{\r
+  icmpouttimestamps++;\r
+}\r
+\r
+void snmp_inc_icmpouttimestampreps(void)\r
+{\r
+  icmpouttimestampreps++;\r
+}\r
+\r
+void snmp_inc_icmpoutaddrmasks(void)\r
+{\r
+  icmpoutaddrmasks++;\r
+}\r
+\r
+void snmp_inc_icmpoutaddrmaskreps(void)\r
+{\r
+  icmpoutaddrmaskreps++;\r
+}\r
+\r
+void snmp_inc_tcpactiveopens(void)\r
+{\r
+  tcpactiveopens++;\r
+}\r
+\r
+void snmp_inc_tcppassiveopens(void)\r
+{\r
+  tcppassiveopens++;\r
+}\r
+\r
+void snmp_inc_tcpattemptfails(void)\r
+{\r
+  tcpattemptfails++;\r
+}\r
+\r
+void snmp_inc_tcpestabresets(void)\r
+{\r
+  tcpestabresets++;\r
+}\r
+\r
+void snmp_inc_tcpinsegs(void)\r
+{\r
+  tcpinsegs++;\r
+}\r
+\r
+void snmp_inc_tcpoutsegs(void)\r
+{\r
+  tcpoutsegs++;\r
+}\r
+\r
+void snmp_inc_tcpretranssegs(void)\r
+{\r
+  tcpretranssegs++;\r
+}\r
+\r
+void snmp_inc_tcpinerrs(void)\r
+{\r
+  tcpinerrs++;\r
+}\r
+\r
+void snmp_inc_tcpoutrsts(void)\r
+{\r
+  tcpoutrsts++;\r
+}\r
+\r
+void snmp_inc_udpindatagrams(void)\r
+{\r
+  udpindatagrams++;\r
+}\r
+\r
+void snmp_inc_udpnoports(void)\r
+{\r
+  udpnoports++;\r
+}\r
+\r
+void snmp_inc_udpinerrors(void)\r
+{\r
+  udpinerrors++;\r
+}\r
+\r
+void snmp_inc_udpoutdatagrams(void)\r
+{\r
+  udpoutdatagrams++;\r
+}\r
+\r
+/**\r
+ * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort)\r
+ * into index tree.\r
+ */\r
+void snmp_insert_udpidx_tree(struct udp_pcb *pcb)\r
+{\r
+  struct mib_list_rootnode *udp_rn;\r
+  struct mib_list_node *udp_node;\r
+  struct ip_addr ip;\r
+  s32_t udpidx[5];\r
+  u8_t level;\r
+\r
+  LWIP_ASSERT("pcb != NULL", pcb != NULL);\r
+  ip.addr = ntohl(pcb->local_ip.addr);\r
+  snmp_iptooid(&ip, &udpidx[0]);\r
+  udpidx[4] = pcb->local_port;\r
+\r
+  udp_rn = &udp_root;\r
+  for (level = 0; level < 5; level++)\r
+  {\r
+    udp_node = NULL;\r
+    snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node);\r
+    if ((level != 4) && (udp_node != NULL))\r
+    {\r
+      if (udp_node->nptr == NULL)\r
+      {\r
+        udp_rn = snmp_mib_lrn_alloc();\r
+        udp_node->nptr = (struct mib_node*)udp_rn;\r
+        if (udp_rn != NULL)\r
+        {\r
+          if (level == 3)\r
+          {\r
+            udp_rn->get_object_def = udpentry_get_object_def;\r
+            udp_rn->get_value = udpentry_get_value;\r
+            udp_rn->set_test = noleafs_set_test;\r
+            udp_rn->set_value = noleafs_set_value;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* udp_rn == NULL, malloc failure */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full"));\r
+          break;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        udp_rn = (struct mib_list_rootnode*)udp_node->nptr;\r
+      }\r
+    }\r
+  }\r
+  udptable.maxlength = 1;\r
+}\r
+\r
+/**\r
+ * Removes udpTable indexes (.udpLocalAddress.udpLocalPort)\r
+ * from index tree.\r
+ */\r
+void snmp_delete_udpidx_tree(struct udp_pcb *pcb)\r
+{\r
+  struct mib_list_rootnode *udp_rn, *next, *del_rn[5];\r
+  struct mib_list_node *udp_n, *del_n[5];\r
+  struct ip_addr ip;\r
+  s32_t udpidx[5];\r
+  u8_t bindings, fc, level, del_cnt;\r
+\r
+  LWIP_ASSERT("pcb != NULL", pcb != NULL);\r
+  ip.addr = ntohl(pcb->local_ip.addr);\r
+  snmp_iptooid(&ip, &udpidx[0]);\r
+  udpidx[4] = pcb->local_port;\r
+\r
+  /* count PCBs for a given binding\r
+     (e.g. when reusing ports or for temp output PCBs) */\r
+  bindings = 0;\r
+  pcb = udp_pcbs;\r
+  while ((pcb != NULL))\r
+  {\r
+    if ((pcb->local_ip.addr == ip.addr) &&\r
+        (pcb->local_port == udpidx[4]))\r
+    {\r
+      bindings++;\r
+    }\r
+    pcb = pcb->next;\r
+  }\r
+  if (bindings == 1)\r
+  {\r
+    /* selectively remove */\r
+    /* mark nodes for deletion */\r
+    level = 0;\r
+    del_cnt = 0;\r
+    udp_rn = &udp_root;\r
+    while ((level < 5) && (udp_rn != NULL))\r
+    {\r
+      fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n);\r
+      if (fc == 0)\r
+      {\r
+        /* udpidx[level] does not exist */\r
+        del_cnt = 0;\r
+        udp_rn = NULL;\r
+      }\r
+      else if (fc == 1)\r
+      {\r
+        del_rn[del_cnt] = udp_rn;\r
+        del_n[del_cnt] = udp_n;\r
+        del_cnt++;\r
+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);\r
+      }\r
+      else if (fc == 2)\r
+      {\r
+        /* reset delete (2 or more childs) */\r
+        del_cnt = 0;\r
+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);\r
+      }\r
+      level++;\r
+    }\r
+    /* delete marked index nodes */\r
+    while (del_cnt > 0)\r
+    {\r
+      del_cnt--;\r
+\r
+      udp_rn = del_rn[del_cnt];\r
+      udp_n = del_n[del_cnt];\r
+\r
+      next = snmp_mib_node_delete(udp_rn, udp_n);\r
+      if (next != NULL)\r
+      {\r
+        LWIP_ASSERT("next_count == 0",next->count == 0);\r
+        snmp_mib_lrn_free(next);\r
+      }\r
+    }\r
+  }\r
+  /* disable getnext traversal on empty table */\r
+  if (udp_root.count == 0) udptable.maxlength = 0;\r
+}\r
+\r
+\r
+void snmp_inc_snmpinpkts(void)\r
+{\r
+  snmpinpkts++;\r
+}\r
+\r
+void snmp_inc_snmpoutpkts(void)\r
+{\r
+  snmpoutpkts++;\r
+}\r
+\r
+void snmp_inc_snmpinbadversions(void)\r
+{\r
+  snmpinbadversions++;\r
+}\r
+\r
+void snmp_inc_snmpinbadcommunitynames(void)\r
+{\r
+  snmpinbadcommunitynames++;\r
+}\r
+\r
+void snmp_inc_snmpinbadcommunityuses(void)\r
+{\r
+  snmpinbadcommunityuses++;\r
+}\r
+\r
+void snmp_inc_snmpinasnparseerrs(void)\r
+{\r
+  snmpinasnparseerrs++;\r
+}\r
+\r
+void snmp_inc_snmpintoobigs(void)\r
+{\r
+  snmpintoobigs++;\r
+}\r
+\r
+void snmp_inc_snmpinnosuchnames(void)\r
+{\r
+  snmpinnosuchnames++;\r
+}\r
+\r
+void snmp_inc_snmpinbadvalues(void)\r
+{\r
+  snmpinbadvalues++;\r
+}\r
+\r
+void snmp_inc_snmpinreadonlys(void)\r
+{\r
+  snmpinreadonlys++;\r
+}\r
+\r
+void snmp_inc_snmpingenerrs(void)\r
+{\r
+  snmpingenerrs++;\r
+}\r
+\r
+void snmp_add_snmpintotalreqvars(u8_t value)\r
+{\r
+  snmpintotalreqvars += value;\r
+}\r
+\r
+void snmp_add_snmpintotalsetvars(u8_t value)\r
+{\r
+  snmpintotalsetvars += value;\r
+}\r
+\r
+void snmp_inc_snmpingetrequests(void)\r
+{\r
+  snmpingetrequests++;\r
+}\r
+\r
+void snmp_inc_snmpingetnexts(void)\r
+{\r
+  snmpingetnexts++;\r
+}\r
+\r
+void snmp_inc_snmpinsetrequests(void)\r
+{\r
+  snmpinsetrequests++;\r
+}\r
+\r
+void snmp_inc_snmpingetresponses(void)\r
+{\r
+  snmpingetresponses++;\r
+}\r
+\r
+void snmp_inc_snmpintraps(void)\r
+{\r
+  snmpintraps++;\r
+}\r
+\r
+void snmp_inc_snmpouttoobigs(void)\r
+{\r
+  snmpouttoobigs++;\r
+}\r
+\r
+void snmp_inc_snmpoutnosuchnames(void)\r
+{\r
+  snmpoutnosuchnames++;\r
+}\r
+\r
+void snmp_inc_snmpoutbadvalues(void)\r
+{\r
+  snmpoutbadvalues++;\r
+}\r
+\r
+void snmp_inc_snmpoutgenerrs(void)\r
+{\r
+  snmpoutgenerrs++;\r
+}\r
+\r
+void snmp_inc_snmpoutgetrequests(void)\r
+{\r
+  snmpoutgetrequests++;\r
+}\r
+\r
+void snmp_inc_snmpoutgetnexts(void)\r
+{\r
+  snmpoutgetnexts++;\r
+}\r
+\r
+void snmp_inc_snmpoutsetrequests(void)\r
+{\r
+  snmpoutsetrequests++;\r
+}\r
+\r
+void snmp_inc_snmpoutgetresponses(void)\r
+{\r
+  snmpoutgetresponses++;\r
+}\r
+\r
+void snmp_inc_snmpouttraps(void)\r
+{\r
+  snmpouttraps++;\r
+}\r
+\r
+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid)\r
+{\r
+  *oid = &snmpgrp_id;\r
+}\r
+\r
+void snmp_set_snmpenableauthentraps(u8_t *value)\r
+{\r
+  if (value != NULL)\r
+  {\r
+    snmpenableauthentraps_ptr = value;\r
+  }\r
+}\r
+\r
+void snmp_get_snmpenableauthentraps(u8_t *value)\r
+{\r
+  *value = *snmpenableauthentraps_ptr;\r
+}\r
+\r
+void\r
+noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  if (ident_len){}\r
+  if (ident){}\r
+  od->instance = MIB_OBJECT_NONE;\r
+}\r
+\r
+void\r
+noleafs_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  if (od){}\r
+  if (len){}\r
+  if (value){}\r
+}\r
+\r
+u8_t\r
+noleafs_set_test(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  if (od){}\r
+  if (len){}\r
+  if (value){}\r
+  /* can't set */\r
+  return 0;\r
+}\r
+\r
+void\r
+noleafs_set_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  if (od){}\r
+  if (len){}\r
+  if (value){}\r
+}\r
+\r
+\r
+/**\r
+ * Returns systems object definitions.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.0 (object id trailer)\r
+ * @param od points to object definition.\r
+ */\r
+static void\r
+system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id));\r
+    switch (id)\r
+    {\r
+      case 1: /* sysDescr */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = *sysdescr_len_ptr;\r
+        break;\r
+      case 2: /* sysObjectID */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);\r
+        od->v_len = sysobjid.len * sizeof(s32_t);\r
+        break;\r
+      case 3: /* sysUpTime */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 4: /* sysContact */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = *syscontact_len_ptr;\r
+        break;\r
+      case 5: /* sysName */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = *sysname_len_ptr;\r
+        break;\r
+      case 6: /* sysLocation */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = *syslocation_len_ptr;\r
+        break;\r
+      case 7: /* sysServices */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns system object value.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.0 (object id trailer)\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value into.\r
+ */\r
+static void\r
+system_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* sysDescr */\r
+      ocstrncpy(value,sysdescr_ptr,len);\r
+      break;\r
+    case 2: /* sysObjectID */\r
+      objectidncpy((s32_t*)value,(s32_t*)sysobjid.id,len / sizeof(s32_t));\r
+      break;\r
+    case 3: /* sysUpTime */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = sysuptime;\r
+      }\r
+      break;\r
+    case 4: /* sysContact */\r
+      ocstrncpy(value,syscontact_ptr,len);\r
+      break;\r
+    case 5: /* sysName */\r
+      ocstrncpy(value,sysname_ptr,len);\r
+      break;\r
+    case 6: /* sysLocation */\r
+      ocstrncpy(value,syslocation_ptr,len);\r
+      break;\r
+    case 7: /* sysServices */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = sysservices;\r
+      }\r
+      break;\r
+  };\r
+}\r
+\r
+static u8_t\r
+system_set_test(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id, set_ok;\r
+\r
+  if (value) {}\r
+  set_ok = 0;\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 4: /* sysContact */\r
+      if ((syscontact_ptr != syscontact_default) &&\r
+          (len <= 255))\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+    case 5: /* sysName */\r
+      if ((sysname_ptr != sysname_default) &&\r
+          (len <= 255))\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+    case 6: /* sysLocation */\r
+      if ((syslocation_ptr != syslocation_default) &&\r
+          (len <= 255))\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+  };\r
+  return set_ok;\r
+}\r
+\r
+static void\r
+system_set_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 4: /* sysContact */\r
+      ocstrncpy(syscontact_ptr,value,len);\r
+      *syscontact_len_ptr = len;\r
+      break;\r
+    case 5: /* sysName */\r
+      ocstrncpy(sysname_ptr,value,len);\r
+      *sysname_len_ptr = len;\r
+      break;\r
+    case 6: /* sysLocation */\r
+      ocstrncpy(syslocation_ptr,value,len);\r
+      *syslocation_len_ptr = len;\r
+      break;\r
+  };\r
+}\r
+\r
+/**\r
+ * Returns interfaces.ifnumber object definition.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.index\r
+ * @param od points to object definition.\r
+ */\r
+static void\r
+interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    od->instance = MIB_OBJECT_SCALAR;\r
+    od->access = MIB_OBJECT_READ_ONLY;\r
+    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+    od->v_len = sizeof(s32_t);\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns interfaces.ifnumber object value.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.0 (object id trailer)\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value into.\r
+ */\r
+static void\r
+interfaces_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  if (len){}\r
+  if (od->id_inst_ptr[0] == 1)\r
+  {\r
+    s32_t *sint_ptr = value;\r
+    *sint_ptr = iflist_root.count;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns ifentry object definitions.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.index\r
+ * @param od points to object definition.\r
+ */\r
+static void\r
+ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id));\r
+    switch (id)\r
+    {\r
+      case 1: /* ifIndex */\r
+      case 3: /* ifType */\r
+      case 4: /* ifMtu */\r
+      case 8: /* ifOperStatus */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 2: /* ifDescr */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        /** @todo this should be some sort of sizeof(struct netif.name) */\r
+        od->v_len = 2;\r
+        break;\r
+      case 5: /* ifSpeed */\r
+      case 21: /* ifOutQLen */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 6: /* ifPhysAddress */\r
+        {\r
+          struct netif *netif;\r
+\r
+          snmp_ifindextonetif(ident[1], &netif);\r
+          od->instance = MIB_OBJECT_TAB;\r
+          od->access = MIB_OBJECT_READ_ONLY;\r
+          od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+          od->v_len = netif->hwaddr_len;\r
+        }\r
+        break;\r
+      case 7: /* ifAdminStatus */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 9: /* ifLastChange */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 10: /* ifInOctets */\r
+      case 11: /* ifInUcastPkts */\r
+      case 12: /* ifInNUcastPkts */\r
+      case 13: /* ifInDiscarts */\r
+      case 14: /* ifInErrors */\r
+      case 15: /* ifInUnkownProtos */\r
+      case 16: /* ifOutOctets */\r
+      case 17: /* ifOutUcastPkts */\r
+      case 18: /* ifOutNUcastPkts */\r
+      case 19: /* ifOutDiscarts */\r
+      case 20: /* ifOutErrors */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 22: /* ifSpecific */\r
+        /** @note returning zeroDotZero (0.0) no media specific MIB support */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);\r
+        od->v_len = ifspecific.len * sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns ifentry object value.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.0 (object id trailer)\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value into.\r
+ */\r
+static void\r
+ifentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  struct netif *netif;\r
+  u8_t id;\r
+\r
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* ifIndex */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = od->id_inst_ptr[1];\r
+      }\r
+      break;\r
+    case 2: /* ifDescr */\r
+      ocstrncpy(value,(u8_t*)netif->name,len);\r
+      break;\r
+    case 3: /* ifType */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = netif->link_type;\r
+      }\r
+      break;\r
+    case 4: /* ifMtu */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = netif->mtu;\r
+      }\r
+      break;\r
+    case 5: /* ifSpeed */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->link_speed;\r
+      }\r
+      break;\r
+    case 6: /* ifPhysAddress */\r
+      ocstrncpy(value,netif->hwaddr,len);\r
+      break;\r
+    case 7: /* ifAdminStatus */\r
+    case 8: /* ifOperStatus */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        if (netif_is_up(netif))\r
+        {\r
+          *sint_ptr = 1;\r
+        }\r
+        else\r
+        {\r
+          *sint_ptr = 2;\r
+        }\r
+      }\r
+      break;\r
+    case 9: /* ifLastChange */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ts;\r
+      }\r
+      break;\r
+    case 10: /* ifInOctets */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifinoctets;\r
+      }\r
+      break;\r
+    case 11: /* ifInUcastPkts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifinucastpkts;\r
+      }\r
+      break;\r
+    case 12: /* ifInNUcastPkts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifinnucastpkts;\r
+      }\r
+      break;\r
+    case 13: /* ifInDiscarts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifindiscards;\r
+      }\r
+      break;\r
+    case 14: /* ifInErrors */\r
+    case 15: /* ifInUnkownProtos */\r
+      /** @todo add these counters! */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = 0;\r
+      }\r
+      break;\r
+    case 16: /* ifOutOctets */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifoutoctets;\r
+      }\r
+      break;\r
+    case 17: /* ifOutUcastPkts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifoutucastpkts;\r
+      }\r
+      break;\r
+    case 18: /* ifOutNUcastPkts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifoutnucastpkts;\r
+      }\r
+      break;\r
+    case 19: /* ifOutDiscarts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifoutdiscards;\r
+      }\r
+      break;\r
+    case 20: /* ifOutErrors */\r
+       /** @todo add this counter! */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = 0;\r
+      }\r
+      break;\r
+    case 21: /* ifOutQLen */\r
+      /** @todo figure out if this must be 0 (no queue) or 1? */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = 0;\r
+      }\r
+      break;\r
+    case 22: /* ifSpecific */\r
+      objectidncpy((s32_t*)value,(s32_t*)ifspecific.id,len / sizeof(s32_t));\r
+      break;\r
+  };\r
+}\r
+\r
+/**\r
+ * Returns atentry object definitions.\r
+ *\r
+ * @param ident_len the address length (6)\r
+ * @param ident points to objectname.atifindex.atnetaddress\r
+ * @param od points to object definition.\r
+ */\r
+static void\r
+atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (5) */\r
+  ident_len += 5;\r
+  ident -= 5;\r
+\r
+  if (ident_len == 6)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    switch (ident[0])\r
+    {\r
+      case 1: /* atIfIndex */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 2: /* atPhysAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = sizeof(struct eth_addr);\r
+        break;\r
+      case 3: /* atNetAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+atentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+  struct eth_addr* ethaddr_ret;\r
+  struct ip_addr* ipaddr_ret;\r
+  struct ip_addr ip;\r
+  struct netif *netif;\r
+\r
+  if (len) {}\r
+\r
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);\r
+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);\r
+  ip.addr = htonl(ip.addr);\r
+\r
+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)\r
+  {\r
+    id = od->id_inst_ptr[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* atIfIndex */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          *sint_ptr = od->id_inst_ptr[1];\r
+        }\r
+        break;\r
+      case 2: /* atPhysAddress */\r
+        {\r
+          struct eth_addr *dst = value;\r
+\r
+          *dst = *ethaddr_ret;\r
+        }\r
+        break;\r
+      case 3: /* atNetAddress */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          *dst = *ipaddr_ret;\r
+        }\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+static void\r
+ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id));\r
+    switch (id)\r
+    {\r
+      case 1: /* ipForwarding */\r
+      case 2: /* ipDefaultTTL */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 3: /* ipInReceives */\r
+      case 4: /* ipInHdrErrors */\r
+      case 5: /* ipInAddrErrors */\r
+      case 6: /* ipForwDatagrams */\r
+      case 7: /* ipInUnknownProtos */\r
+      case 8: /* ipInDiscards */\r
+      case 9: /* ipInDelivers */\r
+      case 10: /* ipOutRequests */\r
+      case 11: /* ipOutDiscards */\r
+      case 12: /* ipOutNoRoutes */\r
+      case 14: /* ipReasmReqds */\r
+      case 15: /* ipReasmOKs */\r
+      case 16: /* ipReasmFails */\r
+      case 17: /* ipFragOKs */\r
+      case 18: /* ipFragFails */\r
+      case 19: /* ipFragCreates */\r
+      case 23: /* ipRoutingDiscards */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 13: /* ipReasmTimeout */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+ip_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+\r
+  if (len) {}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* ipForwarding */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+#if IP_FORWARD\r
+        /* forwarding */\r
+        *sint_ptr = 1;\r
+#else\r
+        /* not-forwarding */\r
+        *sint_ptr = 2;\r
+#endif\r
+      }\r
+      break;\r
+    case 2: /* ipDefaultTTL */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = IP_DEFAULT_TTL;\r
+      }\r
+      break;\r
+    case 3: /* ipInReceives */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipinreceives;\r
+      }\r
+      break;\r
+    case 4: /* ipInHdrErrors */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipinhdrerrors;\r
+      }\r
+      break;\r
+    case 5: /* ipInAddrErrors */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipinaddrerrors;\r
+      }\r
+      break;\r
+    case 6: /* ipForwDatagrams */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipforwdatagrams;\r
+      }\r
+      break;\r
+    case 7: /* ipInUnknownProtos */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipinunknownprotos;\r
+      }\r
+      break;\r
+    case 8: /* ipInDiscards */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipindiscards;\r
+      }\r
+      break;\r
+    case 9: /* ipInDelivers */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipindelivers;\r
+      }\r
+      break;\r
+    case 10: /* ipOutRequests */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipoutrequests;\r
+      }\r
+      break;\r
+    case 11: /* ipOutDiscards */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipoutdiscards;\r
+      }\r
+      break;\r
+    case 12: /* ipOutNoRoutes */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipoutnoroutes;\r
+      }\r
+      break;\r
+    case 13: /* ipReasmTimeout */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+#if IP_REASSEMBLY\r
+        *sint_ptr = IP_REASS_MAXAGE;\r
+#else\r
+        *sint_ptr = 0;\r
+#endif\r
+      }\r
+      break;\r
+    case 14: /* ipReasmReqds */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipreasmreqds;\r
+      }\r
+      break;\r
+    case 15: /* ipReasmOKs */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipreasmoks;\r
+      }\r
+      break;\r
+    case 16: /* ipReasmFails */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipreasmfails;\r
+      }\r
+      break;\r
+    case 17: /* ipFragOKs */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipfragoks;\r
+      }\r
+      break;\r
+    case 18: /* ipFragFails */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipfragfails;\r
+      }\r
+      break;\r
+    case 19: /* ipFragCreates */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipfragcreates;\r
+      }\r
+      break;\r
+    case 23: /* ipRoutingDiscards */\r
+      /** @todo can lwIP discard routes at all?? hardwire this to 0?? */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = iproutingdiscards;\r
+      }\r
+      break;\r
+  };\r
+}\r
+\r
+/**\r
+ * Test ip object value before setting.\r
+ *\r
+ * @param od is the object definition\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value from.\r
+ *\r
+ * @note we allow set if the value matches the hardwired value,\r
+ *   otherwise return badvalue.\r
+ */\r
+static u8_t\r
+ip_set_test(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id, set_ok;\r
+  s32_t *sint_ptr = value;\r
+\r
+  if (len) {}\r
+  set_ok = 0;\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* ipForwarding */\r
+#if IP_FORWARD\r
+      /* forwarding */\r
+      if (*sint_ptr == 1)\r
+#else\r
+      /* not-forwarding */\r
+      if (*sint_ptr == 2)\r
+#endif\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+    case 2: /* ipDefaultTTL */\r
+      if (*sint_ptr == IP_DEFAULT_TTL)\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+  };\r
+  return set_ok;\r
+}\r
+\r
+static void\r
+ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (4) */\r
+  ident_len += 4;\r
+  ident -= 4;\r
+\r
+  if (ident_len == 5)\r
+  {\r
+    u8_t id;\r
+\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipAdEntAddr */\r
+      case 3: /* ipAdEntNetMask */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      case 2: /* ipAdEntIfIndex */\r
+      case 4: /* ipAdEntBcastAddr */\r
+      case 5: /* ipAdEntReasmMaxSize */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+  u16_t ifidx;\r
+  struct ip_addr ip;\r
+  struct netif *netif = netif_list;\r
+\r
+  if (len) {}\r
+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);\r
+  ip.addr = htonl(ip.addr);\r
+  ifidx = 0;\r
+  while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr))\r
+  {\r
+    netif = netif->next;\r
+    ifidx++;\r
+  }\r
+\r
+  if (netif != NULL)\r
+  {\r
+    id = od->id_inst_ptr[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipAdEntAddr */\r
+        {\r
+          struct ip_addr *dst = value;\r
+          *dst = netif->ip_addr;\r
+        }\r
+        break;\r
+      case 2: /* ipAdEntIfIndex */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          *sint_ptr = ifidx + 1;\r
+        }\r
+        break;\r
+      case 3: /* ipAdEntNetMask */\r
+        {\r
+          struct ip_addr *dst = value;\r
+          *dst = netif->netmask;\r
+        }\r
+        break;\r
+      case 4: /* ipAdEntBcastAddr */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+\r
+          /* lwIP oddity, there's no broadcast\r
+            address in the netif we can rely on */\r
+          *sint_ptr = ip_addr_broadcast.addr & 1;\r
+        }\r
+        break;\r
+      case 5: /* ipAdEntReasmMaxSize */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+#if IP_REASSEMBLY\r
+          *sint_ptr = (IP_HLEN + IP_REASS_BUFSIZE);\r
+#else\r
+          /** @todo returning MTU would be a bad thing and\r
+             returning a wild guess like '576' isn't good either */\r
+          *sint_ptr = 0;\r
+#endif\r
+        }\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * @note\r
+ * lwIP IP routing is currently using the network addresses in netif_list.\r
+ * if no suitable network IP is found in netif_list, the default_netif is used.\r
+ */\r
+static void\r
+ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (4) */\r
+  ident_len += 4;\r
+  ident -= 4;\r
+\r
+  if (ident_len == 5)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipRouteDest */\r
+      case 7: /* ipRouteNextHop */\r
+      case 11: /* ipRouteMask */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      case 2: /* ipRouteIfIndex */\r
+      case 3: /* ipRouteMetric1 */\r
+      case 4: /* ipRouteMetric2 */\r
+      case 5: /* ipRouteMetric3 */\r
+      case 6: /* ipRouteMetric4 */\r
+      case 8: /* ipRouteType */\r
+      case 10: /* ipRouteAge */\r
+      case 12: /* ipRouteMetric5 */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 9: /* ipRouteProto */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 13: /* ipRouteInfo */\r
+        /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);\r
+        od->v_len = iprouteinfo.len * sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  struct netif *netif;\r
+  struct ip_addr dest;\r
+  s32_t *ident;\r
+  u8_t id;\r
+\r
+  ident = od->id_inst_ptr;\r
+  snmp_oidtoip(&ident[1], &dest);\r
+  dest.addr = htonl(dest.addr);\r
+\r
+  if (dest.addr == 0)\r
+  {\r
+    /* ip_route() uses default netif for default route */\r
+    netif = netif_default;\r
+  }\r
+  else\r
+  {\r
+    /* not using ip_route(), need exact match! */\r
+    netif = netif_list;\r
+    while ((netif != NULL) &&\r
+            !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) )\r
+    {\r
+      netif = netif->next;\r
+    }\r
+  }\r
+  if (netif != NULL)\r
+  {\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipRouteDest */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte has 0.0.0.0 dest */\r
+            dst->addr = 0;\r
+          }\r
+          else\r
+          {\r
+            /* netifs have netaddress dest */\r
+            dst->addr = netif->ip_addr.addr & netif->netmask.addr;\r
+          }\r
+        }\r
+        break;\r
+      case 2: /* ipRouteIfIndex */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+\r
+          snmp_netiftoifindex(netif, sint_ptr);\r
+        }\r
+        break;\r
+      case 3: /* ipRouteMetric1 */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte has metric 1 */\r
+            *sint_ptr = 1;\r
+          }\r
+          else\r
+          {\r
+            /* other rtes have metric 0 */\r
+            *sint_ptr = 0;\r
+          }\r
+        }\r
+        break;\r
+      case 4: /* ipRouteMetric2 */\r
+      case 5: /* ipRouteMetric3 */\r
+      case 6: /* ipRouteMetric4 */\r
+      case 12: /* ipRouteMetric5 */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          /* not used */\r
+          *sint_ptr = -1;\r
+        }\r
+        break;\r
+      case 7: /* ipRouteNextHop */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte: gateway */\r
+            *dst = netif->gw;\r
+          }\r
+          else\r
+          {\r
+            /* other rtes: netif ip_addr  */\r
+            *dst = netif->ip_addr;\r
+          }\r
+        }\r
+        break;\r
+      case 8: /* ipRouteType */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte is indirect */\r
+            *sint_ptr = 4;\r
+          }\r
+          else\r
+          {\r
+            /* other rtes are direct */\r
+            *sint_ptr = 3;\r
+          }\r
+        }\r
+        break;\r
+      case 9: /* ipRouteProto */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          /* locally defined routes */\r
+          *sint_ptr = 2;\r
+        }\r
+        break;\r
+      case 10: /* ipRouteAge */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          /** @todo (sysuptime - timestamp last change) / 100\r
+              @see snmp_insert_iprteidx_tree() */\r
+          *sint_ptr = 0;\r
+        }\r
+        break;\r
+      case 11: /* ipRouteMask */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte use 0.0.0.0 mask */\r
+            dst->addr = 0;\r
+          }\r
+          else\r
+          {\r
+            /* other rtes use netmask */\r
+            *dst = netif->netmask;\r
+          }\r
+        }\r
+        break;\r
+      case 13: /* ipRouteInfo */\r
+        objectidncpy((s32_t*)value,(s32_t*)iprouteinfo.id,len / sizeof(s32_t));\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+static void\r
+ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (5) */\r
+  ident_len += 5;\r
+  ident -= 5;\r
+\r
+  if (ident_len == 6)\r
+  {\r
+    u8_t id;\r
+\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipNetToMediaIfIndex */\r
+      case 4: /* ipNetToMediaType */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 2: /* ipNetToMediaPhysAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = sizeof(struct eth_addr);\r
+        break;\r
+      case 3: /* ipNetToMediaNetAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+  struct eth_addr* ethaddr_ret;\r
+  struct ip_addr* ipaddr_ret;\r
+  struct ip_addr ip;\r
+  struct netif *netif;\r
+\r
+  if (len) {}\r
+\r
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);\r
+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);\r
+  ip.addr = htonl(ip.addr);\r
+\r
+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)\r
+  {\r
+    id = od->id_inst_ptr[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipNetToMediaIfIndex */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          *sint_ptr = od->id_inst_ptr[1];\r
+        }\r
+        break;\r
+      case 2: /* ipNetToMediaPhysAddress */\r
+        {\r
+          struct eth_addr *dst = value;\r
+\r
+          *dst = *ethaddr_ret;\r
+        }\r
+        break;\r
+      case 3: /* ipNetToMediaNetAddress */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          *dst = *ipaddr_ret;\r
+        }\r
+        break;\r
+      case 4: /* ipNetToMediaType */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          /* dynamic (?) */\r
+          *sint_ptr = 3;\r
+        }\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+static void\r
+icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if ((ident_len == 2) &&\r
+      (ident[0] > 0) && (ident[0] < 27))\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    od->instance = MIB_OBJECT_SCALAR;\r
+    od->access = MIB_OBJECT_READ_ONLY;\r
+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+    od->v_len = sizeof(u32_t);\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+icmp_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u32_t *uint_ptr = value;\r
+  u8_t id;\r
+\r
+  if (len){}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* icmpInMsgs */\r
+      *uint_ptr = icmpinmsgs;\r
+      break;\r
+    case 2: /* icmpInErrors */\r
+      *uint_ptr = icmpinerrors;\r
+      break;\r
+    case 3: /* icmpInDestUnreachs */\r
+      *uint_ptr = icmpindestunreachs;\r
+      break;\r
+    case 4: /* icmpInTimeExcds */\r
+      *uint_ptr = icmpintimeexcds;\r
+      break;\r
+    case 5: /* icmpInParmProbs */\r
+      *uint_ptr = icmpinparmprobs;\r
+      break;\r
+    case 6: /* icmpInSrcQuenchs */\r
+      *uint_ptr = icmpinsrcquenchs;\r
+      break;\r
+    case 7: /* icmpInRedirects */\r
+      *uint_ptr = icmpinredirects;\r
+      break;\r
+    case 8: /* icmpInEchos */\r
+      *uint_ptr = icmpinechos;\r
+      break;\r
+    case 9: /* icmpInEchoReps */\r
+      *uint_ptr = icmpinechoreps;\r
+      break;\r
+    case 10: /* icmpInTimestamps */\r
+      *uint_ptr = icmpintimestamps;\r
+      break;\r
+    case 11: /* icmpInTimestampReps */\r
+      *uint_ptr = icmpintimestampreps;\r
+      break;\r
+    case 12: /* icmpInAddrMasks */\r
+      *uint_ptr = icmpinaddrmasks;\r
+      break;\r
+    case 13: /* icmpInAddrMaskReps */\r
+      *uint_ptr = icmpinaddrmaskreps;\r
+      break;\r
+    case 14: /* icmpOutMsgs */\r
+      *uint_ptr = icmpoutmsgs;\r
+      break;\r
+    case 15: /* icmpOutErrors */\r
+      *uint_ptr = icmpouterrors;\r
+      break;\r
+    case 16: /* icmpOutDestUnreachs */\r
+      *uint_ptr = icmpoutdestunreachs;\r
+      break;\r
+    case 17: /* icmpOutTimeExcds */\r
+      *uint_ptr = icmpouttimeexcds;\r
+      break;\r
+    case 18: /* icmpOutParmProbs */\r
+      *uint_ptr = icmpoutparmprobs;\r
+      break;\r
+    case 19: /* icmpOutSrcQuenchs */\r
+      *uint_ptr = icmpoutsrcquenchs;\r
+      break;\r
+    case 20: /* icmpOutRedirects */\r
+      *uint_ptr = icmpoutredirects;\r
+      break;\r
+    case 21: /* icmpOutEchos */\r
+      *uint_ptr = icmpoutechos;\r
+      break;\r
+    case 22: /* icmpOutEchoReps */\r
+      *uint_ptr = icmpoutechoreps;\r
+      break;\r
+    case 23: /* icmpOutTimestamps */\r
+      *uint_ptr = icmpouttimestamps;\r
+      break;\r
+    case 24: /* icmpOutTimestampReps */\r
+      *uint_ptr = icmpouttimestampreps;\r
+      break;\r
+    case 25: /* icmpOutAddrMasks */\r
+      *uint_ptr = icmpoutaddrmasks;\r
+      break;\r
+    case 26: /* icmpOutAddrMaskReps */\r
+      *uint_ptr = icmpoutaddrmaskreps;\r
+      break;\r
+  }\r
+}\r
+\r
+#if LWIP_TCP\r
+/** @todo tcp grp */\r
+static void\r
+tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));\r
+\r
+    switch (id)\r
+    {\r
+      case 1: /* tcpRtoAlgorithm */\r
+      case 2: /* tcpRtoMin */\r
+      case 3: /* tcpRtoMax */\r
+      case 4: /* tcpMaxConn */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 5: /* tcpActiveOpens */\r
+      case 6: /* tcpPassiveOpens */\r
+      case 7: /* tcpAttemptFails */\r
+      case 8: /* tcpEstabResets */\r
+      case 10: /* tcpInSegs */\r
+      case 11: /* tcpOutSegs */\r
+      case 12: /* tcpRetransSegs */\r
+      case 14: /* tcpInErrs */\r
+      case 15: /* tcpOutRsts */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 9: /* tcpCurrEstab */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+tcp_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u32_t *uint_ptr = value;\r
+  s32_t *sint_ptr = value;\r
+  u8_t id;\r
+\r
+  if (len){}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* tcpRtoAlgorithm, vanj(4) */\r
+      *sint_ptr = 4;\r
+      break;\r
+    case 2: /* tcpRtoMin */\r
+      /* @todo not the actual value, a guess,\r
+          needs to be calculated */\r
+      *sint_ptr = 1000;\r
+      break;\r
+    case 3: /* tcpRtoMax */\r
+      /* @todo not the actual value, a guess,\r
+         needs to be calculated */\r
+      *sint_ptr = 60000;\r
+      break;\r
+    case 4: /* tcpMaxConn */\r
+      *sint_ptr = MEMP_NUM_TCP_PCB;\r
+      break;\r
+    case 5: /* tcpActiveOpens */\r
+      *uint_ptr = tcpactiveopens;\r
+      break;\r
+    case 6: /* tcpPassiveOpens */\r
+      *uint_ptr = tcppassiveopens;\r
+      break;\r
+    case 7: /* tcpAttemptFails */\r
+      *uint_ptr = tcpattemptfails;\r
+      break;\r
+    case 8: /* tcpEstabResets */\r
+      *uint_ptr = tcpestabresets;\r
+      break;\r
+    case 9: /* tcpCurrEstab */\r
+      {\r
+        u16_t tcpcurrestab = 0;\r
+        struct tcp_pcb *pcb = tcp_active_pcbs;\r
+        while (pcb != NULL)\r
+        {\r
+          if ((pcb->state == ESTABLISHED) ||\r
+              (pcb->state == CLOSE_WAIT))\r
+          {\r
+            tcpcurrestab++;\r
+          }\r
+          pcb = pcb->next;\r
+        }\r
+        *uint_ptr = tcpcurrestab;\r
+      }\r
+      break;\r
+    case 10: /* tcpInSegs */\r
+      *uint_ptr = tcpinsegs;\r
+      break;\r
+    case 11: /* tcpOutSegs */\r
+      *uint_ptr = tcpoutsegs;\r
+      break;\r
+    case 12: /* tcpRetransSegs */\r
+      *uint_ptr = tcpretranssegs;\r
+      break;\r
+    case 14: /* tcpInErrs */\r
+      *uint_ptr = tcpinerrs;\r
+      break;\r
+    case 15: /* tcpOutRsts */\r
+      *uint_ptr = tcpoutrsts;\r
+      break;\r
+  }\r
+}\r
+\r
+static void\r
+tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (10) */\r
+  ident_len += 10;\r
+  ident -= 10;\r
+\r
+  if (ident_len == 11)\r
+  {\r
+    u8_t id;\r
+\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));\r
+\r
+    switch (id)\r
+    {\r
+      case 1: /* tcpConnState */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 2: /* tcpConnLocalAddress */\r
+      case 4: /* tcpConnRemAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      case 3: /* tcpConnLocalPort */\r
+      case 5: /* tcpConnRemPort */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  struct ip_addr lip, rip;\r
+  u16_t lport, rport;\r
+  s32_t *ident;\r
+\r
+  ident = od->id_inst_ptr;\r
+  snmp_oidtoip(&ident[1], &lip);\r
+  lip.addr = htonl(lip.addr);\r
+  lport = ident[5];\r
+  snmp_oidtoip(&ident[6], &rip);\r
+  rip.addr = htonl(rip.addr);\r
+  rport = ident[10];\r
+\r
+  /** @todo find matching PCB */\r
+}\r
+#endif\r
+\r
+static void\r
+udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if ((ident_len == 2) &&\r
+      (ident[0] > 0) && (ident[0] < 6))\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    od->instance = MIB_OBJECT_SCALAR;\r
+    od->access = MIB_OBJECT_READ_ONLY;\r
+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+    od->v_len = sizeof(u32_t);\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+udp_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u32_t *uint_ptr = value;\r
+  u8_t id;\r
+\r
+  if (len){}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* udpInDatagrams */\r
+      *uint_ptr = udpindatagrams;\r
+      break;\r
+    case 2: /* udpNoPorts */\r
+      *uint_ptr = udpnoports;\r
+      break;\r
+    case 3: /* udpInErrors */\r
+      *uint_ptr = udpinerrors;\r
+      break;\r
+    case 4: /* udpOutDatagrams */\r
+      *uint_ptr = udpoutdatagrams;\r
+      break;\r
+  }\r
+}\r
+\r
+static void\r
+udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (5) */\r
+  ident_len += 5;\r
+  ident -= 5;\r
+\r
+  if (ident_len == 6)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    switch (ident[0])\r
+    {\r
+      case 1: /* udpLocalAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      case 2: /* udpLocalPort */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+udpentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+  struct udp_pcb *pcb;\r
+  struct ip_addr ip;\r
+  u16_t port;\r
+\r
+  if (len){}\r
+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);\r
+  ip.addr = htonl(ip.addr);\r
+  port = od->id_inst_ptr[5];\r
+\r
+  pcb = udp_pcbs;\r
+  while ((pcb != NULL) &&\r
+         !((pcb->local_ip.addr == ip.addr) &&\r
+           (pcb->local_port == port)))\r
+  {\r
+    pcb = pcb->next;\r
+  }\r
+\r
+  if (pcb != NULL)\r
+  {\r
+    id = od->id_inst_ptr[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* udpLocalAddress */\r
+        {\r
+          struct ip_addr *dst = value;\r
+          *dst = pcb->local_ip;\r
+        }\r
+        break;\r
+      case 2: /* udpLocalPort */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          *sint_ptr = pcb->local_port;\r
+        }\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+static void\r
+snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    u8_t id;\r
+\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* snmpInPkts */\r
+      case 2: /* snmpOutPkts */\r
+      case 3: /* snmpInBadVersions */\r
+      case 4: /* snmpInBadCommunityNames */\r
+      case 5: /* snmpInBadCommunityUses */\r
+      case 6: /* snmpInASNParseErrs */\r
+      case 8: /* snmpInTooBigs */\r
+      case 9: /* snmpInNoSuchNames */\r
+      case 10: /* snmpInBadValues */\r
+      case 11: /* snmpInReadOnlys */\r
+      case 12: /* snmpInGenErrs */\r
+      case 13: /* snmpInTotalReqVars */\r
+      case 14: /* snmpInTotalSetVars */\r
+      case 15: /* snmpInGetRequests */\r
+      case 16: /* snmpInGetNexts */\r
+      case 17: /* snmpInSetRequests */\r
+      case 18: /* snmpInGetResponses */\r
+      case 19: /* snmpInTraps */\r
+      case 20: /* snmpOutTooBigs */\r
+      case 21: /* snmpOutNoSuchNames */\r
+      case 22: /* snmpOutBadValues */\r
+      case 24: /* snmpOutGenErrs */\r
+      case 25: /* snmpOutGetRequests */\r
+      case 26: /* snmpOutGetNexts */\r
+      case 27: /* snmpOutSetRequests */\r
+      case 28: /* snmpOutGetResponses */\r
+      case 29: /* snmpOutTraps */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 30: /* snmpEnableAuthenTraps */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+snmp_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u32_t *uint_ptr = value;\r
+  u8_t id;\r
+\r
+  if (len){}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+      case 1: /* snmpInPkts */\r
+        *uint_ptr = snmpinpkts;\r
+        break;\r
+      case 2: /* snmpOutPkts */\r
+        *uint_ptr = snmpoutpkts;\r
+        break;\r
+      case 3: /* snmpInBadVersions */\r
+        *uint_ptr = snmpinbadversions;\r
+        break;\r
+      case 4: /* snmpInBadCommunityNames */\r
+        *uint_ptr = snmpinbadcommunitynames;\r
+        break;\r
+      case 5: /* snmpInBadCommunityUses */\r
+        *uint_ptr = snmpinbadcommunityuses;\r
+        break;\r
+      case 6: /* snmpInASNParseErrs */\r
+        *uint_ptr = snmpinasnparseerrs;\r
+        break;\r
+      case 8: /* snmpInTooBigs */\r
+        *uint_ptr = snmpintoobigs;\r
+        break;\r
+      case 9: /* snmpInNoSuchNames */\r
+        *uint_ptr = snmpinnosuchnames;\r
+        break;\r
+      case 10: /* snmpInBadValues */\r
+        *uint_ptr = snmpinbadvalues;\r
+        break;\r
+      case 11: /* snmpInReadOnlys */\r
+        *uint_ptr = snmpinreadonlys;\r
+        break;\r
+      case 12: /* snmpInGenErrs */\r
+        *uint_ptr = snmpingenerrs;\r
+        break;\r
+      case 13: /* snmpInTotalReqVars */\r
+        *uint_ptr = snmpintotalreqvars;\r
+        break;\r
+      case 14: /* snmpInTotalSetVars */\r
+        *uint_ptr = snmpintotalsetvars;\r
+        break;\r
+      case 15: /* snmpInGetRequests */\r
+        *uint_ptr = snmpingetrequests;\r
+        break;\r
+      case 16: /* snmpInGetNexts */\r
+        *uint_ptr = snmpingetnexts;\r
+        break;\r
+      case 17: /* snmpInSetRequests */\r
+        *uint_ptr = snmpinsetrequests;\r
+        break;\r
+      case 18: /* snmpInGetResponses */\r
+        *uint_ptr = snmpingetresponses;\r
+        break;\r
+      case 19: /* snmpInTraps */\r
+        *uint_ptr = snmpintraps;\r
+        break;\r
+      case 20: /* snmpOutTooBigs */\r
+        *uint_ptr = snmpouttoobigs;\r
+        break;\r
+      case 21: /* snmpOutNoSuchNames */\r
+        *uint_ptr = snmpoutnosuchnames;\r
+        break;\r
+      case 22: /* snmpOutBadValues */\r
+        *uint_ptr = snmpoutbadvalues;\r
+        break;\r
+      case 24: /* snmpOutGenErrs */\r
+        *uint_ptr = snmpoutgenerrs;\r
+        break;\r
+      case 25: /* snmpOutGetRequests */\r
+        *uint_ptr = snmpoutgetrequests;\r
+        break;\r
+      case 26: /* snmpOutGetNexts */\r
+        *uint_ptr = snmpoutgetnexts;\r
+        break;\r
+      case 27: /* snmpOutSetRequests */\r
+        *uint_ptr = snmpoutsetrequests;\r
+        break;\r
+      case 28: /* snmpOutGetResponses */\r
+        *uint_ptr = snmpoutgetresponses;\r
+        break;\r
+      case 29: /* snmpOutTraps */\r
+        *uint_ptr = snmpouttraps;\r
+        break;\r
+      case 30: /* snmpEnableAuthenTraps */\r
+        *uint_ptr = *snmpenableauthentraps_ptr;\r
+        break;\r
+  };\r
+}\r
+\r
+/**\r
+ * Test snmp object value before setting.\r
+ *\r
+ * @param od is the object definition\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value from.\r
+ */\r
+static u8_t\r
+snmp_set_test(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id, set_ok;\r
+\r
+  if (len) {}\r
+  set_ok = 0;\r
+  id = od->id_inst_ptr[0];\r
+  if (id == 30)\r
+  {\r
+    /* snmpEnableAuthenTraps */\r
+    s32_t *sint_ptr = value;\r
+\r
+    if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default)\r
+    {\r
+      /* we should have writable non-volatile mem here */\r
+      if ((*sint_ptr == 1) || (*sint_ptr == 2))\r
+      {\r
+        set_ok = 1;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* const or hardwired value */\r
+      if (*sint_ptr == snmpenableauthentraps_default)\r
+      {\r
+        set_ok = 1;\r
+      }\r
+    }\r
+  }\r
+  return set_ok;\r
+}\r
+\r
+static void\r
+snmp_set_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+\r
+  if (len) {}\r
+  id = od->id_inst_ptr[0];\r
+  if (id == 30)\r
+  {\r
+    /* snmpEnableAuthenTraps */\r
+    s32_t *sint_ptr = value;\r
+    *snmpenableauthentraps_ptr = *sint_ptr;\r
+  }\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
index e68636a1aa11ec156365cbb60ec1e35a223aafde..1fad58865fb86d244bdbb13ba69e5531f2d7517d 100644 (file)
-/**
- * @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 */
-
+/**\r
+ * @file\r
+ * MIB tree access/construction functions.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP\r
+#include "lwip/snmp_structs.h"\r
+#include "lwip/mem.h"\r
+\r
+\r
+\r
+/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */\r
+const s32_t prefix[4] = {1, 3, 6, 1};\r
+\r
+#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)\r
+/** node stack entry (old news?) */\r
+struct nse\r
+{\r
+  /** right child */\r
+  struct mib_node* r_ptr;\r
+  /** right child identifier */\r
+  s32_t r_id;\r
+  /** right child next level */\r
+  u8_t r_nl;\r
+};\r
+static u8_t node_stack_cnt = 0;\r
+static struct nse node_stack[NODE_STACK_SIZE];\r
+\r
+/**\r
+ * Pushes nse struct onto stack.\r
+ */\r
+static void\r
+push_node(struct nse* node)\r
+{\r
+  LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id));\r
+  if (node_stack_cnt < NODE_STACK_SIZE)\r
+  {\r
+    node_stack[node_stack_cnt] = *node;\r
+    node_stack_cnt++;\r
+  }\r
+}\r
+\r
+/**\r
+ * Pops nse struct from stack.\r
+ */\r
+static void\r
+pop_node(struct nse* node)\r
+{\r
+  if (node_stack_cnt > 0)\r
+  {\r
+    node_stack_cnt--;\r
+    *node = node_stack[node_stack_cnt];\r
+  }\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id));\r
+}\r
+\r
+/**\r
+ * Conversion from ifIndex to lwIP netif\r
+ * @param ifindex is a s32_t object sub-identifier\r
+ * @param netif points to returned netif struct pointer\r
+ */\r
+void\r
+snmp_ifindextonetif(s32_t ifindex, struct netif **netif)\r
+{\r
+  struct netif *nif = netif_list;\r
+  u16_t i, ifidx;\r
+\r
+  ifidx = ifindex - 1;\r
+  i = 0;\r
+  while ((nif != NULL) && (i < ifidx))\r
+  {\r
+    nif = nif->next;\r
+    i++;\r
+  }\r
+  *netif = nif;\r
+}\r
+\r
+/**\r
+ * Conversion from lwIP netif to ifIndex\r
+ * @param netif points to a netif struct\r
+ * @param ifindex points to s32_t object sub-identifier\r
+ */\r
+void\r
+snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)\r
+{\r
+  struct netif *nif = netif_list;\r
+  u16_t i;\r
+\r
+  i = 0;\r
+  while (nif != netif)\r
+  {\r
+    nif = nif->next;\r
+    i++;\r
+  }\r
+  *ifidx = i+1;\r
+}\r
+\r
+/**\r
+ * Conversion from oid to lwIP ip_addr\r
+ * @param ident points to s32_t ident[4] input\r
+ * @param ip points to output struct\r
+ */\r
+void\r
+snmp_oidtoip(s32_t *ident, struct ip_addr *ip)\r
+{\r
+  u32_t ipa;\r
+\r
+  ipa = ident[0];\r
+  ipa <<= 8;\r
+  ipa |= ident[1];\r
+  ipa <<= 8;\r
+  ipa |= ident[2];\r
+  ipa <<= 8;\r
+  ipa |= ident[3];\r
+  ip->addr = ipa;\r
+}\r
+\r
+/**\r
+ * Conversion from lwIP ip_addr to oid\r
+ * @param ip points to input struct\r
+ * @param ident points to s32_t ident[4] output\r
+ */\r
+void\r
+snmp_iptooid(struct ip_addr *ip, s32_t *ident)\r
+{\r
+  u32_t ipa;\r
+\r
+  ipa = ip->addr;\r
+  ident[0] = (ipa >> 24) & 0xff;\r
+  ident[1] = (ipa >> 16) & 0xff;\r
+  ident[2] = (ipa >> 8) & 0xff;\r
+  ident[3] = ipa & 0xff;\r
+}\r
+\r
+struct mib_list_node *\r
+snmp_mib_ln_alloc(s32_t id)\r
+{\r
+  struct mib_list_node *ln;\r
+\r
+  ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node));\r
+  if (ln != NULL)\r
+  {\r
+    ln->prev = NULL;\r
+    ln->next = NULL;\r
+    ln->objid = id;\r
+    ln->nptr = NULL;\r
+  }\r
+  return ln;\r
+}\r
+\r
+void\r
+snmp_mib_ln_free(struct mib_list_node *ln)\r
+{\r
+  mem_free(ln);\r
+}\r
+\r
+struct mib_list_rootnode *\r
+snmp_mib_lrn_alloc(void)\r
+{\r
+  struct mib_list_rootnode *lrn;\r
+\r
+  lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode));\r
+  if (lrn != NULL)\r
+  {\r
+    lrn->get_object_def = noleafs_get_object_def;\r
+    lrn->get_value = noleafs_get_value;\r
+    lrn->set_test = noleafs_set_test;\r
+    lrn->set_value = noleafs_set_value;\r
+    lrn->node_type = MIB_NODE_LR;\r
+    lrn->maxlength = 0;\r
+    lrn->head = NULL;\r
+    lrn->tail = NULL;\r
+    lrn->count = 0;\r
+  }\r
+  return lrn;\r
+}\r
+\r
+void\r
+snmp_mib_lrn_free(struct mib_list_rootnode *lrn)\r
+{\r
+  mem_free(lrn);\r
+}\r
+\r
+/**\r
+ * Inserts node in idx list in a sorted\r
+ * (ascending order) fashion and\r
+ * allocates the node if needed.\r
+ *\r
+ * @param rn points to the root node\r
+ * @param objid is the object sub identifier\r
+ * @param insn points to a pointer to the inserted node\r
+ *   used for constructing the tree.\r
+ * @return -1 if failed, 1 if inserted, 2 if present.\r
+ */\r
+s8_t\r
+snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)\r
+{\r
+  struct mib_list_node *nn;\r
+  s8_t insert;\r
+\r
+  LWIP_ASSERT("rn != NULL",rn != NULL);\r
+\r
+  /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */\r
+  insert = 0;\r
+  if (rn->head == NULL)\r
+  {\r
+    /* empty list, add first node */\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));\r
+    nn = snmp_mib_ln_alloc(objid);\r
+    if (nn != NULL)\r
+    {\r
+      rn->head = nn;\r
+      rn->tail = nn;\r
+      *insn = nn;\r
+      insert = 1;\r
+    }\r
+    else\r
+    {\r
+      insert = -1;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    struct mib_list_node *n;\r
+    /* at least one node is present */\r
+    n = rn->head;\r
+    while ((n != NULL) && (insert == 0))\r
+    {\r
+      if (n->objid == objid)\r
+      {\r
+        /* node is already there */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));\r
+        *insn = n;\r
+        insert = 2;\r
+      }\r
+      else if (n->objid < objid)\r
+      {\r
+        if (n->next == NULL)\r
+        {\r
+          /* alloc and insert at the tail */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));\r
+          nn = snmp_mib_ln_alloc(objid);\r
+          if (nn != NULL)\r
+          {\r
+            nn->next = NULL;\r
+            nn->prev = n;\r
+            n->next = nn;\r
+            rn->tail = nn;\r
+            *insn = nn;\r
+            insert = 1;\r
+          }\r
+          else\r
+          {\r
+            /* insertion failure */\r
+            insert = -1;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* there's more to explore: traverse list */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));\r
+          n = n->next;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* n->objid > objid */\r
+        /* alloc and insert between n->prev and n */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));\r
+        nn = snmp_mib_ln_alloc(objid);\r
+        if (nn != NULL)\r
+        {\r
+          if (n->prev == NULL)\r
+          {\r
+            /* insert at the head */\r
+            nn->next = n;\r
+            nn->prev = NULL;\r
+            rn->head = nn;\r
+            n->prev = nn;\r
+          }\r
+          else\r
+          {\r
+            /* insert in the middle */\r
+            nn->next = n;\r
+            nn->prev = n->prev;\r
+            n->prev->next = nn;\r
+            n->prev = nn;\r
+          }\r
+          *insn = nn;\r
+          insert = 1;\r
+        }\r
+        else\r
+        {\r
+          /* insertion failure */\r
+          insert = -1;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  if (insert == 1)\r
+  {\r
+    rn->count += 1;\r
+  }\r
+  LWIP_ASSERT("insert != 0",insert != 0);\r
+  return insert;\r
+}\r
+\r
+/**\r
+ * Finds node in idx list and returns deletion mark.\r
+ *\r
+ * @param rn points to the root node\r
+ * @param objid  is the object sub identifier\r
+ * @param fn returns pointer to found node\r
+ * @return 0 if not found, 1 if deletable,\r
+ *   2 can't delete (2 or more children), 3 not a list_node\r
+ */\r
+s8_t\r
+snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)\r
+{\r
+  s8_t fc;\r
+  struct mib_list_node *n;\r
+\r
+  LWIP_ASSERT("rn != NULL",rn != NULL);\r
+  n = rn->head;\r
+  while ((n != NULL) && (n->objid != objid))\r
+  {\r
+    n = n->next;\r
+  }\r
+  if (n == NULL)\r
+  {\r
+    fc = 0;\r
+  }\r
+  else if (n->nptr == NULL)\r
+  {\r
+    /* leaf, can delete node */\r
+    fc = 1;\r
+  }\r
+  else\r
+  {\r
+    struct mib_list_rootnode *rn;\r
+\r
+    if (n->nptr->node_type == MIB_NODE_LR)\r
+    {\r
+      rn = (struct mib_list_rootnode *)n->nptr;\r
+      if (rn->count > 1)\r
+      {\r
+        /* can't delete node */\r
+        fc = 2;\r
+      }\r
+      else\r
+      {\r
+        /* count <= 1, can delete node */\r
+        fc = 1;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* other node type */\r
+      fc = 3;\r
+    }\r
+  }\r
+  *fn = n;\r
+  return fc;\r
+}\r
+\r
+/**\r
+ * Removes node from idx list\r
+ * if it has a single child left.\r
+ *\r
+ * @param rn points to the root node\r
+ * @param n points to the node to delete\r
+ * @return the nptr to be freed by caller\r
+ */\r
+struct mib_list_rootnode *\r
+snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)\r
+{\r
+  struct mib_list_rootnode *next;\r
+\r
+  LWIP_ASSERT("rn != NULL",rn != NULL);\r
+  LWIP_ASSERT("n != NULL",n != NULL);\r
+\r
+  /* caller must remove this sub-tree */\r
+  next = (struct mib_list_rootnode*)(n->nptr);\r
+  rn->count -= 1;\r
+\r
+  if (n == rn->head)\r
+  {\r
+    rn->head = n->next;\r
+    if (n->next != NULL)\r
+    {\r
+      /* not last node, new list begin */\r
+      n->next->prev = NULL;\r
+    }\r
+  }\r
+  else if (n == rn->tail)\r
+  {\r
+    rn->tail = n->prev;\r
+    if (n->prev != NULL)\r
+    {\r
+      /* not last node, new list end */\r
+      n->prev->next = NULL;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    /* node must be in the middle */\r
+    n->prev->next = n->next;\r
+    n->next->prev = n->prev;\r
+  }\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));\r
+  snmp_mib_ln_free(n);\r
+  if (rn->count == 0)\r
+  {\r
+    rn->head = NULL;\r
+    rn->tail = NULL;\r
+  }\r
+  return next;\r
+}\r
+\r
+\r
+\r
+/**\r
+ * Searches tree for the supplied (scalar?) object identifier.\r
+ *\r
+ * @param node points to the root of the tree ('.internet')\r
+ * @param ident_len the length of the supplied object identifier\r
+ * @param ident points to the array of sub identifiers\r
+ * @param np points to the found object instance (rerurn)\r
+ * @return pointer to the requested parent (!) node if success, NULL otherwise\r
+ */\r
+struct mib_node *\r
+snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)\r
+{\r
+  u8_t node_type, ext_level;\r
+\r
+  ext_level = 0;\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident));\r
+  while (node != NULL)\r
+  {\r
+    node_type = node->node_type;\r
+    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))\r
+    {\r
+      struct mib_array_node *an;\r
+      u16_t i;\r
+\r
+      if (ident_len > 0)\r
+      {\r
+        /* array node (internal ROM or RAM, fixed length) */\r
+        an = (struct mib_array_node *)node;\r
+        i = 0;\r
+        while ((i < an->maxlength) && (an->objid[i] != *ident))\r
+        {\r
+          i++;\r
+        }\r
+        if (i < an->maxlength)\r
+        {\r
+          /* found it, if available proceed to child, otherwise inspect leaf */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));\r
+          if (an->nptr[i] == NULL)\r
+          {\r
+            /* a scalar leaf OR table,\r
+               inspect remaining instance number / table index */\r
+            np->ident_len = ident_len;\r
+            np->ident = ident;\r
+            return (struct mib_node*)an;\r
+          }\r
+          else\r
+          {\r
+            /* follow next child pointer */\r
+            ident++;\r
+            ident_len--;\r
+            node = an->nptr[i];\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* search failed, identifier mismatch (nosuchname) */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));\r
+          return NULL;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* search failed, short object identifier (nosuchname) */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_LR)\r
+    {\r
+      struct mib_list_rootnode *lrn;\r
+      struct mib_list_node *ln;\r
+\r
+      if (ident_len > 0)\r
+      {\r
+        /* list root node (internal 'RAM', variable length) */\r
+        lrn = (struct mib_list_rootnode *)node;\r
+        ln = lrn->head;\r
+        /* iterate over list, head to tail */\r
+        while ((ln != NULL) && (ln->objid != *ident))\r
+        {\r
+          ln = ln->next;\r
+        }\r
+        if (ln != NULL)\r
+        {\r
+          /* found it, proceed to child */;\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));\r
+          if (ln->nptr == NULL)\r
+          {\r
+            np->ident_len = ident_len;\r
+            np->ident = ident;\r
+            return (struct mib_node*)lrn;\r
+          }\r
+          else\r
+          {\r
+            /* follow next child pointer */\r
+            ident_len--;\r
+            ident++;\r
+            node = ln->nptr;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* search failed */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));\r
+          return NULL;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* search failed, short object identifier (nosuchname) */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_EX)\r
+    {\r
+      struct mib_external_node *en;\r
+      u16_t i, len;\r
+\r
+      if (ident_len > 0)\r
+      {\r
+        /* external node (addressing and access via functions) */\r
+        en = (struct mib_external_node *)node;\r
+\r
+        i = 0;\r
+        len = en->level_length(en->addr_inf,ext_level);\r
+        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0))\r
+        {\r
+          i++;\r
+        }\r
+        if (i < len)\r
+        {\r
+          s32_t debug_id;\r
+\r
+          en->get_objid(en->addr_inf,ext_level,i,&debug_id);\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));\r
+          if ((ext_level + 1) == en->tree_levels)\r
+          {\r
+            np->ident_len = ident_len;\r
+            np->ident = ident;\r
+            return (struct mib_node*)en;\r
+          }\r
+          else\r
+          {\r
+            /* found it, proceed to child */\r
+            ident_len--;\r
+            ident++;\r
+            ext_level++;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* search failed */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));\r
+          return NULL;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* search failed, short object identifier (nosuchname) */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+    else if (node_type == MIB_NODE_SC)\r
+    {\r
+      mib_scalar_node *sn;\r
+\r
+      sn = (mib_scalar_node *)node;\r
+      if ((ident_len == 1) && (*ident == 0))\r
+      {\r
+        np->ident_len = ident_len;\r
+        np->ident = ident;\r
+        return (struct mib_node*)sn;\r
+      }\r
+      else\r
+      {\r
+        /* search failed, short object identifier (nosuchname) */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* unknown node_type */\r
+      LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));\r
+      return NULL;\r
+    }\r
+  }\r
+  /* done, found nothing */\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node));\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * Test table for presence of at least one table entry.\r
+ */\r
+static u8_t\r
+empty_table(struct mib_node *node)\r
+{\r
+  u8_t node_type;\r
+  u8_t empty = 0;\r
+\r
+  if (node != NULL)\r
+  {\r
+    node_type = node->node_type;\r
+    if (node_type == MIB_NODE_LR)\r
+    {\r
+      struct mib_list_rootnode *lrn;\r
+      lrn = (struct mib_list_rootnode *)node;\r
+      if ((lrn->count == 0) || (lrn->head == NULL))\r
+      {\r
+        empty = 1;\r
+      }\r
+    }\r
+    else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))\r
+    {\r
+      struct mib_array_node *an;\r
+      an = (struct mib_array_node *)node;\r
+      if ((an->maxlength == 0) || (an->nptr == NULL))\r
+      {\r
+        empty = 1;\r
+      }\r
+    }\r
+    else if (node_type == MIB_NODE_EX)\r
+    {\r
+      struct mib_external_node *en;\r
+      en = (struct mib_external_node *)node;\r
+      if (en->tree_levels == 0)\r
+      {\r
+        empty = 1;\r
+      }\r
+    }\r
+  }\r
+  return empty;\r
+}\r
+\r
+/**\r
+ * Tree expansion.\r
+ */\r
+struct mib_node *\r
+snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)\r
+{\r
+  u8_t node_type, ext_level, climb_tree;\r
+\r
+  ext_level = 0;\r
+  /* reset node stack */\r
+  node_stack_cnt = 0;\r
+  while (node != NULL)\r
+  {\r
+    climb_tree = 0;\r
+    node_type = node->node_type;\r
+    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))\r
+    {\r
+      struct mib_array_node *an;\r
+      u16_t i;\r
+\r
+      /* array node (internal ROM or RAM, fixed length) */\r
+      an = (struct mib_array_node *)node;\r
+      if (ident_len > 0)\r
+      {\r
+        i = 0;\r
+        while ((i < an->maxlength) && (an->objid[i] < *ident))\r
+        {\r
+          i++;\r
+        }\r
+        if (i < an->maxlength)\r
+        {\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));\r
+          /* add identifier to oidret */\r
+          oidret->id[oidret->len] = an->objid[i];\r
+          (oidret->len)++;\r
+\r
+          if (an->nptr[i] == NULL)\r
+          {\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));\r
+            /* leaf node (e.g. in a fixed size table) */\r
+            if (an->objid[i] > *ident)\r
+            {\r
+              return (struct mib_node*)an;\r
+            }\r
+            else if ((i + 1) < an->maxlength)\r
+            {\r
+              /* an->objid[i] == *ident */\r
+              (oidret->len)--;\r
+              oidret->id[oidret->len] = an->objid[i + 1];\r
+              (oidret->len)++;\r
+              return (struct mib_node*)an;\r
+            }\r
+            else\r
+            {\r
+              /* (i + 1) == an->maxlength */\r
+              (oidret->len)--;\r
+              climb_tree = 1;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            u8_t j;\r
+            struct nse cur_node;\r
+\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));\r
+            /* non-leaf, store right child ptr and id */\r
+            j = i + 1;\r
+            while ((j < an->maxlength) && (empty_table(an->nptr[j])))\r
+            {\r
+              j++;\r
+            }\r
+            if (j < an->maxlength)\r
+            {\r
+              cur_node.r_ptr = an->nptr[j];\r
+              cur_node.r_id = an->objid[j];\r
+              cur_node.r_nl = 0;\r
+            }\r
+            else\r
+            {\r
+              cur_node.r_ptr = NULL;\r
+            }\r
+            push_node(&cur_node);\r
+            if (an->objid[i] == *ident)\r
+            {\r
+              ident_len--;\r
+              ident++;\r
+            }\r
+            else\r
+            {\r
+              /* an->objid[i] < *ident */\r
+              ident_len = 0;\r
+            }\r
+            /* follow next child pointer */\r
+            node = an->nptr[i];\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* i == an->maxlength */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        u8_t j;\r
+        /* ident_len == 0, complete with leftmost '.thing' */\r
+        j = 0;\r
+        while ((j < an->maxlength) && empty_table(an->nptr[j]))\r
+        {\r
+          j++;\r
+        }\r
+        if (j < an->maxlength)\r
+        {\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j]));\r
+          oidret->id[oidret->len] = an->objid[j];\r
+          (oidret->len)++;\r
+          if (an->nptr[j] == NULL)\r
+          {\r
+            /* leaf node */\r
+            return (struct mib_node*)an;\r
+          }\r
+          else\r
+          {\r
+            /* no leaf, continue */\r
+            node = an->nptr[j];\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* j == an->maxlength */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_LR)\r
+    {\r
+      struct mib_list_rootnode *lrn;\r
+      struct mib_list_node *ln;\r
+\r
+      /* list root node (internal 'RAM', variable length) */\r
+      lrn = (struct mib_list_rootnode *)node;\r
+      if (ident_len > 0)\r
+      {\r
+        ln = lrn->head;\r
+        /* iterate over list, head to tail */\r
+        while ((ln != NULL) && (ln->objid < *ident))\r
+        {\r
+          ln = ln->next;\r
+        }\r
+        if (ln != NULL)\r
+        {\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));\r
+          oidret->id[oidret->len] = ln->objid;\r
+          (oidret->len)++;\r
+          if (ln->nptr == NULL)\r
+          {\r
+            /* leaf node */\r
+            if (ln->objid > *ident)\r
+            {\r
+              return (struct mib_node*)lrn;\r
+            }\r
+            else if (ln->next != NULL)\r
+            {\r
+              /* ln->objid == *ident */\r
+              (oidret->len)--;\r
+              oidret->id[oidret->len] = ln->next->objid;\r
+              (oidret->len)++;\r
+              return (struct mib_node*)lrn;\r
+            }\r
+            else\r
+            {\r
+              /* ln->next == NULL */\r
+              (oidret->len)--;\r
+              climb_tree = 1;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            struct mib_list_node *jn;\r
+            struct nse cur_node;\r
+\r
+            /* non-leaf, store right child ptr and id */\r
+            jn = ln->next;\r
+            while ((jn != NULL) && empty_table(jn->nptr))\r
+            {\r
+              jn = jn->next;\r
+            }\r
+            if (jn != NULL)\r
+            {\r
+              cur_node.r_ptr = jn->nptr;\r
+              cur_node.r_id = jn->objid;\r
+              cur_node.r_nl = 0;\r
+            }\r
+            else\r
+            {\r
+              cur_node.r_ptr = NULL;\r
+            }\r
+            push_node(&cur_node);\r
+            if (ln->objid == *ident)\r
+            {\r
+              ident_len--;\r
+              ident++;\r
+            }\r
+            else\r
+            {\r
+              /* ln->objid < *ident */\r
+              ident_len = 0;\r
+            }\r
+            /* follow next child pointer */\r
+            node = ln->nptr;\r
+          }\r
+\r
+        }\r
+        else\r
+        {\r
+          /* ln == NULL */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        struct mib_list_node *jn;\r
+        /* ident_len == 0, complete with leftmost '.thing' */\r
+        jn = lrn->head;\r
+        while ((jn != NULL) && empty_table(jn->nptr))\r
+        {\r
+          jn = jn->next;\r
+        }\r
+        if (jn != NULL)\r
+        {\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));\r
+          oidret->id[oidret->len] = jn->objid;\r
+          (oidret->len)++;\r
+          if (jn->nptr == NULL)\r
+          {\r
+            /* leaf node */\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));\r
+            return (struct mib_node*)lrn;\r
+          }\r
+          else\r
+          {\r
+            /* no leaf, continue */\r
+            node = jn->nptr;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* jn == NULL */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_EX)\r
+    {\r
+      struct mib_external_node *en;\r
+      s32_t ex_id;\r
+\r
+      /* external node (addressing and access via functions) */\r
+      en = (struct mib_external_node *)node;\r
+      if (ident_len > 0)\r
+      {\r
+        u16_t i, len;\r
+\r
+        i = 0;\r
+        len = en->level_length(en->addr_inf,ext_level);\r
+        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0))\r
+        {\r
+          i++;\r
+        }\r
+        if (i < len)\r
+        {\r
+          /* add identifier to oidret */\r
+          en->get_objid(en->addr_inf,ext_level,i,&ex_id);\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));\r
+          oidret->id[oidret->len] = ex_id;\r
+          (oidret->len)++;\r
+\r
+          if ((ext_level + 1) == en->tree_levels)\r
+          {\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));\r
+            /* leaf node */\r
+            if (ex_id > *ident)\r
+            {\r
+              return (struct mib_node*)en;\r
+            }\r
+            else if ((i + 1) < len)\r
+            {\r
+              /* ex_id == *ident */\r
+              en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);\r
+              (oidret->len)--;\r
+              oidret->id[oidret->len] = ex_id;\r
+              (oidret->len)++;\r
+              return (struct mib_node*)en;\r
+            }\r
+            else\r
+            {\r
+              /* (i + 1) == len */\r
+              (oidret->len)--;\r
+              climb_tree = 1;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            u8_t j;\r
+            struct nse cur_node;\r
+\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));\r
+            /* non-leaf, store right child ptr and id */\r
+            j = i + 1;\r
+            if (j < len)\r
+            {\r
+              /* right node is the current external node */\r
+              cur_node.r_ptr = node;\r
+              en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);\r
+              cur_node.r_nl = ext_level + 1;\r
+            }\r
+            else\r
+            {\r
+              cur_node.r_ptr = NULL;\r
+            }\r
+            push_node(&cur_node);\r
+            if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0)\r
+            {\r
+              ident_len--;\r
+              ident++;\r
+            }\r
+            else\r
+            {\r
+              /* external id < *ident */\r
+              ident_len = 0;\r
+            }\r
+            /* proceed to child */\r
+            ext_level++;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* i == len (en->level_len()) */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* ident_len == 0, complete with leftmost '.thing' */\r
+        en->get_objid(en->addr_inf,ext_level,0,&ex_id);\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));\r
+        oidret->id[oidret->len] = ex_id;\r
+        (oidret->len)++;\r
+        if ((ext_level + 1) == en->tree_levels)\r
+        {\r
+          /* leaf node */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));\r
+          return (struct mib_node*)en;\r
+        }\r
+        else\r
+        {\r
+          /* no leaf, proceed to child */\r
+          ext_level++;\r
+        }\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_SC)\r
+    {\r
+      mib_scalar_node *sn;\r
+\r
+      /* scalar node  */\r
+      sn = (mib_scalar_node *)node;\r
+      if (ident_len > 0)\r
+      {\r
+        /* at .0 */\r
+        climb_tree = 1;\r
+      }\r
+      else\r
+      {\r
+        /* ident_len == 0, complete object identifier */\r
+        oidret->id[oidret->len] = 0;\r
+        (oidret->len)++;\r
+        /* leaf node */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));\r
+        return (struct mib_node*)sn;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* unknown/unhandled node_type */\r
+      LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));\r
+      return NULL;\r
+    }\r
+\r
+    if (climb_tree)\r
+    {\r
+      struct nse child;\r
+\r
+      /* find right child ptr */\r
+      child.r_ptr = NULL;\r
+      child.r_id = 0;\r
+      child.r_nl = 0;\r
+      while ((node_stack_cnt > 0) && (child.r_ptr == NULL))\r
+      {\r
+        pop_node(&child);\r
+        /* trim returned oid */\r
+        (oidret->len)--;\r
+      }\r
+      if (child.r_ptr != NULL)\r
+      {\r
+        /* incoming ident is useless beyond this point */\r
+        ident_len = 0;\r
+        oidret->id[oidret->len] = child.r_id;\r
+        oidret->len++;\r
+        node = child.r_ptr;\r
+        ext_level = child.r_nl;\r
+      }\r
+      else\r
+      {\r
+        /* tree ends here ... */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+  }\r
+  /* done, found nothing */\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node));\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * Test object identifier for the iso.org.dod.internet prefix.\r
+ *\r
+ * @param ident_len the length of the supplied object identifier\r
+ * @param ident points to the array of sub identifiers\r
+ * @return 1 if it matches, 0 otherwise\r
+ */\r
+u8_t\r
+snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)\r
+{\r
+  if ((ident_len > 3) &&\r
+      (ident[0] == 1) && (ident[1] == 3) &&\r
+      (ident[2] == 6) && (ident[3] == 1))\r
+  {\r
+    return 1;\r
+  }\r
+  else\r
+  {\r
+    return 0;\r
+  }\r
+}\r
+\r
+/**\r
+ * Expands object identifier to the iso.org.dod.internet\r
+ * prefix for use in getnext operation.\r
+ *\r
+ * @param ident_len the length of the supplied object identifier\r
+ * @param ident points to the array of sub identifiers\r
+ * @param oidret points to returned expanded object identifier\r
+ * @return 1 if it matches, 0 otherwise\r
+ *\r
+ * @note ident_len 0 is allowed, expanding to the first known object id!!\r
+ */\r
+u8_t\r
+snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)\r
+{\r
+  const s32_t *prefix_ptr;\r
+  s32_t *ret_ptr;\r
+  u8_t i;\r
+\r
+  i = 0;\r
+  prefix_ptr = &prefix[0];\r
+  ret_ptr = &oidret->id[0];\r
+  ident_len = ((ident_len < 4)?ident_len:4);\r
+  while ((i < ident_len) && ((*ident) <= (*prefix_ptr)))\r
+  {\r
+    *ret_ptr++ = *prefix_ptr++;\r
+    ident++;\r
+    i++;\r
+  }\r
+  if (i == ident_len)\r
+  {\r
+    /* match, complete missing bits */\r
+    while (i < 4)\r
+    {\r
+      *ret_ptr++ = *prefix_ptr++;\r
+      i++;\r
+    }\r
+    oidret->len = i;\r
+    return 1;\r
+  }\r
+  else\r
+  {\r
+    /* i != ident_len */\r
+    return 0;\r
+  }\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
+\r
index d0718501b391b5f1cbc53aec211190b72c669181..1999d13da4b4a9393838f0ace1dd02d77439194b 100644 (file)
-/**
- * @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 */
+/**\r
+ * @file\r
+ * SNMP input message processing (RFC1157).\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP\r
+#include <string.h>\r
+#include "arch/cc.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/stats.h"\r
+\r
+#include "lwip/snmp.h"\r
+#include "lwip/snmp_asn1.h"\r
+#include "lwip/snmp_msg.h"\r
+#include "lwip/snmp_structs.h"\r
+\r
+\r
+/* public (non-static) constants */\r
+/** SNMP v1 == 0 */\r
+const s32_t snmp_version = 0;\r
+/** default SNMP community string */\r
+const char snmp_publiccommunity[7] = "public";\r
+\r
+/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */\r
+#if (SNMP_CONCURRENT_REQUESTS == 0)\r
+#error "need at least one snmp_msg_pstat"\r
+#endif\r
+struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];\r
+/* UDP Protocol Control Block */\r
+struct udp_pcb *snmp1_pcb = NULL;\r
+\r
+static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);\r
+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);\r
+static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);\r
+\r
+\r
+/**\r
+ * Starts SNMP Agent.\r
+ * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.\r
+ */\r
+void\r
+snmp_init(void)\r
+{\r
+  struct snmp_msg_pstat *msg_ps;\r
+  u8_t i;\r
+\r
+  snmp1_pcb = udp_new();\r
+  if (snmp1_pcb != NULL)\r
+  {\r
+    udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);\r
+    udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);\r
+  }\r
+  msg_ps = &msg_input_list[0];\r
+  for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)\r
+  {\r
+    msg_ps->state = SNMP_MSG_EMPTY;\r
+    msg_ps->error_index = 0;\r
+    msg_ps->error_status = SNMP_ES_NOERROR;\r
+    msg_ps++;\r
+  }\r
+  trap_msg.pcb = snmp1_pcb;\r
+  /* The coldstart trap will only be output\r
+     if our outgoing interface is up & configured  */\r
+  snmp_coldstart_trap();\r
+}\r
+\r
+static void\r
+snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)\r
+{\r
+  snmp_varbind_list_free(&msg_ps->outvb);\r
+  msg_ps->outvb = msg_ps->invb;\r
+  msg_ps->invb.head = NULL;\r
+  msg_ps->invb.tail = NULL;\r
+  msg_ps->invb.count = 0;\r
+  msg_ps->error_status = error;\r
+  msg_ps->error_index = 1 + msg_ps->vb_idx;\r
+  snmp_send_response(msg_ps);\r
+  snmp_varbind_list_free(&msg_ps->outvb);\r
+  msg_ps->state = SNMP_MSG_EMPTY;\r
+}\r
+\r
+static void\r
+snmp_ok_response(struct snmp_msg_pstat *msg_ps)\r
+{\r
+  err_t err_ret;\r
+\r
+  err_ret = snmp_send_response(msg_ps);\r
+  if (err_ret == ERR_MEM)\r
+  {\r
+    /* serious memory problem, can't return tooBig */\r
+#if LWIP_STATS\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event pbufs.used = %"U16_F"\n",lwip_stats.pbuf.used));\r
+#endif\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));\r
+  }\r
+  /* free varbinds (if available) */\r
+  snmp_varbind_list_free(&msg_ps->invb);\r
+  snmp_varbind_list_free(&msg_ps->outvb);\r
+  msg_ps->state = SNMP_MSG_EMPTY;\r
+}\r
+\r
+/**\r
+ * Service an internal or external event for SNMP GET.\r
+ *\r
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)\r
+ * @param msg_ps points to the assosicated message process state\r
+ */\r
+static void\r
+snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)\r
+{\r
+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));\r
+\r
+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_name_ptr np;\r
+\r
+    /* get_object_def() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+    np = msg_ps->ext_name_ptr;\r
+\r
+    /* translate answer into a known lifeform */\r
+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);\r
+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)\r
+    {\r
+      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;\r
+      en->get_value_q(request_id, &msg_ps->ext_object_def);\r
+    }\r
+    else\r
+    {\r
+      en->get_object_def_pc(request_id, np.ident_len, np.ident);\r
+      /* search failed, object id points to unknown object (nosuchname) */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_varbind *vb;\r
+\r
+    /* get_value() answer */\r
+    en = msg_ps->ext_mib_node;\r
+\r
+    /* allocate output varbind */\r
+    vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));\r
+    LWIP_ASSERT("vb != NULL",vb != NULL);\r
+    if (vb != NULL)\r
+    {\r
+      vb->next = NULL;\r
+      vb->prev = NULL;\r
+\r
+      /* move name from invb to outvb */\r
+      vb->ident = msg_ps->vb_ptr->ident;\r
+      vb->ident_len = msg_ps->vb_ptr->ident_len;\r
+      /* ensure this memory is refereced once only */\r
+      msg_ps->vb_ptr->ident = NULL;\r
+      msg_ps->vb_ptr->ident_len = 0;\r
+\r
+      vb->value_type = msg_ps->ext_object_def.asn_type;\r
+      vb->value_len =  msg_ps->ext_object_def.v_len;\r
+      if (vb->value_len > 0)\r
+      {\r
+        vb->value = mem_malloc(vb->value_len);\r
+        LWIP_ASSERT("vb->value != NULL",vb->value != NULL);\r
+        if (vb->value != NULL)\r
+        {\r
+          en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);\r
+          snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+          /* search again (if vb_idx < msg_ps->invb.count) */\r
+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+          msg_ps->vb_idx += 1;\r
+        }\r
+        else\r
+        {\r
+          en->get_value_pc(request_id, &msg_ps->ext_object_def);\r
+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));\r
+          msg_ps->vb_ptr->ident = vb->ident;\r
+          msg_ps->vb_ptr->ident_len = vb->ident_len;\r
+          mem_free(vb);\r
+          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* vb->value_len == 0, empty value (e.g. empty string) */\r
+        en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);\r
+        vb->value = NULL;\r
+        snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+        /* search again (if vb_idx < msg_ps->invb.count) */\r
+        msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+        msg_ps->vb_idx += 1;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      en->get_value_pc(request_id, &msg_ps->ext_object_def);\r
+      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));\r
+      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+    }\r
+  }\r
+\r
+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+         (msg_ps->vb_idx < msg_ps->invb.count))\r
+  {\r
+    struct mib_node *mn;\r
+    struct snmp_name_ptr np;\r
+\r
+    if (msg_ps->vb_idx == 0)\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->invb.head;\r
+    }\r
+    else\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;\r
+    }\r
+    /** test object identifier for .iso.org.dod.internet prefix */\r
+    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))\r
+    {\r
+      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,\r
+                             msg_ps->vb_ptr->ident + 4, &np);\r
+    }\r
+    else\r
+    {\r
+      mn = NULL;\r
+    }\r
+    if (mn != NULL)\r
+    {\r
+      if (mn->node_type == MIB_NODE_EX)\r
+      {\r
+        /* external object */\r
+        struct mib_external_node *en = (struct mib_external_node*)mn;\r
+\r
+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;\r
+        /* save en && args in msg_ps!! */\r
+        msg_ps->ext_mib_node = en;\r
+        msg_ps->ext_name_ptr = np;\r
+\r
+        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);\r
+      }\r
+      else\r
+      {\r
+        /* internal object */\r
+        struct obj_def object_def;\r
+\r
+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;\r
+        mn->get_object_def(np.ident_len, np.ident, &object_def);\r
+        if (object_def.instance != MIB_OBJECT_NONE)\r
+        {\r
+          mn = mn;\r
+        }\r
+        else\r
+        {\r
+          /* search failed, object id points to unknown object (nosuchname) */\r
+          mn =  NULL;\r
+        }\r
+        if (mn != NULL)\r
+        {\r
+          struct snmp_varbind *vb;\r
+\r
+          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;\r
+          /* allocate output varbind */\r
+          vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));\r
+          LWIP_ASSERT("vb != NULL",vb != NULL);\r
+          if (vb != NULL)\r
+          {\r
+            vb->next = NULL;\r
+            vb->prev = NULL;\r
+\r
+            /* move name from invb to outvb */\r
+            vb->ident = msg_ps->vb_ptr->ident;\r
+            vb->ident_len = msg_ps->vb_ptr->ident_len;\r
+            /* ensure this memory is refereced once only */\r
+            msg_ps->vb_ptr->ident = NULL;\r
+            msg_ps->vb_ptr->ident_len = 0;\r
+\r
+            vb->value_type = object_def.asn_type;\r
+            vb->value_len = object_def.v_len;\r
+            if (vb->value_len > 0)\r
+            {\r
+              vb->value = mem_malloc(vb->value_len);\r
+              LWIP_ASSERT("vb->value != NULL",vb->value != NULL);\r
+              if (vb->value != NULL)\r
+              {\r
+                mn->get_value(&object_def, vb->value_len, vb->value);\r
+                snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+                msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+                msg_ps->vb_idx += 1;\r
+              }\r
+              else\r
+              {\r
+                LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));\r
+                msg_ps->vb_ptr->ident = vb->ident;\r
+                msg_ps->vb_ptr->ident_len = vb->ident_len;\r
+                mem_free(vb);\r
+                snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+              }\r
+            }\r
+            else\r
+            {\r
+              /* vb->value_len == 0, empty value (e.g. empty string) */\r
+              vb->value = NULL;\r
+              snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+              msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+              msg_ps->vb_idx += 1;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));\r
+            snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+          }\r
+        }\r
+      }\r
+    }\r
+    if (mn == NULL)\r
+    {\r
+      /* mn == NULL, noSuchName */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+      (msg_ps->vb_idx == msg_ps->invb.count))\r
+  {\r
+    snmp_ok_response(msg_ps);\r
+  }\r
+}\r
+\r
+/**\r
+ * Service an internal or external event for SNMP GETNEXT.\r
+ *\r
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)\r
+ * @param msg_ps points to the assosicated message process state\r
+ */\r
+static void\r
+snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)\r
+{\r
+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));\r
+\r
+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)\r
+  {\r
+    struct mib_external_node *en;\r
+\r
+    /* get_object_def() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+\r
+    /* translate answer into a known lifeform */\r
+    en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);\r
+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)\r
+    {\r
+      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;\r
+      en->get_value_q(request_id, &msg_ps->ext_object_def);\r
+    }\r
+    else\r
+    {\r
+      en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);\r
+      /* search failed, object id points to unknown object (nosuchname) */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_varbind *vb;\r
+\r
+    /* get_value() answer */\r
+    en = msg_ps->ext_mib_node;\r
+\r
+    vb = snmp_varbind_alloc(&msg_ps->ext_oid,\r
+                            msg_ps->ext_object_def.asn_type,\r
+                            msg_ps->ext_object_def.v_len);\r
+    if (vb != NULL)\r
+    {\r
+      en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);\r
+      snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+      msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+      msg_ps->vb_idx += 1;\r
+    }\r
+    else\r
+    {\r
+      en->get_value_pc(request_id, &msg_ps->ext_object_def);\r
+      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));\r
+      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+    }\r
+  }\r
+\r
+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+         (msg_ps->vb_idx < msg_ps->invb.count))\r
+  {\r
+    struct mib_node *mn;\r
+    struct snmp_obj_id oid;\r
+\r
+    if (msg_ps->vb_idx == 0)\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->invb.head;\r
+    }\r
+    else\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;\r
+    }\r
+    if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))\r
+    {\r
+      if (msg_ps->vb_ptr->ident_len > 3)\r
+      {\r
+        /* can offset ident_len and ident */\r
+        mn = snmp_expand_tree((struct mib_node*)&internet,\r
+                              msg_ps->vb_ptr->ident_len - 4,\r
+                              msg_ps->vb_ptr->ident + 4, &oid);\r
+      }\r
+      else\r
+      {\r
+        /* can't offset ident_len -4, ident + 4 */\r
+        mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);\r
+      }\r
+    }\r
+    else\r
+    {\r
+      mn = NULL;\r
+    }\r
+    if (mn != NULL)\r
+    {\r
+      if (mn->node_type == MIB_NODE_EX)\r
+      {\r
+        /* external object */\r
+        struct mib_external_node *en = (struct mib_external_node*)mn;\r
+\r
+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;\r
+        /* save en && args in msg_ps!! */\r
+        msg_ps->ext_mib_node = en;\r
+        msg_ps->ext_oid = oid;\r
+\r
+        en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);\r
+      }\r
+      else\r
+      {\r
+        /* internal object */\r
+        struct obj_def object_def;\r
+        struct snmp_varbind *vb;\r
+\r
+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;\r
+        mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);\r
+\r
+        vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);\r
+        if (vb != NULL)\r
+        {\r
+          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;\r
+          mn->get_value(&object_def, object_def.v_len, vb->value);\r
+          snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+          msg_ps->vb_idx += 1;\r
+        }\r
+        else\r
+        {\r
+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));\r
+          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+        }\r
+      }\r
+    }\r
+    if (mn == NULL)\r
+    {\r
+      /* mn == NULL, noSuchName */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+      (msg_ps->vb_idx == msg_ps->invb.count))\r
+  {\r
+    snmp_ok_response(msg_ps);\r
+  }\r
+}\r
+\r
+/**\r
+ * Service an internal or external event for SNMP SET.\r
+ *\r
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)\r
+ * @param msg_ps points to the assosicated message process state\r
+ */\r
+static void\r
+snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)\r
+{\r
+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));\r
+\r
+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_name_ptr np;\r
+\r
+    /* get_object_def() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+    np = msg_ps->ext_name_ptr;\r
+\r
+    /* translate answer into a known lifeform */\r
+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);\r
+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)\r
+    {\r
+      msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;\r
+      en->set_test_q(request_id, &msg_ps->ext_object_def);\r
+    }\r
+    else\r
+    {\r
+      en->get_object_def_pc(request_id, np.ident_len, np.ident);\r
+      /* search failed, object id points to unknown object (nosuchname) */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_name_ptr np;\r
+\r
+    /* set_test() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+    np = msg_ps->ext_name_ptr;\r
+\r
+    if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)\r
+    {\r
+       if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&\r
+           (en->set_test_a(request_id,&msg_ps->ext_object_def,\r
+                           msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))\r
+      {\r
+        msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+        msg_ps->vb_idx += 1;\r
+      }\r
+      else\r
+      {\r
+        en->set_test_pc(request_id,&msg_ps->ext_object_def);\r
+        /* bad value */\r
+        snmp_error_response(msg_ps,SNMP_ES_BADVALUE);\r
+      }\r
+    }\r
+    else\r
+    {\r
+      en->set_test_pc(request_id,&msg_ps->ext_object_def);\r
+      /* object not available for set */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_name_ptr np;\r
+\r
+    /* get_object_def() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+    np = msg_ps->ext_name_ptr;\r
+\r
+    /* translate answer into a known lifeform */\r
+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);\r
+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)\r
+    {\r
+      msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;\r
+      en->set_value_q(request_id, &msg_ps->ext_object_def,\r
+                      msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);\r
+    }\r
+    else\r
+    {\r
+      en->get_object_def_pc(request_id, np.ident_len, np.ident);\r
+      /* set_value failed, object has disappeared for some odd reason?? */\r
+      snmp_error_response(msg_ps,SNMP_ES_GENERROR);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)\r
+  {\r
+    struct mib_external_node *en;\r
+\r
+    /** set_value_a() @todo: use reply value?? */\r
+    en = msg_ps->ext_mib_node;\r
+    en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);\r
+\r
+    /** @todo use set_value_pc() if toobig */\r
+    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;\r
+    msg_ps->vb_idx += 1;\r
+  }\r
+\r
+  /* test all values before setting */\r
+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+         (msg_ps->vb_idx < msg_ps->invb.count))\r
+  {\r
+    struct mib_node *mn;\r
+    struct snmp_name_ptr np;\r
+\r
+    if (msg_ps->vb_idx == 0)\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->invb.head;\r
+    }\r
+    else\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;\r
+    }\r
+    /** test object identifier for .iso.org.dod.internet prefix */\r
+    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))\r
+    {\r
+      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,\r
+                             msg_ps->vb_ptr->ident + 4, &np);\r
+    }\r
+    else\r
+    {\r
+      mn = NULL;\r
+    }\r
+    if (mn != NULL)\r
+    {\r
+      if (mn->node_type == MIB_NODE_EX)\r
+      {\r
+        /* external object */\r
+        struct mib_external_node *en = (struct mib_external_node*)mn;\r
+\r
+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;\r
+        /* save en && args in msg_ps!! */\r
+        msg_ps->ext_mib_node = en;\r
+        msg_ps->ext_name_ptr = np;\r
+\r
+        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);\r
+      }\r
+      else\r
+      {\r
+        /* internal object */\r
+        struct obj_def object_def;\r
+\r
+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;\r
+        mn->get_object_def(np.ident_len, np.ident, &object_def);\r
+        if (object_def.instance != MIB_OBJECT_NONE)\r
+        {\r
+          mn = mn;\r
+        }\r
+        else\r
+        {\r
+          /* search failed, object id points to unknown object (nosuchname) */\r
+          mn = NULL;\r
+        }\r
+        if (mn != NULL)\r
+        {\r
+          msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;\r
+\r
+          if (object_def.access == MIB_OBJECT_READ_WRITE)\r
+          {\r
+            if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&\r
+                (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))\r
+            {\r
+              msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+              msg_ps->vb_idx += 1;\r
+            }\r
+            else\r
+            {\r
+              /* bad value */\r
+              snmp_error_response(msg_ps,SNMP_ES_BADVALUE);\r
+            }\r
+          }\r
+          else\r
+          {\r
+            /* object not available for set */\r
+            snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+          }\r
+        }\r
+      }\r
+    }\r
+    if (mn == NULL)\r
+    {\r
+      /* mn == NULL, noSuchName */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+\r
+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+      (msg_ps->vb_idx == msg_ps->invb.count))\r
+  {\r
+    msg_ps->vb_idx = 0;\r
+    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;\r
+  }\r
+\r
+  /* set all values "atomically" (be as "atomic" as possible) */\r
+  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&\r
+         (msg_ps->vb_idx < msg_ps->invb.count))\r
+  {\r
+    struct mib_node *mn;\r
+    struct snmp_name_ptr np;\r
+\r
+    if (msg_ps->vb_idx == 0)\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->invb.head;\r
+    }\r
+    else\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;\r
+    }\r
+    /* skip iso prefix test, was done previously while settesting() */\r
+    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,\r
+                           msg_ps->vb_ptr->ident + 4, &np);\r
+    /* check if object is still available\r
+       (e.g. external hot-plug thingy present?) */\r
+    if (mn != NULL)\r
+    {\r
+      if (mn->node_type == MIB_NODE_EX)\r
+      {\r
+        /* external object */\r
+        struct mib_external_node *en = (struct mib_external_node*)mn;\r
+\r
+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;\r
+        /* save en && args in msg_ps!! */\r
+        msg_ps->ext_mib_node = en;\r
+        msg_ps->ext_name_ptr = np;\r
+\r
+        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);\r
+      }\r
+      else\r
+      {\r
+        /* internal object */\r
+        struct obj_def object_def;\r
+\r
+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;\r
+        mn->get_object_def(np.ident_len, np.ident, &object_def);\r
+        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;\r
+        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);\r
+        msg_ps->vb_idx += 1;\r
+      }\r
+    }\r
+  }\r
+  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&\r
+      (msg_ps->vb_idx == msg_ps->invb.count))\r
+  {\r
+    /* simply echo the input if we can set it\r
+       @todo do we need to return the actual value?\r
+       e.g. if value is silently modified or behaves sticky? */\r
+    msg_ps->outvb = msg_ps->invb;\r
+    msg_ps->invb.head = NULL;\r
+    msg_ps->invb.tail = NULL;\r
+    msg_ps->invb.count = 0;\r
+    snmp_ok_response(msg_ps);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+ * Handle one internal or external event.\r
+ * Called for one async event. (recv external/private answer)\r
+ *\r
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)\r
+ */\r
+void\r
+snmp_msg_event(u8_t request_id)\r
+{\r
+  struct snmp_msg_pstat *msg_ps;\r
+\r
+  if (request_id < SNMP_CONCURRENT_REQUESTS)\r
+  {\r
+    msg_ps = &msg_input_list[request_id];\r
+    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)\r
+    {\r
+      snmp_msg_getnext_event(request_id, msg_ps);\r
+    }\r
+    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)\r
+    {\r
+      snmp_msg_get_event(request_id, msg_ps);\r
+    }\r
+    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)\r
+    {\r
+      snmp_msg_set_event(request_id, msg_ps);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/* lwIP UDP receive callback function */\r
+static void\r
+snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)\r
+{\r
+  struct udp_hdr *udphdr;\r
+\r
+  /* suppress unused argument warning */\r
+  if (arg);\r
+  /* peek in the UDP header (goto IP payload) */\r
+  pbuf_header(p, UDP_HLEN);\r
+  udphdr = p->payload;\r
+\r
+  /* check if datagram is really directed at us (including broadcast requests) */\r
+  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == 161))\r
+  {\r
+    struct snmp_msg_pstat *msg_ps;\r
+    u8_t req_idx;\r
+\r
+    /* traverse input message process list, look for SNMP_MSG_EMPTY */\r
+    msg_ps = &msg_input_list[0];\r
+    req_idx = 0;\r
+    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))\r
+    {\r
+      req_idx++;\r
+      msg_ps++;\r
+    }\r
+    if (req_idx != SNMP_CONCURRENT_REQUESTS)\r
+    {\r
+      err_t err_ret;\r
+      u16_t payload_len;\r
+      u16_t payload_ofs;\r
+      u16_t varbind_ofs = 0;\r
+\r
+      /* accepting request */\r
+      snmp_inc_snmpinpkts();\r
+      /* record used 'protocol control block' */\r
+      msg_ps->pcb = pcb;\r
+      /* source address (network order) */\r
+      msg_ps->sip = *addr;\r
+      /* source port (host order (lwIP oddity)) */\r
+      msg_ps->sp = port;\r
+      /* read UDP payload length from UDP header */\r
+      payload_len = ntohs(udphdr->len) - UDP_HLEN;\r
+\r
+      /* adjust to UDP payload */\r
+      payload_ofs = UDP_HLEN;\r
+\r
+      /* check total length, version, community, pdu type */\r
+      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);\r
+      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||\r
+           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||\r
+           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&\r
+          ((msg_ps->error_status == SNMP_ES_NOERROR) &&\r
+           (msg_ps->error_index == 0)) )\r
+      {\r
+        /* Only accept requests and requests without error (be robust) */\r
+        err_ret = err_ret;\r
+      }\r
+      else\r
+      {\r
+        /* Reject response and trap headers or error requests as input! */\r
+        err_ret = ERR_ARG;\r
+      }\r
+      if (err_ret == ERR_OK)\r
+      {\r
+        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));\r
+\r
+        /* Builds a list of variable bindings. Copy the varbinds from the pbuf\r
+          chain to glue them when these are divided over two or more pbuf's. */\r
+        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);\r
+        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))\r
+        {\r
+          /* we've decoded the incoming message, release input msg now */\r
+          pbuf_free(p);\r
+\r
+          msg_ps->error_status = SNMP_ES_NOERROR;\r
+          msg_ps->error_index = 0;\r
+          /* find object for each variable binding */\r
+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+          /* first variable binding from list to inspect */\r
+          msg_ps->vb_idx = 0;\r
+\r
+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));\r
+\r
+          /* handle input event and as much objects as possible in one go */\r
+          snmp_msg_event(req_idx);\r
+        }\r
+        else\r
+        {\r
+          /* varbind-list decode failed, or varbind list empty.\r
+             drop request silently, do not return error!\r
+             (errors are only returned for a specific varbind failure) */\r
+          pbuf_free(p);\r
+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* header check failed\r
+           drop request silently, do not return error! */\r
+        pbuf_free(p);\r
+        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* exceeding number of concurrent requests */\r
+      pbuf_free(p);\r
+    }\r
+  }\r
+  else\r
+  {\r
+    /* datagram not for us */\r
+    pbuf_free(p);\r
+  }\r
+}\r
+\r
+/**\r
+ * Checks and decodes incoming SNMP message header, logs header errors.\r
+ *\r
+ * @param p points to pbuf chain of SNMP message (UDP payload)\r
+ * @param ofs points to first octet of SNMP message\r
+ * @param pdu_len the length of the UDP payload\r
+ * @param ofs_ret returns the ofset of the variable bindings\r
+ * @param m_stat points to the current message request state return\r
+ * @return\r
+ * - ERR_OK SNMP header is sane and accepted\r
+ * - ERR_ARG SNMP header is either malformed or rejected\r
+ */\r
+static err_t\r
+snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)\r
+{\r
+  err_t derr;\r
+  u16_t len, ofs_base;\r
+  u8_t  len_octets;\r
+  u8_t  type;\r
+  s32_t version;\r
+\r
+  ofs_base = ofs;\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) ||\r
+      (pdu_len != (1 + len_octets + len)) ||\r
+      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))\r
+  {\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))\r
+  {\r
+    /* can't decode or no integer (version) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* can't decode */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  if (version != 0)\r
+  {\r
+    /* not version 1 */\r
+    snmp_inc_snmpinbadversions();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))\r
+  {\r
+    /* can't decode or no octet string (community) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);\r
+  if (derr != ERR_OK)\r
+  {\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  /* add zero terminator */\r
+  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));\r
+  m_stat->community[len] = 0;\r
+  m_stat->com_strlen = len;\r
+  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)\r
+  {\r
+    /** @todo: move this if we need to check more names */\r
+    snmp_inc_snmpinbadcommunitynames();\r
+    snmp_authfail_trap();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if (derr != ERR_OK)\r
+  {\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  switch(type)\r
+  {\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):\r
+      /* GetRequest PDU */\r
+      snmp_inc_snmpingetrequests();\r
+      derr = ERR_OK;\r
+      break;\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):\r
+      /* GetNextRequest PDU */\r
+      snmp_inc_snmpingetnexts();\r
+      derr = ERR_OK;\r
+      break;\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):\r
+      /* GetResponse PDU */\r
+      snmp_inc_snmpingetresponses();\r
+      derr = ERR_ARG;\r
+      break;\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):\r
+      /* SetRequest PDU */\r
+      snmp_inc_snmpinsetrequests();\r
+      derr = ERR_OK;\r
+      break;\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):\r
+      /* Trap PDU */\r
+      snmp_inc_snmpintraps();\r
+      derr = ERR_ARG;\r
+      break;\r
+    default:\r
+      snmp_inc_snmpinasnparseerrs();\r
+      derr = ERR_ARG;\r
+      break;\r
+  }\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* unsupported input PDU for this agent (no parse error) */\r
+    return ERR_ARG;\r
+  }\r
+  m_stat->rt = type & 0x1F;\r
+  ofs += (1 + len_octets);\r
+  if (len != (pdu_len - (ofs - ofs_base)))\r
+  {\r
+    /* decoded PDU length does not equal actual payload length */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))\r
+  {\r
+    /* can't decode or no integer (request ID) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* can't decode */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))\r
+  {\r
+    /* can't decode or no integer (error-status) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  /* must be noError (0) for incoming requests.\r
+     log errors for mib-2 completeness and for debug purposes */\r
+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* can't decode */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  switch (m_stat->error_status)\r
+  {\r
+    case SNMP_ES_TOOBIG:\r
+      snmp_inc_snmpintoobigs();\r
+      break;\r
+    case SNMP_ES_NOSUCHNAME:\r
+      snmp_inc_snmpinnosuchnames();\r
+      break;\r
+    case SNMP_ES_BADVALUE:\r
+      snmp_inc_snmpinbadvalues();\r
+      break;\r
+    case SNMP_ES_READONLY:\r
+      snmp_inc_snmpinreadonlys();\r
+      break;\r
+    case SNMP_ES_GENERROR:\r
+      snmp_inc_snmpingenerrs();\r
+      break;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))\r
+  {\r
+    /* can't decode or no integer (error-index) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  /* must be 0 for incoming requests.\r
+     decode anyway to catch bad integers (and dirty tricks) */\r
+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* can't decode */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  *ofs_ret = ofs;\r
+  return ERR_OK;\r
+}\r
+\r
+static err_t\r
+snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)\r
+{\r
+  err_t derr;\r
+  u16_t len, vb_len;\r
+  u8_t  len_octets;\r
+  u8_t type;\r
+\r
+  /* variable binding list */\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);\r
+  if ((derr != ERR_OK) ||\r
+      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))\r
+  {\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets);\r
+\r
+  /* start with empty list */\r
+  m_stat->invb.count = 0;\r
+  m_stat->invb.head = NULL;\r
+  m_stat->invb.tail = NULL;\r
+\r
+  while (vb_len > 0)\r
+  {\r
+    struct snmp_obj_id oid, oid_value;\r
+    struct snmp_varbind *vb;\r
+\r
+    snmp_asn1_dec_type(p, ofs, &type);\r
+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+    if ((derr != ERR_OK) ||\r
+        (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||\r
+        (len <= 0) || (len > vb_len))\r
+    {\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+    ofs += (1 + len_octets);\r
+    vb_len -= (1 + len_octets);\r
+\r
+    snmp_asn1_dec_type(p, ofs, &type);\r
+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+    if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))\r
+    {\r
+      /* can't decode object name length */\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+    derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);\r
+    if (derr != ERR_OK)\r
+    {\r
+      /* can't decode object name */\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+    ofs += (1 + len_octets + len);\r
+    vb_len -= (1 + len_octets + len);\r
+\r
+    snmp_asn1_dec_type(p, ofs, &type);\r
+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+    if (derr != ERR_OK)\r
+    {\r
+      /* can't decode object value length */\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+\r
+    switch (type)\r
+    {\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):\r
+        vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));\r
+        if (vb != NULL)\r
+        {\r
+          s32_t *vptr = vb->value;\r
+\r
+          derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);\r
+          snmp_varbind_tail_add(&m_stat->invb, vb);\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):\r
+        vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));\r
+        if (vb != NULL)\r
+        {\r
+          u32_t *vptr = vb->value;\r
+\r
+          derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);\r
+          snmp_varbind_tail_add(&m_stat->invb, vb);\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):\r
+        vb = snmp_varbind_alloc(&oid, type, len);\r
+        if (vb != NULL)\r
+        {\r
+          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);\r
+          snmp_varbind_tail_add(&m_stat->invb, vb);\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):\r
+        vb = snmp_varbind_alloc(&oid, type, 0);\r
+        if (vb != NULL)\r
+        {\r
+          snmp_varbind_tail_add(&m_stat->invb, vb);\r
+          derr = ERR_OK;\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):\r
+        derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);\r
+        if (derr == ERR_OK)\r
+        {\r
+          vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));\r
+          if (vb != NULL)\r
+          {\r
+            u8_t i = oid_value.len;\r
+            s32_t *vptr = vb->value;\r
+\r
+            while(i > 0)\r
+            {\r
+              i--;\r
+              vptr[i] = oid_value.id[i];\r
+            }\r
+            snmp_varbind_tail_add(&m_stat->invb, vb);\r
+            derr = ERR_OK;\r
+          }\r
+          else\r
+          {\r
+            derr = ERR_ARG;\r
+          }\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):\r
+        if (len == 4)\r
+        {\r
+          /* must be exactly 4 octets! */\r
+          vb = snmp_varbind_alloc(&oid, type, 4);\r
+          if (vb != NULL)\r
+          {\r
+            derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);\r
+            snmp_varbind_tail_add(&m_stat->invb, vb);\r
+          }\r
+          else\r
+          {\r
+            derr = ERR_ARG;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      default:\r
+        derr = ERR_ARG;\r
+        break;\r
+    }\r
+    if (derr != ERR_OK)\r
+    {\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+    ofs += (1 + len_octets + len);\r
+    vb_len -= (1 + len_octets + len);\r
+  }\r
+\r
+  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)\r
+  {\r
+    snmp_add_snmpintotalsetvars(m_stat->invb.count);\r
+  }\r
+  else\r
+  {\r
+    snmp_add_snmpintotalreqvars(m_stat->invb.count);\r
+  }\r
+\r
+  *ofs_ret = ofs;\r
+  return ERR_OK;\r
+}\r
+\r
+struct snmp_varbind*\r
+snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)\r
+{\r
+  struct snmp_varbind *vb;\r
+\r
+  vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));\r
+  LWIP_ASSERT("vb != NULL",vb != NULL);\r
+  if (vb != NULL)\r
+  {\r
+    u8_t i;\r
+\r
+    vb->next = NULL;\r
+    vb->prev = NULL;\r
+    i = oid->len;\r
+    vb->ident_len = i;\r
+    if (i > 0)\r
+    {\r
+      /* allocate array of s32_t for our object identifier */\r
+      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);\r
+      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);\r
+      if (vb->ident == NULL)\r
+      {\r
+        mem_free(vb);\r
+        return NULL;\r
+      }\r
+      while(i > 0)\r
+      {\r
+        i--;\r
+        vb->ident[i] = oid->id[i];\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* i == 0, pass zero length object identifier */\r
+      vb->ident = NULL;\r
+    }\r
+    vb->value_type = type;\r
+    vb->value_len = len;\r
+    if (len > 0)\r
+    {\r
+      /* allocate raw bytes for our object value */\r
+      vb->value = mem_malloc(len);\r
+      LWIP_ASSERT("vb->value != NULL",vb->value != NULL);\r
+      if (vb->value == NULL)\r
+      {\r
+        if (vb->ident != NULL)\r
+        {\r
+          mem_free(vb->ident);\r
+        }\r
+        mem_free(vb);\r
+        return NULL;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* ASN1_NUL type, or zero length ASN1_OC_STR */\r
+      vb->value = NULL;\r
+    }\r
+  }\r
+  return vb;\r
+}\r
+\r
+void\r
+snmp_varbind_free(struct snmp_varbind *vb)\r
+{\r
+  if (vb->value != NULL )\r
+  {\r
+    mem_free(vb->value);\r
+  }\r
+  if (vb->ident != NULL )\r
+  {\r
+    mem_free(vb->ident);\r
+  }\r
+  mem_free(vb);\r
+}\r
+\r
+void\r
+snmp_varbind_list_free(struct snmp_varbind_root *root)\r
+{\r
+  struct snmp_varbind *vb, *prev;\r
+\r
+  vb = root->tail;\r
+  while ( vb != NULL )\r
+  {\r
+    prev = vb->prev;\r
+    snmp_varbind_free(vb);\r
+    vb = prev;\r
+  }\r
+  root->count = 0;\r
+  root->head = NULL;\r
+  root->tail = NULL;\r
+}\r
+\r
+void\r
+snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)\r
+{\r
+  if (root->count == 0)\r
+  {\r
+    /* add first varbind to list */\r
+    root->head = vb;\r
+    root->tail = vb;\r
+  }\r
+  else\r
+  {\r
+    /* add nth varbind to list tail */\r
+    root->tail->next = vb;\r
+    vb->prev = root->tail;\r
+    root->tail = vb;\r
+  }\r
+  root->count += 1;\r
+}\r
+\r
+struct snmp_varbind*\r
+snmp_varbind_tail_remove(struct snmp_varbind_root *root)\r
+{\r
+  struct snmp_varbind* vb;\r
+\r
+  if (root->count > 0)\r
+  {\r
+    /* remove tail varbind */\r
+    vb = root->tail;\r
+    root->tail = vb->prev;\r
+    vb->prev->next = NULL;\r
+    root->count -= 1;\r
+  }\r
+  else\r
+  {\r
+    /* nothing to remove */\r
+    vb = NULL;\r
+  }\r
+  return vb;\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
index c8961c9b395253c432169b6195d851b979179c4f..0da70de4afead375ad3765b0fcb954b68beb9339 100644 (file)
-/**
- * @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 */
+/**\r
+ * @file\r
+ * SNMP output message processing (RFC1157).\r
+ *\r
+ * Output responses and traps are build in two passes:\r
+ *\r
+ * Pass 0: iterate over the output message backwards to determine encoding lengths\r
+ * Pass 1: the actual forward encoding of internal form into ASN1\r
+ *\r
+ * The single-pass encoding method described by Comer & Stevens\r
+ * requires extra buffer space and copying for reversal of the packet.\r
+ * The buffer requirement can be prohibitively large for big payloads\r
+ * (>= 484) therefore we use the two encoding passes.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP\r
+#include "arch/cc.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/netif.h"\r
+\r
+#include "lwip/snmp.h"\r
+#include "lwip/snmp_asn1.h"\r
+#include "lwip/snmp_msg.h"\r
+\r
+struct snmp_trap_dst\r
+{\r
+  /* destination IP address in network order */\r
+  struct ip_addr dip;\r
+  /* set to 0 when disabled, >0 when enabled */\r
+  u8_t enable;\r
+};\r
+#if (SNMP_TRAP_DESTINATIONS == 0)\r
+#error "need at least one trap destination"\r
+#endif\r
+struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];\r
+\r
+/** TRAP message structure */\r
+struct snmp_msg_trap trap_msg;\r
+\r
+static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);\r
+static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);\r
+static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);\r
+\r
+static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);\r
+static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);\r
+static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);\r
+\r
+/**\r
+ * Sets enable switch for this trap destination.\r
+ * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1\r
+ * @param enable switch if 0 destination is disabled >0 enabled.\r
+ */\r
+void\r
+snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)\r
+{\r
+  if (dst_idx < SNMP_TRAP_DESTINATIONS)\r
+  {\r
+    trap_dst[dst_idx].enable = enable;\r
+  }\r
+}\r
+\r
+/**\r
+ * Sets IPv4 address for this trap destination.\r
+ * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1\r
+ * @param dst IPv4 address in host order.\r
+ */\r
+void\r
+snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst)\r
+{\r
+  if (dst_idx < SNMP_TRAP_DESTINATIONS)\r
+  {\r
+    trap_dst[dst_idx].dip.addr = htonl(dst->addr);\r
+  }\r
+}\r
+\r
+/**\r
+ * Sends a 'getresponse' message to the request originator.\r
+ *\r
+ * @param m_stat points to the current message request state source\r
+ * @return ERR_OK when success, ERR_MEM if we're out of memory\r
+ *\r
+ * @note the caller is responsible for filling in outvb in the m_stat\r
+ * and provide error-status and index (except for tooBig errors) ...\r
+ */\r
+err_t\r
+snmp_send_response(struct snmp_msg_pstat *m_stat)\r
+{\r
+  struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};\r
+  struct pbuf *p;\r
+  u16_t tot_len;\r
+  err_t err;\r
+\r
+  /* pass 0, calculate length fields */\r
+  tot_len = snmp_varbind_list_sum(&m_stat->outvb);\r
+  tot_len = snmp_resp_header_sum(m_stat, tot_len);\r
+\r
+  /* try allocating pbuf(s) for complete response */\r
+  p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);\r
+  if (p == NULL)\r
+  {\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));\r
+\r
+    /* can't construct reply, return error-status tooBig */\r
+    m_stat->error_status = SNMP_ES_TOOBIG;\r
+    m_stat->error_index = 0;\r
+    /* pass 0, recalculate lengths, for empty varbind-list */\r
+    tot_len = snmp_varbind_list_sum(&emptyvb);\r
+    tot_len = snmp_resp_header_sum(m_stat, tot_len);\r
+    /* retry allocation once for header and empty varbind-list */\r
+    p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);\r
+  }\r
+  if (p != NULL)\r
+  {\r
+    /* first pbuf alloc try or retry alloc success */\r
+    u16_t ofs;\r
+\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));\r
+\r
+    /* pass 1, size error, encode packet ino the pbuf(s) */\r
+    ofs = snmp_resp_header_enc(m_stat, p);\r
+    if (m_stat->error_status == SNMP_ES_TOOBIG)\r
+    {\r
+      snmp_varbind_list_enc(&emptyvb, p, ofs);\r
+    }\r
+    else\r
+    {\r
+      snmp_varbind_list_enc(&m_stat->outvb, p, ofs);\r
+    }\r
+\r
+    switch (m_stat->error_status)\r
+    {\r
+      case SNMP_ES_TOOBIG:\r
+        snmp_inc_snmpouttoobigs();\r
+        break;\r
+      case SNMP_ES_NOSUCHNAME:\r
+        snmp_inc_snmpoutnosuchnames();\r
+        break;\r
+      case SNMP_ES_BADVALUE:\r
+        snmp_inc_snmpoutbadvalues();\r
+        break;\r
+      case SNMP_ES_GENERROR:\r
+        snmp_inc_snmpoutgenerrs();\r
+        break;\r
+    }\r
+    snmp_inc_snmpoutgetresponses();\r
+    snmp_inc_snmpoutpkts();\r
+\r
+    /** @todo do we need separate rx and tx pcbs for threaded case? */\r
+    /** connect to the originating source */\r
+    udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);\r
+    err = udp_send(m_stat->pcb, p);\r
+    if (err == ERR_MEM)\r
+    {\r
+      /** @todo release some memory, retry and return tooBig? tooMuchHassle? */\r
+      err = ERR_MEM;\r
+    }\r
+    else\r
+    {\r
+      err = ERR_OK;\r
+    }\r
+    /** disassociate remote address and port with this pcb */\r
+    udp_disconnect(m_stat->pcb);\r
+\r
+    pbuf_free(p);\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));\r
+    return err;\r
+  }\r
+  else\r
+  {\r
+    /* first pbuf alloc try or retry alloc failed\r
+       very low on memory, couldn't return tooBig */\r
+    return ERR_MEM;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+ * Sends an generic or enterprise specific trap message.\r
+ *\r
+ * @param generic_trap is the trap code\r
+ * @param eoid points to enterprise object identifier\r
+ * @param specific_trap used for enterprise traps when generic_trap == 6\r
+ * @return ERR_OK when success, ERR_MEM if we're out of memory\r
+ *\r
+ * @note the caller is responsible for filling in outvb in the trap_msg\r
+ * @note the use of the enterpise identifier field\r
+ * is per RFC1215.\r
+ * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps\r
+ * and .iso.org.dod.internet.private.enterprises.yourenterprise\r
+ * (sysObjectID) for specific traps.\r
+ */\r
+err_t\r
+snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)\r
+{\r
+  struct snmp_trap_dst *td;\r
+  struct netif *dst_if;\r
+  struct ip_addr dst_ip;\r
+  struct pbuf *p;\r
+  u16_t i,tot_len;\r
+\r
+  for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)\r
+  {\r
+    if ((td->enable != 0) && (td->dip.addr != 0))\r
+    {\r
+      /* network order trap destination */\r
+      trap_msg.dip.addr = td->dip.addr;\r
+      /* lookup current source address for this dst */\r
+      dst_if = ip_route(&td->dip);\r
+      dst_ip.addr = ntohl(dst_if->ip_addr.addr);\r
+      trap_msg.sip_raw[0] = dst_ip.addr >> 24;\r
+      trap_msg.sip_raw[1] = dst_ip.addr >> 16;\r
+      trap_msg.sip_raw[2] = dst_ip.addr >> 8;\r
+      trap_msg.sip_raw[3] = dst_ip.addr;\r
+      trap_msg.gen_trap = generic_trap;\r
+      trap_msg.spc_trap = specific_trap;\r
+      if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)\r
+      {\r
+        /* enterprise-Specific trap */\r
+        trap_msg.enterprise = eoid;\r
+      }\r
+      else\r
+      {\r
+        /* generic (MIB-II) trap */\r
+        snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);\r
+      }\r
+      snmp_get_sysuptime(&trap_msg.ts);\r
+\r
+      /* pass 0, calculate length fields */\r
+      tot_len = snmp_varbind_list_sum(&trap_msg.outvb);\r
+      tot_len = snmp_trap_header_sum(&trap_msg, tot_len);\r
+\r
+      /* allocate pbuf(s) */\r
+      p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);\r
+      if (p != NULL)\r
+      {\r
+        u16_t ofs;\r
+\r
+        /* pass 1, encode packet ino the pbuf(s) */\r
+        ofs = snmp_trap_header_enc(&trap_msg, p);\r
+        snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);\r
+\r
+        snmp_inc_snmpouttraps();\r
+        snmp_inc_snmpoutpkts();\r
+\r
+        /** connect to the TRAP destination */\r
+        udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);\r
+        udp_send(trap_msg.pcb, p);\r
+        /** disassociate remote address and port with this pcb */\r
+        udp_disconnect(trap_msg.pcb);\r
+\r
+        pbuf_free(p);\r
+      }\r
+      else\r
+      {\r
+        return ERR_MEM;\r
+      }\r
+    }\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+void\r
+snmp_coldstart_trap(void)\r
+{\r
+  trap_msg.outvb.head = NULL;\r
+  trap_msg.outvb.tail = NULL;\r
+  trap_msg.outvb.count = 0;\r
+  snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);\r
+}\r
+\r
+void\r
+snmp_authfail_trap(void)\r
+{\r
+  u8_t enable;\r
+  snmp_get_snmpenableauthentraps(&enable);\r
+  if (enable == 1)\r
+  {\r
+    trap_msg.outvb.head = NULL;\r
+    trap_msg.outvb.tail = NULL;\r
+    trap_msg.outvb.count = 0;\r
+    snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);\r
+  }\r
+}\r
+\r
+/**\r
+ * Sums response header field lengths from tail to head and\r
+ * returns resp_header_lengths for second encoding pass.\r
+ *\r
+ * @param vb_len varbind-list length\r
+ * @param rhl points to returned header lengths\r
+ * @return the required lenght for encoding the response header\r
+ */\r
+static u16_t\r
+snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)\r
+{\r
+  u16_t tot_len;\r
+  struct snmp_resp_header_lengths *rhl;\r
+\r
+  rhl = &m_stat->rhl;\r
+  tot_len = vb_len;\r
+  snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);\r
+  snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);\r
+  tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);\r
+  snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);\r
+  tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);\r
+  snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);\r
+  tot_len += 1 + rhl->ridlenlen + rhl->ridlen;\r
+\r
+  rhl->pdulen = tot_len;\r
+  snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);\r
+  tot_len += 1 + rhl->pdulenlen;\r
+\r
+  rhl->comlen = m_stat->com_strlen;\r
+  snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);\r
+  tot_len += 1 + rhl->comlenlen + rhl->comlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);\r
+  snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);\r
+  tot_len += 1 + rhl->verlen + rhl->verlenlen;\r
+\r
+  rhl->seqlen = tot_len;\r
+  snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);\r
+  tot_len += 1 + rhl->seqlenlen;\r
+\r
+  return tot_len;\r
+}\r
+\r
+/**\r
+ * Sums trap header field lengths from tail to head and\r
+ * returns trap_header_lengths for second encoding pass.\r
+ *\r
+ * @param vb_len varbind-list length\r
+ * @param thl points to returned header lengths\r
+ * @return the required lenght for encoding the trap header\r
+ */\r
+static u16_t\r
+snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)\r
+{\r
+  u16_t tot_len;\r
+  struct snmp_trap_header_lengths *thl;\r
+\r
+  thl = &m_trap->thl;\r
+  tot_len = vb_len;\r
+\r
+  snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);\r
+  snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);\r
+  tot_len += 1 + thl->tslen + thl->tslenlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);\r
+  snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);\r
+  tot_len += 1 + thl->strplen + thl->strplenlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);\r
+  snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);\r
+  tot_len += 1 + thl->gtrplen + thl->gtrplenlen;\r
+\r
+  thl->aaddrlen = 4;\r
+  snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);\r
+  tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;\r
+\r
+  snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);\r
+  snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);\r
+  tot_len += 1 + thl->eidlen + thl->eidlenlen;\r
+\r
+  thl->pdulen = tot_len;\r
+  snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);\r
+  tot_len += 1 + thl->pdulenlen;\r
+\r
+  thl->comlen = sizeof(snmp_publiccommunity) - 1;\r
+  snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);\r
+  tot_len += 1 + thl->comlenlen + thl->comlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);\r
+  snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);\r
+  tot_len += 1 + thl->verlen + thl->verlenlen;\r
+\r
+  thl->seqlen = tot_len;\r
+  snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);\r
+  tot_len += 1 + thl->seqlenlen;\r
+\r
+  return tot_len;\r
+}\r
+\r
+/**\r
+ * Sums varbind lengths from tail to head and\r
+ * annotates lengths in varbind for second encoding pass.\r
+ *\r
+ * @param root points to the root of the variable binding list\r
+ * @return the required lenght for encoding the variable bindings\r
+ */\r
+static u16_t\r
+snmp_varbind_list_sum(struct snmp_varbind_root *root)\r
+{\r
+  struct snmp_varbind *vb;\r
+  u32_t *uint_ptr;\r
+  s32_t *sint_ptr;\r
+  u16_t tot_len;\r
+\r
+  tot_len = 0;\r
+  vb = root->tail;\r
+  while ( vb != NULL )\r
+  {\r
+    /* encoded value lenght depends on type */\r
+    switch (vb->value_type)\r
+    {\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):\r
+        sint_ptr = vb->value;\r
+        snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);\r
+        break;\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):\r
+        uint_ptr = vb->value;\r
+        snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):\r
+        vb->vlen = vb->value_len;\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):\r
+        sint_ptr = vb->value;\r
+        snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);\r
+        break;\r
+      default:\r
+        /* unsupported type */\r
+        vb->vlen = 0;\r
+        break;\r
+    };\r
+    /* encoding length of value length field */\r
+    snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);\r
+    snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);\r
+    snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);\r
+\r
+    vb->seqlen = 1 + vb->vlenlen + vb->vlen;\r
+    vb->seqlen += 1 + vb->olenlen + vb->olen;\r
+    snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);\r
+\r
+    /* varbind seq */\r
+    tot_len += 1 + vb->seqlenlen + vb->seqlen;\r
+\r
+    vb = vb->prev;\r
+  }\r
+\r
+  /* varbind-list seq */\r
+  root->seqlen = tot_len;\r
+  snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);\r
+  tot_len += 1 + root->seqlenlen;\r
+\r
+  return tot_len;\r
+}\r
+\r
+/**\r
+ * Encodes response header from head to tail.\r
+ */\r
+static u16_t\r
+snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)\r
+{\r
+  u16_t ofs;\r
+\r
+  ofs = 0;\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);\r
+  ofs += m_stat->rhl.seqlenlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);\r
+  ofs += m_stat->rhl.verlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);\r
+  ofs += m_stat->rhl.verlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);\r
+  ofs += m_stat->rhl.comlenlen;\r
+  snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);\r
+  ofs += m_stat->rhl.comlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);\r
+  ofs += m_stat->rhl.pdulenlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);\r
+  ofs += m_stat->rhl.ridlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);\r
+  ofs += m_stat->rhl.ridlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);\r
+  ofs += m_stat->rhl.errstatlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);\r
+  ofs += m_stat->rhl.errstatlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);\r
+  ofs += m_stat->rhl.erridxlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);\r
+  ofs += m_stat->rhl.erridxlen;\r
+\r
+  return ofs;\r
+}\r
+\r
+/**\r
+ * Encodes trap header from head to tail.\r
+ */\r
+static u16_t\r
+snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)\r
+{\r
+  u16_t ofs;\r
+\r
+  ofs = 0;\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);\r
+  ofs += m_trap->thl.seqlenlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);\r
+  ofs += m_trap->thl.verlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);\r
+  ofs += m_trap->thl.verlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);\r
+  ofs += m_trap->thl.comlenlen;\r
+  snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);\r
+  ofs += m_trap->thl.comlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);\r
+  ofs += m_trap->thl.pdulenlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);\r
+  ofs += m_trap->thl.eidlenlen;\r
+  snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);\r
+  ofs += m_trap->thl.eidlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);\r
+  ofs += m_trap->thl.aaddrlenlen;\r
+  snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);\r
+  ofs += m_trap->thl.aaddrlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);\r
+  ofs += m_trap->thl.gtrplenlen;\r
+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);\r
+  ofs += m_trap->thl.gtrplen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);\r
+  ofs += m_trap->thl.strplenlen;\r
+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);\r
+  ofs += m_trap->thl.strplen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);\r
+  ofs += m_trap->thl.tslenlen;\r
+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);\r
+  ofs += m_trap->thl.tslen;\r
+\r
+  return ofs;\r
+}\r
+\r
+/**\r
+ * Encodes varbind list from head to tail.\r
+ */\r
+static u16_t\r
+snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)\r
+{\r
+  struct snmp_varbind *vb;\r
+  s32_t *sint_ptr;\r
+  u32_t *uint_ptr;\r
+  u8_t *raw_ptr;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, root->seqlen);\r
+  ofs += root->seqlenlen;\r
+\r
+  vb = root->head;\r
+  while ( vb != NULL )\r
+  {\r
+    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));\r
+    ofs += 1;\r
+    snmp_asn1_enc_length(p, ofs, vb->seqlen);\r
+    ofs += vb->seqlenlen;\r
+\r
+    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));\r
+    ofs += 1;\r
+    snmp_asn1_enc_length(p, ofs, vb->olen);\r
+    ofs += vb->olenlen;\r
+    snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);\r
+    ofs += vb->olen;\r
+\r
+    snmp_asn1_enc_type(p, ofs, vb->value_type);\r
+    ofs += 1;\r
+    snmp_asn1_enc_length(p, ofs, vb->vlen);\r
+    ofs += vb->vlenlen;\r
+\r
+    switch (vb->value_type)\r
+    {\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):\r
+        sint_ptr = vb->value;\r
+        snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);\r
+        break;\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):\r
+        uint_ptr = vb->value;\r
+        snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):\r
+        raw_ptr = vb->value;\r
+        snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):\r
+        sint_ptr = vb->value;\r
+        snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);\r
+        break;\r
+      default:\r
+        /* unsupported type */\r
+        break;\r
+    };\r
+    ofs += vb->vlen;\r
+    vb = vb->next;\r
+  }\r
+  return ofs;\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
index d5b37406bbef9fdb62c780e2033bdf95c7334b26..e3cf4a3b5001d8fb755c5091abc5b03ccf460b15 100644 (file)
-/*
- * 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 */
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+\r
+#include "lwip/stats.h"\r
+#include "lwip/mem.h"\r
+\r
+\r
+#if LWIP_STATS\r
+struct stats_ lwip_stats;\r
+\r
+void\r
+stats_init(void)\r
+{\r
+  memset(&lwip_stats, 0, sizeof(struct stats_));\r
+}\r
+#if LWIP_STATS_DISPLAY\r
+void\r
+stats_display_proto(struct stats_proto *proto, char *name)\r
+{\r
+  LWIP_PLATFORM_DIAG(("\n%s\n\t", name));\r
+  LWIP_PLATFORM_DIAG(("xmit: %"S16_F"\n\t", proto->xmit)); \r
+  LWIP_PLATFORM_DIAG(("rexmit: %"S16_F"\n\t", proto->rexmit)); \r
+  LWIP_PLATFORM_DIAG(("recv: %"S16_F"\n\t", proto->recv)); \r
+  LWIP_PLATFORM_DIAG(("fw: %"S16_F"\n\t", proto->fw)); \r
+  LWIP_PLATFORM_DIAG(("drop: %"S16_F"\n\t", proto->drop)); \r
+  LWIP_PLATFORM_DIAG(("chkerr: %"S16_F"\n\t", proto->chkerr)); \r
+  LWIP_PLATFORM_DIAG(("lenerr: %"S16_F"\n\t", proto->lenerr)); \r
+  LWIP_PLATFORM_DIAG(("memerr: %"S16_F"\n\t", proto->memerr)); \r
+  LWIP_PLATFORM_DIAG(("rterr: %"S16_F"\n\t", proto->rterr)); \r
+  LWIP_PLATFORM_DIAG(("proterr: %"S16_F"\n\t", proto->proterr)); \r
+  LWIP_PLATFORM_DIAG(("opterr: %"S16_F"\n\t", proto->opterr)); \r
+  LWIP_PLATFORM_DIAG(("err: %"S16_F"\n\t", proto->err)); \r
+  LWIP_PLATFORM_DIAG(("cachehit: %"S16_F"\n", proto->cachehit)); \r
+}\r
+\r
+void\r
+stats_display_pbuf(struct stats_pbuf *pbuf)\r
+{\r
+  LWIP_PLATFORM_DIAG(("\nPBUF\n\t"));\r
+  LWIP_PLATFORM_DIAG(("avail: %"S16_F"\n\t", pbuf->avail)); \r
+  LWIP_PLATFORM_DIAG(("used: %"S16_F"\n\t", pbuf->used)); \r
+  LWIP_PLATFORM_DIAG(("max: %"S16_F"\n\t", pbuf->max)); \r
+  LWIP_PLATFORM_DIAG(("err: %"S16_F"\n\t", pbuf->err)); \r
+  LWIP_PLATFORM_DIAG(("alloc_locked: %"S16_F"\n\t", pbuf->alloc_locked)); \r
+  LWIP_PLATFORM_DIAG(("refresh_locked: %"S16_F"\n", pbuf->refresh_locked)); \r
+}\r
+\r
+void\r
+stats_display_mem(struct stats_mem *mem, char *name)\r
+{\r
+  LWIP_PLATFORM_DIAG(("\n MEM %s\n\t", name));\r
+  LWIP_PLATFORM_DIAG(("avail: %"MEM_SIZE_F"\n\t", mem->avail)); \r
+  LWIP_PLATFORM_DIAG(("used: %"MEM_SIZE_F"\n\t", mem->used)); \r
+  LWIP_PLATFORM_DIAG(("max: %"MEM_SIZE_F"\n\t", mem->max)); \r
+  LWIP_PLATFORM_DIAG(("err: %"MEM_SIZE_F"\n", mem->err));\r
+  \r
+}\r
+\r
+void\r
+stats_display(void)\r
+{\r
+  s16_t i;\r
+  char * memp_names[] = {"PBUF", "RAW_PCB", "UDP_PCB", "TCP_PCB", "TCP_PCB_LISTEN",\r
+        "TCP_SEG", "NETBUF", "NETCONN", "API_MSG", "TCP_MSG", "TIMEOUT"};\r
+  stats_display_proto(&lwip_stats.link, "LINK");\r
+  stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");\r
+  stats_display_proto(&lwip_stats.ip, "IP");\r
+  stats_display_proto(&lwip_stats.icmp, "ICMP");\r
+  stats_display_proto(&lwip_stats.udp, "UDP");\r
+  stats_display_proto(&lwip_stats.tcp, "TCP");\r
+  stats_display_pbuf(&lwip_stats.pbuf);\r
+  stats_display_mem(&lwip_stats.mem, "HEAP");\r
+  for (i = 0; i < MEMP_MAX; i++) {\r
+    stats_display_mem(&lwip_stats.memp[i], memp_names[i]);\r
+  }\r
+  \r
+}\r
+#endif /* LWIP_STATS_DISPLAY */\r
+#endif /* LWIP_STATS */\r
+\r
index b7bfbf98cc32d8cd0dc8da44254c9d5e5de8b73f..2ecb880a1f64b3a27e5e998ade978b4090ee9473 100644 (file)
-/*
- * 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 */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/opt.h"\r
+#include "lwip/def.h"\r
+#include "lwip/memp.h"\r
+\r
+#if (NO_SYS == 0)\r
+\r
+struct sswt_cb\r
+{\r
+    s16_t timeflag;\r
+    sys_sem_t *psem;\r
+};\r
+\r
+\r
+\r
+void\r
+sys_mbox_fetch(sys_mbox_t mbox, void **msg)\r
+{\r
+  u32_t time;\r
+  struct sys_timeouts *timeouts;\r
+  struct sys_timeo *tmptimeout;\r
+  sys_timeout_handler h;\r
+  void *arg;\r
+\r
+\r
+ again:\r
+  timeouts = sys_arch_timeouts();\r
+\r
+  if (!timeouts || !timeouts->next) {\r
+    sys_arch_mbox_fetch(mbox, msg, 0);\r
+  } else {\r
+    if (timeouts->next->time > 0) {\r
+      time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);\r
+    } else {\r
+      time = SYS_ARCH_TIMEOUT;\r
+    }\r
+\r
+    if (time == SYS_ARCH_TIMEOUT) {\r
+      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message\r
+   could be fetched. We should now call the timeout handler and\r
+   deallocate the memory allocated for the timeout. */\r
+      tmptimeout = timeouts->next;\r
+      timeouts->next = tmptimeout->next;\r
+      h = tmptimeout->h;\r
+      arg = tmptimeout->arg;\r
+      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);\r
+      if (h != NULL) {\r
+        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void *)h, (void *)arg));\r
+       h(arg);\r
+      }\r
+\r
+      /* We try again to fetch a message from the mbox. */\r
+      goto again;\r
+    } else {\r
+      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout\r
+   occured. The time variable is set to the number of\r
+   milliseconds we waited for the message. */\r
+      if (time <= timeouts->next->time) {\r
+  timeouts->next->time -= time;\r
+      } else {\r
+  timeouts->next->time = 0;\r
+      }\r
+    }\r
+\r
+  }\r
+}\r
+\r
+void\r
+sys_sem_wait(sys_sem_t sem)\r
+{\r
+  u32_t time;\r
+  struct sys_timeouts *timeouts;\r
+  struct sys_timeo *tmptimeout;\r
+  sys_timeout_handler h;\r
+  void *arg;\r
+\r
+  /*  while (sys_arch_sem_wait(sem, 1000) == 0);\r
+      return;*/\r
+\r
+ again:\r
+\r
+  timeouts = sys_arch_timeouts();\r
+\r
+  if (!timeouts || !timeouts->next) {\r
+    sys_arch_sem_wait(sem, 0);\r
+  } else {\r
+    if (timeouts->next->time > 0) {\r
+      time = sys_arch_sem_wait(sem, timeouts->next->time);\r
+    } else {\r
+      time = SYS_ARCH_TIMEOUT;\r
+    }\r
+\r
+    if (time == SYS_ARCH_TIMEOUT) {\r
+      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message\r
+   could be fetched. We should now call the timeout handler and\r
+   deallocate the memory allocated for the timeout. */\r
+      tmptimeout = timeouts->next;\r
+      timeouts->next = tmptimeout->next;\r
+      h = tmptimeout->h;\r
+      arg = tmptimeout->arg;\r
+      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);\r
+      if (h != NULL) {\r
+        LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void *)h, (void *)arg));\r
+        h(arg);\r
+      }\r
+\r
+\r
+      /* We try again to fetch a message from the mbox. */\r
+      goto again;\r
+    } else {\r
+      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout\r
+   occured. The time variable is set to the number of\r
+   milliseconds we waited for the message. */\r
+      if (time <= timeouts->next->time) {\r
+  timeouts->next->time -= time;\r
+      } else {\r
+  timeouts->next->time = 0;\r
+      }\r
+    }\r
+\r
+  }\r
+}\r
+\r
+void\r
+sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)\r
+{\r
+  struct sys_timeouts *timeouts;\r
+  struct sys_timeo *timeout, *t;\r
+\r
+  timeout = memp_malloc(MEMP_SYS_TIMEOUT);\r
+  if (timeout == NULL) {\r
+    return;\r
+  }\r
+  timeout->next = NULL;\r
+  timeout->h = h;\r
+  timeout->arg = arg;\r
+  timeout->time = msecs;\r
+\r
+  timeouts = sys_arch_timeouts();\r
+\r
+  LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",\r
+    (void *)timeout, msecs, (void *)h, (void *)arg));\r
+\r
+  LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);\r
+\r
+  if (timeouts->next == NULL) {\r
+    timeouts->next = timeout;\r
+    return;\r
+  }\r
+\r
+  if (timeouts->next->time > msecs) {\r
+    timeouts->next->time -= msecs;\r
+    timeout->next = timeouts->next;\r
+    timeouts->next = timeout;\r
+  } else {\r
+    for(t = timeouts->next; t != NULL; t = t->next) {\r
+      timeout->time -= t->time;\r
+      if (t->next == NULL || t->next->time > timeout->time) {\r
+        if (t->next != NULL) {\r
+          t->next->time -= timeout->time;\r
+        }\r
+        timeout->next = t->next;\r
+        t->next = timeout;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+}\r
+\r
+/* Go through timeout list (for this task only) and remove the first matching entry,\r
+   even though the timeout has not triggered yet.\r
+*/\r
+\r
+void\r
+sys_untimeout(sys_timeout_handler h, void *arg)\r
+{\r
+    struct sys_timeouts *timeouts;\r
+    struct sys_timeo *prev_t, *t;\r
+\r
+    timeouts = sys_arch_timeouts();\r
+\r
+    if (timeouts->next == NULL)\r
+        return;\r
+\r
+    for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next)\r
+    {\r
+        if ((t->h == h) && (t->arg == arg))\r
+        {\r
+            /* We have a match */\r
+            /* Unlink from previous in list */\r
+            if (prev_t == NULL)\r
+                timeouts->next = t->next;\r
+            else\r
+                prev_t->next = t->next;\r
+            /* If not the last one, add time of this one back to next */\r
+            if (t->next != NULL)\r
+                t->next->time += t->time;\r
+            memp_free(MEMP_SYS_TIMEOUT, t);\r
+            return;\r
+        }\r
+    }\r
+    return;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+static void\r
+sswt_handler(void *arg)\r
+{\r
+    struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;\r
+\r
+    /* Timeout. Set flag to TRUE and signal semaphore */\r
+    sswt_cb->timeflag = 1;\r
+    sys_sem_signal(*(sswt_cb->psem));\r
+}\r
+\r
+/* Wait for a semaphore with timeout (specified in ms) */\r
+/* timeout = 0: wait forever */\r
+/* Returns 0 on timeout. 1 otherwise */\r
+\r
+int\r
+sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)\r
+{\r
+    struct sswt_cb sswt_cb;\r
+\r
+    sswt_cb.psem = &sem;\r
+    sswt_cb.timeflag = 0;\r
+\r
+    /* If timeout is zero, then just wait forever */\r
+    if (timeout > 0)\r
+        /* Create a timer and pass it the address of our flag */\r
+        sys_timeout(timeout, sswt_handler, &sswt_cb);\r
+    sys_sem_wait(sem);\r
+    /* Was it a timeout? */\r
+    if (sswt_cb.timeflag)\r
+    {\r
+        /* timeout */\r
+        return 0;\r
+    } else {\r
+        /* Not a timeout. Remove timeout entry */\r
+        sys_untimeout(sswt_handler, &sswt_cb);\r
+        return 1;\r
+    }\r
+\r
+}\r
+\r
+\r
+void\r
+sys_msleep(u32_t ms)\r
+{\r
+  sys_sem_t delaysem = sys_sem_new(0);\r
+\r
+  sys_sem_wait_timeout(delaysem, ms);\r
+\r
+  sys_sem_free(delaysem);\r
+}\r
+\r
+\r
+#endif /* NO_SYS */\r
index 89dfd2413336c794b1dfecee898c66f950501173..5b69ee7cfb55fb250434511dadf1f6bf93d6bc9c 100644 (file)
-/**
- * @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 */
-
-
-
-
-
-
-
-
-
-
+/**\r
+ * @file\r
+ *\r
+ * Transmission Control Protocol for IP\r
+ *\r
+ * This file contains common functions for the TCP implementation, such as functinos\r
+ * for manipulating the data structures and the TCP timer functions. TCP functions\r
+ * related to input and output is found in tcp_in.c and tcp_out.c respectively.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/snmp.h"\r
+\r
+#include "lwip/tcp.h"\r
+#if LWIP_TCP\r
+\r
+/* Incremented every coarse grained timer shot (typically every 500 ms). */\r
+u32_t tcp_ticks;\r
+const u8_t tcp_backoff[13] =\r
+    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};\r
+\r
+/* The TCP PCB lists. */\r
+\r
+/** List of all TCP PCBs in LISTEN state */\r
+union tcp_listen_pcbs_t tcp_listen_pcbs;\r
+/** List of all TCP PCBs that are in a state in which\r
+ * they accept or send data. */\r
+struct tcp_pcb *tcp_active_pcbs;  \r
+/** List of all TCP PCBs in TIME-WAIT state */\r
+struct tcp_pcb *tcp_tw_pcbs;\r
+\r
+struct tcp_pcb *tcp_tmp_pcb;\r
+\r
+static u8_t tcp_timer;\r
+static u16_t tcp_new_port(void);\r
+\r
+/**\r
+ * Initializes the TCP layer.\r
+ */\r
+void\r
+tcp_init(void)\r
+{\r
+  /* Clear globals. */\r
+  tcp_listen_pcbs.listen_pcbs = NULL;\r
+  tcp_active_pcbs = NULL;\r
+  tcp_tw_pcbs = NULL;\r
+  tcp_tmp_pcb = NULL;\r
+  \r
+  /* initialize timer */\r
+  tcp_ticks = 0;\r
+  tcp_timer = 0;\r
+  \r
+}\r
+\r
+/**\r
+ * Called periodically to dispatch TCP timers.\r
+ *\r
+ */\r
+void\r
+tcp_tmr(void)\r
+{\r
+  /* Call tcp_fasttmr() every 250 ms */\r
+  tcp_fasttmr();\r
+\r
+  if (++tcp_timer & 1) {\r
+    /* Call tcp_tmr() every 500 ms, i.e., every other timer\r
+       tcp_tmr() is called. */\r
+    tcp_slowtmr();\r
+  }\r
+}\r
+\r
+/**\r
+ * Closes the connection held by the PCB.\r
+ *\r
+ */\r
+err_t\r
+tcp_close(struct tcp_pcb *pcb)\r
+{\r
+  err_t err;\r
+\r
+#if TCP_DEBUG\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));\r
+  tcp_debug_print_state(pcb->state);\r
+#endif /* TCP_DEBUG */\r
+\r
+  switch (pcb->state) {\r
+  case CLOSED:\r
+    /* Closing a pcb in the CLOSED state might seem erroneous,\r
+     * however, it is in this state once allocated and as yet unused\r
+     * and the user needs some way to free it should the need arise.\r
+     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)\r
+     * or for a pcb that has been used and then entered the CLOSED state \r
+     * is erroneous, but this should never happen as the pcb has in those cases\r
+     * been freed, and so any remaining handles are bogus. */\r
+    err = ERR_OK;\r
+    memp_free(MEMP_TCP_PCB, pcb);\r
+    pcb = NULL;\r
+    break;\r
+  case LISTEN:\r
+    err = ERR_OK;\r
+    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);\r
+    memp_free(MEMP_TCP_PCB_LISTEN, pcb);\r
+    pcb = NULL;\r
+    break;\r
+  case SYN_SENT:\r
+    err = ERR_OK;\r
+    tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
+    memp_free(MEMP_TCP_PCB, pcb);\r
+    pcb = NULL;\r
+    snmp_inc_tcpattemptfails();\r
+    break;\r
+  case SYN_RCVD:\r
+    err = tcp_send_ctrl(pcb, TCP_FIN);\r
+    if (err == ERR_OK) {\r
+      snmp_inc_tcpattemptfails();\r
+      pcb->state = FIN_WAIT_1;\r
+    }\r
+    break;\r
+  case ESTABLISHED:\r
+    err = tcp_send_ctrl(pcb, TCP_FIN);\r
+    if (err == ERR_OK) {\r
+      snmp_inc_tcpestabresets();\r
+      pcb->state = FIN_WAIT_1;\r
+    }\r
+    break;\r
+  case CLOSE_WAIT:\r
+    err = tcp_send_ctrl(pcb, TCP_FIN);\r
+    if (err == ERR_OK) {\r
+      snmp_inc_tcpestabresets();\r
+      pcb->state = LAST_ACK;\r
+    }\r
+    break;\r
+  default:\r
+    /* Has already been closed, do nothing. */\r
+    err = ERR_OK;\r
+    pcb = NULL;\r
+    break;\r
+  }\r
+\r
+  if (pcb != NULL && err == ERR_OK) {\r
+    err = tcp_output(pcb);\r
+  }\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Aborts a connection by sending a RST to the remote host and deletes\r
+ * the local protocol control block. This is done when a connection is\r
+ * killed because of shortage of memory.\r
+ *\r
+ */\r
+void\r
+tcp_abort(struct tcp_pcb *pcb)\r
+{\r
+  u32_t seqno, ackno;\r
+  u16_t remote_port, local_port;\r
+  struct ip_addr remote_ip, local_ip;\r
+#if LWIP_CALLBACK_API  \r
+  void (* errf)(void *arg, err_t err);\r
+#endif /* LWIP_CALLBACK_API */\r
+  void *errf_arg;\r
+\r
+  \r
+  /* Figure out on which TCP PCB list we are, and remove us. If we\r
+     are in an active state, call the receive function associated with\r
+     the PCB with a NULL argument, and send an RST to the remote end. */\r
+  if (pcb->state == TIME_WAIT) {\r
+    tcp_pcb_remove(&tcp_tw_pcbs, pcb);\r
+    memp_free(MEMP_TCP_PCB, pcb);\r
+  } else {\r
+    seqno = pcb->snd_nxt;\r
+    ackno = pcb->rcv_nxt;\r
+    ip_addr_set(&local_ip, &(pcb->local_ip));\r
+    ip_addr_set(&remote_ip, &(pcb->remote_ip));\r
+    local_port = pcb->local_port;\r
+    remote_port = pcb->remote_port;\r
+#if LWIP_CALLBACK_API\r
+    errf = pcb->errf;\r
+#endif /* LWIP_CALLBACK_API */\r
+    errf_arg = pcb->callback_arg;\r
+    tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
+    if (pcb->unacked != NULL) {\r
+      tcp_segs_free(pcb->unacked);\r
+    }\r
+    if (pcb->unsent != NULL) {\r
+      tcp_segs_free(pcb->unsent);\r
+    }\r
+#if TCP_QUEUE_OOSEQ    \r
+    if (pcb->ooseq != NULL) {\r
+      tcp_segs_free(pcb->ooseq);\r
+    }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+    memp_free(MEMP_TCP_PCB, pcb);\r
+    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);\r
+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));\r
+    tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);\r
+  }\r
+}\r
+\r
+/**\r
+ * Binds the connection to a local portnumber and IP address. If the\r
+ * IP address is not given (i.e., ipaddr == NULL), the IP address of\r
+ * the outgoing network interface is used instead.\r
+ *\r
+ */\r
+\r
+err_t\r
+tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)\r
+{\r
+  struct tcp_pcb *cpcb;\r
+\r
+  if (port == 0) {\r
+    port = tcp_new_port();\r
+  }\r
+  /* Check if the address already is in use. */\r
+  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;\r
+      cpcb != NULL; cpcb = cpcb->next) {\r
+    if (cpcb->local_port == port) {\r
+      if (ip_addr_isany(&(cpcb->local_ip)) ||\r
+        ip_addr_isany(ipaddr) ||\r
+        ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\r
+          return ERR_USE;\r
+      }\r
+    }\r
+  }\r
+  for(cpcb = tcp_active_pcbs;\r
+      cpcb != NULL; cpcb = cpcb->next) {\r
+    if (cpcb->local_port == port) {\r
+      if (ip_addr_isany(&(cpcb->local_ip)) ||\r
+   ip_addr_isany(ipaddr) ||\r
+   ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\r
+  return ERR_USE;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (!ip_addr_isany(ipaddr)) {\r
+    pcb->local_ip = *ipaddr;\r
+  }\r
+  pcb->local_port = port;\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));\r
+  return ERR_OK;\r
+}\r
+#if LWIP_CALLBACK_API\r
+static err_t\r
+tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)\r
+{\r
+  (void)arg;\r
+  (void)pcb;\r
+  (void)err;\r
+\r
+  return ERR_ABRT;\r
+}\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+/**\r
+ * Set the state of the connection to be LISTEN, which means that it\r
+ * is able to accept incoming connections. The protocol control block\r
+ * is reallocated in order to consume less memory. Setting the\r
+ * connection to LISTEN is an irreversible process.\r
+ *\r
+ */\r
+struct tcp_pcb *\r
+tcp_listen(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_pcb_listen *lpcb;\r
+\r
+  /* already listening? */\r
+  if (pcb->state == LISTEN) {\r
+    return pcb;\r
+  }\r
+  lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);\r
+  if (lpcb == NULL) {\r
+    return NULL;\r
+  }\r
+  lpcb->callback_arg = pcb->callback_arg;\r
+  lpcb->local_port = pcb->local_port;\r
+  lpcb->state = LISTEN;\r
+  lpcb->so_options = pcb->so_options;\r
+  lpcb->so_options |= SOF_ACCEPTCONN;\r
+  lpcb->ttl = pcb->ttl;\r
+  lpcb->tos = pcb->tos;\r
+  ip_addr_set(&lpcb->local_ip, &pcb->local_ip);\r
+  memp_free(MEMP_TCP_PCB, pcb);\r
+#if LWIP_CALLBACK_API\r
+  lpcb->accept = tcp_accept_null;\r
+#endif /* LWIP_CALLBACK_API */\r
+  TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);\r
+  return (struct tcp_pcb *)lpcb;\r
+}\r
+\r
+/**\r
+ * This function should be called by the application when it has\r
+ * processed the data. The purpose is to advertise a larger window\r
+ * when the data has been processed.\r
+ *\r
+ */\r
+void\r
+tcp_recved(struct tcp_pcb *pcb, u16_t len)\r
+{\r
+  if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {\r
+    pcb->rcv_wnd = TCP_WND;\r
+  } else {\r
+    pcb->rcv_wnd += len;\r
+  }\r
+  if (!(pcb->flags & TF_ACK_DELAY) &&\r
+     !(pcb->flags & TF_ACK_NOW)) {\r
+    /*\r
+     * We send an ACK here (if one is not already pending, hence\r
+     * the above tests) as tcp_recved() implies that the application\r
+     * has processed some data, and so we can open the receiver's\r
+     * window to allow more to be transmitted.  This could result in\r
+     * two ACKs being sent for each received packet in some limited cases\r
+     * (where the application is only receiving data, and is slow to\r
+     * process it) but it is necessary to guarantee that the sender can\r
+     * continue to transmit.\r
+     */\r
+    tcp_ack(pcb);\r
+  } \r
+  else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {\r
+    /* If we can send a window update such that there is a full\r
+     * segment available in the window, do so now.  This is sort of\r
+     * nagle-like in its goals, and tries to hit a compromise between\r
+     * sending acks each time the window is updated, and only sending\r
+     * window updates when a timer expires.  The "threshold" used\r
+     * above (currently TCP_WND/2) can be tuned to be more or less\r
+     * aggressive  */\r
+    tcp_ack_now(pcb);\r
+  }\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",\r
+         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));\r
+}\r
+\r
+/**\r
+ * A nastly hack featuring 'goto' statements that allocates a\r
+ * new TCP local port.\r
+ */\r
+static u16_t\r
+tcp_new_port(void)\r
+{\r
+  struct tcp_pcb *pcb;\r
+#ifndef TCP_LOCAL_PORT_RANGE_START\r
+#define TCP_LOCAL_PORT_RANGE_START 4096\r
+#define TCP_LOCAL_PORT_RANGE_END   0x7fff\r
+#endif\r
+  static u16_t port = TCP_LOCAL_PORT_RANGE_START;\r
+  \r
+ again:\r
+  if (++port > TCP_LOCAL_PORT_RANGE_END) {\r
+    port = TCP_LOCAL_PORT_RANGE_START;\r
+  }\r
+  \r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->local_port == port) {\r
+      goto again;\r
+    }\r
+  }\r
+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->local_port == port) {\r
+      goto again;\r
+    }\r
+  }\r
+  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->local_port == port) {\r
+      goto again;\r
+    }\r
+  }\r
+  return port;\r
+}\r
+\r
+/**\r
+ * Connects to another host. The function given as the "connected"\r
+ * argument will be called when the connection has been established.\r
+ *\r
+ */\r
+err_t\r
+tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,\r
+      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))\r
+{\r
+  u32_t optdata;\r
+  err_t ret;\r
+  u32_t iss;\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));\r
+  if (ipaddr != NULL) {\r
+    pcb->remote_ip = *ipaddr;\r
+  } else {\r
+    return ERR_VAL;\r
+  }\r
+  pcb->remote_port = port;\r
+  if (pcb->local_port == 0) {\r
+    pcb->local_port = tcp_new_port();\r
+  }\r
+  iss = tcp_next_iss();\r
+  pcb->rcv_nxt = 0;\r
+  pcb->snd_nxt = iss;\r
+  pcb->lastack = iss - 1;\r
+  pcb->snd_lbb = iss - 1;\r
+  pcb->rcv_wnd = TCP_WND;\r
+  pcb->snd_wnd = TCP_WND;\r
+  pcb->mss = TCP_MSS;\r
+  pcb->cwnd = 1;\r
+  pcb->ssthresh = pcb->mss * 10;\r
+  pcb->state = SYN_SENT;\r
+#if LWIP_CALLBACK_API  \r
+  pcb->connected = connected;\r
+#endif /* LWIP_CALLBACK_API */  \r
+  TCP_REG(&tcp_active_pcbs, pcb);\r
+\r
+  snmp_inc_tcpactiveopens();\r
+  \r
+  /* Build an MSS option */\r
+  optdata = htonl(((u32_t)2 << 24) | \r
+      ((u32_t)4 << 16) | \r
+      (((u32_t)pcb->mss / 256) << 8) |\r
+      (pcb->mss & 255));\r
+\r
+  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);\r
+  if (ret == ERR_OK) { \r
+    tcp_output(pcb);\r
+  }\r
+  return ret;\r
+} \r
+\r
+/**\r
+ * Called every 500 ms and implements the retransmission timer and the timer that\r
+ * removes PCBs that have been in TIME-WAIT for enough time. It also increments\r
+ * various timers such as the inactivity timer in each PCB.\r
+ */\r
+void\r
+tcp_slowtmr(void)\r
+{\r
+  struct tcp_pcb *pcb, *pcb2, *prev;\r
+  u32_t eff_wnd;\r
+  u8_t pcb_remove;      /* flag if a PCB should be removed */\r
+  err_t err;\r
+\r
+  err = ERR_OK;\r
+\r
+  ++tcp_ticks;\r
+\r
+  /* Steps through all of the active PCBs. */\r
+  prev = NULL;\r
+  pcb = tcp_active_pcbs;\r
+  if (pcb == NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));\r
+  }\r
+  while (pcb != NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));\r
+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);\r
+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);\r
+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);\r
+\r
+    pcb_remove = 0;\r
+\r
+    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {\r
+      ++pcb_remove;\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));\r
+    }\r
+    else if (pcb->nrtx == TCP_MAXRTX) {\r
+      ++pcb_remove;\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));\r
+    } else {\r
+      ++pcb->rtime;\r
+      if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {\r
+\r
+        /* Time for a retransmission. */\r
+        LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"U16_F" pcb->rto %"U16_F"\n",\r
+          pcb->rtime, pcb->rto));\r
+\r
+        /* Double retransmission time-out unless we are trying to\r
+         * connect to somebody (i.e., we are in SYN_SENT). */\r
+        if (pcb->state != SYN_SENT) {\r
+          pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];\r
+        }\r
+        /* Reduce congestion window and ssthresh. */\r
+        eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);\r
+        pcb->ssthresh = eff_wnd >> 1;\r
+        if (pcb->ssthresh < pcb->mss) {\r
+          pcb->ssthresh = pcb->mss * 2;\r
+        }\r
+        pcb->cwnd = pcb->mss;\r
+        LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh %"U16_F"\n",\r
+                                pcb->cwnd, pcb->ssthresh));\r
\r
+        /* The following needs to be called AFTER cwnd is set to one mss - STJ */\r
+        tcp_rexmit_rto(pcb);\r
+     }\r
+    }\r
+    /* Check if this PCB has stayed too long in FIN-WAIT-2 */\r
+    if (pcb->state == FIN_WAIT_2) {\r
+      if ((u32_t)(tcp_ticks - pcb->tmr) >\r
+        TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {\r
+        ++pcb_remove;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));\r
+      }\r
+    }\r
+\r
+   /* Check if KEEPALIVE should be sent */\r
+   if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {\r
+      if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)  {\r
+         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",\r
+                                 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),\r
+                                 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));\r
+\r
+         tcp_abort(pcb);\r
+      }\r
+      else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) {\r
+         tcp_keepalive(pcb);\r
+         pcb->keep_cnt++;\r
+      }\r
+   }\r
+\r
+    /* If this PCB has queued out of sequence data, but has been\r
+       inactive for too long, will drop the data (it will eventually\r
+       be retransmitted). */\r
+#if TCP_QUEUE_OOSEQ    \r
+    if (pcb->ooseq != NULL &&\r
+       (u32_t)tcp_ticks - pcb->tmr >=\r
+       pcb->rto * TCP_OOSEQ_TIMEOUT) {\r
+      tcp_segs_free(pcb->ooseq);\r
+      pcb->ooseq = NULL;\r
+      LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));\r
+    }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+    /* Check if this PCB has stayed too long in SYN-RCVD */\r
+    if (pcb->state == SYN_RCVD) {\r
+      if ((u32_t)(tcp_ticks - pcb->tmr) >\r
+        TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {\r
+        ++pcb_remove;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));\r
+      }\r
+    }\r
+\r
+    /* Check if this PCB has stayed too long in LAST-ACK */\r
+    if (pcb->state == LAST_ACK) {\r
+      if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {\r
+        ++pcb_remove;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));\r
+      }\r
+    }\r
+\r
+    /* If the PCB should be removed, do it. */\r
+    if (pcb_remove) {\r
+      tcp_pcb_purge(pcb);      \r
+      /* Remove PCB from tcp_active_pcbs list. */\r
+      if (prev != NULL) {\r
+  LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);\r
+        prev->next = pcb->next;\r
+      } else {\r
+        /* This PCB was the first. */\r
+        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);\r
+        tcp_active_pcbs = pcb->next;\r
+      }\r
+\r
+      TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);\r
+\r
+      pcb2 = pcb->next;\r
+      memp_free(MEMP_TCP_PCB, pcb);\r
+      pcb = pcb2;\r
+    } else {\r
+\r
+      /* We check if we should poll the connection. */\r
+      ++pcb->polltmr;\r
+      if (pcb->polltmr >= pcb->pollinterval) {\r
+        pcb->polltmr = 0;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));\r
+        TCP_EVENT_POLL(pcb, err);\r
+        if (err == ERR_OK) {\r
+          tcp_output(pcb);\r
+        }\r
+      }\r
+      \r
+      prev = pcb;\r
+      pcb = pcb->next;\r
+    }\r
+  }\r
+\r
+  \r
+  /* Steps through all of the TIME-WAIT PCBs. */\r
+  prev = NULL;    \r
+  pcb = tcp_tw_pcbs;\r
+  while (pcb != NULL) {\r
+    LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);\r
+    pcb_remove = 0;\r
+\r
+    /* Check if this PCB has stayed long enough in TIME-WAIT */\r
+    if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {\r
+      ++pcb_remove;\r
+    }\r
+    \r
+\r
+\r
+    /* If the PCB should be removed, do it. */\r
+    if (pcb_remove) {\r
+      tcp_pcb_purge(pcb);      \r
+      /* Remove PCB from tcp_tw_pcbs list. */\r
+      if (prev != NULL) {\r
+  LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);\r
+        prev->next = pcb->next;\r
+      } else {\r
+        /* This PCB was the first. */\r
+        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);\r
+        tcp_tw_pcbs = pcb->next;\r
+      }\r
+      pcb2 = pcb->next;\r
+      memp_free(MEMP_TCP_PCB, pcb);\r
+      pcb = pcb2;\r
+    } else {\r
+      prev = pcb;\r
+      pcb = pcb->next;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.\r
+ */\r
+void\r
+tcp_fasttmr(void)\r
+{\r
+  struct tcp_pcb *pcb;\r
+\r
+  /* send delayed ACKs */  \r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->flags & TF_ACK_DELAY) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));\r
+      tcp_ack_now(pcb);\r
+      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Deallocates a list of TCP segments (tcp_seg structures).\r
+ *\r
+ */\r
+u8_t\r
+tcp_segs_free(struct tcp_seg *seg)\r
+{\r
+  u8_t count = 0;\r
+  struct tcp_seg *next;\r
+  while (seg != NULL) {\r
+    next = seg->next;\r
+    count += tcp_seg_free(seg);\r
+    seg = next;\r
+  }\r
+  return count;\r
+}\r
+\r
+/**\r
+ * Frees a TCP segment.\r
+ *\r
+ */\r
+u8_t\r
+tcp_seg_free(struct tcp_seg *seg)\r
+{\r
+  u8_t count = 0;\r
+  \r
+  if (seg != NULL) {\r
+    if (seg->p != NULL) {\r
+      count = pbuf_free(seg->p);\r
+#if TCP_DEBUG\r
+      seg->p = NULL;\r
+#endif /* TCP_DEBUG */\r
+    }\r
+    memp_free(MEMP_TCP_SEG, seg);\r
+  }\r
+  return count;\r
+}\r
+\r
+/**\r
+ * Sets the priority of a connection.\r
+ *\r
+ */\r
+void\r
+tcp_setprio(struct tcp_pcb *pcb, u8_t prio)\r
+{\r
+  pcb->prio = prio;\r
+}\r
+#if TCP_QUEUE_OOSEQ\r
+\r
+/**\r
+ * Returns a copy of the given TCP segment.\r
+ *\r
+ */ \r
+struct tcp_seg *\r
+tcp_seg_copy(struct tcp_seg *seg)\r
+{\r
+  struct tcp_seg *cseg;\r
+\r
+  cseg = memp_malloc(MEMP_TCP_SEG);\r
+  if (cseg == NULL) {\r
+    return NULL;\r
+  }\r
+  memcpy((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); \r
+  pbuf_ref(cseg->p);\r
+  return cseg;\r
+}\r
+#endif\r
+\r
+#if LWIP_CALLBACK_API\r
+static err_t\r
+tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\r
+{\r
+  arg = arg;\r
+  if (p != NULL) {\r
+    pbuf_free(p);\r
+  } else if (err == ERR_OK) {\r
+    return tcp_close(pcb);\r
+  }\r
+  return ERR_OK;\r
+}\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+static void\r
+tcp_kill_prio(u8_t prio)\r
+{\r
+  struct tcp_pcb *pcb, *inactive;\r
+  u32_t inactivity;\r
+  u8_t mprio;\r
+\r
+\r
+  mprio = TCP_PRIO_MAX;\r
+  \r
+  /* We kill the oldest active connection that has lower priority than\r
+     prio. */\r
+  inactivity = 0;\r
+  inactive = NULL;\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->prio <= prio &&\r
+       pcb->prio <= mprio &&\r
+       (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {\r
+      inactivity = tcp_ticks - pcb->tmr;\r
+      inactive = pcb;\r
+      mprio = pcb->prio;\r
+    }\r
+  }\r
+  if (inactive != NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",\r
+           (void *)inactive, inactivity));\r
+    tcp_abort(inactive);\r
+  }      \r
+}\r
+\r
+\r
+static void\r
+tcp_kill_timewait(void)\r
+{\r
+  struct tcp_pcb *pcb, *inactive;\r
+  u32_t inactivity;\r
+\r
+  inactivity = 0;\r
+  inactive = NULL;\r
+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {\r
+      inactivity = tcp_ticks - pcb->tmr;\r
+      inactive = pcb;\r
+    }\r
+  }\r
+  if (inactive != NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",\r
+           (void *)inactive, inactivity));\r
+    tcp_abort(inactive);\r
+  }      \r
+}\r
+\r
+\r
+\r
+struct tcp_pcb *\r
+tcp_alloc(u8_t prio)\r
+{\r
+  struct tcp_pcb *pcb;\r
+  u32_t iss;\r
+  \r
+  pcb = memp_malloc(MEMP_TCP_PCB);\r
+  if (pcb == NULL) {\r
+    /* Try killing oldest connection in TIME-WAIT. */\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));\r
+    tcp_kill_timewait();\r
+    pcb = memp_malloc(MEMP_TCP_PCB);\r
+    if (pcb == NULL) {\r
+      tcp_kill_prio(prio);    \r
+      pcb = memp_malloc(MEMP_TCP_PCB);\r
+    }\r
+  }\r
+  if (pcb != NULL) {\r
+    memset(pcb, 0, sizeof(struct tcp_pcb));\r
+    pcb->prio = TCP_PRIO_NORMAL;\r
+    pcb->snd_buf = TCP_SND_BUF;\r
+    pcb->snd_queuelen = 0;\r
+    pcb->rcv_wnd = TCP_WND;\r
+    pcb->tos = 0;\r
+    pcb->ttl = TCP_TTL;\r
+    pcb->mss = TCP_MSS;\r
+    pcb->rto = 3000 / TCP_SLOW_INTERVAL;\r
+    pcb->sa = 0;\r
+    pcb->sv = 3000 / TCP_SLOW_INTERVAL;\r
+    pcb->rtime = 0;\r
+    pcb->cwnd = 1;\r
+    iss = tcp_next_iss();\r
+    pcb->snd_wl2 = iss;\r
+    pcb->snd_nxt = iss;\r
+    pcb->snd_max = iss;\r
+    pcb->lastack = iss;\r
+    pcb->snd_lbb = iss;   \r
+    pcb->tmr = tcp_ticks;\r
+\r
+    pcb->polltmr = 0;\r
+\r
+#if LWIP_CALLBACK_API\r
+    pcb->recv = tcp_recv_null;\r
+#endif /* LWIP_CALLBACK_API */  \r
+    \r
+    /* Init KEEPALIVE timer */\r
+    pcb->keepalive = TCP_KEEPDEFAULT;\r
+    pcb->keep_cnt = 0;\r
+  }\r
+  return pcb;\r
+}\r
+\r
+/**\r
+ * Creates a new TCP protocol control block but doesn't place it on\r
+ * any of the TCP PCB lists.\r
+ *\r
+ * @internal: Maybe there should be a idle TCP PCB list where these\r
+ * PCBs are put on. We can then implement port reservation using\r
+ * tcp_bind(). Currently, we lack this (BSD socket type of) feature.\r
+ */\r
+\r
+struct tcp_pcb *\r
+tcp_new(void)\r
+{\r
+  return tcp_alloc(TCP_PRIO_NORMAL);\r
+}\r
+\r
+/*\r
+ * tcp_arg():\r
+ *\r
+ * Used to specify the argument that should be passed callback\r
+ * functions.\r
+ *\r
+ */ \r
+\r
+void\r
+tcp_arg(struct tcp_pcb *pcb, void *arg)\r
+{  \r
+  pcb->callback_arg = arg;\r
+}\r
+#if LWIP_CALLBACK_API\r
+\r
+/**\r
+ * Used to specify the function that should be called when a TCP\r
+ * connection receives data.\r
+ *\r
+ */ \r
+void\r
+tcp_recv(struct tcp_pcb *pcb,\r
+   err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))\r
+{\r
+  pcb->recv = recv;\r
+}\r
+\r
+/**\r
+ * Used to specify the function that should be called when TCP data\r
+ * has been successfully delivered to the remote host.\r
+ *\r
+ */ \r
+\r
+void\r
+tcp_sent(struct tcp_pcb *pcb,\r
+   err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))\r
+{\r
+  pcb->sent = sent;\r
+}\r
+\r
+/**\r
+ * Used to specify the function that should be called when a fatal error\r
+ * has occured on the connection.\r
+ *\r
+ */ \r
+void\r
+tcp_err(struct tcp_pcb *pcb,\r
+   void (* errf)(void *arg, err_t err))\r
+{\r
+  pcb->errf = errf;\r
+}\r
+\r
+/**\r
+ * Used for specifying the function that should be called when a\r
+ * LISTENing connection has been connected to another host.\r
+ *\r
+ */ \r
+void\r
+tcp_accept(struct tcp_pcb *pcb,\r
+     err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))\r
+{\r
+  ((struct tcp_pcb_listen *)pcb)->accept = accept;\r
+}\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+\r
+/**\r
+ * Used to specify the function that should be called periodically\r
+ * from TCP. The interval is specified in terms of the TCP coarse\r
+ * timer interval, which is called twice a second.\r
+ *\r
+ */ \r
+void\r
+tcp_poll(struct tcp_pcb *pcb,\r
+   err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)\r
+{\r
+#if LWIP_CALLBACK_API\r
+  pcb->poll = poll;\r
+#endif /* LWIP_CALLBACK_API */  \r
+  pcb->pollinterval = interval;\r
+}\r
+\r
+/**\r
+ * Purges a TCP PCB. Removes any buffered data and frees the buffer memory.\r
+ *\r
+ */\r
+void\r
+tcp_pcb_purge(struct tcp_pcb *pcb)\r
+{\r
+  if (pcb->state != CLOSED &&\r
+     pcb->state != TIME_WAIT &&\r
+     pcb->state != LISTEN) {\r
+\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));\r
+    \r
+    if (pcb->unsent != NULL) {    \r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));\r
+    }\r
+    if (pcb->unacked != NULL) {    \r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));\r
+    }\r
+#if TCP_QUEUE_OOSEQ /* LW */\r
+    if (pcb->ooseq != NULL) {    \r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));\r
+    }\r
+    \r
+    tcp_segs_free(pcb->ooseq);\r
+    pcb->ooseq = NULL;\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+    tcp_segs_free(pcb->unsent);\r
+    tcp_segs_free(pcb->unacked);\r
+    pcb->unacked = pcb->unsent = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+ * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.\r
+ *\r
+ */\r
+void\r
+tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)\r
+{\r
+  TCP_RMV(pcblist, pcb);\r
+\r
+  tcp_pcb_purge(pcb);\r
+  \r
+  /* if there is an outstanding delayed ACKs, send it */\r
+  if (pcb->state != TIME_WAIT &&\r
+     pcb->state != LISTEN &&\r
+     pcb->flags & TF_ACK_DELAY) {\r
+    pcb->flags |= TF_ACK_NOW;\r
+    tcp_output(pcb);\r
+  }  \r
+  pcb->state = CLOSED;\r
+\r
+  LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());\r
+}\r
+\r
+/**\r
+ * Calculates a new initial sequence number for new connections.\r
+ *\r
+ */\r
+u32_t\r
+tcp_next_iss(void)\r
+{\r
+  static u32_t iss = 6510;\r
+  \r
+  iss += tcp_ticks;       /* XXX */\r
+  return iss;\r
+}\r
+\r
+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG\r
+void\r
+tcp_debug_print(struct tcp_hdr *tcphdr)\r
+{\r
+  LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",\r
+         ntohs(tcphdr->src), ntohs(tcphdr->dest)));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",\r
+          ntohl(tcphdr->seqno)));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",\r
+         ntohl(tcphdr->ackno)));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",\r
+       TCPH_HDRLEN(tcphdr),\r
+         TCPH_FLAGS(tcphdr) >> 5 & 1,\r
+         TCPH_FLAGS(tcphdr) >> 4 & 1,\r
+         TCPH_FLAGS(tcphdr) >> 3 & 1,\r
+         TCPH_FLAGS(tcphdr) >> 2 & 1,\r
+         TCPH_FLAGS(tcphdr) >> 1 & 1,\r
+         TCPH_FLAGS(tcphdr) & 1,\r
+         ntohs(tcphdr->wnd)));\r
+  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",\r
+         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+}\r
+\r
+void\r
+tcp_debug_print_state(enum tcp_state s)\r
+{\r
+  LWIP_DEBUGF(TCP_DEBUG, ("State: "));\r
+  switch (s) {\r
+  case CLOSED:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));\r
+    break;\r
+ case LISTEN:\r
+   LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));\r
+   break;\r
+  case SYN_SENT:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));\r
+    break;\r
+  case SYN_RCVD:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));\r
+    break;\r
+  case ESTABLISHED:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));\r
+    break;\r
+  case FIN_WAIT_1:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));\r
+    break;\r
+  case FIN_WAIT_2:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));\r
+    break;\r
+  case CLOSE_WAIT:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));\r
+    break;\r
+  case CLOSING:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));\r
+    break;\r
+  case LAST_ACK:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));\r
+    break;\r
+  case TIME_WAIT:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));\r
+   break;\r
+  }\r
+}\r
+\r
+void\r
+tcp_debug_print_flags(u8_t flags)\r
+{\r
+  if (flags & TCP_FIN) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("FIN "));\r
+  }\r
+  if (flags & TCP_SYN) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("SYN "));\r
+  }\r
+  if (flags & TCP_RST) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("RST "));\r
+  }\r
+  if (flags & TCP_PSH) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("PSH "));\r
+  }\r
+  if (flags & TCP_ACK) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("ACK "));\r
+  }\r
+  if (flags & TCP_URG) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("URG "));\r
+  }\r
+  if (flags & TCP_ECE) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("ECE "));\r
+  }\r
+  if (flags & TCP_CWR) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("CWR "));\r
+  }\r
+}\r
+\r
+void\r
+tcp_debug_print_pcbs(void)\r
+{\r
+  struct tcp_pcb *pcb;\r
+  LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
+                       pcb->local_port, pcb->remote_port,\r
+                       pcb->snd_nxt, pcb->rcv_nxt));\r
+    tcp_debug_print_state(pcb->state);\r
+  }    \r
+  LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));\r
+  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
+                       pcb->local_port, pcb->remote_port,\r
+                       pcb->snd_nxt, pcb->rcv_nxt));\r
+    tcp_debug_print_state(pcb->state);\r
+  }    \r
+  LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));\r
+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
+                       pcb->local_port, pcb->remote_port,\r
+                       pcb->snd_nxt, pcb->rcv_nxt));\r
+    tcp_debug_print_state(pcb->state);\r
+  }    \r
+}\r
+\r
+s16_t\r
+tcp_pcbs_sane(void)\r
+{\r
+  struct tcp_pcb *pcb;\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);\r
+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);\r
+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);\r
+  }\r
+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);\r
+  }\r
+  return 1;\r
+}\r
+#endif /* TCP_DEBUG */\r
+#endif /* LWIP_TCP */\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
index f6a3b870715a101e9f375520b8beba7864dcdce2..fc79ae332cc0878d1c9dbeb1da05aa5eb9777e1e 100644 (file)
-/**
- * @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 */
-
-
+/**\r
+ * @file\r
+ *\r
+ * Transmission Control Protocol, incoming traffic\r
+ *\r
+ * The input processing functions of the TCP layer.\r
+ *\r
+ * These functions are generally called in the order (ip_input() ->)\r
+ * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).\r
+ * \r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+\r
+#include "lwip/inet.h"\r
+#include "lwip/tcp.h"\r
+\r
+#include "lwip/stats.h"\r
+#include "arch/perf.h"\r
+#include "lwip/snmp.h"\r
+\r
+#if LWIP_TCP\r
+/* These variables are global to all functions involved in the input\r
+   processing of TCP segments. They are set by the tcp_input()\r
+   function. */\r
+static struct tcp_seg inseg;\r
+static struct tcp_hdr *tcphdr;\r
+static struct ip_hdr *iphdr;\r
+static u32_t seqno, ackno;\r
+static u8_t flags;\r
+static u16_t tcplen;\r
+\r
+static u8_t recv_flags;\r
+static struct pbuf *recv_data;\r
+\r
+struct tcp_pcb *tcp_input_pcb;\r
+\r
+/* Forward declarations. */\r
+static err_t tcp_process(struct tcp_pcb *pcb);\r
+static u8_t tcp_receive(struct tcp_pcb *pcb);\r
+static void tcp_parseopt(struct tcp_pcb *pcb);\r
+\r
+static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);\r
+static err_t tcp_timewait_input(struct tcp_pcb *pcb);\r
+\r
+/* tcp_input:\r
+ *\r
+ * The initial input processing of TCP. It verifies the TCP header, demultiplexes\r
+ * the segment between the PCBs and passes it on to tcp_process(), which implements\r
+ * the TCP finite state machine. This function is called by the IP layer (in\r
+ * ip_input()).\r
+ */\r
+\r
+void\r
+tcp_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct tcp_pcb *pcb, *prev;\r
+  struct tcp_pcb_listen *lpcb;\r
+  u8_t hdrlen;\r
+  err_t err;\r
+\r
+  PERF_START;\r
+\r
+  TCP_STATS_INC(tcp.recv);\r
+  snmp_inc_tcpinsegs();\r
+\r
+  iphdr = p->payload;\r
+  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);\r
+\r
+#if TCP_INPUT_DEBUG\r
+  tcp_debug_print(tcphdr);\r
+#endif\r
+\r
+  /* remove header from payload */\r
+  if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {\r
+    /* drop short packets */\r
+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));\r
+    TCP_STATS_INC(tcp.lenerr);\r
+    TCP_STATS_INC(tcp.drop);\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+  /* Don't even process incoming broadcasts/multicasts. */\r
+  if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||\r
+      ip_addr_ismulticast(&(iphdr->dest))) {\r
+    snmp_inc_tcpinerrs();\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+#if CHECKSUM_CHECK_TCP\r
+  /* Verify TCP checksum. */\r
+  if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),\r
+      (struct ip_addr *)&(iphdr->dest),\r
+      IP_PROTO_TCP, p->tot_len) != 0) {\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",\r
+        inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest),\r
+      IP_PROTO_TCP, p->tot_len)));\r
+#if TCP_DEBUG\r
+    tcp_debug_print(tcphdr);\r
+#endif /* TCP_DEBUG */\r
+    TCP_STATS_INC(tcp.chkerr);\r
+    TCP_STATS_INC(tcp.drop);\r
+    snmp_inc_tcpinerrs();\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+#endif\r
+\r
+  /* Move the payload pointer in the pbuf so that it points to the\r
+     TCP data instead of the TCP header. */\r
+  hdrlen = TCPH_HDRLEN(tcphdr);\r
+  pbuf_header(p, -(hdrlen * 4));\r
+\r
+  /* Convert fields in TCP header to host byte order. */\r
+  tcphdr->src = ntohs(tcphdr->src);\r
+  tcphdr->dest = ntohs(tcphdr->dest);\r
+  seqno = tcphdr->seqno = ntohl(tcphdr->seqno);\r
+  ackno = tcphdr->ackno = ntohl(tcphdr->ackno);\r
+  tcphdr->wnd = ntohs(tcphdr->wnd);\r
+\r
+  flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;\r
+  tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);\r
+\r
+  /* Demultiplex an incoming segment. First, we check if it is destined\r
+     for an active connection. */\r
+  prev = NULL;\r
+\r
+  \r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);\r
+    LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);\r
+    LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);\r
+    if (pcb->remote_port == tcphdr->src &&\r
+       pcb->local_port == tcphdr->dest &&\r
+       ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&\r
+       ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {\r
+\r
+      /* Move this PCB to the front of the list so that subsequent\r
+         lookups will be faster (we exploit locality in TCP segment\r
+         arrivals). */\r
+      LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);\r
+      if (prev != NULL) {\r
+        prev->next = pcb->next;\r
+        pcb->next = tcp_active_pcbs;\r
+        tcp_active_pcbs = pcb;\r
+      }\r
+      LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);\r
+      break;\r
+    }\r
+    prev = pcb;\r
+  }\r
+\r
+  if (pcb == NULL) {\r
+    /* If it did not go to an active connection, we check the connections\r
+       in the TIME-WAIT state. */\r
+    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+      LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);\r
+      if (pcb->remote_port == tcphdr->src &&\r
+         pcb->local_port == tcphdr->dest &&\r
+         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&\r
+         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {\r
+        /* We don't really care enough to move this PCB to the front\r
+           of the list since we are not very likely to receive that\r
+           many segments for connections in TIME-WAIT. */\r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));\r
+        tcp_timewait_input(pcb);\r
+        pbuf_free(p);\r
+        return;\r
+      }\r
+    }\r
+\r
+  /* Finally, if we still did not get a match, we check all PCBs that\r
+     are LISTENing for incoming connections. */\r
+    prev = NULL;\r
+    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {\r
+      if ((ip_addr_isany(&(lpcb->local_ip)) ||\r
+        ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&\r
+        lpcb->local_port == tcphdr->dest) {\r
+        /* Move this PCB to the front of the list so that subsequent\r
+           lookups will be faster (we exploit locality in TCP segment\r
+           arrivals). */\r
+        if (prev != NULL) {\r
+          ((struct tcp_pcb_listen *)prev)->next = lpcb->next;\r
+                /* our successor is the remainder of the listening list */\r
+          lpcb->next = tcp_listen_pcbs.listen_pcbs;\r
+                /* put this listening pcb at the head of the listening list */\r
+          tcp_listen_pcbs.listen_pcbs = lpcb;\r
+        }\r
+      \r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));\r
+        tcp_listen_input(lpcb);\r
+        pbuf_free(p);\r
+        return;\r
+      }\r
+      prev = (struct tcp_pcb *)lpcb;\r
+    }\r
+  }\r
+\r
+#if TCP_INPUT_DEBUG\r
+  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));\r
+  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));\r
+  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));\r
+#endif /* TCP_INPUT_DEBUG */\r
+\r
+\r
+  if (pcb != NULL) {\r
+    /* The incoming segment belongs to a connection. */\r
+#if TCP_INPUT_DEBUG\r
+#if TCP_DEBUG\r
+    tcp_debug_print_state(pcb->state);\r
+#endif /* TCP_DEBUG */\r
+#endif /* TCP_INPUT_DEBUG */\r
+\r
+    /* Set up a tcp_seg structure. */\r
+    inseg.next = NULL;\r
+    inseg.len = p->tot_len;\r
+    inseg.dataptr = p->payload;\r
+    inseg.p = p;\r
+    inseg.tcphdr = tcphdr;\r
+\r
+    recv_data = NULL;\r
+    recv_flags = 0;\r
+\r
+    tcp_input_pcb = pcb;\r
+    err = tcp_process(pcb);\r
+    tcp_input_pcb = NULL;\r
+    /* A return value of ERR_ABRT means that tcp_abort() was called\r
+       and that the pcb has been freed. If so, we don't do anything. */\r
+    if (err != ERR_ABRT) {\r
+      if (recv_flags & TF_RESET) {\r
+        /* TF_RESET means that the connection was reset by the other\r
+           end. We then call the error callback to inform the\r
+           application that the connection is dead before we\r
+           deallocate the PCB. */\r
+        TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);\r
+        tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
+        memp_free(MEMP_TCP_PCB, pcb);\r
+            } else if (recv_flags & TF_CLOSED) {\r
+        /* The connection has been closed and we will deallocate the\r
+           PCB. */\r
+        tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
+        memp_free(MEMP_TCP_PCB, pcb);\r
+            } else {\r
+        err = ERR_OK;\r
+        /* If the application has registered a "sent" function to be\r
+           called when new send buffer space is available, we call it\r
+           now. */\r
+        if (pcb->acked > 0) {\r
+          TCP_EVENT_SENT(pcb, pcb->acked, err);\r
+        }\r
+      \r
+        if (recv_data != NULL) {\r
+          /* Notify application that data has been received. */\r
+          TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);\r
+        }\r
+      \r
+        /* If a FIN segment was received, we call the callback\r
+           function with a NULL buffer to indicate EOF. */\r
+        if (recv_flags & TF_GOT_FIN) {\r
+          TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);\r
+        }\r
+        /* If there were no errors, we try to send something out. */\r
+        if (err == ERR_OK) {\r
+          tcp_output(pcb);\r
+        }\r
+      }\r
+    }\r
+\r
+\r
+    /* give up our reference to inseg.p */\r
+    if (inseg.p != NULL)\r
+    {\r
+      pbuf_free(inseg.p);\r
+      inseg.p = NULL;\r
+    }\r
+#if TCP_INPUT_DEBUG\r
+#if TCP_DEBUG\r
+    tcp_debug_print_state(pcb->state);\r
+#endif /* TCP_DEBUG */\r
+#endif /* TCP_INPUT_DEBUG */\r
+      \r
+  } else {\r
+\r
+    /* If no matching PCB was found, send a TCP RST (reset) to the\r
+       sender. */\r
+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));\r
+    if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {\r
+      TCP_STATS_INC(tcp.proterr);\r
+      TCP_STATS_INC(tcp.drop);\r
+      tcp_rst(ackno, seqno + tcplen,\r
+        &(iphdr->dest), &(iphdr->src),\r
+        tcphdr->dest, tcphdr->src);\r
+    }\r
+    pbuf_free(p);\r
+  }\r
+\r
+  LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());\r
+  PERF_STOP("tcp_input");\r
+}\r
+\r
+/* tcp_listen_input():\r
+ *\r
+ * Called by tcp_input() when a segment arrives for a listening\r
+ * connection.\r
+ */\r
+\r
+static err_t\r
+tcp_listen_input(struct tcp_pcb_listen *pcb)\r
+{\r
+  struct tcp_pcb *npcb;\r
+  u32_t optdata;\r
+\r
+  /* In the LISTEN state, we check for incoming SYN segments,\r
+     creates a new PCB, and responds with a SYN|ACK. */\r
+  if (flags & TCP_ACK) {\r
+    /* For incoming segments with the ACK flag set, respond with a\r
+       RST. */\r
+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));\r
+    tcp_rst(ackno + 1, seqno + tcplen,\r
+      &(iphdr->dest), &(iphdr->src),\r
+      tcphdr->dest, tcphdr->src);\r
+  } else if (flags & TCP_SYN) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));\r
+    npcb = tcp_alloc(pcb->prio);\r
+    /* If a new PCB could not be created (probably due to lack of memory),\r
+       we don't do anything, but rely on the sender will retransmit the\r
+       SYN at a time when we have more memory available. */\r
+    if (npcb == NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));\r
+      TCP_STATS_INC(tcp.memerr);\r
+      return ERR_MEM;\r
+    }\r
+    /* Set up the new PCB. */\r
+    ip_addr_set(&(npcb->local_ip), &(iphdr->dest));\r
+    npcb->local_port = pcb->local_port;\r
+    ip_addr_set(&(npcb->remote_ip), &(iphdr->src));\r
+    npcb->remote_port = tcphdr->src;\r
+    npcb->state = SYN_RCVD;\r
+    npcb->rcv_nxt = seqno + 1;\r
+    npcb->snd_wnd = tcphdr->wnd;\r
+    npcb->ssthresh = npcb->snd_wnd;\r
+    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */\r
+    npcb->callback_arg = pcb->callback_arg;\r
+#if LWIP_CALLBACK_API\r
+    npcb->accept = pcb->accept;\r
+#endif /* LWIP_CALLBACK_API */\r
+    /* inherit socket options */\r
+    npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);\r
+    /* Register the new PCB so that we can begin receiving segments\r
+       for it. */\r
+    TCP_REG(&tcp_active_pcbs, npcb);\r
+\r
+    /* Parse any options in the SYN. */\r
+    tcp_parseopt(npcb);\r
+\r
+    snmp_inc_tcppassiveopens();\r
+\r
+    /* Build an MSS option. */\r
+    optdata = htonl(((u32_t)2 << 24) |\r
+        ((u32_t)4 << 16) |\r
+        (((u32_t)npcb->mss / 256) << 8) |\r
+        (npcb->mss & 255));\r
+    /* Send a SYN|ACK together with the MSS option. */\r
+    tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4);\r
+    return tcp_output(npcb);\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+/* tcp_timewait_input():\r
+ *\r
+ * Called by tcp_input() when a segment arrives for a connection in\r
+ * TIME_WAIT.\r
+ */\r
+\r
+static err_t\r
+tcp_timewait_input(struct tcp_pcb *pcb)\r
+{\r
+  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {\r
+    pcb->rcv_nxt = seqno + tcplen;\r
+  }\r
+  if (tcplen > 0) {\r
+    tcp_ack_now(pcb);\r
+  }\r
+  return tcp_output(pcb);\r
+}\r
+\r
+/* tcp_process\r
+ *\r
+ * Implements the TCP state machine. Called by tcp_input. In some\r
+ * states tcp_receive() is called to receive data. The tcp_seg\r
+ * argument will be freed by the caller (tcp_input()) unless the\r
+ * recv_data pointer in the pcb is set.\r
+ */\r
+\r
+static err_t\r
+tcp_process(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_seg *rseg;\r
+  u8_t acceptable = 0;\r
+  err_t err;\r
+  u8_t accepted_inseq;\r
+\r
+  err = ERR_OK;\r
+\r
+  /* Process incoming RST segments. */\r
+  if (flags & TCP_RST) {\r
+    /* First, determine if the reset is acceptable. */\r
+    if (pcb->state == SYN_SENT) {\r
+      if (ackno == pcb->snd_nxt) {\r
+        acceptable = 1;\r
+      }\r
+    } else {\r
+      /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&\r
+          TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {\r
+      */\r
+      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {\r
+        acceptable = 1;\r
+      }\r
+    }\r
+\r
+    if (acceptable) {\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));\r
+      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);\r
+      recv_flags = TF_RESET;\r
+      pcb->flags &= ~TF_ACK_DELAY;\r
+      return ERR_RST;\r
+    } else {\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",\r
+       seqno, pcb->rcv_nxt));\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",\r
+       seqno, pcb->rcv_nxt));\r
+      return ERR_OK;\r
+    }\r
+  }\r
+\r
+  /* Update the PCB (in)activity timer. */\r
+  pcb->tmr = tcp_ticks;\r
+  pcb->keep_cnt = 0;\r
+\r
+  /* Do different things depending on the TCP state. */\r
+  switch (pcb->state) {\r
+  case SYN_SENT:\r
+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,\r
+     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));\r
+    /* received SYN ACK with expected sequence number? */\r
+    if ((flags & TCP_ACK) && (flags & TCP_SYN)\r
+        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {\r
+      pcb->snd_buf++;\r
+      pcb->rcv_nxt = seqno + 1;\r
+      pcb->lastack = ackno;\r
+      pcb->snd_wnd = tcphdr->wnd;\r
+      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */\r
+      pcb->state = ESTABLISHED;\r
+      pcb->cwnd = pcb->mss;\r
+      --pcb->snd_queuelen;\r
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));\r
+      rseg = pcb->unacked;\r
+      pcb->unacked = rseg->next;\r
+      tcp_seg_free(rseg);\r
+\r
+      /* Parse any options in the SYNACK. */\r
+      tcp_parseopt(pcb);\r
+\r
+      /* Call the user specified function to call when sucessfully\r
+       * connected. */\r
+      TCP_EVENT_CONNECTED(pcb, ERR_OK, err);\r
+      tcp_ack(pcb);\r
+    }\r
+    /* received ACK? possibly a half-open connection */\r
+    else if (flags & TCP_ACK) {\r
+      /* send a RST to bring the other side in a non-synchronized state. */\r
+      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),\r
+        tcphdr->dest, tcphdr->src);\r
+    }\r
+    break;\r
+  case SYN_RCVD:\r
+    if (flags & TCP_ACK &&\r
+       !(flags & TCP_RST)) {\r
+      /* expected ACK number? */\r
+      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {\r
+        pcb->state = ESTABLISHED;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+#if LWIP_CALLBACK_API\r
+        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);\r
+#endif\r
+        /* Call the accept function. */\r
+        TCP_EVENT_ACCEPT(pcb, ERR_OK, err);\r
+        if (err != ERR_OK) {\r
+          /* If the accept function returns with an error, we abort\r
+           * the connection. */\r
+          tcp_abort(pcb);\r
+          return ERR_ABRT;\r
+        }\r
+        /* If there was any data contained within this ACK,\r
+         * we'd better pass it on to the application as well. */\r
+        tcp_receive(pcb);\r
+        pcb->cwnd = pcb->mss;\r
+      }\r
+      /* incorrect ACK number */\r
+      else {\r
+        /* send RST */\r
+        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),\r
+          tcphdr->dest, tcphdr->src);\r
+      }\r
+    }\r
+    break;\r
+  case CLOSE_WAIT:\r
+    /* FALLTHROUGH */\r
+  case ESTABLISHED:\r
+    accepted_inseq = tcp_receive(pcb);\r
+    if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */\r
+      tcp_ack_now(pcb);\r
+      pcb->state = CLOSE_WAIT;\r
+    }\r
+    break;\r
+  case FIN_WAIT_1:\r
+    tcp_receive(pcb);\r
+    if (flags & TCP_FIN) {\r
+      if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
+        LWIP_DEBUGF(TCP_DEBUG,\r
+          ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+        tcp_ack_now(pcb);\r
+        tcp_pcb_purge(pcb);\r
+        TCP_RMV(&tcp_active_pcbs, pcb);\r
+        pcb->state = TIME_WAIT;\r
+        TCP_REG(&tcp_tw_pcbs, pcb);\r
+      } else {\r
+        tcp_ack_now(pcb);\r
+        pcb->state = CLOSING;\r
+      }\r
+    } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
+      pcb->state = FIN_WAIT_2;\r
+    }\r
+    break;\r
+  case FIN_WAIT_2:\r
+    tcp_receive(pcb);\r
+    if (flags & TCP_FIN) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+      tcp_ack_now(pcb);\r
+      tcp_pcb_purge(pcb);\r
+      TCP_RMV(&tcp_active_pcbs, pcb);\r
+      pcb->state = TIME_WAIT;\r
+      TCP_REG(&tcp_tw_pcbs, pcb);\r
+    }\r
+    break;\r
+  case CLOSING:\r
+    tcp_receive(pcb);\r
+    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+      tcp_ack_now(pcb);\r
+      tcp_pcb_purge(pcb);\r
+      TCP_RMV(&tcp_active_pcbs, pcb);\r
+      pcb->state = TIME_WAIT;\r
+      TCP_REG(&tcp_tw_pcbs, pcb);\r
+    }\r
+    break;\r
+  case LAST_ACK:\r
+    tcp_receive(pcb);\r
+    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+      pcb->state = CLOSED;\r
+      recv_flags = TF_CLOSED;\r
+    }\r
+    break;\r
+  default:\r
+    break;\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+/* tcp_receive:\r
+ *\r
+ * Called by tcp_process. Checks if the given segment is an ACK for outstanding\r
+ * data, and if so frees the memory of the buffered data. Next, is places the\r
+ * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment\r
+ * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until\r
+ * i it has been removed from the buffer.\r
+ *\r
+ * If the incoming segment constitutes an ACK for a segment that was used for RTT\r
+ * estimation, the RTT is estimated here as well.\r
+ *\r
+ * @return 1 if \r
+ */\r
+\r
+static u8_t\r
+tcp_receive(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_seg *next;\r
+#if TCP_QUEUE_OOSEQ\r
+  struct tcp_seg *prev, *cseg;\r
+#endif\r
+  struct pbuf *p;\r
+  s32_t off;\r
+  s16_t m;\r
+  u32_t right_wnd_edge;\r
+  u16_t new_tot_len;\r
+  u8_t accepted_inseq = 0;\r
+\r
+  if (flags & TCP_ACK) {\r
+    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;\r
+\r
+    /* Update window. */\r
+    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||\r
+       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||\r
+       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {\r
+      pcb->snd_wnd = tcphdr->wnd;\r
+      pcb->snd_wl1 = seqno;\r
+      pcb->snd_wl2 = ackno;\r
+      LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U32_F"\n", pcb->snd_wnd));\r
+#if TCP_WND_DEBUG\r
+    } else {\r
+      if (pcb->snd_wnd != tcphdr->wnd) {\r
+        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",\r
+                               pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));\r
+      }\r
+#endif /* TCP_WND_DEBUG */\r
+    }\r
+\r
+    if (pcb->lastack == ackno) {\r
+      pcb->acked = 0;\r
+\r
+      if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){\r
+        ++pcb->dupacks;\r
+        if (pcb->dupacks >= 3 && pcb->unacked != NULL) {\r
+          if (!(pcb->flags & TF_INFR)) {\r
+            /* This is fast retransmit. Retransmit the first unacked segment. */\r
+            LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n",\r
+                                       (u16_t)pcb->dupacks, pcb->lastack,\r
+                                       ntohl(pcb->unacked->tcphdr->seqno)));\r
+            tcp_rexmit(pcb);\r
+            /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */\r
+            /*pcb->ssthresh = LWIP_MAX((pcb->snd_max -\r
+                                      pcb->lastack) / 2,\r
+                                      2 * pcb->mss);*/\r
+            /* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */\r
+            if (pcb->cwnd > pcb->snd_wnd)\r
+              pcb->ssthresh = pcb->snd_wnd / 2;\r
+            else\r
+              pcb->ssthresh = pcb->cwnd / 2;\r
+\r
+            pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;\r
+            pcb->flags |= TF_INFR;\r
+          } else {\r
+            /* Inflate the congestion window, but not if it means that\r
+               the value overflows. */\r
+            if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {\r
+              pcb->cwnd += pcb->mss;\r
+            }\r
+          }\r
+        }\r
+      } else {\r
+        LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",\r
+                                   pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));\r
+      }\r
+    } else\r
+      /*if (TCP_SEQ_LT(pcb->lastack, ackno) &&\r
+        TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */\r
+      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){\r
+      /* We come here when the ACK acknowledges new data. */\r
+      \r
+      /* Reset the "IN Fast Retransmit" flag, since we are no longer\r
+         in fast retransmit. Also reset the congestion window to the\r
+         slow start threshold. */\r
+      if (pcb->flags & TF_INFR) {\r
+        pcb->flags &= ~TF_INFR;\r
+        pcb->cwnd = pcb->ssthresh;\r
+      }\r
+\r
+      /* Reset the number of retransmissions. */\r
+      pcb->nrtx = 0;\r
+\r
+      /* Reset the retransmission time-out. */\r
+      pcb->rto = (pcb->sa >> 3) + pcb->sv;\r
+\r
+      /* Update the send buffer space. */\r
+      pcb->acked = ackno - pcb->lastack;\r
+\r
+      pcb->snd_buf += pcb->acked;\r
+\r
+      /* Reset the fast retransmit variables. */\r
+      pcb->dupacks = 0;\r
+      pcb->lastack = ackno;\r
+\r
+      /* Update the congestion control variables (cwnd and\r
+         ssthresh). */\r
+      if (pcb->state >= ESTABLISHED) {\r
+        if (pcb->cwnd < pcb->ssthresh) {\r
+          if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {\r
+            pcb->cwnd += pcb->mss;\r
+          }\r
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));\r
+        } else {\r
+          u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);\r
+          if (new_cwnd > pcb->cwnd) {\r
+            pcb->cwnd = new_cwnd;\r
+          }\r
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));\r
+        }\r
+      }\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",\r
+                                    ackno,\r
+                                    pcb->unacked != NULL?\r
+                                    ntohl(pcb->unacked->tcphdr->seqno): 0,\r
+                                    pcb->unacked != NULL?\r
+                                    ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));\r
+\r
+      /* Remove segment from the unacknowledged list if the incoming\r
+         ACK acknowlegdes them. */\r
+      while (pcb->unacked != NULL &&\r
+             TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +\r
+                         TCP_TCPLEN(pcb->unacked), ackno)) {\r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",\r
+                                      ntohl(pcb->unacked->tcphdr->seqno),\r
+                                      ntohl(pcb->unacked->tcphdr->seqno) +\r
+                                      TCP_TCPLEN(pcb->unacked)));\r
+\r
+        next = pcb->unacked;\r
+        pcb->unacked = pcb->unacked->next;\r
+\r
+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));\r
+        pcb->snd_queuelen -= pbuf_clen(next->p);\r
+        tcp_seg_free(next);\r
+\r
+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));\r
+        if (pcb->snd_queuelen != 0) {\r
+          LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||\r
+                      pcb->unsent != NULL);\r
+        }\r
+      }\r
+      pcb->polltmr = 0;\r
+    }\r
+\r
+    /* We go through the ->unsent list to see if any of the segments\r
+       on the list are acknowledged by the ACK. This may seem\r
+       strange since an "unsent" segment shouldn't be acked. The\r
+       rationale is that lwIP puts all outstanding segments on the\r
+       ->unsent list after a retransmission, so these segments may\r
+       in fact have been sent once. */\r
+    while (pcb->unsent != NULL &&\r
+           /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&\r
+             TCP_SEQ_LEQ(ackno, pcb->snd_max)*/\r
+           TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)\r
+           ) {\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",\r
+                                    ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +\r
+                                    TCP_TCPLEN(pcb->unsent)));\r
+\r
+      next = pcb->unsent;\r
+      pcb->unsent = pcb->unsent->next;\r
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));\r
+      pcb->snd_queuelen -= pbuf_clen(next->p);\r
+      tcp_seg_free(next);\r
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));\r
+      if (pcb->snd_queuelen != 0) {\r
+        LWIP_ASSERT("tcp_receive: valid queue length",\r
+          pcb->unacked != NULL || pcb->unsent != NULL);\r
+      }\r
+\r
+      if (pcb->unsent != NULL) {\r
+        pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);\r
+      }\r
+    }\r
+    /* End of ACK for new data processing. */\r
+\r
+    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",\r
+                                pcb->rttest, pcb->rtseq, ackno));\r
+\r
+    /* RTT estimation calculations. This is done by checking if the\r
+       incoming segment acknowledges the segment we use to take a\r
+       round-trip time measurement. */\r
+    if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {\r
+      m = tcp_ticks - pcb->rttest;\r
+\r
+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",\r
+                                  m, m * TCP_SLOW_INTERVAL));\r
+\r
+      /* This is taken directly from VJs original code in his paper */\r
+      m = m - (pcb->sa >> 3);\r
+      pcb->sa += m;\r
+      if (m < 0) {\r
+        m = -m;\r
+      }\r
+      m = m - (pcb->sv >> 2);\r
+      pcb->sv += m;\r
+      pcb->rto = (pcb->sa >> 3) + pcb->sv;\r
+\r
+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" miliseconds)\n",\r
+                                  pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));\r
+\r
+      pcb->rttest = 0;\r
+    }\r
+  }\r
+\r
+  /* If the incoming segment contains data, we must process it\r
+     further. */\r
+  if (tcplen > 0) {\r
+    /* This code basically does three things:\r
+\r
+    +) If the incoming segment contains data that is the next\r
+    in-sequence data, this data is passed to the application. This\r
+    might involve trimming the first edge of the data. The rcv_nxt\r
+    variable and the advertised window are adjusted.\r
+\r
+    +) If the incoming segment has data that is above the next\r
+    sequence number expected (->rcv_nxt), the segment is placed on\r
+    the ->ooseq queue. This is done by finding the appropriate\r
+    place in the ->ooseq queue (which is ordered by sequence\r
+    number) and trim the segment in both ends if needed. An\r
+    immediate ACK is sent to indicate that we received an\r
+    out-of-sequence segment.\r
+\r
+    +) Finally, we check if the first segment on the ->ooseq queue\r
+    now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If\r
+    rcv_nxt > ooseq->seqno, we must trim the first edge of the\r
+    segment on ->ooseq before we adjust rcv_nxt. The data in the\r
+    segments that are now on sequence are chained onto the\r
+    incoming segment so that we only need to call the application\r
+    once.\r
+    */\r
+\r
+    /* First, we check if we must trim the first edge. We have to do\r
+       this if the sequence number of the incoming segment is less\r
+       than rcv_nxt, and the sequence number plus the length of the\r
+       segment is larger than rcv_nxt. */\r
+    /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){\r
+          if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/\r
+    if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){\r
+      /* Trimming the first edge is done by pushing the payload\r
+         pointer in the pbuf downwards. This is somewhat tricky since\r
+         we do not want to discard the full contents of the pbuf up to\r
+         the new starting point of the data since we have to keep the\r
+         TCP header which is present in the first pbuf in the chain.\r
+         \r
+         What is done is really quite a nasty hack: the first pbuf in\r
+         the pbuf chain is pointed to by inseg.p. Since we need to be\r
+         able to deallocate the whole pbuf, we cannot change this\r
+         inseg.p pointer to point to any of the later pbufs in the\r
+         chain. Instead, we point the ->payload pointer in the first\r
+         pbuf to data in one of the later pbufs. We also set the\r
+         inseg.data pointer to point to the right place. This way, the\r
+         ->p pointer will still point to the first pbuf, but the\r
+         ->p->payload pointer will point to data in another pbuf.\r
+         \r
+         After we are done with adjusting the pbuf pointers we must\r
+         adjust the ->data pointer in the seg and the segment\r
+         length.*/\r
+      \r
+      off = pcb->rcv_nxt - seqno;\r
+      p = inseg.p;\r
+      LWIP_ASSERT("inseg.p != NULL", inseg.p);\r
+      if (inseg.p->len < off) {\r
+        new_tot_len = inseg.p->tot_len - off;\r
+        while (p->len < off) {\r
+          off -= p->len;\r
+          /* KJM following line changed (with addition of new_tot_len var)\r
+             to fix bug #9076\r
+             inseg.p->tot_len -= p->len; */\r
+          p->tot_len = new_tot_len;\r
+          p->len = 0;\r
+          p = p->next;\r
+        }\r
+        pbuf_header(p, -off);\r
+      } else {\r
+        pbuf_header(inseg.p, -off);\r
+      }\r
+      /* KJM following line changed to use p->payload rather than inseg->p->payload\r
+         to fix bug #9076 */\r
+      inseg.dataptr = p->payload;\r
+      inseg.len -= pcb->rcv_nxt - seqno;\r
+      inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;\r
+    }\r
+    else {\r
+      if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){\r
+        /* the whole segment is < rcv_nxt */\r
+        /* must be a duplicate of a packet that has already been correctly handled */\r
+        \r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));\r
+        tcp_ack_now(pcb);\r
+      }\r
+    }\r
+\r
+    /* The sequence number must be within the window (above rcv_nxt\r
+       and below rcv_nxt + rcv_wnd) in order to be further\r
+       processed. */\r
+    /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&\r
+      TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/\r
+    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){\r
+      if (pcb->rcv_nxt == seqno) {\r
+        accepted_inseq = 1; \r
+        /* The incoming segment is the next in sequence. We check if\r
+           we have to trim the end of the segment and update rcv_nxt\r
+           and pass the data to the application. */\r
+#if TCP_QUEUE_OOSEQ\r
+        if (pcb->ooseq != NULL &&\r
+            TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {\r
+          /* We have to trim the second edge of the incoming\r
+             segment. */\r
+          inseg.len = pcb->ooseq->tcphdr->seqno - seqno;\r
+          pbuf_realloc(inseg.p, inseg.len);\r
+        }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+        tcplen = TCP_TCPLEN(&inseg);\r
+\r
+        /* First received FIN will be ACKed +1, on any successive (duplicate)\r
+         * FINs we are already in CLOSE_WAIT and have already done +1.\r
+         */\r
+        if (pcb->state != CLOSE_WAIT) {\r
+          pcb->rcv_nxt += tcplen;\r
+        }\r
+\r
+        /* Update the receiver's (our) window. */\r
+        if (pcb->rcv_wnd < tcplen) {\r
+          pcb->rcv_wnd = 0;\r
+        } else {\r
+          pcb->rcv_wnd -= tcplen;\r
+        }\r
+\r
+        /* If there is data in the segment, we make preparations to\r
+           pass this up to the application. The ->recv_data variable\r
+           is used for holding the pbuf that goes to the\r
+           application. The code for reassembling out-of-sequence data\r
+           chains its data on this pbuf as well.\r
+\r
+           If the segment was a FIN, we set the TF_GOT_FIN flag that will\r
+           be used to indicate to the application that the remote side has\r
+           closed its end of the connection. */\r
+        if (inseg.p->tot_len > 0) {\r
+          recv_data = inseg.p;\r
+          /* Since this pbuf now is the responsibility of the\r
+             application, we delete our reference to it so that we won't\r
+             (mistakingly) deallocate it. */\r
+          inseg.p = NULL;\r
+        }\r
+        if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {\r
+          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));\r
+          recv_flags = TF_GOT_FIN;\r
+        }\r
+\r
+#if TCP_QUEUE_OOSEQ\r
+        /* We now check if we have segments on the ->ooseq queue that\r
+           is now in sequence. */\r
+        while (pcb->ooseq != NULL &&\r
+               pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {\r
+\r
+          cseg = pcb->ooseq;\r
+          seqno = pcb->ooseq->tcphdr->seqno;\r
+\r
+          pcb->rcv_nxt += TCP_TCPLEN(cseg);\r
+          if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {\r
+            pcb->rcv_wnd = 0;\r
+          } else {\r
+            pcb->rcv_wnd -= TCP_TCPLEN(cseg);\r
+          }\r
+          if (cseg->p->tot_len > 0) {\r
+            /* Chain this pbuf onto the pbuf that we will pass to\r
+               the application. */\r
+            if (recv_data) {\r
+              pbuf_cat(recv_data, cseg->p);\r
+            } else {\r
+              recv_data = cseg->p;\r
+            }\r
+            cseg->p = NULL;\r
+          }\r
+          if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {\r
+            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));\r
+            recv_flags = TF_GOT_FIN;\r
+            if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */\r
+              pcb->state = CLOSE_WAIT;\r
+            } \r
+          }\r
+\r
+\r
+          pcb->ooseq = cseg->next;\r
+          tcp_seg_free(cseg);\r
+        }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+\r
+        /* Acknowledge the segment(s). */\r
+        tcp_ack(pcb);\r
+\r
+      } else {\r
+        /* We get here if the incoming segment is out-of-sequence. */\r
+        tcp_ack_now(pcb);\r
+#if TCP_QUEUE_OOSEQ\r
+        /* We queue the segment on the ->ooseq queue. */\r
+        if (pcb->ooseq == NULL) {\r
+          pcb->ooseq = tcp_seg_copy(&inseg);\r
+        } else {\r
+          /* If the queue is not empty, we walk through the queue and\r
+             try to find a place where the sequence number of the\r
+             incoming segment is between the sequence numbers of the\r
+             previous and the next segment on the ->ooseq queue. That is\r
+             the place where we put the incoming segment. If needed, we\r
+             trim the second edges of the previous and the incoming\r
+             segment so that it will fit into the sequence.\r
+\r
+             If the incoming segment has the same sequence number as a\r
+             segment on the ->ooseq queue, we discard the segment that\r
+             contains less data. */\r
+\r
+          prev = NULL;\r
+          for(next = pcb->ooseq; next != NULL; next = next->next) {\r
+            if (seqno == next->tcphdr->seqno) {\r
+              /* The sequence number of the incoming segment is the\r
+                 same as the sequence number of the segment on\r
+                 ->ooseq. We check the lengths to see which one to\r
+                 discard. */\r
+              if (inseg.len > next->len) {\r
+                /* The incoming segment is larger than the old\r
+                   segment. We replace the old segment with the new\r
+                   one. */\r
+                cseg = tcp_seg_copy(&inseg);\r
+                if (cseg != NULL) {\r
+                  cseg->next = next->next;\r
+                  if (prev != NULL) {\r
+                    prev->next = cseg;\r
+                  } else {\r
+                    pcb->ooseq = cseg;\r
+                  }\r
+                }\r
+                break;\r
+              } else {\r
+                /* Either the lenghts are the same or the incoming\r
+                   segment was smaller than the old one; in either\r
+                   case, we ditch the incoming segment. */\r
+                break;\r
+              }\r
+            } else {\r
+              if (prev == NULL) {\r
+                if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {\r
+                  /* The sequence number of the incoming segment is lower\r
+                     than the sequence number of the first segment on the\r
+                     queue. We put the incoming segment first on the\r
+                     queue. */\r
+\r
+                  if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {\r
+                    /* We need to trim the incoming segment. */\r
+                    inseg.len = next->tcphdr->seqno - seqno;\r
+                    pbuf_realloc(inseg.p, inseg.len);\r
+                  }\r
+                  cseg = tcp_seg_copy(&inseg);\r
+                  if (cseg != NULL) {\r
+                    cseg->next = next;\r
+                    pcb->ooseq = cseg;\r
+                  }\r
+                  break;\r
+                }\r
+              } else \r
+                /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&\r
+                  TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/\r
+                if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){\r
+                /* The sequence number of the incoming segment is in\r
+                   between the sequence numbers of the previous and\r
+                   the next segment on ->ooseq. We trim and insert the\r
+                   incoming segment and trim the previous segment, if\r
+                   needed. */\r
+                if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {\r
+                  /* We need to trim the incoming segment. */\r
+                  inseg.len = next->tcphdr->seqno - seqno;\r
+                  pbuf_realloc(inseg.p, inseg.len);\r
+                }\r
+\r
+                cseg = tcp_seg_copy(&inseg);\r
+                if (cseg != NULL) {\r
+                  cseg->next = next;\r
+                  prev->next = cseg;\r
+                  if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {\r
+                    /* We need to trim the prev segment. */\r
+                    prev->len = seqno - prev->tcphdr->seqno;\r
+                    pbuf_realloc(prev->p, prev->len);\r
+                  }\r
+                }\r
+                break;\r
+              }\r
+              /* If the "next" segment is the last segment on the\r
+                 ooseq queue, we add the incoming segment to the end\r
+                 of the list. */\r
+              if (next->next == NULL &&\r
+                  TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {\r
+                next->next = tcp_seg_copy(&inseg);\r
+                if (next->next != NULL) {\r
+                  if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {\r
+                    /* We need to trim the last segment. */\r
+                    next->len = seqno - next->tcphdr->seqno;\r
+                    pbuf_realloc(next->p, next->len);\r
+                  }\r
+                }\r
+                break;\r
+              }\r
+            }\r
+            prev = next;\r
+          }\r
+        }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+      }\r
+    } else {\r
+      /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||\r
+        TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/\r
+      if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){\r
+        tcp_ack_now(pcb);\r
+      }\r
+    }\r
+  } else {\r
+    /* Segments with length 0 is taken care of here. Segments that\r
+       fall out of the window are ACKed. */\r
+    /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||\r
+      TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/\r
+    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){\r
+      tcp_ack_now(pcb);\r
+    }\r
+  }\r
+  return accepted_inseq;\r
+}\r
+\r
+/*\r
+ * tcp_parseopt:\r
+ *\r
+ * Parses the options contained in the incoming segment. (Code taken\r
+ * from uIP with only small changes.)\r
+ *\r
+ */\r
+\r
+static void\r
+tcp_parseopt(struct tcp_pcb *pcb)\r
+{\r
+  u8_t c;\r
+  u8_t *opts, opt;\r
+  u16_t mss;\r
+\r
+  opts = (u8_t *)tcphdr + TCP_HLEN;\r
+\r
+  /* Parse the TCP MSS option, if present. */\r
+  if(TCPH_HDRLEN(tcphdr) > 0x5) {\r
+    for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) {\r
+      opt = opts[c];\r
+      if (opt == 0x00) {\r
+        /* End of options. */\r
+  break;\r
+      } else if (opt == 0x01) {\r
+        ++c;\r
+        /* NOP option. */\r
+      } else if (opt == 0x02 &&\r
+        opts[c + 1] == 0x04) {\r
+        /* An MSS option with the right option length. */\r
+        mss = (opts[c + 2] << 8) | opts[c + 3];\r
+        pcb->mss = mss > TCP_MSS? TCP_MSS: mss;\r
+\r
+        /* And we are done processing options. */\r
+        break;\r
+      } else {\r
+  if (opts[c + 1] == 0) {\r
+          /* If the length field is zero, the options are malformed\r
+             and we don't process them further. */\r
+          break;\r
+        }\r
+        /* All other options have a length field, so that we easily\r
+           can skip past them. */\r
+        c += opts[c + 1];\r
+      }\r
+    }\r
+  }\r
+}\r
+#endif /* LWIP_TCP */\r
+\r
+\r
index b268201b5a6429f92488b7336e422183248c0e59..8802fea0e9e2a3b29325e767d5a1e4373ece9b61 100644 (file)
-/**
- * @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) {
+/**\r
+ * @file\r
+ *\r
+ * Transmission Control Protocol, outgoing traffic\r
+ *\r
+ * The output functions of TCP.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/opt.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+\r
+#if LWIP_TCP\r
+\r
+/* Forward declarations.*/\r
+static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);\r
+\r
+err_t\r
+tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)\r
+{\r
+  /* no data, no length, flags, copy=1, no optdata, no optdatalen */\r
+  return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);\r
+}\r
+\r
+/**\r
+ * Write data for sending (but does not send it immediately).\r
+ *\r
+ * It waits in the expectation of more data being sent soon (as\r
+ * it can send them more efficiently by combining them together).\r
+ * To prompt the system to send data now, call tcp_output() after\r
+ * calling tcp_write().\r
+ * \r
+ * @arg pcb Protocol control block of the TCP connection to enqueue data for. \r
+ * \r
+ * @see tcp_write()\r
+ */\r
+\r
+err_t\r
+tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)\r
+{\r
+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%"U16_F", copy=%"U16_F")\n", (void *)pcb,\r
+    arg, len, (u16_t)copy));\r
+  /* connection is in valid state for data transmission? */\r
+  if (pcb->state == ESTABLISHED ||\r
+     pcb->state == CLOSE_WAIT ||\r
+     pcb->state == SYN_SENT ||\r
+     pcb->state == SYN_RCVD) {\r
+    if (len > 0) {\r
+      return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);\r
+    }\r
+    return ERR_OK;\r
+  } else {\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n"));\r
+    return ERR_CONN;\r
+  }\r
+}\r
+\r
+/**\r
+ * Enqueue either data or TCP options (but not both) for tranmission\r
+ * \r
+ * \r
+ * \r
+ * @arg pcb Protocol control block for the TCP connection to enqueue data for.\r
+ * @arg arg Pointer to the data to be enqueued for sending.\r
+ * @arg len Data length in bytes\r
+ * @arg flags\r
+ * @arg copy 1 if data must be copied, 0 if data is non-volatile and can be\r
+ * referenced.\r
+ * @arg optdata\r
+ * @arg optlen\r
+ */\r
+err_t\r
+tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,\r
+  u8_t flags, u8_t copy,\r
+  u8_t *optdata, u8_t optlen)\r
+{\r
+  struct pbuf *p;\r
+  struct tcp_seg *seg, *useg, *queue;\r
+  u32_t left, seqno;\r
+  u16_t seglen;\r
+  void *ptr;\r
+  u8_t queuelen;\r
+\r
+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", copy=%"U16_F")\n",\r
+    (void *)pcb, arg, len, (u16_t)flags, (u16_t)copy));\r
+  LWIP_ASSERT("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",\r
+      len == 0 || optlen == 0);\r
+  LWIP_ASSERT("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",\r
+      arg == NULL || optdata == NULL);\r
+  /* fail on too much data */\r
+  if (len > pcb->snd_buf) {\r
     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) {
+    return ERR_MEM;\r
+  }\r
+  left = len;\r
+  ptr = arg;\r
+\r
+  /* seqno will be the sequence number of the first segment enqueued\r
+   * by the call to this function. */\r
+  seqno = pcb->snd_lbb;\r
+\r
+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));\r
+\r
+  /* If total number of pbufs on the unsent/unacked queues exceeds the\r
+   * configured maximum, return an error */\r
+  queuelen = pcb->snd_queuelen;\r
+  if (queuelen >= TCP_SND_QUEUELEN) {\r
     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) {
+    TCP_STATS_INC(tcp.memerr);\r
+    return ERR_MEM;\r
+  }\r
+  if (queuelen != 0) {\r
+    LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",\r
+      pcb->unacked != NULL || pcb->unsent != NULL);\r
+  } else {\r
+    LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",\r
+      pcb->unacked == NULL && pcb->unsent == NULL);\r
+  }\r
+\r
+  /* First, break up the data into segments and tuck them together in\r
+   * the local "queue" variable. */\r
+  useg = queue = seg = NULL;\r
+  seglen = 0;\r
+  while (queue == NULL || left > 0) {\r
+\r
+    /* The segment length should be the MSS if the data to be enqueued\r
+     * is larger than the MSS. */\r
+    seglen = left > pcb->mss? pcb->mss: left;\r
+\r
+    /* Allocate memory for tcp_seg, and fill in fields. */\r
+    seg = memp_malloc(MEMP_TCP_SEG);\r
+    if (seg == NULL) {\r
       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) {
+      goto memerr;\r
+    }\r
+    seg->next = NULL;\r
+    seg->p = NULL;\r
+\r
+    /* first segment of to-be-queued data? */\r
+    if (queue == NULL) {\r
+      queue = seg;\r
+    }\r
+    /* subsequent segments of to-be-queued data */\r
+    else {\r
+      /* Attach the segment to the end of the queued segments */\r
+      LWIP_ASSERT("useg != NULL", useg != NULL);\r
+      useg->next = seg;\r
+    }\r
+    /* remember last segment of to-be-queued data for next iteration */\r
+    useg = seg;\r
+\r
+    /* If copy is set, memory should be allocated\r
+     * and data copied into pbuf, otherwise data comes from\r
+     * ROM or other static memory, and need not be copied. If\r
+     * optdata is != NULL, we have options instead of data. */\r
+     \r
+    /* options? */\r
+    if (optdata != NULL) {\r
+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {\r
+        goto memerr;\r
+      }\r
+      ++queuelen;\r
+      seg->dataptr = seg->p->payload;\r
+    }\r
+    /* copy from volatile memory? */\r
+    else if (copy) {\r
+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {\r
         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) {
+        goto memerr;\r
+      }\r
+      ++queuelen;\r
+      if (arg != NULL) {\r
+        memcpy(seg->p->payload, ptr, seglen);\r
+      }\r
+      seg->dataptr = seg->p->payload;\r
+    }\r
+    /* do not copy data */\r
+    else {\r
+      /* First, allocate a pbuf for holding the data.\r
+       * since the referenced data is available at least until it is sent out on the\r
+       * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM\r
+       * instead of PBUF_REF here.\r
+       */\r
+      if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {\r
         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);
+        goto memerr;\r
+      }\r
+      ++queuelen;\r
+      /* reference the non-volatile payload data */\r
+      p->payload = ptr;\r
+      seg->dataptr = ptr;\r
+\r
+      /* Second, allocate a pbuf for the headers. */\r
+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {\r
+        /* If allocation fails, we have to deallocate the data pbuf as\r
+         * well. */\r
+        pbuf_free(p);\r
         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) {
+        goto memerr;\r
+      }\r
+      ++queuelen;\r
+\r
+      /* Concatenate the headers and data pbufs together. */\r
+      pbuf_cat(seg->p/*header*/, p/*data*/);\r
+      p = NULL;\r
+    }\r
+\r
+    /* Now that there are more segments queued, we check again if the\r
+    length of the queue exceeds the configured maximum. */\r
+    if (queuelen > TCP_SND_QUEUELEN) {\r
       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)) {
+      goto memerr;\r
+    }\r
+\r
+    seg->len = seglen;\r
+\r
+    /* build TCP header */\r
+    if (pbuf_header(seg->p, TCP_HLEN)) {\r
       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);
-  }
+      TCP_STATS_INC(tcp.err);\r
+      goto memerr;\r
+    }\r
+    seg->tcphdr = seg->p->payload;\r
+    seg->tcphdr->src = htons(pcb->local_port);\r
+    seg->tcphdr->dest = htons(pcb->remote_port);\r
+    seg->tcphdr->seqno = htonl(seqno);\r
+    seg->tcphdr->urgp = 0;\r
+    TCPH_FLAGS_SET(seg->tcphdr, flags);\r
+    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */\r
+\r
+    /* Copy the options into the header, if they are present. */\r
+    if (optdata == NULL) {\r
+      TCPH_HDRLEN_SET(seg->tcphdr, 5);\r
+    }\r
+    else {\r
+      TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));\r
+      /* Copy options into data portion of segment.\r
+       Options can thus only be sent in non data carrying\r
+       segments such as SYN|ACK. */\r
+      memcpy(seg->dataptr, optdata, optlen);\r
+    }\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",\r
+      ntohl(seg->tcphdr->seqno),\r
+      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),\r
+      (u16_t)flags));\r
+\r
+    left -= seglen;\r
+    seqno += seglen;\r
+    ptr = (void *)((u8_t *)ptr + seglen);\r
+  }\r
+\r
+  /* Now that the data to be enqueued has been broken up into TCP\r
+  segments in the queue variable, we add them to the end of the\r
+  pcb->unsent queue. */\r
+  if (pcb->unsent == NULL) {\r
+    useg = NULL;\r
+  }\r
+  else {\r
+    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);\r
+  }\r
+  /* { useg is last segment on the unsent queue, NULL if list is empty } */\r
+\r
+  /* If there is room in the last pbuf on the unsent queue,\r
+  chain the first pbuf on the queue together with that. */\r
+  if (useg != NULL &&\r
+    TCP_TCPLEN(useg) != 0 &&\r
+    !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&\r
+    !(flags & (TCP_SYN | TCP_FIN)) &&\r
+    /* fit within max seg size */\r
+    useg->len + queue->len <= pcb->mss) {\r
+    /* Remove TCP header from first segment of our to-be-queued list */\r
+    pbuf_header(queue->p, -TCP_HLEN);\r
+    pbuf_cat(useg->p, queue->p);\r
+    useg->len += queue->len;\r
+    useg->next = queue->next;\r
+\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len));\r
+    if (seg == queue) {\r
+      seg = NULL;\r
+    }\r
+    memp_free(MEMP_TCP_SEG, queue);\r
+  }\r
+  else {\r
+    /* empty list */\r
+    if (useg == NULL) {\r
+      /* initialize list with this segment */\r
+      pcb->unsent = queue;\r
+    }\r
+    /* enqueue segment */\r
+    else {\r
+      useg->next = queue;\r
+    }\r
+  }\r
+  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {\r
+    ++len;\r
+  }\r
+  pcb->snd_lbb += len;\r
+\r
+  pcb->snd_buf -= len;\r
+\r
+  /* update number of segments on the queues */\r
+  pcb->snd_queuelen = queuelen;\r
+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));\r
+  if (pcb->snd_queuelen != 0) {\r
+    LWIP_ASSERT("tcp_enqueue: valid queue length",\r
+      pcb->unacked != NULL || pcb->unsent != NULL);\r
+  }\r
+\r
+  /* Set the PSH flag in the last segment that we enqueued, but only\r
+  if the segment has data (indicated by seglen > 0). */\r
+  if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) {\r
+    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);\r
+  }\r
+\r
+  return ERR_OK;\r
+memerr:\r
+  TCP_STATS_INC(tcp.memerr);\r
+\r
+  if (queue != NULL) {\r
+    tcp_segs_free(queue);\r
+  }\r
+  if (pcb->snd_queuelen != 0) {\r
+    LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||\r
+      pcb->unsent != NULL);\r
+  }\r
   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 */
-
-
-
-
-
-
-
-
-
+  return ERR_MEM;\r
+}\r
+\r
+/* find out what we can send and send it */\r
+err_t\r
+tcp_output(struct tcp_pcb *pcb)\r
+{\r
+  struct pbuf *p;\r
+  struct tcp_hdr *tcphdr;\r
+  struct tcp_seg *seg, *useg;\r
+  u32_t wnd;\r
+#if TCP_CWND_DEBUG\r
+  s16_t i = 0;\r
+#endif /* TCP_CWND_DEBUG */\r
+\r
+  /* First, check if we are invoked by the TCP input processing\r
+     code. If so, we do not output anything. Instead, we rely on the\r
+     input processing code to call us when input processing is done\r
+     with. */\r
+  if (tcp_input_pcb == pcb) {\r
+    return ERR_OK;\r
+  }\r
+\r
+  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);\r
+\r
+  seg = pcb->unsent;\r
+\r
+  /* useg should point to last segment on unacked queue */\r
+  useg = pcb->unacked;\r
+  if (useg != NULL) {\r
+    for (; useg->next != NULL; useg = useg->next);\r
+  }                                                                             \r
+   \r
+  /* If the TF_ACK_NOW flag is set and no data will be sent (either\r
+   * because the ->unsent queue is empty or because the window does\r
+   * not allow it), construct an empty ACK segment and send it.\r
+   *\r
+   * If data is to be sent, we will just piggyback the ACK (see below).\r
+   */\r
+  if (pcb->flags & TF_ACK_NOW &&\r
+     (seg == NULL ||\r
+      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {\r
+    p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
+    if (p == NULL) {\r
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));\r
+      return ERR_BUF;\r
+    }\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));\r
+    /* remove ACK flags from the PCB, as we send an empty ACK now */\r
+    pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\r
+\r
+    tcphdr = p->payload;\r
+    tcphdr->src = htons(pcb->local_port);\r
+    tcphdr->dest = htons(pcb->remote_port);\r
+    tcphdr->seqno = htonl(pcb->snd_nxt);\r
+    tcphdr->ackno = htonl(pcb->rcv_nxt);\r
+    TCPH_FLAGS_SET(tcphdr, TCP_ACK);\r
+    tcphdr->wnd = htons(pcb->rcv_wnd);\r
+    tcphdr->urgp = 0;\r
+    TCPH_HDRLEN_SET(tcphdr, 5);\r
+\r
+    tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),\r
+          IP_PROTO_TCP, p->tot_len);\r
+#endif\r
+    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\r
+        IP_PROTO_TCP);\r
+    pbuf_free(p);\r
+\r
+    return ERR_OK;\r
+  }\r
+\r
+#if TCP_OUTPUT_DEBUG\r
+  if (seg == NULL) {\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", (void*)pcb->unsent));\r
+  }\r
+#endif /* TCP_OUTPUT_DEBUG */\r
+#if TCP_CWND_DEBUG\r
+  if (seg == NULL) {\r
+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", seg == NULL, ack %"U32_F"\n",\r
+                            pcb->snd_wnd, pcb->cwnd, wnd,\r
+                            pcb->lastack));\r
+  } else {\r
+    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",\r
+                            pcb->snd_wnd, pcb->cwnd, wnd,\r
+                            ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,\r
+                            ntohl(seg->tcphdr->seqno), pcb->lastack));\r
+  }\r
+#endif /* TCP_CWND_DEBUG */\r
+  /* data available and window allows it to be sent? */\r
+  while (seg != NULL &&\r
+  ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {\r
+#if TCP_CWND_DEBUG\r
+    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",\r
+                            pcb->snd_wnd, pcb->cwnd, wnd,\r
+                            ntohl(seg->tcphdr->seqno) + seg->len -\r
+                            pcb->lastack,\r
+                            ntohl(seg->tcphdr->seqno), pcb->lastack, i));\r
+    ++i;\r
+#endif /* TCP_CWND_DEBUG */\r
+\r
+    pcb->unsent = seg->next;\r
+\r
+    if (pcb->state != SYN_SENT) {\r
+      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);\r
+      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\r
+    }\r
+\r
+    tcp_output_segment(seg, pcb);\r
+    pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);\r
+    if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {\r
+      pcb->snd_max = pcb->snd_nxt;\r
+    }\r
+    /* put segment on unacknowledged list if length > 0 */\r
+    if (TCP_TCPLEN(seg) > 0) {\r
+      seg->next = NULL;\r
+      /* unacked list is empty? */\r
+      if (pcb->unacked == NULL) {\r
+        pcb->unacked = seg;\r
+        useg = seg;\r
+      /* unacked list is not empty? */\r
+      } else {\r
+        /* In the case of fast retransmit, the packet should not go to the tail\r
+         * of the unacked queue, but rather at the head. We need to check for\r
+         * this case. -STJ Jul 27, 2004 */\r
+        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){\r
+          /* add segment to head of unacked list */\r
+          seg->next = pcb->unacked;\r
+          pcb->unacked = seg;\r
+        } else {\r
+          /* add segment to tail of unacked list */\r
+          useg->next = seg;\r
+          useg = useg->next;\r
+        }\r
+      }\r
+    /* do not queue empty segments on the unacked list */\r
+    } else {\r
+      tcp_seg_free(seg);\r
+    }\r
+    seg = pcb->unsent;\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Actually send a TCP segment over IP\r
+ */\r
+static void\r
+tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)\r
+{\r
+  u16_t len;\r
+  struct netif *netif;\r
+\r
+  /** @bug Exclude retransmitted segments from this count. */\r
+  snmp_inc_tcpoutsegs();\r
+\r
+  /* The TCP header has already been constructed, but the ackno and\r
+   wnd fields remain. */\r
+  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);\r
+\r
+  /* silly window avoidance */\r
+  if (pcb->rcv_wnd < pcb->mss) {\r
+    seg->tcphdr->wnd = 0;\r
+  } else {\r
+    /* advertise our receive window size in this TCP segment */\r
+    seg->tcphdr->wnd = htons(pcb->rcv_wnd);\r
+  }\r
+\r
+  /* If we don't have a local IP address, we get one by\r
+     calling ip_route(). */\r
+  if (ip_addr_isany(&(pcb->local_ip))) {\r
+    netif = ip_route(&(pcb->remote_ip));\r
+    if (netif == NULL) {\r
+      return;\r
+    }\r
+    ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));\r
+  }\r
+\r
+  pcb->rtime = 0;\r
+\r
+  if (pcb->rttest == 0) {\r
+    pcb->rttest = tcp_ticks;\r
+    pcb->rtseq = ntohl(seg->tcphdr->seqno);\r
+\r
+    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));\r
+  }\r
+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",\r
+          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +\r
+          seg->len));\r
+\r
+  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);\r
+\r
+  seg->p->len -= len;\r
+  seg->p->tot_len -= len;\r
+\r
+  seg->p->payload = seg->tcphdr;\r
+\r
+  seg->tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,\r
+             &(pcb->local_ip),\r
+             &(pcb->remote_ip),\r
+             IP_PROTO_TCP, seg->p->tot_len);\r
+#endif\r
+  TCP_STATS_INC(tcp.xmit);\r
+\r
+  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\r
+      IP_PROTO_TCP);\r
+}\r
+\r
+void\r
+tcp_rst(u32_t seqno, u32_t ackno,\r
+  struct ip_addr *local_ip, struct ip_addr *remote_ip,\r
+  u16_t local_port, u16_t remote_port)\r
+{\r
+  struct pbuf *p;\r
+  struct tcp_hdr *tcphdr;\r
+  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
+  if (p == NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));\r
+      return;\r
+  }\r
+\r
+  tcphdr = p->payload;\r
+  tcphdr->src = htons(local_port);\r
+  tcphdr->dest = htons(remote_port);\r
+  tcphdr->seqno = htonl(seqno);\r
+  tcphdr->ackno = htonl(ackno);\r
+  TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);\r
+  tcphdr->wnd = htons(TCP_WND);\r
+  tcphdr->urgp = 0;\r
+  TCPH_HDRLEN_SET(tcphdr, 5);\r
+\r
+  tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,\r
+              IP_PROTO_TCP, p->tot_len);\r
+#endif\r
+  TCP_STATS_INC(tcp.xmit);\r
+  snmp_inc_tcpoutrsts();\r
+   /* Send output with hardcoded TTL since we have no access to the pcb */\r
+  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);\r
+  pbuf_free(p);\r
+  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));\r
+}\r
+\r
+/* requeue all unacked segments for retransmission */\r
+void\r
+tcp_rexmit_rto(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_seg *seg;\r
+\r
+  if (pcb->unacked == NULL) {\r
+    return;\r
+  }\r
+\r
+  /* Move all unacked segments to the head of the unsent queue */\r
+  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);\r
+  /* concatenate unsent queue after unacked queue */\r
+  seg->next = pcb->unsent;\r
+  /* unsent queue is the concatenated queue (of unacked, unsent) */\r
+  pcb->unsent = pcb->unacked;\r
+  /* unacked queue is now empty */\r
+  pcb->unacked = NULL;\r
+\r
+  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);\r
+  /* increment number of retransmissions */\r
+  ++pcb->nrtx;\r
+\r
+  /* Don't take any RTT measurements after retransmitting. */\r
+  pcb->rttest = 0;\r
+\r
+  /* Do the actual retransmission */\r
+  tcp_output(pcb);\r
+}\r
+\r
+void\r
+tcp_rexmit(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_seg *seg;\r
+\r
+  if (pcb->unacked == NULL) {\r
+    return;\r
+  }\r
+\r
+  /* Move the first unacked segment to the unsent queue */\r
+  seg = pcb->unacked->next;\r
+  pcb->unacked->next = pcb->unsent;\r
+  pcb->unsent = pcb->unacked;\r
+  pcb->unacked = seg;\r
+\r
+  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);\r
+\r
+  ++pcb->nrtx;\r
+\r
+  /* Don't take any rtt measurements after retransmitting. */\r
+  pcb->rttest = 0;\r
+\r
+  /* Do the actual retransmission. */\r
+  snmp_inc_tcpretranssegs();\r
+  tcp_output(pcb);\r
+\r
+}\r
+\r
+\r
+void\r
+tcp_keepalive(struct tcp_pcb *pcb)\r
+{\r
+   struct pbuf *p;\r
+   struct tcp_hdr *tcphdr;\r
+\r
+   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",\r
+                           ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),\r
+                           ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));\r
+\r
+   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));\r
+   \r
+   p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
+\r
+   if(p == NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n"));\r
+      return;\r
+   }\r
+\r
+   tcphdr = p->payload;\r
+   tcphdr->src = htons(pcb->local_port);\r
+   tcphdr->dest = htons(pcb->remote_port);\r
+   tcphdr->seqno = htonl(pcb->snd_nxt - 1);\r
+   tcphdr->ackno = htonl(pcb->rcv_nxt);\r
+   tcphdr->wnd = htons(pcb->rcv_wnd);\r
+   tcphdr->urgp = 0;\r
+   TCPH_HDRLEN_SET(tcphdr, 5);\r
+   \r
+   tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+   tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len);\r
+#endif\r
+  TCP_STATS_INC(tcp.xmit);\r
+\r
+   /* Send output to IP */\r
+  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);\r
+\r
+  pbuf_free(p);\r
+\r
+  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt));\r
+}\r
+\r
+#endif /* LWIP_TCP */\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
index c487d266f01826d1b8df49b4c973fdb1af597711..3d5980f47dbeda7f997f9001c4a3bd41c89665d2 100644 (file)
-/**
- * @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,
+/**\r
+ * @file\r
+ * User Datagram Protocol module\r
+ *\r
+ */\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+\r
+/* udp.c\r
+ *\r
+ * The code for the User Datagram Protocol UDP.\r
+ *\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/icmp.h"\r
+\r
+#include "lwip/stats.h"\r
+\r
+#include "arch/perf.h"\r
+#include "lwip/snmp.h"\r
+\r
+/* The list of UDP PCBs */\r
+#if LWIP_UDP\r
+/* exported in udp.h (was static) */\r
+struct udp_pcb *udp_pcbs = NULL;\r
+\r
+static struct udp_pcb *pcb_cache = NULL;\r
+\r
+void\r
+udp_init(void)\r
+{\r
+  udp_pcbs = pcb_cache = NULL;\r
+}\r
+\r
+/**\r
+ * Process an incoming UDP datagram.\r
+ *\r
+ * Given an incoming UDP datagram (as a chain of pbufs) this function\r
+ * finds a corresponding UDP PCB and\r
+ *\r
+ * @param pbuf pbuf to be demultiplexed to a UDP PCB.\r
+ * @param netif network interface on which the datagram was received.\r
+ *\r
+ */\r
+void\r
+udp_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct udp_hdr *udphdr;\r
+  struct udp_pcb *pcb;\r
+  struct udp_pcb *uncon_pcb;\r
+  struct ip_hdr *iphdr;\r
+  u16_t src, dest;\r
+  u8_t local_match;\r
+\r
+  PERF_START;\r
+\r
+  UDP_STATS_INC(udp.recv);\r
+\r
+  iphdr = p->payload;\r
+\r
+  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN)) {\r
+    /* drop short packets */\r
+//    LWIP_DEBUGF(UDP_DEBUG,\r
 //                ("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 */
+\r
+    UDP_STATS_INC(udp.lenerr);\r
+    UDP_STATS_INC(udp.drop);\r
+    snmp_inc_udpinerrors();\r
+    pbuf_free(p);\r
+    goto end;\r
+  }\r
+\r
+  pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4)));\r
+\r
+  udphdr = (struct udp_hdr *)p->payload;\r
+\r
+  LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));\r
+\r
+  src = ntohs(udphdr->src);\r
+  dest = ntohs(udphdr->dest);\r
+\r
+  udp_debug_print(udphdr);\r
+\r
+  /* print the UDP source and destination */\r
+  LWIP_DEBUGF(UDP_DEBUG,\r
+              ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "\r
+               "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",\r
+               ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),\r
+               ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),\r
+               ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),\r
+               ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));\r
+\r
+  local_match = 0;\r
+  uncon_pcb = NULL;\r
+  /* Iterate through the UDP pcb list for a matching pcb */\r
+  for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    /* print the PCB local and remote address */\r
+    LWIP_DEBUGF(UDP_DEBUG,\r
+                ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "\r
+                 "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",\r
+                 ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),\r
+                 ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,\r
+                 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),\r
+                 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));\r
+\r
+    /* compare PCB local addr+port to UDP destination addr+port */\r
+    if ((pcb->local_port == dest) &&\r
+        (ip_addr_isany(&pcb->local_ip) ||\r
+         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || \r
+         ip_addr_isbroadcast(&(iphdr->dest), inp))) {\r
+      local_match = 1;\r
+      if ((uncon_pcb == NULL) && \r
+          ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {\r
+        /* the first unconnected matching PCB */     \r
+        uncon_pcb = pcb;\r
+      }\r
+    }\r
+    /* compare PCB remote addr+port to UDP source addr+port */\r
+    if ((local_match != 0) &&\r
+        (pcb->remote_port == src) &&\r
+        (ip_addr_isany(&pcb->remote_ip) ||\r
+         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {\r
+      /* the first fully matching PCB */\r
+      break;\r
+    }\r
+  }\r
+  /* no fully matching pcb found? then look for an unconnected pcb */\r
+  if (pcb == NULL) {\r
+    pcb = uncon_pcb;\r
+  }\r
+\r
+  /* Check checksum if this is a match or if it was directed at us. */\r
+  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {\r
+    LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: calculating checksum\n"));\r
+#ifdef IPv6\r
+    if (iphdr->nexthdr == IP_PROTO_UDPLITE) {\r
+#else\r
+    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {\r
+#endif /* IPv4 */\r
+      /* Do the UDP Lite checksum */\r
+#if CHECKSUM_CHECK_UDP\r
+      if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),\r
+                             (struct ip_addr *)&(iphdr->dest),\r
+                             IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) {\r
+        LWIP_DEBUGF(UDP_DEBUG | 2,\r
+                    ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));\r
+        UDP_STATS_INC(udp.chkerr);\r
+        UDP_STATS_INC(udp.drop);\r
+        snmp_inc_udpinerrors();\r
+        pbuf_free(p);\r
+        goto end;\r
+      }\r
+#endif\r
+    } else {\r
+#if CHECKSUM_CHECK_UDP\r
+      if (udphdr->chksum != 0) {\r
+        if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),\r
+                               (struct ip_addr *)&(iphdr->dest),\r
+                               IP_PROTO_UDP, p->tot_len) != 0) {\r
+          LWIP_DEBUGF(UDP_DEBUG | 2,\r
+                      ("udp_input: UDP datagram discarded due to failing checksum\n"));\r
+          UDP_STATS_INC(udp.chkerr);\r
+          UDP_STATS_INC(udp.drop);\r
+          snmp_inc_udpinerrors();\r
+          pbuf_free(p);\r
+          goto end;\r
+        }\r
+      }\r
+#endif\r
+    }\r
+    pbuf_header(p, -UDP_HLEN);\r
+    if (pcb != NULL) {\r
+      snmp_inc_udpindatagrams();\r
+      /* callback */\r
+      if (pcb->recv != NULL)\r
+        pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);\r
+    } else {\r
+      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n"));\r
+\r
+      /* No match was found, send ICMP destination port unreachable unless\r
+         destination address was broadcast/multicast. */\r
+\r
+      if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&\r
+          !ip_addr_ismulticast(&iphdr->dest)) {\r
+\r
+        /* restore pbuf pointer */\r
+        p->payload = iphdr;\r
+        icmp_dest_unreach(p, ICMP_DUR_PORT);\r
+      }\r
+      UDP_STATS_INC(udp.proterr);\r
+      UDP_STATS_INC(udp.drop);\r
+      snmp_inc_udpnoports();\r
+      pbuf_free(p);\r
+    }\r
+  } else {\r
+    pbuf_free(p);\r
+  }\r
+end:\r
+  PERF_STOP("udp_input");\r
+}\r
+\r
+/**\r
+ * Send data to a specified address using UDP.\r
+ *\r
+ * @param pcb UDP PCB used to send the data.\r
+ * @param pbuf chain of pbuf's to be sent.\r
+ * @param dst_ip Destination IP address.\r
+ * @param dst_port Destination UDP port.\r
+ *\r
+ * If the PCB already has a remote address association, it will\r
+ * be restored after the data is sent.\r
+ * \r
+ * @return lwIP error code.\r
+ * - ERR_OK. Successful. No error occured.\r
+ * - ERR_MEM. Out of memory.\r
+ * - ERR_RTE. Could not find route to destination address.\r
+ *\r
+ * @see udp_disconnect() udp_send()\r
+ */\r
+err_t\r
+udp_sendto(struct udp_pcb *pcb, struct pbuf *p,\r
+  struct ip_addr *dst_ip, u16_t dst_port)\r
+{\r
+  err_t err;\r
+  /* temporary space for current PCB remote address */\r
+  struct ip_addr pcb_remote_ip;\r
+  u16_t pcb_remote_port;\r
+  /* remember current remote peer address of PCB */\r
+  pcb_remote_ip.addr = pcb->remote_ip.addr;\r
+  pcb_remote_port = pcb->remote_port;\r
+  /* copy packet destination address to PCB remote peer address */\r
+  pcb->remote_ip.addr = dst_ip->addr;\r
+  pcb->remote_port = dst_port;\r
+  /* send to the packet destination address */\r
+  err = udp_send(pcb, p);\r
+  /* restore PCB remote peer address */\r
+  pcb->remote_ip.addr = pcb_remote_ip.addr;\r
+  pcb->remote_port = pcb_remote_port;\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Send data using UDP.\r
+ *\r
+ * @param pcb UDP PCB used to send the data.\r
+ * @param pbuf chain of pbuf's to be sent.\r
+ *\r
+ * @return lwIP error code.\r
+ * - ERR_OK. Successful. No error occured.\r
+ * - ERR_MEM. Out of memory.\r
+ * - ERR_RTE. Could not find route to destination address.\r
+ *\r
+ * @see udp_disconnect() udp_sendto()\r
+ */\r
+err_t\r
+udp_send(struct udp_pcb *pcb, struct pbuf *p)\r
+{\r
+  struct udp_hdr *udphdr;\r
+  struct netif *netif;\r
+  struct ip_addr *src_ip;\r
+  err_t err;\r
+  struct pbuf *q; /* q will be sent down the stack */\r
+\r
+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_send\n"));\r
+\r
+  /* if the PCB is not yet bound to a port, bind it here */\r
+  if (pcb->local_port == 0) {\r
+    LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));\r
+    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);\r
+    if (err != ERR_OK) {\r
+      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));\r
+      return err;\r
+    }\r
+  }\r
+  /* find the outgoing network interface for this packet */\r
+  netif = ip_route(&(pcb->remote_ip));\r
+  /* no outgoing network interface could be found? */\r
+  if (netif == NULL) {\r
+    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", pcb->remote_ip.addr));\r
+    UDP_STATS_INC(udp.rterr);\r
+    return ERR_RTE;\r
+  }\r
+\r
+  /* not enough space to add an UDP header to first pbuf in given p chain? */\r
+  if (pbuf_header(p, UDP_HLEN)) {\r
+    /* allocate header in a seperate new pbuf */\r
+    q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);\r
+    /* new header pbuf could not be allocated? */\r
+    if (q == NULL) {\r
+      LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: could not allocate header\n"));\r
+      return ERR_MEM;\r
+    }\r
+    /* chain header q in front of given pbuf p */\r
+    pbuf_chain(q, p);\r
+    /* first pbuf q points to header pbuf */\r
+    LWIP_DEBUGF(UDP_DEBUG,\r
+                ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));\r
+    /* adding a header within p succeeded */\r
+  } else {\r
+    /* first pbuf q equals given pbuf */\r
+    q = p;\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));\r
+  }\r
+  /* q now represents the packet to be sent */\r
+  udphdr = q->payload;\r
+  udphdr->src = htons(pcb->local_port);\r
+  udphdr->dest = htons(pcb->remote_port);\r
+  /* in UDP, 0 checksum means 'no checksum' */\r
+  udphdr->chksum = 0x0000; \r
+\r
+  /* PCB local address is IP_ANY_ADDR? */\r
+  if (ip_addr_isany(&pcb->local_ip)) {\r
+    /* use outgoing network interface IP address as source address */\r
+    src_ip = &(netif->ip_addr);\r
+  } else {\r
+    /* use UDP PCB local IP address as source address */\r
+    src_ip = &(pcb->local_ip);\r
+  }\r
+\r
+  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));\r
+\r
+  /* UDP Lite protocol? */\r
+  if (pcb->flags & UDP_FLAGS_UDPLITE) {\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));\r
+    /* set UDP message length in UDP header */\r
+    udphdr->len = htons(pcb->chksum_len);\r
+    /* calculate checksum */\r
+#if CHECKSUM_GEN_UDP\r
+    udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip),\r
+                                        IP_PROTO_UDP, pcb->chksum_len);\r
+    /* chksum zero must become 0xffff, as zero means 'no checksum' */\r
+    if (udphdr->chksum == 0x0000)\r
+      udphdr->chksum = 0xffff;\r
+#else\r
+    udphdr->chksum = 0x0000;\r
+#endif\r
+    /* output to IP */\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));\r
+    err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);    \r
+  } else {      /* UDP */\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));\r
+    udphdr->len = htons(q->tot_len);\r
+    /* calculate checksum */\r
+#if CHECKSUM_GEN_UDP\r
+    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {\r
+      udphdr->chksum = inet_chksum_pseudo(q, src_ip, &pcb->remote_ip, IP_PROTO_UDP, q->tot_len);\r
+      /* chksum zero must become 0xffff, as zero means 'no checksum' */\r
+      if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;\r
+    }\r
+#else\r
+    udphdr->chksum = 0x0000;\r
+#endif\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));\r
+    /* output to IP */\r
+    err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);    \r
+  }\r
+  /* TODO: must this be increased even if error occured? */\r
+  snmp_inc_udpoutdatagrams();\r
+\r
+  /* did we chain a seperate header pbuf earlier? */\r
+  if (q != p) {\r
+    /* free the header pbuf */\r
+    pbuf_free(q);\r
+    q = NULL;\r
+    /* p is still referenced by the caller, and will live on */\r
+  }\r
+\r
+  UDP_STATS_INC(udp.xmit);\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Bind an UDP PCB.\r
+ *\r
+ * @param pcb UDP PCB to be bound with a local address ipaddr and port.\r
+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to\r
+ * bind to all local interfaces.\r
+ * @param port local UDP port to bind with.\r
+ *\r
+ * @return lwIP error code.\r
+ * - ERR_OK. Successful. No error occured.\r
+ * - ERR_USE. The specified ipaddr and port are already bound to by\r
+ * another UDP PCB.\r
+ *\r
+ * @see udp_disconnect()\r
+ */\r
+err_t\r
+udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)\r
+{\r
+  struct udp_pcb *ipcb;\r
+  u8_t rebind;\r
+\r
+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = "));\r
+  ip_addr_debug_print(UDP_DEBUG, ipaddr);\r
+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %"U16_F")\n", port));\r
+\r
+  rebind = 0;\r
+  /* Check for double bind and rebind of the same pcb */\r
+  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {\r
+    /* is this UDP PCB already on active list? */\r
+    if (pcb == ipcb) {\r
+      /* pcb may occur at most once in active list */\r
+      LWIP_ASSERT("rebind == 0", rebind == 0);\r
+      /* pcb already in list, just rebind */\r
+      rebind = 1;\r
+    }\r
+\r
+    /* this code does not allow upper layer to share a UDP port for\r
+       listening to broadcast or multicast traffic (See SO_REUSE_ADDR and\r
+       SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR\r
+       combine with implementation of UDP PCB flags. Leon Woestenberg. */\r
+#ifdef LWIP_UDP_TODO\r
+    /* port matches that of PCB in list? */\r
+    else\r
+      if ((ipcb->local_port == port) &&\r
+          /* IP address matches, or one is IP_ADDR_ANY? */\r
+          (ip_addr_isany(&(ipcb->local_ip)) ||\r
+           ip_addr_isany(ipaddr) ||\r
+           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {\r
+        /* other PCB already binds to this local IP and port */\r
+        LWIP_DEBUGF(UDP_DEBUG,\r
+                    ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));\r
+        return ERR_USE;\r
+      }\r
+#endif\r
+  }\r
+\r
+  ip_addr_set(&pcb->local_ip, ipaddr);\r
+\r
+  /* no port specified? */\r
+  if (port == 0) {\r
+#ifndef UDP_LOCAL_PORT_RANGE_START\r
+#define UDP_LOCAL_PORT_RANGE_START 4096\r
+#define UDP_LOCAL_PORT_RANGE_END   0x7fff\r
+#endif\r
+    port = UDP_LOCAL_PORT_RANGE_START;\r
+    ipcb = udp_pcbs;\r
+    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {\r
+      if (ipcb->local_port == port) {\r
+        port++;\r
+        ipcb = udp_pcbs;\r
+      } else\r
+        ipcb = ipcb->next;\r
+    }\r
+    if (ipcb != NULL) {\r
+      /* no more ports available in local range */\r
+      LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));\r
+      return ERR_USE;\r
+    }\r
+  }\r
+  pcb->local_port = port;\r
+  snmp_insert_udpidx_tree(pcb);\r
+  /* pcb not active yet? */\r
+  if (rebind == 0) {\r
+    /* place the PCB on the active list if not already there */\r
+    pcb->next = udp_pcbs;\r
+    udp_pcbs = pcb;\r
+  }\r
+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE,\r
+              ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",\r
+               (u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),\r
+               (u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),\r
+               (u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),\r
+               (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));\r
+  return ERR_OK;\r
+}\r
+/**\r
+ * Connect an UDP PCB.\r
+ *\r
+ * This will associate the UDP PCB with the remote address.\r
+ *\r
+ * @param pcb UDP PCB to be connected with remote address ipaddr and port.\r
+ * @param ipaddr remote IP address to connect with.\r
+ * @param port remote UDP port to connect with.\r
+ *\r
+ * @return lwIP error code\r
+ *\r
+ * @see udp_disconnect()\r
+ */\r
+err_t\r
+udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)\r
+{\r
+  struct udp_pcb *ipcb;\r
+\r
+  if (pcb->local_port == 0) {\r
+    err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);\r
+    if (err != ERR_OK)\r
+      return err;\r
+  }\r
+\r
+  ip_addr_set(&pcb->remote_ip, ipaddr);\r
+  pcb->remote_port = port;\r
+  pcb->flags |= UDP_FLAGS_CONNECTED;\r
+/** TODO: this functionality belongs in upper layers */\r
+#ifdef LWIP_UDP_TODO\r
+  /* Nail down local IP for netconn_addr()/getsockname() */\r
+  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {\r
+    struct netif *netif;\r
+\r
+    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {\r
+      LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));\r
+      UDP_STATS_INC(udp.rterr);\r
+      return ERR_RTE;\r
+    }\r
+    /** TODO: this will bind the udp pcb locally, to the interface which\r
+        is used to route output packets to the remote address. However, we\r
+        might want to accept incoming packets on any interface! */\r
+    pcb->local_ip = netif->ip_addr;\r
+  } else if (ip_addr_isany(&pcb->remote_ip)) {\r
+    pcb->local_ip.addr = 0;\r
+  }\r
+#endif\r
+  LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE,\r
+              ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",\r
+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),\r
+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),\r
+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),\r
+               (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));\r
+\r
+  /* Insert UDP PCB into the list of active UDP PCBs. */\r
+  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {\r
+    if (pcb == ipcb) {\r
+      /* already on the list, just return */\r
+      return ERR_OK;\r
+    }\r
+  }\r
+  /* PCB not yet on the list, add PCB now */\r
+  pcb->next = udp_pcbs;\r
+  udp_pcbs = pcb;\r
+  return ERR_OK;\r
+}\r
+\r
+void\r
+udp_disconnect(struct udp_pcb *pcb)\r
+{\r
+  /* reset remote address association */\r
+  ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);\r
+  pcb->remote_port = 0;\r
+  /* mark PCB as unconnected */\r
+  pcb->flags &= ~UDP_FLAGS_CONNECTED;\r
+}\r
+\r
+void\r
+udp_recv(struct udp_pcb *pcb,\r
+         void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,\r
+                       struct ip_addr *addr, u16_t port),\r
+         void *recv_arg)\r
+{\r
+  /* remember recv() callback and user data */\r
+  pcb->recv = recv;\r
+  pcb->recv_arg = recv_arg;\r
+}\r
+\r
+/**\r
+ * Remove an UDP PCB.\r
+ *\r
+ * @param pcb UDP PCB to be removed. The PCB is removed from the list of\r
+ * UDP PCB's and the data structure is freed from memory.\r
+ *\r
+ * @see udp_new()\r
+ */\r
+void\r
+udp_remove(struct udp_pcb *pcb)\r
+{\r
+  struct udp_pcb *pcb2;\r
+\r
+  snmp_delete_udpidx_tree(pcb);\r
+  /* pcb to be removed is first in list? */\r
+  if (udp_pcbs == pcb) {\r
+    /* make list start at 2nd pcb */\r
+    udp_pcbs = udp_pcbs->next;\r
+    /* pcb not 1st in list */\r
+  } else\r
+    for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {\r
+      /* find pcb in udp_pcbs list */\r
+      if (pcb2->next != NULL && pcb2->next == pcb) {\r
+        /* remove pcb from list */\r
+        pcb2->next = pcb->next;\r
+      }\r
+    }\r
+  memp_free(MEMP_UDP_PCB, pcb);\r
+}\r
+\r
+/**\r
+ * Create a UDP PCB.\r
+ *\r
+ * @return The UDP PCB which was created. NULL if the PCB data structure\r
+ * could not be allocated.\r
+ *\r
+ * @see udp_remove()\r
+ */\r
+struct udp_pcb *\r
+udp_new(void)\r
+{\r
+  struct udp_pcb *pcb;\r
+  pcb = memp_malloc(MEMP_UDP_PCB);\r
+  /* could allocate UDP PCB? */\r
+  if (pcb != NULL) {\r
+    /* initialize PCB to all zeroes */\r
+    memset(pcb, 0, sizeof(struct udp_pcb));\r
+    pcb->ttl = UDP_TTL;\r
+  }\r
+  return pcb;\r
+}\r
+\r
+#if UDP_DEBUG\r
+void\r
+udp_debug_print(struct udp_hdr *udphdr)\r
+{\r
+  LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     %5"U16_F"     | (src port, dest port)\n",\r
+                          ntohs(udphdr->src), ntohs(udphdr->dest)));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     0x%04"X16_F"    | (len, chksum)\n",\r
+                          ntohs(udphdr->len), ntohs(udphdr->chksum)));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));\r
+}\r
+#endif /* UDP_DEBUG */\r
+\r
+#endif /* LWIP_UDP */\r
index 634405b714f1f6465a4991386bf2344af12adddd..04307e7432baffa337e9ae6b0741ae1145a8c084 100644 (file)
-/*
- * 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__ */
-    
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_ICMP_H__\r
+#define __LWIP_ICMP_H__\r
+\r
+#include "lwip/arch.h"\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/pbuf.h"\r
+\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+\r
+#define ICMP_ER 0      /* echo reply */\r
+#define ICMP_DUR 3     /* destination unreachable */\r
+#define ICMP_SQ 4      /* source quench */\r
+#define ICMP_RD 5      /* redirect */\r
+#define ICMP_ECHO 8    /* echo */\r
+#define ICMP_TE 11     /* time exceeded */\r
+#define ICMP_PP 12     /* parameter problem */\r
+#define ICMP_TS 13     /* timestamp */\r
+#define ICMP_TSR 14    /* timestamp reply */\r
+#define ICMP_IRQ 15    /* information request */\r
+#define ICMP_IR 16     /* information reply */\r
+\r
+enum icmp_dur_type {\r
+  ICMP_DUR_NET = 0,    /* net unreachable */\r
+  ICMP_DUR_HOST = 1,   /* host unreachable */\r
+  ICMP_DUR_PROTO = 2,  /* protocol unreachable */\r
+  ICMP_DUR_PORT = 3,   /* port unreachable */\r
+  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */\r
+  ICMP_DUR_SR = 5      /* source route failed */\r
+};\r
+\r
+enum icmp_te_type {\r
+  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */\r
+  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */\r
+};\r
+\r
+void icmp_input(struct pbuf *p, struct netif *inp);\r
+\r
+void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);\r
+void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct icmp_echo_hdr {\r
+  PACK_STRUCT_FIELD(u16_t _type_code);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+  PACK_STRUCT_FIELD(u16_t id);\r
+  PACK_STRUCT_FIELD(u16_t seqno);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+\r
+PACK_STRUCT_BEGIN\r
+struct icmp_dur_hdr {\r
+  PACK_STRUCT_FIELD(u16_t _type_code);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+  PACK_STRUCT_FIELD(u32_t unused);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+\r
+PACK_STRUCT_BEGIN\r
+struct icmp_te_hdr {\r
+  PACK_STRUCT_FIELD(u16_t _type_code);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+  PACK_STRUCT_FIELD(u32_t unused);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)\r
+#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)\r
+\r
+#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))\r
+#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))\r
+\r
+#endif /* __LWIP_ICMP_H__ */\r
+    \r
index 57a55a3773da131ec0cb9eb0fb599c8ad2cab102..9e77b74c33a11d59c6e961603295610abd782f9c 100644 (file)
@@ -1,99 +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__ */
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_INET_H__\r
+#define __LWIP_INET_H__\r
+\r
+#include "lwip/arch.h"\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+\r
+u16_t inet_chksum(void *dataptr, u16_t len);\r
+#if 0 /* optimized routine */\r
+u16_t inet_chksum4(u8_t *dataptr, u16_t len);\r
+#endif\r
+u16_t inet_chksum_pbuf(struct pbuf *p);\r
+u16_t inet_chksum_pseudo(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u16_t proto_len);\r
+\r
+u32_t inet_addr(const char *cp);\r
+int inet_aton(const char *cp, struct in_addr *addr);\r
+char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */\r
+\r
+#ifdef htons\r
+#undef htons\r
+#endif /* htons */\r
+#ifdef htonl\r
+#undef htonl\r
+#endif /* htonl */\r
+#ifdef ntohs\r
+#undef ntohs\r
+#endif /* ntohs */\r
+#ifdef ntohl\r
+#undef ntohl\r
+#endif /* ntohl */\r
+\r
+#ifndef LWIP_PLATFORM_BYTESWAP\r
+#define LWIP_PLATFORM_BYTESWAP 0\r
+#endif\r
+\r
+#if BYTE_ORDER == BIG_ENDIAN\r
+#define htons(x) (x)\r
+#define ntohs(x) (x)\r
+#define htonl(x) (x)\r
+#define ntohl(x) (x)\r
+#else /* BYTE_ORDER != BIG_ENDIAN */\r
+#ifdef LWIP_PREFIX_BYTEORDER_FUNCS\r
+/* workaround for naming collisions on some platforms */\r
+#define htons lwip_htons\r
+#define ntohs lwip_ntohs\r
+#define htonl lwip_htonl\r
+#define ntohl lwip_ntohl\r
+#endif\r
+#if LWIP_PLATFORM_BYTESWAP\r
+#define htons(x) LWIP_PLATFORM_HTONS(x)\r
+#define ntohs(x) LWIP_PLATFORM_HTONS(x)\r
+#define htonl(x) LWIP_PLATFORM_HTONL(x)\r
+#define ntohl(x) LWIP_PLATFORM_HTONL(x)\r
+#else\r
+u16_t htons(u16_t x);\r
+u16_t ntohs(u16_t x);\r
+u32_t htonl(u32_t x);\r
+u32_t ntohl(u32_t x);\r
+#endif\r
+\r
+#endif\r
+\r
+#endif /* __LWIP_INET_H__ */\r
+\r
index 9f745f5d90017f67f23dee1e2f94a7f77be49849..e5a8da0a9d5042f9190cdbdd6b89454faa22e7dc 100644 (file)
-/*
- * 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__ */
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_IP_H__\r
+#define __LWIP_IP_H__\r
+\r
+#include "lwip/arch.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+\r
+#include "lwip/err.h"\r
+\r
+\r
+void ip_init(void);\r
+struct netif *ip_route(struct ip_addr *dest);\r
+err_t ip_input(struct pbuf *p, struct netif *inp);\r
+err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+    u8_t ttl, u8_t tos, u8_t proto);\r
+err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t ttl, u8_t tos, u8_t proto,\r
+       struct netif *netif);\r
+\r
+#define IP_HLEN 20\r
+\r
+#define IP_PROTO_ICMP 1\r
+#define IP_PROTO_UDP 17\r
+#define IP_PROTO_UDPLITE 136\r
+#define IP_PROTO_TCP 6\r
+\r
+/* This is passed as the destination address to ip_output_if (not\r
+   to ip_output), meaning that an IP header already is constructed\r
+   in the pbuf. This is used when TCP retransmits. */\r
+#ifdef IP_HDRINCL\r
+#undef IP_HDRINCL\r
+#endif /* IP_HDRINCL */\r
+#define IP_HDRINCL  NULL\r
+\r
+\r
+/* This is the common part of all PCB types. It needs to be at the\r
+   beginning of a PCB type definition. It is located here so that\r
+   changes to this common part are made in one location instead of\r
+   having to change all PCB structs. */\r
+#define IP_PCB struct ip_addr local_ip; \\r
+  struct ip_addr remote_ip; \\r
+   /* Socket options */  \\r
+  u16_t so_options;      \\r
+   /* Type Of Service */ \\r
+  u8_t tos;              \\r
+  /* Time To Live */     \\r
+  u8_t ttl\r
+\r
+/*\r
+ * Option flags per-socket. These are the same like SO_XXX.\r
+ */\r
+#define SOF_DEBUG     (u16_t)0x0001U    /* turn on debugging info recording */\r
+#define SOF_ACCEPTCONN  (u16_t)0x0002U    /* socket has had listen() */\r
+#define SOF_REUSEADDR (u16_t)0x0004U    /* allow local address reuse */\r
+#define SOF_KEEPALIVE (u16_t)0x0008U    /* keep connections alive */\r
+#define SOF_DONTROUTE (u16_t)0x0010U    /* just use interface addresses */\r
+#define SOF_BROADCAST (u16_t)0x0020U    /* permit sending of broadcast msgs */\r
+#define SOF_USELOOPBACK (u16_t)0x0040U    /* bypass hardware when possible */\r
+#define SOF_LINGER      (u16_t)0x0080U    /* linger on close if data present */\r
+#define SOF_OOBINLINE (u16_t)0x0100U    /* leave received OOB data in line */\r
+#define SOF_REUSEPORT (u16_t)0x0200U    /* allow local address & port reuse */\r
+\r
+\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ip_hdr {\r
+  /* version / header length / type of service */\r
+  PACK_STRUCT_FIELD(u16_t _v_hl_tos);\r
+  /* total length */\r
+  PACK_STRUCT_FIELD(u16_t _len);\r
+  /* identification */\r
+  PACK_STRUCT_FIELD(u16_t _id);\r
+  /* fragment offset field */\r
+  PACK_STRUCT_FIELD(u16_t _offset);\r
+#define IP_RF 0x8000        /* reserved fragment flag */\r
+#define IP_DF 0x4000        /* dont fragment flag */\r
+#define IP_MF 0x2000        /* more fragments flag */\r
+#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */\r
+  /* time to live / protocol*/\r
+  PACK_STRUCT_FIELD(u16_t _ttl_proto);\r
+  /* checksum */\r
+  PACK_STRUCT_FIELD(u16_t _chksum);\r
+  /* source and destination IP addresses */\r
+  PACK_STRUCT_FIELD(struct ip_addr src);\r
+  PACK_STRUCT_FIELD(struct ip_addr dest); \r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#define IPH_V(hdr)  (ntohs((hdr)->_v_hl_tos) >> 12)\r
+#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)\r
+#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)\r
+#define IPH_LEN(hdr) ((hdr)->_len)\r
+#define IPH_ID(hdr) ((hdr)->_id)\r
+#define IPH_OFFSET(hdr) ((hdr)->_offset)\r
+#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)\r
+#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)\r
+#define IPH_CHKSUM(hdr) ((hdr)->_chksum)\r
+\r
+#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))\r
+#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)\r
+#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)\r
+#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)\r
+#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8)))\r
+#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))\r
+#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)\r
+\r
+#if IP_DEBUG\r
+void ip_debug_print(struct pbuf *p);\r
+#else\r
+#define ip_debug_print(p)\r
+#endif /* IP_DEBUG */\r
+\r
+#endif /* __LWIP_IP_H__ */\r
+\r
+\r
index d877ebebe8a271319686b5833e40977098688354..1f0f75481299d9e1dadfa37d67ac4f884efd69c8 100644 (file)
-/*
- * 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__ */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_IP_ADDR_H__\r
+#define __LWIP_IP_ADDR_H__\r
+\r
+#include "lwip/arch.h"\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ip_addr {\r
+  PACK_STRUCT_FIELD(u32_t addr);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/*\r
+ * struct ipaddr2 is used in the definition of the ARP packet format in\r
+ * order to support compilers that don't have structure packing.\r
+ */\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ip_addr2 {\r
+  PACK_STRUCT_FIELD(u16_t addrw[2]);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/* For compatibility with BSD code */\r
+struct in_addr {\r
+  u32_t s_addr;\r
+};\r
+\r
+struct netif;\r
+\r
+extern const struct ip_addr ip_addr_any;\r
+extern const struct ip_addr ip_addr_broadcast;\r
+\r
+/** IP_ADDR_ can be used as a fixed IP address\r
+ *  for the wildcard and the broadcast address\r
+ */\r
+#define IP_ADDR_ANY         ((struct ip_addr *)&ip_addr_any)\r
+#define IP_ADDR_BROADCAST   ((struct ip_addr *)&ip_addr_broadcast)\r
+\r
+#define INADDR_NONE         ((u32_t)0xffffffff)  /* 255.255.255.255 */\r
+#define INADDR_LOOPBACK     ((u32_t)0x7f000001)  /* 127.0.0.1 */\r
+\r
+/* Definitions of the bits in an Internet address integer.\r
+\r
+   On subnets, host and network parts are found according to\r
+   the subnet mask, not these masks.  */\r
+\r
+#define IN_CLASSA(a)        ((((u32_t)(a)) & 0x80000000) == 0)\r
+#define IN_CLASSA_NET       0xff000000\r
+#define IN_CLASSA_NSHIFT    24\r
+#define IN_CLASSA_HOST      (0xffffffff & ~IN_CLASSA_NET)\r
+#define IN_CLASSA_MAX       128\r
+\r
+#define IN_CLASSB(a)        ((((u32_t)(a)) & 0xc0000000) == 0x80000000)\r
+#define IN_CLASSB_NET       0xffff0000\r
+#define IN_CLASSB_NSHIFT    16\r
+#define IN_CLASSB_HOST      (0xffffffff & ~IN_CLASSB_NET)\r
+#define IN_CLASSB_MAX       65536\r
+\r
+#define IN_CLASSC(a)        ((((u32_t)(a)) & 0xe0000000) == 0xc0000000)\r
+#define IN_CLASSC_NET       0xffffff00\r
+#define IN_CLASSC_NSHIFT    8\r
+#define IN_CLASSC_HOST      (0xffffffff & ~IN_CLASSC_NET)\r
+\r
+#define IN_CLASSD(a)        (((u32_t)(a) & 0xf0000000) == 0xe0000000)\r
+#define IN_CLASSD_NET       0xf0000000          /* These ones aren't really */\r
+#define IN_CLASSD_NSHIFT    28                  /*   net and host fields, but */\r
+#define IN_CLASSD_HOST      0x0fffffff          /*   routing needn't know. */\r
+#define IN_MULTICAST(a)     IN_CLASSD(a)\r
+\r
+#define IN_EXPERIMENTAL(a)  (((u32_t)(a) & 0xf0000000) == 0xf0000000)\r
+#define IN_BADCLASS(a)      (((u32_t)(a) & 0xf0000000) == 0xf0000000)\r
+\r
+#define IN_LOOPBACKNET      127                 /* official! */\r
+\r
+#define IP4_ADDR(ipaddr, a,b,c,d) \\r
+        (ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \\r
+                               ((u32_t)((b) & 0xff) << 16) | \\r
+                               ((u32_t)((c) & 0xff) << 8) | \\r
+                                (u32_t)((d) & 0xff))\r
+\r
+#define ip_addr_set(dest, src) (dest)->addr = \\r
+                               ((src) == NULL? 0:\\r
+                               (src)->addr)\r
+/**\r
+ * Determine if two address are on the same network.\r
+ *\r
+ * @arg addr1 IP address 1\r
+ * @arg addr2 IP address 2\r
+ * @arg mask network identifier mask\r
+ * @return !0 if the network identifiers of both address match\r
+ */\r
+#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \\r
+                                              (mask)->addr) == \\r
+                                             ((addr2)->addr & \\r
+                                              (mask)->addr))\r
+#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)\r
+\r
+#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)\r
+\r
+u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);\r
+\r
+#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000)) == ntohl(0xe0000000))\r
+\r
+#define ip_addr_debug_print(debug, ipaddr) \\r
+        LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \\r
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \\r
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \\r
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \\r
+                ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0))\r
+\r
+/* These are cast to u16_t, with the intent that they are often arguments\r
+ * to printf using the U16_F format from cc.h. */\r
+#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)\r
+#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)\r
+#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)\r
+#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)\r
+\r
+#endif /* __LWIP_IP_ADDR_H__ */\r
index a326c1ce1357610652f0ae9dc19eb438479b2004..30be1a8f28a5e495d1a7269be8cc843d9641a099 100644 (file)
@@ -1,49 +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__ */
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Jani Monoses <jani@iv.ro>\r
+ *\r
+ */\r
+\r
+#ifndef __LWIP_IP_FRAG_H__\r
+#define __LWIP_IP_FRAG_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/err.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/ip_addr.h"\r
+\r
+void ip_frag_init(void);\r
+void ip_reass_tmr(void);\r
+struct pbuf * ip_reass(struct pbuf *p);\r
+err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest);\r
+\r
+#endif /* __LWIP_IP_FRAG_H__ */\r
+\r
+\r
index 7f0ad596666dda1c26b722d7bbcab568258620d1..1059eca2e3699280c23e26b8a52bf5772dc29957 100644 (file)
-/*
- * 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__ */
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_API_H__\r
+#define __LWIP_API_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+\r
+#include "lwip/ip.h"\r
+\r
+#include "lwip/raw.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+\r
+#include "lwip/err.h"\r
+\r
+#define NETCONN_NOCOPY 0x00\r
+#define NETCONN_COPY   0x01\r
+\r
+enum netconn_type {\r
+  NETCONN_TCP,\r
+  NETCONN_UDP,\r
+  NETCONN_UDPLITE,\r
+  NETCONN_UDPNOCHKSUM,\r
+  NETCONN_RAW\r
+};\r
+\r
+enum netconn_state {\r
+  NETCONN_NONE,\r
+  NETCONN_WRITE,\r
+  NETCONN_ACCEPT,\r
+  NETCONN_RECV,\r
+  NETCONN_CONNECT,\r
+  NETCONN_CLOSE\r
+};\r
+\r
+enum netconn_evt {\r
+  NETCONN_EVT_RCVPLUS,\r
+  NETCONN_EVT_RCVMINUS,\r
+  NETCONN_EVT_SENDPLUS,\r
+  NETCONN_EVT_SENDMINUS\r
+};\r
+\r
+struct netbuf {\r
+  struct pbuf *p, *ptr;\r
+  struct ip_addr *fromaddr;\r
+  u16_t fromport;\r
+  err_t err;\r
+};\r
+\r
+struct netconn {\r
+  enum netconn_type type;\r
+  enum netconn_state state;\r
+  union {\r
+    struct tcp_pcb *tcp;\r
+    struct udp_pcb *udp;\r
+    struct raw_pcb *raw;\r
+  } pcb;\r
+  err_t err;\r
+  sys_mbox_t mbox;\r
+  sys_mbox_t recvmbox;\r
+  sys_mbox_t acceptmbox;\r
+  sys_sem_t sem;\r
+  int socket;\r
+  u16_t recv_avail;\r
+  void (* callback)(struct netconn *, enum netconn_evt, u16_t len);\r
+};\r
+\r
+/* Network buffer functions: */\r
+struct netbuf *   netbuf_new      (void);\r
+void              netbuf_delete   (struct netbuf *buf);\r
+void *            netbuf_alloc    (struct netbuf *buf, u16_t size);\r
+void              netbuf_free     (struct netbuf *buf);\r
+void              netbuf_ref      (struct netbuf *buf,\r
+           void *dataptr, u16_t size);\r
+void              netbuf_chain    (struct netbuf *head,\r
+           struct netbuf *tail);\r
+\r
+u16_t             netbuf_len      (struct netbuf *buf);\r
+err_t             netbuf_data     (struct netbuf *buf,\r
+           void **dataptr, u16_t *len);\r
+s8_t              netbuf_next     (struct netbuf *buf);\r
+void              netbuf_first    (struct netbuf *buf);\r
+\r
+void              netbuf_copy     (struct netbuf *buf,\r
+           void *dataptr, u16_t len);\r
+void              netbuf_copy_partial(struct netbuf *buf, void *dataptr, \r
+              u16_t len, u16_t offset);\r
+struct ip_addr *  netbuf_fromaddr (struct netbuf *buf);\r
+u16_t             netbuf_fromport (struct netbuf *buf);\r
+\r
+/* Network connection functions: */\r
+struct netconn *  netconn_new     (enum netconn_type type);\r
+struct\r
+netconn *netconn_new_with_callback(enum netconn_type t,\r
+                                   void (*callback)(struct netconn *, enum netconn_evt, u16_t len));\r
+struct\r
+netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,\r
+                                   void (*callback)(struct netconn *, enum netconn_evt, u16_t len));\r
+err_t             netconn_delete  (struct netconn *conn);\r
+enum netconn_type netconn_type    (struct netconn *conn);\r
+err_t             netconn_peer    (struct netconn *conn,\r
+           struct ip_addr *addr,\r
+           u16_t *port);\r
+err_t             netconn_addr    (struct netconn *conn,\r
+           struct ip_addr **addr,\r
+           u16_t *port);\r
+err_t             netconn_bind    (struct netconn *conn,\r
+           struct ip_addr *addr,\r
+           u16_t port);\r
+err_t             netconn_connect (struct netconn *conn,\r
+           struct ip_addr *addr,\r
+           u16_t port);\r
+err_t             netconn_disconnect (struct netconn *conn);\r
+err_t             netconn_listen  (struct netconn *conn);\r
+struct netconn *  netconn_accept  (struct netconn *conn);\r
+struct netbuf *   netconn_recv    (struct netconn *conn);\r
+err_t             netconn_send    (struct netconn *conn,\r
+           struct netbuf *buf);\r
+err_t             netconn_write   (struct netconn *conn,\r
+           void *dataptr, u16_t size,\r
+           u8_t copy);\r
+err_t             netconn_close   (struct netconn *conn);\r
+\r
+err_t             netconn_err     (struct netconn *conn);\r
+\r
+#endif /* __LWIP_API_H__ */\r
+\r
+\r
index 3fef3dd0c5ee6172c117ff983a801bef27eb1e34..87f3db5f12c2e906fe2ed1fb0ea558d1aea9b138 100644 (file)
@@ -1,94 +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__ */
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_API_MSG_H__\r
+#define __LWIP_API_MSG_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+\r
+#include "lwip/ip.h"\r
+\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+\r
+#include "lwip/api.h"\r
+\r
+enum api_msg_type {\r
+  API_MSG_NEWCONN,\r
+  API_MSG_DELCONN,\r
+  \r
+  API_MSG_BIND,\r
+  API_MSG_CONNECT,\r
+  API_MSG_DISCONNECT,\r
+\r
+  API_MSG_LISTEN,\r
+  API_MSG_ACCEPT,\r
+\r
+  API_MSG_SEND,\r
+  API_MSG_RECV,\r
+  API_MSG_WRITE,\r
+\r
+  API_MSG_CLOSE,\r
+  \r
+  API_MSG_MAX\r
+};\r
+\r
+struct api_msg_msg {\r
+  struct netconn *conn;\r
+  enum netconn_type conntype;\r
+  union {\r
+    struct pbuf *p;   \r
+    struct  {\r
+      struct ip_addr *ipaddr;\r
+      u16_t port;\r
+    } bc;\r
+    struct {\r
+      void *dataptr;\r
+      u16_t len;\r
+      u8_t copy;\r
+    } w;    \r
+    sys_mbox_t mbox;\r
+    u16_t len;\r
+  } msg;\r
+};\r
+\r
+struct api_msg {\r
+  enum api_msg_type type;\r
+  struct api_msg_msg msg;\r
+};\r
+\r
+void api_msg_input(struct api_msg *msg);\r
+void api_msg_post(struct api_msg *msg);\r
+\r
+#endif /* __LWIP_API_MSG_H__ */\r
+\r
index 356a016fa97f0baf3c954328a658f3df611513ca..b43dd6445e5f303a90768d63763b99c25f8137ae 100644 (file)
-/*
- * 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 */
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_ARCH_H__\r
+#define __LWIP_ARCH_H__\r
+\r
+#ifndef LITTLE_ENDIAN\r
+#define LITTLE_ENDIAN 1234\r
+#endif\r
+\r
+#ifndef BIG_ENDIAN\r
+#define BIG_ENDIAN 4321\r
+#endif\r
+\r
+#include "arch/cc.h"\r
+\r
+#ifndef PACK_STRUCT_BEGIN\r
+#define PACK_STRUCT_BEGIN\r
+#endif /* PACK_STRUCT_BEGIN */\r
+\r
+#ifndef PACK_STRUCT_END\r
+#define PACK_STRUCT_END\r
+#endif /* PACK_STRUCT_END */\r
+\r
+#ifndef PACK_STRUCT_FIELD\r
+#define PACK_STRUCT_FIELD(x) x\r
+#endif /* PACK_STRUCT_FIELD */\r
+\r
 #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__ */
+\r
+#ifdef LWIP_PROVIDE_ERRNO\r
+\r
+#define  EPERM     1  /* Operation not permitted */\r
+#define  ENOENT     2  /* No such file or directory */\r
+#define  ESRCH     3  /* No such process */\r
+#define  EINTR     4  /* Interrupted system call */\r
+#define  EIO     5  /* I/O error */\r
+#define  ENXIO     6  /* No such device or address */\r
+#define  E2BIG     7  /* Arg list too long */\r
+#define  ENOEXEC     8  /* Exec format error */\r
+#define  EBADF     9  /* Bad file number */\r
+#define  ECHILD    10  /* No child processes */\r
+#define  EAGAIN    11  /* Try again */\r
+#define  ENOMEM    12  /* Out of memory */\r
+#define  EACCES    13  /* Permission denied */\r
+#define  EFAULT    14  /* Bad address */\r
+#define  ENOTBLK    15  /* Block device required */\r
+#define  EBUSY    16  /* Device or resource busy */\r
+#define  EEXIST    17  /* File exists */\r
+#define  EXDEV    18  /* Cross-device link */\r
+#define  ENODEV    19  /* No such device */\r
+#define  ENOTDIR    20  /* Not a directory */\r
+#define  EISDIR    21  /* Is a directory */\r
+#define  EINVAL    22  /* Invalid argument */\r
+#define  ENFILE    23  /* File table overflow */\r
+#define  EMFILE    24  /* Too many open files */\r
+#define  ENOTTY    25  /* Not a typewriter */\r
+#define  ETXTBSY    26  /* Text file busy */\r
+#define  EFBIG    27  /* File too large */\r
+#define  ENOSPC    28  /* No space left on device */\r
+#define  ESPIPE    29  /* Illegal seek */\r
+#define  EROFS    30  /* Read-only file system */\r
+#define  EMLINK    31  /* Too many links */\r
+#define  EPIPE    32  /* Broken pipe */\r
+#define  EDOM    33  /* Math argument out of domain of func */\r
+#define  ERANGE    34  /* Math result not representable */\r
+#define  EDEADLK    35  /* Resource deadlock would occur */\r
+#define  ENAMETOOLONG  36  /* File name too long */\r
+#define  ENOLCK    37  /* No record locks available */\r
+#define  ENOSYS    38  /* Function not implemented */\r
+#define  ENOTEMPTY  39  /* Directory not empty */\r
+#define  ELOOP    40  /* Too many symbolic links encountered */\r
+#define  EWOULDBLOCK  EAGAIN  /* Operation would block */\r
+#define  ENOMSG    42  /* No message of desired type */\r
+#define  EIDRM    43  /* Identifier removed */\r
+#define  ECHRNG    44  /* Channel number out of range */\r
+#define  EL2NSYNC  45  /* Level 2 not synchronized */\r
+#define  EL3HLT    46  /* Level 3 halted */\r
+#define  EL3RST    47  /* Level 3 reset */\r
+#define  ELNRNG    48  /* Link number out of range */\r
+#define  EUNATCH    49  /* Protocol driver not attached */\r
+#define  ENOCSI    50  /* No CSI structure available */\r
+#define  EL2HLT    51  /* Level 2 halted */\r
+#define  EBADE    52  /* Invalid exchange */\r
+#define  EBADR    53  /* Invalid request descriptor */\r
+#define  EXFULL    54  /* Exchange full */\r
+#define  ENOANO    55  /* No anode */\r
+#define  EBADRQC    56  /* Invalid request code */\r
+#define  EBADSLT    57  /* Invalid slot */\r
+\r
+#define  EDEADLOCK  EDEADLK\r
+\r
+#define  EBFONT    59  /* Bad font file format */\r
+#define  ENOSTR    60  /* Device not a stream */\r
+#define  ENODATA    61  /* No data available */\r
+#define  ETIME    62  /* Timer expired */\r
+#define  ENOSR    63  /* Out of streams resources */\r
+#define  ENONET    64  /* Machine is not on the network */\r
+#define  ENOPKG    65  /* Package not installed */\r
+#define  EREMOTE    66  /* Object is remote */\r
+#define  ENOLINK    67  /* Link has been severed */\r
+#define  EADV    68  /* Advertise error */\r
+#define  ESRMNT    69  /* Srmount error */\r
+#define  ECOMM    70  /* Communication error on send */\r
+#define  EPROTO    71  /* Protocol error */\r
+#define  EMULTIHOP  72  /* Multihop attempted */\r
+#define  EDOTDOT    73  /* RFS specific error */\r
+#define  EBADMSG    74  /* Not a data message */\r
+#define  EOVERFLOW  75  /* Value too large for defined data type */\r
+#define  ENOTUNIQ  76  /* Name not unique on network */\r
+#define  EBADFD    77  /* File descriptor in bad state */\r
+#define  EREMCHG    78  /* Remote address changed */\r
+#define  ELIBACC    79  /* Can not access a needed shared library */\r
+#define  ELIBBAD    80  /* Accessing a corrupted shared library */\r
+#define  ELIBSCN    81  /* .lib section in a.out corrupted */\r
+#define  ELIBMAX    82  /* Attempting to link in too many shared libraries */\r
+#define  ELIBEXEC  83  /* Cannot exec a shared library directly */\r
+#define  EILSEQ    84  /* Illegal byte sequence */\r
+#define  ERESTART  85  /* Interrupted system call should be restarted */\r
+#define  ESTRPIPE  86  /* Streams pipe error */\r
+#define  EUSERS    87  /* Too many users */\r
+#define  ENOTSOCK  88  /* Socket operation on non-socket */\r
+#define  EDESTADDRREQ  89  /* Destination address required */\r
+#define  EMSGSIZE  90  /* Message too long */\r
+#define  EPROTOTYPE  91  /* Protocol wrong type for socket */\r
+#define  ENOPROTOOPT  92  /* Protocol not available */\r
+#define  EPROTONOSUPPORT  93  /* Protocol not supported */\r
+#define  ESOCKTNOSUPPORT  94  /* Socket type not supported */\r
+#define  EOPNOTSUPP  95  /* Operation not supported on transport endpoint */\r
+#define  EPFNOSUPPORT  96  /* Protocol family not supported */\r
+#define  EAFNOSUPPORT  97  /* Address family not supported by protocol */\r
+#define  EADDRINUSE  98  /* Address already in use */\r
+#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */\r
+#define  ENETDOWN  100  /* Network is down */\r
+#define  ENETUNREACH  101  /* Network is unreachable */\r
+#define  ENETRESET  102  /* Network dropped connection because of reset */\r
+#define  ECONNABORTED  103  /* Software caused connection abort */\r
+#define  ECONNRESET  104  /* Connection reset by peer */\r
+#define  ENOBUFS    105  /* No buffer space available */\r
+#define  EISCONN    106  /* Transport endpoint is already connected */\r
+#define  ENOTCONN  107  /* Transport endpoint is not connected */\r
+#define  ESHUTDOWN  108  /* Cannot send after transport endpoint shutdown */\r
+#define  ETOOMANYREFS  109  /* Too many references: cannot splice */\r
+#define  ETIMEDOUT  110  /* Connection timed out */\r
+#define  ECONNREFUSED  111  /* Connection refused */\r
+#define  EHOSTDOWN  112  /* Host is down */\r
+#define  EHOSTUNREACH  113  /* No route to host */\r
+#define  EALREADY  114  /* Operation already in progress */\r
+#define  EINPROGRESS  115  /* Operation now in progress */\r
+#define  ESTALE    116  /* Stale NFS file handle */\r
+#define  EUCLEAN    117  /* Structure needs cleaning */\r
+#define  ENOTNAM    118  /* Not a XENIX named type file */\r
+#define  ENAVAIL    119  /* No XENIX semaphores available */\r
+#define  EISNAM    120  /* Is a named type file */\r
+#define  EREMOTEIO  121  /* Remote I/O error */\r
+#define  EDQUOT    122  /* Quota exceeded */\r
+\r
+#define  ENOMEDIUM  123  /* No medium found */\r
+#define  EMEDIUMTYPE  124  /* Wrong medium type */\r
+\r
+\r
+#define ENSROK    0 /* DNS server returned answer with no data */\r
+#define ENSRNODATA  160 /* DNS server returned answer with no data */\r
+#define ENSRFORMERR 161 /* DNS server claims query was misformatted */\r
+#define ENSRSERVFAIL 162  /* DNS server returned general failure */\r
+#define ENSRNOTFOUND 163  /* Domain name not found */\r
+#define ENSRNOTIMP  164 /* DNS server does not implement requested operation */\r
+#define ENSRREFUSED 165 /* DNS server refused query */\r
+#define ENSRBADQUERY 166  /* Misformatted DNS query */\r
+#define ENSRBADNAME 167 /* Misformatted domain name */\r
+#define ENSRBADFAMILY 168 /* Unsupported address family */\r
+#define ENSRBADRESP 169 /* Misformatted DNS reply */\r
+#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */\r
+#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */\r
+#define ENSROF    172 /* End of file */\r
+#define ENSRFILE  173 /* Error reading file */\r
+#define ENSRNOMEM 174 /* Out of memory */\r
+#define ENSRDESTRUCTION 175 /* Application terminated lookup */\r
+#define ENSRQUERYDOMAINTOOLONG  176 /* Domain name is too long */\r
+#define ENSRCNAMELOOP 177 /* Domain name is too long */\r
+\r
+#ifndef errno\r
+extern int errno;\r
+#endif\r
+\r
+#endif /* LWIP_PROVIDE_ERRNO */\r
+\r
+#endif /* __LWIP_ARCH_H__ */\r
index 8f63a7b625e736543a98961a9a60f3ec4367ea04..3649cbd6ce4b13c73174beda8003d7dc7297741b 100644 (file)
@@ -1,87 +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__ */
-
-
-
-
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_DEBUG_H__\r
+#define __LWIP_DEBUG_H__\r
+\r
+#include "arch/cc.h"\r
+\r
+/** lower two bits indicate debug level\r
+ * - 0 off\r
+ * - 1 warning\r
+ * - 2 serious\r
+ * - 3 severe\r
+ */\r
+\r
+#define DBG_LEVEL_OFF     0\r
+#define DBG_LEVEL_WARNING 1  /* bad checksums, dropped packets, ... */\r
+#define DBG_LEVEL_SERIOUS 2  /* memory allocation failures, ... */\r
+#define DBG_LEVEL_SEVERE  3  /* */ \r
+#define DBG_MASK_LEVEL    3\r
+\r
+/** flag for LWIP_DEBUGF to enable that debug message */\r
+#define DBG_ON  0x80U\r
+/** flag for LWIP_DEBUGF to disable that debug message */\r
+#define DBG_OFF 0x00U\r
+\r
+/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */\r
+#define DBG_TRACE   0x40U\r
+/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */\r
+#define DBG_STATE   0x20U\r
+/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */\r
+#define DBG_FRESH   0x10U\r
+/** flag for LWIP_DEBUGF to halt after printing this debug message */\r
+#define DBG_HALT    0x08U\r
+\r
+#ifndef LWIP_NOASSERT\r
+#  define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0)\r
+#else\r
+#  define LWIP_ASSERT(x,y) \r
+#endif\r
+\r
+#ifdef LWIP_DEBUG\r
+/** print debug message only if debug message type is enabled...\r
+ *  AND is of correct type AND is at least DBG_LEVEL\r
+ */\r
+#  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)\r
+#  define LWIP_ERROR(x)   do { LWIP_PLATFORM_DIAG(x); } while(0)  \r
+#else /* LWIP_DEBUG */\r
+#  define LWIP_DEBUGF(debug,x) \r
+#  define LWIP_ERROR(x)  \r
+#endif /* LWIP_DEBUG */\r
+\r
+#endif /* __LWIP_DEBUG_H__ */\r
+\r
+\r
+\r
+\r
+\r
+\r
index eba9b8774dbbb8ed834f113bb9d42a6365de63a5..f26bdd0406f74b773e1f19e20d3ddafb5a40c875 100644 (file)
@@ -1,47 +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__ */
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_DEF_H__\r
+#define __LWIP_DEF_H__\r
+\r
+/* this might define NULL already */\r
+#include "arch/cc.h"\r
+\r
+#define LWIP_MAX(x , y)  (x) > (y) ? (x) : (y)\r
+#define LWIP_MIN(x , y)  (x) < (y) ? (x) : (y)\r
+\r
+#ifndef NULL\r
+#define NULL ((void *)0)\r
+#endif\r
+\r
+\r
+#endif /* __LWIP_DEF_H__ */\r
+\r
index bfe753f26a8bd2bdb7c9abe6dd6d349ff57aeddd..df51bdc96e5cf64ee6f2b098a63419ac0b2bf9e9 100644 (file)
-/** @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__*/
+/** @file\r
+ */\r
+\r
+#ifndef __LWIP_DHCP_H__\r
+#define __LWIP_DHCP_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/udp.h"\r
+\r
+/** period (in seconds) of the application calling dhcp_coarse_tmr() */\r
+#define DHCP_COARSE_TIMER_SECS 60 \r
+/** period (in milliseconds) of the application calling dhcp_fine_tmr() */\r
+#define DHCP_FINE_TIMER_MSECS 500 \r
+\r
+struct dhcp\r
+{\r
+  /** current DHCP state machine state */\r
+  u8_t state;\r
+  /** retries of current request */\r
+  u8_t tries;\r
+  /** transaction identifier of last sent request */ \r
+  u32_t xid;\r
+  /** our connection to the DHCP server */ \r
+  struct udp_pcb *pcb;\r
+  /** (first) pbuf of incoming msg */\r
+  struct pbuf *p;\r
+  /** incoming msg */\r
+  struct dhcp_msg *msg_in;\r
+  /** incoming msg options */\r
+  struct dhcp_msg *options_in; \r
+  /** ingoing msg options length */\r
+  u16_t options_in_len;\r
+\r
+  struct pbuf *p_out; /* pbuf of outcoming msg */\r
+  struct dhcp_msg *msg_out; /* outgoing msg */\r
+  u16_t options_out_len; /* outgoing msg options length */\r
+  u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */\r
+  u16_t t1_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */\r
+  u16_t t2_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */\r
+  struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */\r
+  struct ip_addr offered_ip_addr;\r
+  struct ip_addr offered_sn_mask;\r
+  struct ip_addr offered_gw_addr;\r
+  struct ip_addr offered_bc_addr;\r
+#define DHCP_MAX_DNS 2\r
+  u32_t dns_count; /* actual number of DNS servers obtained */\r
+  struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */\r
\r
+  u32_t offered_t0_lease; /* lease period (in seconds) */\r
+  u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */\r
+  u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period)  */\r
+/** Patch #1308\r
+ *  TODO: See dhcp.c "TODO"s\r
+ */\r
+#if 0\r
+  struct ip_addr offered_si_addr;\r
+  u8_t *boot_file_name;\r
+#endif\r
+};\r
+\r
+/* MUST be compiled with "pack structs" or equivalent! */\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+/** minimum set of fields of any DHCP message */\r
+struct dhcp_msg\r
+{\r
+  PACK_STRUCT_FIELD(u8_t op);\r
+  PACK_STRUCT_FIELD(u8_t htype);\r
+  PACK_STRUCT_FIELD(u8_t hlen);\r
+  PACK_STRUCT_FIELD(u8_t hops);\r
+  PACK_STRUCT_FIELD(u32_t xid);\r
+  PACK_STRUCT_FIELD(u16_t secs);\r
+  PACK_STRUCT_FIELD(u16_t flags);\r
+  PACK_STRUCT_FIELD(struct ip_addr ciaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr yiaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr siaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr giaddr);\r
+#define DHCP_CHADDR_LEN 16U\r
+  PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);\r
+#define DHCP_SNAME_LEN 64U\r
+  PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);\r
+#define DHCP_FILE_LEN 128U\r
+  PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);\r
+  PACK_STRUCT_FIELD(u32_t cookie);\r
+#define DHCP_MIN_OPTIONS_LEN 68U\r
+/** make sure user does not configure this too small */\r
+#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))\r
+#  undef DHCP_OPTIONS_LEN\r
+#endif\r
+/** allow this to be configured in lwipopts.h, but not too small */\r
+#if (!defined(DHCP_OPTIONS_LEN))\r
+/** set this to be sufficient for your options in outgoing DHCP msgs */\r
+#  define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN\r
+#endif\r
+  PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/** start DHCP configuration */\r
+err_t dhcp_start(struct netif *netif);\r
+/** enforce early lease renewal (not needed normally)*/\r
+err_t dhcp_renew(struct netif *netif);\r
+/** release the DHCP lease, usually called before dhcp_stop()*/\r
+err_t dhcp_release(struct netif *netif);\r
+/** stop DHCP configuration */\r
+void dhcp_stop(struct netif *netif);\r
+/** inform server of our manual IP address */\r
+void dhcp_inform(struct netif *netif);\r
+\r
+/** if enabled, check whether the offered IP address is not in use, using ARP */\r
+#if DHCP_DOES_ARP_CHECK\r
+void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);\r
+#endif\r
+\r
+/** to be called every minute */\r
+void dhcp_coarse_tmr(void);\r
+/** to be called every half second */\r
+void dhcp_fine_tmr(void);\r
\r
+/** DHCP message item offsets and length */\r
+#define DHCP_MSG_OFS (UDP_DATA_OFS)  \r
+  #define DHCP_OP_OFS (DHCP_MSG_OFS + 0)\r
+  #define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)\r
+  #define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)\r
+  #define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)\r
+  #define DHCP_XID_OFS (DHCP_MSG_OFS + 4)\r
+  #define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)\r
+  #define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)\r
+  #define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)\r
+  #define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)\r
+  #define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)\r
+  #define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)\r
+  #define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)\r
+  #define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)\r
+  #define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)\r
+#define DHCP_MSG_LEN 236\r
+\r
+#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)\r
+#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)\r
+\r
+#define DHCP_CLIENT_PORT 68  \r
+#define DHCP_SERVER_PORT 67\r
+\r
+/** DHCP client states */\r
+#define DHCP_REQUESTING 1\r
+#define DHCP_INIT 2\r
+#define DHCP_REBOOTING 3\r
+#define DHCP_REBINDING 4\r
+#define DHCP_RENEWING 5\r
+#define DHCP_SELECTING 6\r
+#define DHCP_INFORMING 7\r
+#define DHCP_CHECKING 8\r
+#define DHCP_PERMANENT 9\r
+#define DHCP_BOUND 10\r
+/** not yet implemented #define DHCP_RELEASING 11 */\r
+#define DHCP_BACKING_OFF 12\r
+#define DHCP_OFF 13\r
\r
+#define DHCP_BOOTREQUEST 1\r
+#define DHCP_BOOTREPLY 2\r
+\r
+#define DHCP_DISCOVER 1\r
+#define DHCP_OFFER 2\r
+#define DHCP_REQUEST 3\r
+#define DHCP_DECLINE 4\r
+#define DHCP_ACK 5\r
+#define DHCP_NAK 6\r
+#define DHCP_RELEASE 7\r
+#define DHCP_INFORM 8\r
+\r
+#define DHCP_HTYPE_ETH 1\r
+\r
+#define DHCP_HLEN_ETH 6\r
+\r
+#define DHCP_BROADCAST_FLAG 15\r
+#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)\r
+\r
+/** BootP options */\r
+#define DHCP_OPTION_PAD 0\r
+#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */\r
+#define DHCP_OPTION_ROUTER 3\r
+#define DHCP_OPTION_DNS_SERVER 6 \r
+#define DHCP_OPTION_HOSTNAME 12\r
+#define DHCP_OPTION_IP_TTL 23\r
+#define DHCP_OPTION_MTU 26\r
+#define DHCP_OPTION_BROADCAST 28\r
+#define DHCP_OPTION_TCP_TTL 37\r
+#define DHCP_OPTION_END 255\r
+\r
+/** DHCP options */\r
+#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */\r
+#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */\r
+#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */\r
+\r
+#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */\r
+#define DHCP_OPTION_MESSAGE_TYPE_LEN 1\r
+\r
+\r
+#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */\r
+#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */\r
+\r
+#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */\r
+#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2\r
+\r
+#define DHCP_OPTION_T1 58 /* T1 renewal time */\r
+#define DHCP_OPTION_T2 59 /* T2 rebinding time */\r
+#define DHCP_OPTION_CLIENT_ID 61\r
+#define DHCP_OPTION_TFTP_SERVERNAME 66\r
+#define DHCP_OPTION_BOOTFILE 67\r
+\r
+/** possible combinations of overloading the file and sname fields with options */\r
+#define DHCP_OVERLOAD_NONE 0\r
+#define DHCP_OVERLOAD_FILE 1\r
+#define DHCP_OVERLOAD_SNAME  2\r
+#define DHCP_OVERLOAD_SNAME_FILE 3\r
+\r
+#endif /*__LWIP_DHCP_H__*/\r
index c92cb26d7693e422706442c74715fbdc939e1417..fc90f2eabadb9418db10aa6ff8c6d9437c096736 100644 (file)
@@ -1,70 +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__ */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_ERR_H__\r
+#define __LWIP_ERR_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "arch/cc.h"\r
+\r
+typedef s8_t err_t;\r
+\r
+/* Definitions for error constants. */\r
+\r
+#define ERR_OK    0      /* No error, everything OK. */\r
+#define ERR_MEM  -1      /* Out of memory error.     */\r
+#define ERR_BUF  -2      /* Buffer error.            */\r
+\r
+\r
+#define ERR_ABRT -3      /* Connection aborted.      */\r
+#define ERR_RST  -4      /* Connection reset.        */\r
+#define ERR_CLSD -5      /* Connection closed.       */\r
+#define ERR_CONN -6      /* Not connected.           */\r
+\r
+#define ERR_VAL  -7      /* Illegal value.           */\r
+\r
+#define ERR_ARG  -8      /* Illegal argument.        */\r
+\r
+#define ERR_RTE  -9      /* Routing problem.         */\r
+\r
+#define ERR_USE  -10     /* Address in use.          */\r
+\r
+#define ERR_IF   -11     /* Low-level netif error    */\r
+#define ERR_ISCONN -12   /* Already connected.       */\r
+\r
+\r
+#ifdef LWIP_DEBUG\r
+extern char *lwip_strerr(err_t err);\r
+#else\r
+#define lwip_strerr(x) ""\r
+#endif /* LWIP_DEBUG */\r
+#endif /* __LWIP_ERR_H__ */\r
index f14d1768fe510d4af2fc698cdf55ee8ba8c27b94..3d57389b56a1a113daa32f5786d2ab27a2606786 100644 (file)
@@ -1,69 +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__ */
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_MEM_H__\r
+#define __LWIP_MEM_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/arch.h"\r
+\r
+#if MEM_SIZE > 64000l\r
+typedef u32_t mem_size_t;\r
+#define MEM_SIZE_F U32_F\r
+#else\r
+typedef u16_t mem_size_t;\r
+#define MEM_SIZE_F U16_F\r
+#endif /* MEM_SIZE > 64000 */\r
+\r
+#if MEM_LIBC_MALLOC\r
+/* aliases for C library malloc() */\r
+#define mem_init()\r
+#define mem_free(x) free(x)\r
+#define mem_malloc(x) malloc(x)\r
+#define mem_realloc(x, size) realloc(x,size)\r
+#else\r
+/* lwIP alternative malloc */\r
+void mem_init(void);\r
+void *mem_malloc(mem_size_t size);\r
+void mem_free(void *mem);\r
+void *mem_realloc(void *mem, mem_size_t size);\r
+#endif\r
+\r
+#ifndef MEM_ALIGN_SIZE\r
+#define MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))\r
+#endif\r
+\r
+#ifndef MEM_ALIGN\r
+#define MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))\r
+#endif\r
+\r
+#endif /* __LWIP_MEM_H__ */\r
+\r
index 1cd46fa3fe378de2a896ed0624a2e2ca8610d6ba..6da033f27d3ea5b3612d98db2d4bb2a81faad605 100644 (file)
@@ -1,63 +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__  */
-    
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#ifndef __LWIP_MEMP_H__\r
+#define __LWIP_MEMP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+typedef enum {\r
+  MEMP_PBUF,\r
+  MEMP_RAW_PCB,\r
+  MEMP_UDP_PCB,\r
+  MEMP_TCP_PCB,\r
+  MEMP_TCP_PCB_LISTEN,\r
+  MEMP_TCP_SEG,\r
+\r
+  MEMP_NETBUF,\r
+  MEMP_NETCONN,\r
+  MEMP_API_MSG,\r
+  MEMP_TCPIP_MSG,\r
+\r
+  MEMP_SYS_TIMEOUT,\r
+  \r
+  MEMP_MAX\r
+} memp_t;\r
+\r
+void memp_init(void);\r
+\r
+void *memp_malloc(memp_t type);\r
+void *memp_realloc(memp_t fromtype, memp_t totype, void *mem);\r
+void memp_free(memp_t type, void *mem);\r
+\r
+#endif /* __LWIP_MEMP_H__  */\r
+    \r
index b7737699296d46e81ffbb3981fbcbf519c48bc61..efc59fdc3eeeb09907c2a87bb1878b72eb4202b8 100644 (file)
-/*
- * 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__ */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_NETIF_H__\r
+#define __LWIP_NETIF_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/err.h"\r
+\r
+#include "lwip/ip_addr.h"\r
+\r
+#include "lwip/inet.h"\r
+#include "lwip/pbuf.h"\r
+#if LWIP_DHCP\r
+#  include "lwip/dhcp.h"\r
+#endif\r
+\r
+/** must be the maximum of all used hardware address lengths\r
+    across all types of interfaces in use */\r
+#define NETIF_MAX_HWADDR_LEN 6U\r
+\r
+/** TODO: define the use (where, when, whom) of netif flags */\r
+\r
+/** whether the network interface is 'up'. this is\r
+ * a software flag used to control whether this network\r
+ * interface is enabled and processes traffic.\r
+ */\r
+#define NETIF_FLAG_UP 0x1U\r
+/** if set, the netif has broadcast capability */\r
+#define NETIF_FLAG_BROADCAST 0x2U\r
+/** if set, the netif is one end of a point-to-point connection */\r
+#define NETIF_FLAG_POINTTOPOINT 0x4U\r
+/** if set, the interface is configured using DHCP */\r
+#define NETIF_FLAG_DHCP 0x08U\r
+/** if set, the interface has an active link\r
+ *  (set by the network interface driver) */\r
+#define NETIF_FLAG_LINK_UP 0x10U\r
+\r
+/** Generic data structure used for all lwIP network interfaces.\r
+ *  The following fields should be filled in by the initialization\r
+ *  function for the device driver: hwaddr_len, hwaddr[], mtu, flags */\r
+\r
+struct netif {\r
+  /** pointer to next in linked list */\r
+  struct netif *next;\r
+\r
+  /** IP address configuration in network byte order */\r
+  struct ip_addr ip_addr;\r
+  struct ip_addr netmask;\r
+  struct ip_addr gw;\r
+\r
+  /** This function is called by the network device driver\r
+   *  to pass a packet up the TCP/IP stack. */\r
+  err_t (* input)(struct pbuf *p, struct netif *inp);\r
+  /** This function is called by the IP module when it wants\r
+   *  to send a packet on the interface. This function typically\r
+   *  first resolves the hardware address, then sends the packet. */\r
+  err_t (* output)(struct netif *netif, struct pbuf *p,\r
+       struct ip_addr *ipaddr);\r
+  /** This function is called by the ARP module when it wants\r
+   *  to send a packet on the interface. This function outputs\r
+   *  the pbuf as-is on the link medium. */\r
+  err_t (* linkoutput)(struct netif *netif, struct pbuf *p);\r
+  /** This field can be set by the device driver and could point\r
+   *  to state information for the device. */\r
+  void *state;\r
+#if LWIP_DHCP\r
+  /** the DHCP client state information for this netif */\r
+  struct dhcp *dhcp;\r
+#endif\r
+  /** number of bytes used in hwaddr */\r
+  u8_t hwaddr_len;\r
+  /** link level hardware address of this interface */\r
+  u8_t hwaddr[NETIF_MAX_HWADDR_LEN];\r
+  /** maximum transfer unit (in bytes) */\r
+  u16_t mtu;\r
+  /** flags (see NETIF_FLAG_ above) */\r
+  u8_t flags;\r
+  /** descriptive abbreviation */\r
+  char name[2];\r
+  /** number of this interface */\r
+  u8_t num;\r
+#if LWIP_SNMP\r
+  /** link type (ifType values per RFC1213) */\r
+  u8_t link_type;\r
+  /** (estimate) link speed */\r
+  u32_t link_speed;\r
+  /** timestamp at last change made (up/down) */\r
+  u32_t ts;\r
+  /** counters */\r
+  u32_t ifinoctets;\r
+  u32_t ifinucastpkts;\r
+  u32_t ifinnucastpkts;\r
+  u32_t ifindiscards;\r
+  u32_t ifoutoctets;\r
+  u32_t ifoutucastpkts;\r
+  u32_t ifoutnucastpkts;\r
+  u32_t ifoutdiscards;\r
+#endif\r
+};\r
+\r
+/** The list of network interfaces. */\r
+extern struct netif *netif_list;\r
+/** The default network interface. */\r
+extern struct netif *netif_default;\r
+\r
+/* netif_init() must be called first. */\r
+void netif_init(void);\r
+\r
+struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,\r
+      struct ip_addr *gw,\r
+      void *state,\r
+      err_t (* init)(struct netif *netif),\r
+      err_t (* input)(struct pbuf *p, struct netif *netif));\r
+\r
+void\r
+netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,\r
+    struct ip_addr *gw);\r
+void netif_remove(struct netif * netif);\r
+\r
+/* Returns a network interface given its name. The name is of the form\r
+   "et0", where the first two letters are the "name" field in the\r
+   netif structure, and the digit is in the num field in the same\r
+   structure. */\r
+struct netif *netif_find(char *name);\r
+\r
+void netif_set_default(struct netif *netif);\r
+\r
+void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);\r
+void netif_set_netmask(struct netif *netif, struct ip_addr *netmast);\r
+void netif_set_gw(struct netif *netif, struct ip_addr *gw);\r
+void netif_set_up(struct netif *netif);\r
+void netif_set_down(struct netif *netif);\r
+u8_t netif_is_up(struct netif *netif);\r
+\r
+#endif /* __LWIP_NETIF_H__ */\r
index 546aa30357cefb90564f38c547081c6402f4ff81..0b187e1215f66f63b766c10407363b6ff7a16ea7 100644 (file)
-/*
- * 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__ */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#ifndef __LWIP_PBUF_H__\r
+#define __LWIP_PBUF_H__\r
+\r
+#include "arch/cc.h"\r
+\r
+\r
+#define PBUF_TRANSPORT_HLEN 20\r
+#define PBUF_IP_HLEN        20\r
+\r
+typedef enum {\r
+  PBUF_TRANSPORT,\r
+  PBUF_IP,\r
+  PBUF_LINK,\r
+  PBUF_RAW\r
+} pbuf_layer;\r
+\r
+typedef enum {\r
+  PBUF_RAM,\r
+  PBUF_ROM,\r
+  PBUF_REF,\r
+  PBUF_POOL\r
+} pbuf_flag;\r
+\r
+/* Definitions for the pbuf flag field. These are NOT the flags that\r
+ * are passed to pbuf_alloc(). */\r
+#define PBUF_FLAG_RAM   0x00U    /* Flags that pbuf data is stored in RAM */\r
+#define PBUF_FLAG_ROM   0x01U    /* Flags that pbuf data is stored in ROM */\r
+#define PBUF_FLAG_POOL  0x02U    /* Flags that the pbuf comes from the pbuf pool */\r
+#define PBUF_FLAG_REF   0x04U    /* Flags thet the pbuf payload refers to RAM */\r
+\r
+/** indicates this packet was broadcast on the link */\r
+#define PBUF_FLAG_LINK_BROADCAST 0x80U\r
+\r
+struct pbuf {\r
+  /** next pbuf in singly linked pbuf chain */\r
+  struct pbuf *next;\r
+\r
+  /** pointer to the actual data in the buffer */\r
+  void *payload;\r
+  \r
+  /**\r
+   * total length of this buffer and all next buffers in chain\r
+   * belonging to the same packet.\r
+   *\r
+   * For non-queue packet chains this is the invariant:\r
+   * p->tot_len == p->len + (p->next? p->next->tot_len: 0)\r
+   */\r
+  u16_t tot_len;\r
+  \r
+  /** length of this buffer */\r
+  u16_t len;  \r
+\r
+  /** flags telling the type of pbuf, see PBUF_FLAG_ */\r
+  u16_t flags;\r
+  \r
+  /**\r
+   * the reference count always equals the number of pointers\r
+   * that refer to this pbuf. This can be pointers from an application,\r
+   * the stack itself, or pbuf->next pointers from a chain.\r
+   */\r
+  u16_t ref;\r
+  \r
+};\r
+\r
+void pbuf_init(void);\r
+\r
+struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag);\r
+void pbuf_realloc(struct pbuf *p, u16_t size); \r
+u8_t pbuf_header(struct pbuf *p, s16_t header_size);\r
+void pbuf_ref(struct pbuf *p);\r
+void pbuf_ref_chain(struct pbuf *p);\r
+u8_t pbuf_free(struct pbuf *p);\r
+u8_t pbuf_clen(struct pbuf *p);  \r
+void pbuf_cat(struct pbuf *h, struct pbuf *t);\r
+void pbuf_chain(struct pbuf *h, struct pbuf *t);\r
+struct pbuf *pbuf_take(struct pbuf *f);\r
+struct pbuf *pbuf_dechain(struct pbuf *p);\r
+void pbuf_queue(struct pbuf *p, struct pbuf *n);\r
+struct pbuf * pbuf_dequeue(struct pbuf *p);\r
+\r
+#endif /* __LWIP_PBUF_H__ */\r
index 6f7a98717f0523ae957a73c8b118e259a974d893..83b32da9d67272cd85fa483d4249e7e1d8556a05 100644 (file)
@@ -1,74 +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__ */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_RAW_H__\r
+#define __LWIP_RAW_H__\r
+\r
+#include "lwip/arch.h"\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/ip.h"\r
+\r
+struct raw_pcb {\r
+/* Common members of all PCB types */\r
+  IP_PCB;\r
+\r
+  struct raw_pcb *next;\r
+\r
+  u16_t protocol;\r
+\r
+  u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,\r
+    struct ip_addr *addr);\r
+  void *recv_arg;\r
+};\r
+\r
+/* The following functions is the application layer interface to the\r
+   RAW code. */\r
+struct raw_pcb * raw_new        (u16_t proto);\r
+void             raw_remove     (struct raw_pcb *pcb);\r
+err_t            raw_bind       (struct raw_pcb *pcb, struct ip_addr *ipaddr);\r
+err_t            raw_connect    (struct raw_pcb *pcb, struct ip_addr *ipaddr);\r
+\r
+void             raw_recv       (struct raw_pcb *pcb,\r
+                                 u8_t (* recv)(void *arg, struct raw_pcb *pcb,\r
+                                              struct pbuf *p,\r
+                                              struct ip_addr *addr),\r
+                                 void *recv_arg);\r
+err_t            raw_sendto    (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);\r
+err_t            raw_send       (struct raw_pcb *pcb, struct pbuf *p);\r
+\r
+/* The following functions are the lower layer interface to RAW. */\r
+u8_t              raw_input      (struct pbuf *p, struct netif *inp);\r
+void             raw_init       (void);\r
+\r
+\r
+#endif /* __LWIP_RAW_H__ */\r
index 8a37aa35ab3eff4bc4f3d73e29d0c47c0f27dedf..5fc28a4d6d618748a4916c6228773bba642bc212 100644 (file)
@@ -1,63 +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
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ */\r
+\r
+/*\r
+ * This is the interface to the platform specific serial IO module\r
+ * It needs to be implemented by those platforms which need SLIP or PPP\r
+ */\r
+\r
+#include "arch/cc.h"\r
+\r
+#ifndef __sio_fd_t_defined\r
+typedef void * sio_fd_t;\r
+#endif\r
+\r
+#ifndef sio_open\r
+sio_fd_t sio_open(u8_t);\r
+#endif\r
+\r
+#ifndef sio_send\r
+void sio_send(u8_t, sio_fd_t);\r
+#endif\r
+\r
+#ifndef sio_recv\r
+u8_t sio_recv(sio_fd_t);\r
+#endif\r
+\r
+#ifndef sio_read\r
+u32_t sio_read(sio_fd_t, u8_t *, u32_t);\r
+#endif\r
+\r
+#ifndef sio_write\r
+u32_t sio_write(sio_fd_t, u8_t *, u32_t);\r
+#endif\r
+\r
+#ifndef sio_read_abort\r
+void sio_read_abort(sio_fd_t);\r
+#endif\r
index 95145ce0c2b5ac3bb5c282084133e67629cb33e2..987ebd90a29354ba30ea63af5c14a04c6b316ddf 100644 (file)
-/*
- * 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__ */
+/*\r
+ * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>\r
+ * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Leon Woestenberg <leon.woestenberg@axon.tv>\r
+ *\r
+ */\r
+#ifndef __LWIP_SNMP_H__\r
+#define __LWIP_SNMP_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/udp.h"\r
+\r
+/* SNMP support available? */\r
+#if defined(LWIP_SNMP) && (LWIP_SNMP > 0)\r
+\r
+/** fixed maximum length for object identifier type */\r
+#define LWIP_SNMP_OBJ_ID_LEN 32\r
+/** internal object identifier representation */\r
+struct snmp_obj_id\r
+{\r
+  u8_t len;\r
+  s32_t id[LWIP_SNMP_OBJ_ID_LEN];\r
+};\r
+\r
+/* system */\r
+void snmp_set_sysdesr(u8_t* str, u8_t* strlen);\r
+void snmp_set_sysobjid(struct snmp_obj_id *oid);\r
+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid);\r
+void snmp_inc_sysuptime(void);\r
+void snmp_get_sysuptime(u32_t *value);\r
+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen);\r
+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen);\r
+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen);\r
+\r
+/* network interface */\r
+void snmp_add_ifinoctets(struct netif *ni, u32_t value); \r
+void snmp_inc_ifinucastpkts(struct netif *ni);\r
+void snmp_inc_ifinnucastpkts(struct netif *ni);\r
+void snmp_inc_ifindiscards(struct netif *ni);\r
+void snmp_add_ifoutoctets(struct netif *ni, u32_t value);\r
+void snmp_inc_ifoutucastpkts(struct netif *ni);\r
+void snmp_inc_ifoutnucastpkts(struct netif *ni);\r
+void snmp_inc_ifoutdiscards(struct netif *ni);\r
+void snmp_inc_iflist(void);\r
+void snmp_dec_iflist(void);\r
+\r
+/* ARP (for atTable and ipNetToMediaTable) */\r
+void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip);\r
+void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip);\r
+\r
+/* IP */\r
+void snmp_inc_ipinreceives(void);\r
+void snmp_inc_ipinhdrerrors(void);\r
+void snmp_inc_ipinaddrerrors(void);\r
+void snmp_inc_ipforwdatagrams(void);\r
+void snmp_inc_ipinunknownprotos(void);\r
+void snmp_inc_ipindiscards(void);\r
+void snmp_inc_ipindelivers(void);\r
+void snmp_inc_ipoutrequests(void);\r
+void snmp_inc_ipoutdiscards(void);\r
+void snmp_inc_ipoutnoroutes(void);\r
+void snmp_inc_ipreasmreqds(void);\r
+void snmp_inc_ipreasmoks(void);\r
+void snmp_inc_ipreasmfails(void);\r
+void snmp_inc_ipfragoks(void);\r
+void snmp_inc_ipfragfails(void);\r
+void snmp_inc_ipfragcreates(void);\r
+void snmp_inc_iproutingdiscards(void);\r
+void snmp_insert_ipaddridx_tree(struct netif *ni);\r
+void snmp_delete_ipaddridx_tree(struct netif *ni);\r
+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni);\r
+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni);\r
+\r
+/* ICMP */\r
+void snmp_inc_icmpinmsgs(void);\r
+void snmp_inc_icmpinerrors(void);\r
+void snmp_inc_icmpindestunreachs(void);\r
+void snmp_inc_icmpintimeexcds(void);\r
+void snmp_inc_icmpinparmprobs(void);\r
+void snmp_inc_icmpinsrcquenchs(void);\r
+void snmp_inc_icmpinredirects(void);\r
+void snmp_inc_icmpinechos(void);\r
+void snmp_inc_icmpinechoreps(void);\r
+void snmp_inc_icmpintimestamps(void);\r
+void snmp_inc_icmpintimestampreps(void);\r
+void snmp_inc_icmpinaddrmasks(void);\r
+void snmp_inc_icmpinaddrmaskreps(void);\r
+void snmp_inc_icmpoutmsgs(void);\r
+void snmp_inc_icmpouterrors(void);\r
+void snmp_inc_icmpoutdestunreachs(void);\r
+void snmp_inc_icmpouttimeexcds(void);\r
+void snmp_inc_icmpoutparmprobs(void);\r
+void snmp_inc_icmpoutsrcquenchs(void);\r
+void snmp_inc_icmpoutredirects(void); \r
+void snmp_inc_icmpoutechos(void);\r
+void snmp_inc_icmpoutechoreps(void);\r
+void snmp_inc_icmpouttimestamps(void);\r
+void snmp_inc_icmpouttimestampreps(void);\r
+void snmp_inc_icmpoutaddrmasks(void);\r
+void snmp_inc_icmpoutaddrmaskreps(void);\r
+\r
+/* TCP */\r
+void snmp_inc_tcpactiveopens(void);\r
+void snmp_inc_tcppassiveopens(void);\r
+void snmp_inc_tcpattemptfails(void);\r
+void snmp_inc_tcpestabresets(void);\r
+void snmp_inc_tcpinsegs(void);\r
+void snmp_inc_tcpoutsegs(void);\r
+void snmp_inc_tcpretranssegs(void);\r
+void snmp_inc_tcpinerrs(void);\r
+void snmp_inc_tcpoutrsts(void);\r
+\r
+/* UDP */\r
+void snmp_inc_udpindatagrams(void);\r
+void snmp_inc_udpnoports(void);\r
+void snmp_inc_udpinerrors(void);\r
+void snmp_inc_udpoutdatagrams(void);\r
+void snmp_insert_udpidx_tree(struct udp_pcb *pcb);\r
+void snmp_delete_udpidx_tree(struct udp_pcb *pcb);\r
+\r
+/* SNMP */\r
+void snmp_inc_snmpinpkts(void);\r
+void snmp_inc_snmpoutpkts(void);\r
+void snmp_inc_snmpinbadversions(void);\r
+void snmp_inc_snmpinbadcommunitynames(void);\r
+void snmp_inc_snmpinbadcommunityuses(void);\r
+void snmp_inc_snmpinasnparseerrs(void);\r
+void snmp_inc_snmpintoobigs(void);\r
+void snmp_inc_snmpinnosuchnames(void);\r
+void snmp_inc_snmpinbadvalues(void);\r
+void snmp_inc_snmpinreadonlys(void);\r
+void snmp_inc_snmpingenerrs(void);\r
+void snmp_add_snmpintotalreqvars(u8_t value);\r
+void snmp_add_snmpintotalsetvars(u8_t value);\r
+void snmp_inc_snmpingetrequests(void);\r
+void snmp_inc_snmpingetnexts(void);\r
+void snmp_inc_snmpinsetrequests(void);\r
+void snmp_inc_snmpingetresponses(void);\r
+void snmp_inc_snmpintraps(void);\r
+void snmp_inc_snmpouttoobigs(void);\r
+void snmp_inc_snmpoutnosuchnames(void);\r
+void snmp_inc_snmpoutbadvalues(void);\r
+void snmp_inc_snmpoutgenerrs(void);\r
+void snmp_inc_snmpoutgetrequests(void);\r
+void snmp_inc_snmpoutgetnexts(void);\r
+void snmp_inc_snmpoutsetrequests(void);\r
+void snmp_inc_snmpoutgetresponses(void);\r
+void snmp_inc_snmpouttraps(void);\r
+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid);\r
+void snmp_set_snmpenableauthentraps(u8_t *value);\r
+void snmp_get_snmpenableauthentraps(u8_t *value);\r
+\r
+/* LWIP_SNMP support not available */\r
+/* define everything to be empty */\r
+#else\r
+\r
+/* system */\r
+#define snmp_set_sysdesr(str, strlen)\r
+#define snmp_get_sysobjid_ptr(oid)\r
+#define snmp_inc_sysuptime()\r
+#define snmp_get_sysuptime(value)\r
+\r
+/* network interface */\r
+#define snmp_add_ifinoctets(ni,value) \r
+#define snmp_inc_ifinucastpkts(ni)\r
+#define snmp_inc_ifinnucastpkts(ni)\r
+#define snmp_inc_ifindiscards(ni)\r
+#define snmp_add_ifoutoctets(ni,value)\r
+#define snmp_inc_ifoutucastpkts(ni)\r
+#define snmp_inc_ifoutnucastpkts(ni)\r
+#define snmp_inc_ifoutdiscards(ni)\r
+#define snmp_inc_iflist()\r
+#define snmp_dec_iflist()\r
+\r
+/* ARP */\r
+#define snmp_insert_arpidx_tree(ni,ip)\r
+#define snmp_delete_arpidx_tree(ni,ip)\r
+\r
+/* IP */\r
+#define snmp_inc_ipinreceives()\r
+#define snmp_inc_ipinhdrerrors()\r
+#define snmp_inc_ipinaddrerrors()\r
+#define snmp_inc_ipforwdatagrams()\r
+#define snmp_inc_ipinunknownprotos()\r
+#define snmp_inc_ipindiscards()\r
+#define snmp_inc_ipindelivers()\r
+#define snmp_inc_ipoutrequests()\r
+#define snmp_inc_ipoutdiscards()\r
+#define snmp_inc_ipoutnoroutes()\r
+#define snmp_inc_ipreasmreqds()\r
+#define snmp_inc_ipreasmoks()\r
+#define snmp_inc_ipreasmfails()\r
+#define snmp_inc_ipfragoks()\r
+#define snmp_inc_ipfragfails()\r
+#define snmp_inc_ipfragcreates()\r
+#define snmp_inc_iproutingdiscards()\r
+#define snmp_insert_ipaddridx_tree(ni)\r
+#define snmp_delete_ipaddridx_tree(ni)\r
+#define snmp_insert_iprteidx_tree(dflt, ni)\r
+#define snmp_delete_iprteidx_tree(dflt, ni)\r
+\r
+/* ICMP */\r
+#define snmp_inc_icmpinmsgs()\r
+#define snmp_inc_icmpinerrors() \r
+#define snmp_inc_icmpindestunreachs() \r
+#define snmp_inc_icmpintimeexcds()\r
+#define snmp_inc_icmpinparmprobs() \r
+#define snmp_inc_icmpinsrcquenchs() \r
+#define snmp_inc_icmpinredirects() \r
+#define snmp_inc_icmpinechos() \r
+#define snmp_inc_icmpinechoreps()\r
+#define snmp_inc_icmpintimestamps() \r
+#define snmp_inc_icmpintimestampreps()\r
+#define snmp_inc_icmpinaddrmasks()\r
+#define snmp_inc_icmpinaddrmaskreps()\r
+#define snmp_inc_icmpoutmsgs()\r
+#define snmp_inc_icmpouterrors()\r
+#define snmp_inc_icmpoutdestunreachs() \r
+#define snmp_inc_icmpouttimeexcds() \r
+#define snmp_inc_icmpoutparmprobs()\r
+#define snmp_inc_icmpoutsrcquenchs()\r
+#define snmp_inc_icmpoutredirects() \r
+#define snmp_inc_icmpoutechos() \r
+#define snmp_inc_icmpoutechoreps()\r
+#define snmp_inc_icmpouttimestamps()\r
+#define snmp_inc_icmpouttimestampreps()\r
+#define snmp_inc_icmpoutaddrmasks()\r
+#define snmp_inc_icmpoutaddrmaskreps()\r
+/* TCP */\r
+#define snmp_inc_tcpactiveopens()\r
+#define snmp_inc_tcppassiveopens()\r
+#define snmp_inc_tcpattemptfails()\r
+#define snmp_inc_tcpestabresets()\r
+#define snmp_inc_tcpinsegs()\r
+#define snmp_inc_tcpoutsegs()\r
+#define snmp_inc_tcpretranssegs()\r
+#define snmp_inc_tcpinerrs()\r
+#define snmp_inc_tcpoutrsts()\r
+\r
+/* UDP */\r
+#define snmp_inc_udpindatagrams()\r
+#define snmp_inc_udpnoports()\r
+#define snmp_inc_udpinerrors()\r
+#define snmp_inc_udpoutdatagrams()\r
+#define snmp_insert_udpidx_tree(pcb)\r
+#define snmp_delete_udpidx_tree(pcb)\r
+\r
+/* SNMP */\r
+#define snmp_inc_snmpinpkts()\r
+#define snmp_inc_snmpoutpkts()\r
+#define snmp_inc_snmpinbadversions()\r
+#define snmp_inc_snmpinbadcommunitynames()\r
+#define snmp_inc_snmpinbadcommunityuses()\r
+#define snmp_inc_snmpinasnparseerrs()\r
+#define snmp_inc_snmpintoobigs()\r
+#define snmp_inc_snmpinnosuchnames()\r
+#define snmp_inc_snmpinbadvalues()\r
+#define snmp_inc_snmpinreadonlys()\r
+#define snmp_inc_snmpingenerrs()\r
+#define snmp_add_snmpintotalreqvars(value)\r
+#define snmp_add_snmpintotalsetvars(value)\r
+#define snmp_inc_snmpingetrequests()\r
+#define snmp_inc_snmpingetnexts()\r
+#define snmp_inc_snmpinsetrequests()\r
+#define snmp_inc_snmpingetresponses()\r
+#define snmp_inc_snmpintraps()\r
+#define snmp_inc_snmpouttoobigs()\r
+#define snmp_inc_snmpoutnosuchnames()\r
+#define snmp_inc_snmpoutbadvalues()\r
+#define snmp_inc_snmpoutgenerrs()\r
+#define snmp_inc_snmpoutgetrequests()\r
+#define snmp_inc_snmpoutgetnexts()\r
+#define snmp_inc_snmpoutsetrequests()\r
+#define snmp_inc_snmpoutgetresponses()\r
+#define snmp_inc_snmpouttraps()\r
+#define snmp_get_snmpgrpid_ptr(oid)\r
+#define snmp_set_snmpenableauthentraps(value)\r
+#define snmp_get_snmpenableauthentraps(value)\r
+\r
+#endif\r
+\r
+#endif /* __LWIP_SNMP_H__ */\r
index c1df94a946c44f4ef290daa28c39330163234e03..d83d41d40f5868de2eb0d948d598f3f5afa3bc24 100644 (file)
@@ -1,90 +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
+/**\r
+ * @file\r
+ * Abstract Syntax Notation One (ISO 8824, 8825) codec.\r
+ */\r
\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#ifndef __LWIP_SNMP_ASN1_H__\r
+#define __LWIP_SNMP_ASN1_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "arch/cc.h"\r
+#include "lwip/err.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/snmp.h"\r
+\r
+#define SNMP_ASN1_UNIV   (!0x80 | !0x40)\r
+#define SNMP_ASN1_APPLIC (!0x80 |  0x40)\r
+#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)\r
+\r
+#define SNMP_ASN1_CONSTR (0x20)\r
+#define SNMP_ASN1_PRIMIT (!0x20)\r
+\r
+/* universal tags */\r
+#define SNMP_ASN1_INTEG  2\r
+#define SNMP_ASN1_OC_STR 4\r
+#define SNMP_ASN1_NUL    5\r
+#define SNMP_ASN1_OBJ_ID 6\r
+#define SNMP_ASN1_SEQ    16\r
+\r
+/* application specific (SNMP) tags */\r
+#define SNMP_ASN1_IPADDR 0    /* octet string size(4) */\r
+#define SNMP_ASN1_COUNTER 1   /* u32_t */\r
+#define SNMP_ASN1_GAUGE 2     /* u32_t */\r
+#define SNMP_ASN1_TIMETICKS 3 /* u32_t */\r
+#define SNMP_ASN1_OPAQUE 4    /* octet string */\r
+\r
+/* context specific (SNMP) tags */\r
+#define SNMP_ASN1_PDU_GET_REQ 0\r
+#define SNMP_ASN1_PDU_GET_NEXT_REQ 1\r
+#define SNMP_ASN1_PDU_GET_RESP 2\r
+#define SNMP_ASN1_PDU_SET_REQ 3\r
+#define SNMP_ASN1_PDU_TRAP 4\r
+\r
+err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type);\r
+err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length);\r
+err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value);\r
+err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value);\r
+err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid);\r
+err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw);\r
+\r
+void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);\r
+void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);\r
+void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);\r
+void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);\r
+err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);\r
+err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);\r
+err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value);\r
+err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value);\r
+err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);\r
+err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);\r
+\r
+#endif\r
index 66faedd472e345f3824f0804e4b265ed72f6ac8d..4d91d30464dad91efcb5f9f5c5f36d5c3b053af4 100644 (file)
-/**
- * @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
+/**\r
+ * @file\r
+ * SNMP Agent message handling structures.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#ifndef __LWIP_SNMP_MSG_H__\r
+#define __LWIP_SNMP_MSG_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "arch/cc.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/snmp_structs.h"\r
+\r
+#if SNMP_PRIVATE_MIB\r
+#include "private_mib.h"\r
+#endif\r
+\r
+#define SNMP_IN_PORT 161\r
+#define SNMP_TRAP_PORT 162\r
+\r
+#define SNMP_ES_NOERROR 0\r
+#define SNMP_ES_TOOBIG 1\r
+#define SNMP_ES_NOSUCHNAME 2\r
+#define SNMP_ES_BADVALUE 3\r
+#define SNMP_ES_READONLY 4\r
+#define SNMP_ES_GENERROR 5\r
+\r
+#define SNMP_GENTRAP_COLDSTART 0\r
+#define SNMP_GENTRAP_WARMSTART 1\r
+#define SNMP_GENTRAP_AUTHFAIL 4\r
+#define SNMP_GENTRAP_ENTERPRISESPC 6\r
+\r
+struct snmp_varbind\r
+{\r
+  /* next pointer, NULL for last in list */\r
+  struct snmp_varbind *next;\r
+  /* previous pointer, NULL for first in list */\r
+  struct snmp_varbind *prev;\r
+\r
+  /* object identifier length (in s32_t) */\r
+  u8_t ident_len;\r
+  /* object identifier array */\r
+  s32_t *ident;\r
+\r
+  /* object value ASN1 type */\r
+  u8_t value_type;\r
+  /* object value length (in u8_t) */\r
+  u8_t value_len;\r
+  /* object value */\r
+  void *value;\r
+\r
+  /* encoding varbind seq length length */\r
+  u8_t seqlenlen;\r
+  /* encoding object identifier length length */\r
+  u8_t olenlen;\r
+  /* encoding object value length length */\r
+  u8_t vlenlen;\r
+  /* encoding varbind seq length */\r
+  u16_t seqlen;\r
+  /* encoding object identifier length */\r
+  u16_t olen;\r
+  /* encoding object value length */\r
+  u16_t vlen;\r
+};\r
+\r
+struct snmp_varbind_root\r
+{\r
+  struct snmp_varbind *head;\r
+  struct snmp_varbind *tail;\r
+  /* number of variable bindings in list */\r
+  u8_t count;\r
+  /* encoding varbind-list seq length length */\r
+  u8_t seqlenlen;\r
+  /* encoding varbind-list seq length */\r
+  u16_t seqlen;\r
+};\r
+\r
+/** output response message header length fields */\r
+struct snmp_resp_header_lengths\r
+{\r
+  /* encoding error-index length length */\r
+  u8_t erridxlenlen;\r
+  /* encoding error-status length length */\r
+  u8_t errstatlenlen;\r
+  /* encoding request id length length */\r
+  u8_t ridlenlen;\r
+  /* encoding pdu length length */\r
+  u8_t pdulenlen;\r
+  /* encoding community length length */\r
+  u8_t comlenlen;\r
+  /* encoding version length length */\r
+  u8_t verlenlen;\r
+  /* encoding sequence length length */\r
+  u8_t seqlenlen;\r
+\r
+  /* encoding error-index length */\r
+  u16_t erridxlen;\r
+  /* encoding error-status length */\r
+  u16_t errstatlen;\r
+  /* encoding request id length */\r
+  u16_t ridlen;\r
+  /* encoding pdu length */\r
+  u16_t pdulen;\r
+  /* encoding community length */\r
+  u16_t comlen;\r
+  /* encoding version length */\r
+  u16_t verlen;\r
+  /* encoding sequence length */\r
+  u16_t seqlen;\r
+};\r
+\r
+/** output response message header length fields */\r
+struct snmp_trap_header_lengths\r
+{\r
+  /* encoding timestamp length length */\r
+  u8_t tslenlen;\r
+  /* encoding specific-trap length length */\r
+  u8_t strplenlen;\r
+  /* encoding generic-trap length length */\r
+  u8_t gtrplenlen;\r
+  /* encoding agent-addr length length */\r
+  u8_t aaddrlenlen;\r
+  /* encoding enterprise-id length length */\r
+  u8_t eidlenlen;\r
+  /* encoding pdu length length */\r
+  u8_t pdulenlen;\r
+  /* encoding community length length */\r
+  u8_t comlenlen;\r
+  /* encoding version length length */\r
+  u8_t verlenlen;\r
+  /* encoding sequence length length */\r
+  u8_t seqlenlen;\r
+\r
+  /* encoding timestamp length */\r
+  u16_t tslen;\r
+  /* encoding specific-trap length */\r
+  u16_t strplen;\r
+  /* encoding generic-trap length */\r
+  u16_t gtrplen;\r
+  /* encoding agent-addr length */\r
+  u16_t aaddrlen;\r
+  /* encoding enterprise-id length */\r
+  u16_t eidlen;\r
+  /* encoding pdu length */\r
+  u16_t pdulen;\r
+  /* encoding community length */\r
+  u16_t comlen;\r
+  /* encoding version length */\r
+  u16_t verlen;\r
+  /* encoding sequence length */\r
+  u16_t seqlen;\r
+};\r
+\r
+/* Accepting new SNMP messages. */\r
+#define SNMP_MSG_EMPTY                 0\r
+/* Search for matching object for variable binding. */\r
+#define SNMP_MSG_SEARCH_OBJ            1\r
+/* Perform SNMP operation on in-memory object.\r
+   Pass-through states, for symmetry only. */\r
+#define SNMP_MSG_INTERNAL_GET_OBJDEF   2\r
+#define SNMP_MSG_INTERNAL_GET_VALUE    3\r
+#define SNMP_MSG_INTERNAL_SET_TEST     4\r
+#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5\r
+#define SNMP_MSG_INTERNAL_SET_VALUE    6\r
+/* Perform SNMP operation on object located externally.\r
+   In theory this could be used for building a proxy agent.\r
+   Practical use is for an enterprise spc. app. gateway. */\r
+#define SNMP_MSG_EXTERNAL_GET_OBJDEF   7\r
+#define SNMP_MSG_EXTERNAL_GET_VALUE    8\r
+#define SNMP_MSG_EXTERNAL_SET_TEST     9\r
+#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10\r
+#define SNMP_MSG_EXTERNAL_SET_VALUE    11\r
+\r
+#define SNMP_COMMUNITY_STR_LEN 64\r
+struct snmp_msg_pstat\r
+{\r
+  /* lwIP local port (161) binding */\r
+  struct udp_pcb *pcb;\r
+  /* source IP address */\r
+  struct ip_addr sip;\r
+  /* source UDP port */\r
+  u16_t sp;\r
+  /* request type */\r
+  u8_t rt;\r
+  /* request ID */\r
+  s32_t rid;\r
+  /* error status */\r
+  s32_t error_status;\r
+  /* error index */\r
+  s32_t error_index;\r
+  /* community name (zero terminated) */\r
+  u8_t community[SNMP_COMMUNITY_STR_LEN + 1];\r
+  /* community string length (exclusive zero term) */\r
+  u8_t com_strlen;\r
+  /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */\r
+  u8_t state;\r
+  /* saved arguments for MSG_EXTERNAL_x */\r
+  struct mib_external_node *ext_mib_node;\r
+  struct snmp_name_ptr ext_name_ptr;\r
+  struct obj_def ext_object_def;\r
+  struct snmp_obj_id ext_oid;\r
+  /* index into input variable binding list */\r
+  u8_t vb_idx;\r
+  /* ptr into input variable binding list */\r
+  struct snmp_varbind *vb_ptr;\r
+  /* list of variable bindings from input */\r
+  struct snmp_varbind_root invb;\r
+  /* list of variable bindings to output */\r
+  struct snmp_varbind_root outvb;\r
+  /* output response lengths used in ASN encoding */\r
+  struct snmp_resp_header_lengths rhl;\r
+};\r
+\r
+struct snmp_msg_trap\r
+{\r
+  /* lwIP local port (161) binding */\r
+  struct udp_pcb *pcb;\r
+  /* destination IP address in network order */\r
+  struct ip_addr dip;\r
+\r
+  /* source enterprise ID (sysObjectID) */\r
+  struct snmp_obj_id *enterprise;\r
+  /* source IP address, raw network order format */\r
+  u8_t sip_raw[4];\r
+  /* generic trap code */\r
+  u32_t gen_trap;\r
+  /* specific trap code */\r
+  u32_t spc_trap;\r
+  /* timestamp */\r
+  u32_t ts;\r
+  /* list of variable bindings to output */\r
+  struct snmp_varbind_root outvb;\r
+  /* output trap lengths used in ASN encoding */\r
+  struct snmp_trap_header_lengths thl;\r
+};\r
+\r
+/** Agent Version constant, 0 = v1 oddity */\r
+extern const s32_t snmp_version;\r
+/** Agent default "public" community string */\r
+extern const char snmp_publiccommunity[7];\r
+\r
+extern struct snmp_msg_trap trap_msg;\r
+\r
+/** Agent setup, start listening to port 161. */\r
+void snmp_init(void);\r
+void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);\r
+void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst);\r
+\r
+/** Varbind-list functions. */\r
+struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);\r
+void snmp_varbind_free(struct snmp_varbind *vb);\r
+void snmp_varbind_list_free(struct snmp_varbind_root *root);\r
+void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);\r
+struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);\r
+\r
+/** Handle an internal (recv) or external (private response) event. */\r
+void snmp_msg_event(u8_t request_id);\r
+err_t snmp_send_response(struct snmp_msg_pstat *m_stat);\r
+err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap);\r
+void snmp_coldstart_trap(void);\r
+void snmp_authfail_trap(void);\r
+\r
+#endif\r
index f48546645608bfcaab77d7a3a45ff473c7e9b3c0..f76632e1d6512e69c17fbac331bab86e21898c58 100644 (file)
-/**
- * @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
+/**\r
+ * @file\r
+ * Generic MIB tree structures.\r
+ *\r
+ * @todo namespace prefixes\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#ifndef __LWIP_SNMP_STRUCTS_H__\r
+#define __LWIP_SNMP_STRUCTS_H__\r
+\r
+#include "lwip/opt.h"\r
+#if LWIP_SNMP\r
+\r
+#include "arch/cc.h"\r
+#include "lwip/snmp.h"\r
+\r
+#if SNMP_PRIVATE_MIB\r
+#include "private_mib.h"\r
+#endif\r
+\r
+/* MIB object instance */\r
+#define MIB_OBJECT_NONE 0 \r
+#define MIB_OBJECT_SCALAR 1\r
+#define MIB_OBJECT_TAB 2\r
+\r
+/* MIB object access */\r
+#define MIB_OBJECT_READ_ONLY 0\r
+#define MIB_OBJECT_READ_WRITE 1\r
+#define MIB_OBJECT_WRITE_ONLY 2\r
+#define MIB_OBJECT_NOT_ACCESSIBLE 3\r
+\r
+/** object definition returned by (get_object_def)() */\r
+struct obj_def\r
+{\r
+  /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */\r
+  u8_t instance;\r
+  /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */\r
+  u8_t access;\r
+  /* ASN type for this object */\r
+  u8_t asn_type;\r
+  /* value length (host length) */\r
+  u16_t v_len;\r
+  /* length of instance part of supplied object identifier */\r
+  u8_t  id_inst_len;\r
+  /* instance part of supplied object identifier */\r
+  s32_t *id_inst_ptr;\r
+};\r
+\r
+struct snmp_name_ptr\r
+{\r
+  u8_t ident_len;\r
+  s32_t *ident;\r
+};\r
+\r
+/** MIB const scalar (.0) node */\r
+#define MIB_NODE_SC 0x01\r
+/** MIB const array node */\r
+#define MIB_NODE_AR 0x02\r
+/** MIB array node (mem_malloced from RAM) */\r
+#define MIB_NODE_RA 0x03\r
+/** MIB list root node (mem_malloced from RAM) */\r
+#define MIB_NODE_LR 0x04\r
+/** MIB node for external objects */\r
+#define MIB_NODE_EX 0x05\r
+\r
+/** node "base class" layout, the mandatory fields for a node  */\r
+struct mib_node\r
+{\r
+  /** returns struct obj_def for the given object identifier */\r
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  /** returns object value for the given object identifier,\r
+     @note the caller must allocate at least len bytes for the value */\r
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);\r
+  /** tests length and/or range BEFORE setting */\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  /** sets object value, only to be called when set_test()  */\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);  \r
+  /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */\r
+  const u8_t node_type;\r
+  /* array or max list length */\r
+  const u16_t maxlength;\r
+};\r
+\r
+/** derived node for scalars .0 index */\r
+typedef struct mib_node mib_scalar_node;\r
+\r
+/** derived node, points to a fixed size const array\r
+    of sub-identifiers plus a 'child' pointer */\r
+struct mib_array_node\r
+{\r
+  /* inherited "base class" members */\r
+  void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (* const get_value)(struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);\r
+\r
+  const u8_t node_type;\r
+  const u16_t maxlength;\r
+\r
+  /* aditional struct members */\r
+  const s32_t *objid;\r
+  struct mib_node* const *nptr;\r
+};\r
+\r
+/** derived node, points to a fixed size mem_malloced array\r
+    of sub-identifiers plus a 'child' pointer */\r
+struct mib_ram_array_node\r
+{\r
+  /* inherited "base class" members */\r
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);\r
+\r
+  u8_t node_type;\r
+  u16_t maxlength;\r
+\r
+  /* aditional struct members */\r
+  s32_t *objid;\r
+  struct mib_node **nptr;\r
+};\r
+\r
+struct mib_list_node\r
+{\r
+  struct mib_list_node *prev;  \r
+  struct mib_list_node *next;\r
+  s32_t objid;\r
+  struct mib_node *nptr;\r
+};\r
+\r
+/** derived node, points to a doubly linked list\r
+    of sub-identifiers plus a 'child' pointer */\r
+struct mib_list_rootnode\r
+{\r
+  /* inherited "base class" members */\r
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);\r
+\r
+  u8_t node_type;\r
+  u16_t maxlength;\r
+\r
+  /* aditional struct members */\r
+  struct mib_list_node *head;\r
+  struct mib_list_node *tail;\r
+  /* counts list nodes in list  */\r
+  u16_t count;\r
+};\r
+\r
+/** derived node, has access functions for mib object in external memory or device\r
+    using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */\r
+struct mib_external_node\r
+{\r
+  /* inherited "base class" members */\r
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);\r
+\r
+  u8_t node_type;\r
+  u16_t maxlength;\r
+\r
+  /* aditional struct members */\r
+  /** points to an extenal (in memory) record of some sort of addressing\r
+      information, passed to and interpreted by the funtions below */\r
+  void* addr_inf;\r
+  /** tree levels under this node */\r
+  u8_t tree_levels;\r
+  /** number of objects at this level */\r
+  u16_t (*level_length)(void* addr_inf, u8_t level);\r
+  /** compares object sub identifier with external id\r
+      return zero when equal, nonzero when unequal */\r
+  s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id);\r
+  void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id);\r
+\r
+  /** async Questions */\r
+  void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident);\r
+  void (*get_value_q)(u8_t rid, struct obj_def *od);\r
+  void (*set_test_q)(u8_t rid, struct obj_def *od);\r
+  void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value);\r
+  /** async Answers */\r
+  void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\r
+  /** async Panic Close (agent returns error reply, \r
+      e.g. used for external transaction cleanup) */\r
+  void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident);\r
+  void (*get_value_pc)(u8_t rid, struct obj_def *od);\r
+  void (*set_test_pc)(u8_t rid, struct obj_def *od);\r
+  void (*set_value_pc)(u8_t rid, struct obj_def *od);\r
+};\r
+\r
+/** export MIB tree from mib2.c */\r
+extern const struct mib_array_node internet;\r
+\r
+/** dummy function pointers for non-leaf MIB nodes from mib2.c */\r
+void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+void noleafs_get_value(struct obj_def *od, u16_t len, void *value);\r
+u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);\r
+void noleafs_set_value(struct obj_def *od, u16_t len, void *value);\r
+\r
+void snmp_oidtoip(s32_t *ident, struct ip_addr *ip);\r
+void snmp_iptooid(struct ip_addr *ip, s32_t *ident);\r
+void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);\r
+void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);\r
+\r
+struct mib_list_node* snmp_mib_ln_alloc(s32_t id);\r
+void snmp_mib_ln_free(struct mib_list_node *ln);\r
+struct mib_list_rootnode* snmp_mib_lrn_alloc(void);\r
+void snmp_mib_lrn_free(struct mib_list_rootnode *lrn);\r
+\r
+s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn);\r
+s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn);\r
+struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n);\r
+\r
+struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np);\r
+struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);\r
+u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident);\r
+u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);\r
+\r
+#endif /* LWIP_SNMP */\r
+#endif\r
index d5f8ccf74aa793629cb0fb081e347101f434e326..9c25035ad495dd9ef6650debfc4ae71638af74f1 100644 (file)
-/*
- * 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__ */
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+\r
+#ifndef __LWIP_SOCKETS_H__\r
+#define __LWIP_SOCKETS_H__\r
+#include "lwip/ip_addr.h"\r
+\r
+struct sockaddr_in {\r
+  u8_t sin_len;\r
+  u8_t sin_family;\r
+  u16_t sin_port;\r
+  struct in_addr sin_addr;\r
+  char sin_zero[8];\r
+};\r
+\r
+struct sockaddr {\r
+  u8_t sa_len;\r
+  u8_t sa_family;\r
+  char sa_data[14];\r
+};\r
+\r
+#ifndef socklen_t\r
+#  define socklen_t int\r
+#endif\r
+\r
+\r
+#define SOCK_STREAM     1\r
+#define SOCK_DGRAM      2\r
+#define SOCK_RAW        3\r
+\r
+/*\r
+ * Option flags per-socket.\r
+ */\r
+#define  SO_DEBUG  0x0001    /* turn on debugging info recording */\r
+#define  SO_ACCEPTCONN  0x0002    /* socket has had listen() */\r
+#define  SO_REUSEADDR  0x0004    /* allow local address reuse */\r
+#define  SO_KEEPALIVE  0x0008    /* keep connections alive */\r
+#define  SO_DONTROUTE  0x0010    /* just use interface addresses */\r
+#define  SO_BROADCAST  0x0020    /* permit sending of broadcast msgs */\r
+#define  SO_USELOOPBACK  0x0040    /* bypass hardware when possible */\r
+#define  SO_LINGER  0x0080    /* linger on close if data present */\r
+#define  SO_OOBINLINE  0x0100    /* leave received OOB data in line */\r
+#define         SO_REUSEPORT   0x0200          /* allow local address & port reuse */\r
+\r
+#define SO_DONTLINGER   (int)(~SO_LINGER)\r
+\r
+/*\r
+ * Additional options, not kept in so_options.\r
+ */\r
+#define SO_SNDBUF  0x1001    /* send buffer size */\r
+#define SO_RCVBUF  0x1002    /* receive buffer size */\r
+#define SO_SNDLOWAT  0x1003    /* send low-water mark */\r
+#define SO_RCVLOWAT  0x1004    /* receive low-water mark */\r
+#define SO_SNDTIMEO  0x1005    /* send timeout */\r
+#define SO_RCVTIMEO  0x1006    /* receive timeout */\r
+#define  SO_ERROR  0x1007    /* get error status and clear */\r
+#define  SO_TYPE    0x1008    /* get socket type */\r
+\r
+\r
+\r
+/*\r
+ * Structure used for manipulating linger option.\r
+ */\r
+struct linger {\r
+       int l_onoff;                /* option on/off */\r
+       int l_linger;               /* linger time */\r
+};\r
+\r
+/*\r
+ * Level number for (get/set)sockopt() to apply to socket itself.\r
+ */\r
+#define  SOL_SOCKET  0xfff    /* options for socket level */\r
+\r
+\r
+#define AF_UNSPEC       0\r
+#define AF_INET         2\r
+#define PF_INET         AF_INET\r
+#define PF_UNSPEC       AF_UNSPEC\r
+\r
+#define IPPROTO_IP      0\r
+#define IPPROTO_TCP     6\r
+#define IPPROTO_UDP     17\r
+\r
+#define INADDR_ANY      0\r
+#define INADDR_BROADCAST 0xffffffff\r
+\r
+/* Flags we can use with send and recv. */\r
+#define MSG_DONTWAIT    0x40            /* Nonblocking i/o for this operation only */\r
+\r
+\r
+/*\r
+ * Options for level IPPROTO_IP\r
+ */\r
+#define IP_TOS       1\r
+#define IP_TTL       2\r
+\r
+\r
+#define IPTOS_TOS_MASK          0x1E\r
+#define IPTOS_TOS(tos)          ((tos) & IPTOS_TOS_MASK)\r
+#define IPTOS_LOWDELAY          0x10\r
+#define IPTOS_THROUGHPUT        0x08\r
+#define IPTOS_RELIABILITY       0x04\r
+#define IPTOS_LOWCOST           0x02\r
+#define IPTOS_MINCOST           IPTOS_LOWCOST\r
+\r
+/*\r
+ * Definitions for IP precedence (also in ip_tos) (hopefully unused)\r
+ */\r
+#define IPTOS_PREC_MASK                 0xe0\r
+#define IPTOS_PREC(tos)                ((tos) & IPTOS_PREC_MASK)\r
+#define IPTOS_PREC_NETCONTROL           0xe0\r
+#define IPTOS_PREC_INTERNETCONTROL      0xc0\r
+#define IPTOS_PREC_CRITIC_ECP           0xa0\r
+#define IPTOS_PREC_FLASHOVERRIDE        0x80\r
+#define IPTOS_PREC_FLASH                0x60\r
+#define IPTOS_PREC_IMMEDIATE            0x40\r
+#define IPTOS_PREC_PRIORITY             0x20\r
+#define IPTOS_PREC_ROUTINE              0x00\r
+\r
+\r
+/*\r
+ * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.\r
+ *\r
+ *\r
+ * Ioctl's have the command encoded in the lower word,\r
+ * and the size of any in or out parameters in the upper\r
+ * word.  The high 2 bits of the upper word are used\r
+ * to encode the in/out status of the parameter; for now\r
+ * we restrict parameters to at most 128 bytes.\r
+ */\r
+#if !defined(FIONREAD) || !defined(FIONBIO)\r
+#define IOCPARM_MASK    0x7f            /* parameters must be < 128 bytes */\r
+#define IOC_VOID        0x20000000      /* no parameters */\r
+#define IOC_OUT         0x40000000      /* copy out parameters */\r
+#define IOC_IN          0x80000000      /* copy in parameters */\r
+#define IOC_INOUT       (IOC_IN|IOC_OUT)\r
+                                        /* 0x20000000 distinguishes new &\r
+                                           old ioctl's */\r
+#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y))\r
+\r
+#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))\r
+\r
+#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))\r
+#endif\r
+\r
+#ifndef FIONREAD\r
+#define FIONREAD    _IOR('f', 127, unsigned long) /* get # bytes to read */\r
+#endif\r
+#ifndef FIONBIO\r
+#define FIONBIO     _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */\r
+#endif\r
+\r
+/* Socket I/O Controls */\r
+#ifndef SIOCSHIWAT\r
+#define SIOCSHIWAT  _IOW('s',  0, unsigned long)  /* set high watermark */\r
+#define SIOCGHIWAT  _IOR('s',  1, unsigned long)  /* get high watermark */\r
+#define SIOCSLOWAT  _IOW('s',  2, unsigned long)  /* set low watermark */\r
+#define SIOCGLOWAT  _IOR('s',  3, unsigned long)  /* get low watermark */\r
+#define SIOCATMARK  _IOR('s',  7, unsigned long)  /* at oob mark? */\r
+#endif\r
+\r
+#ifndef O_NONBLOCK\r
+#define O_NONBLOCK    04000U\r
+#endif\r
+\r
+#ifndef FD_SET\r
+  #undef  FD_SETSIZE\r
+  #define FD_SETSIZE    16\r
+  #define FD_SET(n, p)  ((p)->fd_bits[(n)/8] |=  (1 << ((n) & 7)))\r
+  #define FD_CLR(n, p)  ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7)))\r
+  #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] &   (1 << ((n) & 7)))\r
+  #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p)))\r
+\r
+  typedef struct fd_set {\r
+          unsigned char fd_bits [(FD_SETSIZE+7)/8];\r
+        } fd_set;\r
+\r
+/* \r
+ * only define this in sockets.c so it does not interfere\r
+ * with other projects namespaces where timeval is present\r
+ */ \r
+#ifndef LWIP_TIMEVAL_PRIVATE\r
+#define LWIP_TIMEVAL_PRIVATE 1\r
+#endif\r
+\r
+#if LWIP_TIMEVAL_PRIVATE\r
+  struct timeval {\r
+    long    tv_sec;         /* seconds */\r
+    long    tv_usec;        /* and microseconds */\r
+  };\r
+#endif\r
+\r
+#endif\r
+\r
+int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);\r
+int lwip_bind(int s, struct sockaddr *name, socklen_t namelen);\r
+int lwip_shutdown(int s, int how);\r
+int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);\r
+int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen);\r
+int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen);\r
+int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen);\r
+int lwip_close(int s);\r
+int lwip_connect(int s, struct sockaddr *name, socklen_t namelen);\r
+int lwip_listen(int s, int backlog);\r
+int lwip_recv(int s, void *mem, int len, unsigned int flags);\r
+int lwip_read(int s, void *mem, int len);\r
+int lwip_recvfrom(int s, void *mem, int len, unsigned int flags,\r
+      struct sockaddr *from, socklen_t *fromlen);\r
+int lwip_send(int s, void *dataptr, int size, unsigned int flags);\r
+int lwip_sendto(int s, void *dataptr, int size, unsigned int flags,\r
+    struct sockaddr *to, socklen_t tolen);\r
+int lwip_socket(int domain, int type, int protocol);\r
+int lwip_write(int s, void *dataptr, int size);\r
+int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,\r
+                struct timeval *timeout);\r
+int lwip_ioctl(int s, long cmd, void *argp);\r
+\r
+#if LWIP_COMPAT_SOCKETS\r
+#define accept(a,b,c)         lwip_accept(a,b,c)\r
+#define bind(a,b,c)           lwip_bind(a,b,c)\r
+#define shutdown(a,b)         lwip_shutdown(a,b)\r
+#define close(s)              lwip_close(s)\r
+#define connect(a,b,c)        lwip_connect(a,b,c)\r
+#define getsockname(a,b,c)    lwip_getsockname(a,b,c)\r
+#define getpeername(a,b,c)    lwip_getpeername(a,b,c)\r
+#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)\r
+#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)\r
+#define listen(a,b)           lwip_listen(a,b)\r
+#define recv(a,b,c,d)         lwip_recv(a,b,c,d)\r
+#define read(a,b,c)           lwip_read(a,b,c)\r
+#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)\r
+#define send(a,b,c,d)         lwip_send(a,b,c,d)\r
+#define sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f)\r
+#define socket(a,b,c)         lwip_socket(a,b,c)\r
+#define write(a,b,c)          lwip_write(a,b,c)\r
+#define select(a,b,c,d,e)     lwip_select(a,b,c,d,e)\r
+#define ioctlsocket(a,b,c)    lwip_ioctl(a,b,c)\r
+#endif /* LWIP_COMPAT_SOCKETS */\r
+\r
+#endif /* __LWIP_SOCKETS_H__ */\r
+\r
index 71acfd068f3730beedf233d4089d6edeb5fedab4..29dfd5731e13b9ebec3eb506a8e3333f0cfa7a9b 100644 (file)
-/*
- * 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__ */
-
-
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_STATS_H__\r
+#define __LWIP_STATS_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "arch/cc.h"\r
+\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+\r
+#if LWIP_STATS\r
+\r
+struct stats_proto {\r
+  u16_t xmit;    /* Transmitted packets. */\r
+  u16_t rexmit;  /* Retransmitted packets. */\r
+  u16_t recv;    /* Received packets. */\r
+  u16_t fw;      /* Forwarded packets. */\r
+  u16_t drop;    /* Dropped packets. */\r
+  u16_t chkerr;  /* Checksum error. */\r
+  u16_t lenerr;  /* Invalid length error. */\r
+  u16_t memerr;  /* Out of memory error. */\r
+  u16_t rterr;   /* Routing error. */\r
+  u16_t proterr; /* Protocol error. */\r
+  u16_t opterr;  /* Error in options. */\r
+  u16_t err;     /* Misc error. */\r
+  u16_t cachehit;\r
+};\r
+\r
+struct stats_mem {\r
+  mem_size_t avail;\r
+  mem_size_t used;\r
+  mem_size_t max;  \r
+  mem_size_t err;\r
+};\r
+\r
+struct stats_pbuf {\r
+  u16_t avail;\r
+  u16_t used;\r
+  u16_t max;  \r
+  u16_t err;\r
+\r
+  u16_t alloc_locked;\r
+  u16_t refresh_locked;\r
+};\r
+\r
+struct stats_syselem {\r
+  u16_t used;\r
+  u16_t max;\r
+  u16_t err;\r
+};\r
+\r
+struct stats_sys {\r
+  struct stats_syselem sem;\r
+  struct stats_syselem mbox;\r
+};\r
+\r
+struct stats_ {\r
+  struct stats_proto link;\r
+  struct stats_proto ip_frag;\r
+  struct stats_proto ip;\r
+  struct stats_proto icmp;\r
+  struct stats_proto udp;\r
+  struct stats_proto tcp;\r
+  struct stats_pbuf pbuf;\r
+  struct stats_mem mem;\r
+  struct stats_mem memp[MEMP_MAX];\r
+  struct stats_sys sys;\r
+};\r
+\r
+extern struct stats_ lwip_stats;\r
+\r
+\r
+void stats_init(void);\r
+\r
+#define STATS_INC(x) ++lwip_stats.x\r
+#else\r
+#define stats_init()\r
+#define STATS_INC(x)\r
+#endif /* LWIP_STATS */\r
+\r
+#if TCP_STATS\r
+#define TCP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define TCP_STATS_INC(x)\r
+#endif\r
+\r
+#if UDP_STATS\r
+#define UDP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define UDP_STATS_INC(x)\r
+#endif\r
+\r
+#if ICMP_STATS\r
+#define ICMP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define ICMP_STATS_INC(x)\r
+#endif\r
+\r
+#if IP_STATS\r
+#define IP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define IP_STATS_INC(x)\r
+#endif\r
+\r
+#if IPFRAG_STATS\r
+#define IPFRAG_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define IPFRAG_STATS_INC(x)\r
+#endif\r
+\r
+#if LINK_STATS\r
+#define LINK_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define LINK_STATS_INC(x)\r
+#endif\r
+\r
+/* Display of statistics */\r
+#if LWIP_STATS_DISPLAY\r
+void stats_display(void);\r
+#else\r
+#define stats_display()\r
+#endif\r
+\r
+#endif /* __LWIP_STATS_H__ */\r
+\r
+\r
+\r
+\r
index c18c3abf3806cf002b5d1d26f603928e1c5b1247..ce8d5ffbdf7d80a42067ee2e6eae220473f31888 100644 (file)
-/*
- * 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__ */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_SYS_H__\r
+#define __LWIP_SYS_H__\r
+\r
+#include "arch/cc.h"\r
+\r
+#include "lwip/opt.h"\r
+\r
+\r
+#if NO_SYS\r
+\r
+/* For a totally minimal and standalone system, we provide null\r
+   definitions of the sys_ functions. */\r
+typedef u8_t sys_sem_t;\r
+typedef u8_t sys_mbox_t;\r
+struct sys_timeo {u8_t dummy;};\r
+\r
+#define sys_init()\r
+#define sys_timeout(m,h,a)\r
+#define sys_untimeout(m,a)\r
+#define sys_sem_new(c) c\r
+#define sys_sem_signal(s)\r
+#define sys_sem_wait(s)\r
+#define sys_sem_free(s)\r
+#define sys_mbox_new() 0\r
+#define sys_mbox_fetch(m,d)\r
+#define sys_mbox_post(m,d)\r
+#define sys_mbox_free(m)\r
+\r
+#define sys_thread_new(t,a,p)\r
+\r
+#else /* NO_SYS */\r
+\r
+#include "arch/sys_arch.h"\r
+\r
+/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */\r
+#define SYS_ARCH_TIMEOUT 0xffffffff\r
+\r
+typedef void (* sys_timeout_handler)(void *arg);\r
+\r
+struct sys_timeo {\r
+  struct sys_timeo *next;\r
+  u32_t time;\r
+  sys_timeout_handler h;\r
+  void *arg;\r
+};\r
+\r
+struct sys_timeouts {\r
+  struct sys_timeo *next;\r
+};\r
+\r
+/* sys_init() must be called before anthing else. */\r
+void sys_init(void);\r
+\r
+/*\r
+ * sys_timeout():\r
+ *\r
+ * Schedule a timeout a specified amount of milliseconds in the\r
+ * future. When the timeout occurs, the specified timeout handler will\r
+ * be called. The handler will be passed the "arg" argument when\r
+ * called.\r
+ *\r
+ */\r
+void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg);\r
+void sys_untimeout(sys_timeout_handler h, void *arg);\r
+struct sys_timeouts *sys_arch_timeouts(void);\r
+\r
+/* Semaphore functions. */\r
+sys_sem_t sys_sem_new(u8_t count);\r
+void sys_sem_signal(sys_sem_t sem);\r
+u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout);\r
+void sys_sem_free(sys_sem_t sem);\r
+void sys_sem_wait(sys_sem_t sem);\r
+int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout);\r
+\r
+/* Time functions. */\r
+#ifndef sys_msleep\r
+void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */\r
+#endif\r
+#ifndef sys_jiffies\r
+u32_t sys_jiffies(void); /* since power up. */\r
+#endif\r
+\r
+/* Mailbox functions. */\r
+sys_mbox_t sys_mbox_new(void);\r
+void sys_mbox_post(sys_mbox_t mbox, void *msg);\r
+u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout);\r
+void sys_mbox_free(sys_mbox_t mbox);\r
+void sys_mbox_fetch(sys_mbox_t mbox, void **msg);\r
+\r
+\r
+/* Thread functions. */\r
+sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio);\r
+\r
+/* The following functions are used only in Unix code, and\r
+   can be omitted when porting the stack. */\r
+/* Returns the current time in microseconds. */\r
+unsigned long sys_now(void);\r
+\r
+#endif /* NO_SYS */\r
+\r
+/* Critical Region Protection */\r
+/* These functions must be implemented in the sys_arch.c file.\r
+   In some implementations they can provide a more light-weight protection\r
+   mechanism than using semaphores. Otherwise semaphores can be used for\r
+   implementation */\r
+#ifndef SYS_ARCH_PROTECT\r
+/** SYS_LIGHTWEIGHT_PROT\r
+ * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection\r
+ * for certain critical regions during buffer allocation, deallocation and memory\r
+ * allocation and deallocation.\r
+ */\r
+#if SYS_LIGHTWEIGHT_PROT\r
+\r
+/** SYS_ARCH_DECL_PROTECT\r
+ * declare a protection variable. This macro will default to defining a variable of\r
+ * type sys_prot_t. If a particular port needs a different implementation, then\r
+ * this macro may be defined in sys_arch.h.\r
+ */\r
+#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev\r
+/** SYS_ARCH_PROTECT\r
+ * Perform a "fast" protect. This could be implemented by\r
+ * disabling interrupts for an embedded system or by using a semaphore or\r
+ * mutex. The implementation should allow calling SYS_ARCH_PROTECT when\r
+ * already protected. The old protection level is returned in the variable\r
+ * "lev". This macro will default to calling the sys_arch_protect() function\r
+ * which should be implemented in sys_arch.c. If a particular port needs a\r
+ * different implementation, then this macro may be defined in sys_arch.h\r
+ */\r
+#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()\r
+/** SYS_ARCH_UNPROTECT\r
+ * Perform a "fast" set of the protection level to "lev". This could be\r
+ * implemented by setting the interrupt level to "lev" within the MACRO or by\r
+ * using a semaphore or mutex.  This macro will default to calling the\r
+ * sys_arch_unprotect() function which should be implemented in\r
+ * sys_arch.c. If a particular port needs a different implementation, then\r
+ * this macro may be defined in sys_arch.h\r
+ */\r
+#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)\r
+sys_prot_t sys_arch_protect(void);\r
+void sys_arch_unprotect(sys_prot_t pval);\r
+\r
+#else\r
+\r
+#define SYS_ARCH_DECL_PROTECT(lev)\r
+#define SYS_ARCH_PROTECT(lev)\r
+#define SYS_ARCH_UNPROTECT(lev)\r
+\r
+#endif /* SYS_LIGHTWEIGHT_PROT */\r
+\r
+#endif /* SYS_ARCH_PROTECT */\r
+\r
+#endif /* __LWIP_SYS_H__ */\r
index 9f8689227db1d620d6fecde53c191696d73dc2ee..b4f78bf56dd9b985d7e4b58cf837ec203bddc084 100644 (file)
-/*
- * 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__ */
-
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_TCP_H__\r
+#define __LWIP_TCP_H__\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/mem.h"\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/opt.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/icmp.h"\r
+\r
+#include "lwip/err.h"\r
+\r
+struct tcp_pcb;\r
+\r
+/* Functions for interfacing with TCP: */\r
+\r
+/* Lower layer interface to TCP: */\r
+void             tcp_init    (void);  /* Must be called first to\r
+           initialize TCP. */\r
+void             tcp_tmr     (void);  /* Must be called every\r
+           TCP_TMR_INTERVAL\r
+           ms. (Typically 250 ms). */\r
+/* Application program's interface: */\r
+struct tcp_pcb * tcp_new     (void);\r
+struct tcp_pcb * tcp_alloc   (u8_t prio);\r
+\r
+void             tcp_arg     (struct tcp_pcb *pcb, void *arg);\r
+void             tcp_accept  (struct tcp_pcb *pcb,\r
+            err_t (* accept)(void *arg, struct tcp_pcb *newpcb,\r
+                 err_t err));\r
+void             tcp_recv    (struct tcp_pcb *pcb,\r
+            err_t (* recv)(void *arg, struct tcp_pcb *tpcb,\r
+          struct pbuf *p, err_t err));\r
+void             tcp_sent    (struct tcp_pcb *pcb,\r
+            err_t (* sent)(void *arg, struct tcp_pcb *tpcb,\r
+               u16_t len));\r
+void             tcp_poll    (struct tcp_pcb *pcb,\r
+            err_t (* poll)(void *arg, struct tcp_pcb *tpcb),\r
+            u8_t interval);\r
+void             tcp_err     (struct tcp_pcb *pcb,\r
+            void (* err)(void *arg, err_t err));\r
+\r
+#define          tcp_mss(pcb)      ((pcb)->mss)\r
+#define          tcp_sndbuf(pcb)   ((pcb)->snd_buf)\r
+\r
+void             tcp_recved  (struct tcp_pcb *pcb, u16_t len);\r
+err_t            tcp_bind    (struct tcp_pcb *pcb, struct ip_addr *ipaddr,\r
+            u16_t port);\r
+err_t            tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr,\r
+            u16_t port, err_t (* connected)(void *arg,\r
+                    struct tcp_pcb *tpcb,\r
+                    err_t err));\r
+struct tcp_pcb * tcp_listen  (struct tcp_pcb *pcb);\r
+void             tcp_abort   (struct tcp_pcb *pcb);\r
+err_t            tcp_close   (struct tcp_pcb *pcb);\r
+err_t            tcp_write   (struct tcp_pcb *pcb, const void *dataptr, u16_t len,\r
+            u8_t copy);\r
+\r
+void             tcp_setprio (struct tcp_pcb *pcb, u8_t prio);\r
+\r
+#define TCP_PRIO_MIN    1\r
+#define TCP_PRIO_NORMAL 64\r
+#define TCP_PRIO_MAX    127\r
+\r
+/* It is also possible to call these two functions at the right\r
+   intervals (instead of calling tcp_tmr()). */\r
+void             tcp_slowtmr (void);\r
+void             tcp_fasttmr (void);\r
+\r
+\r
+/* Only used by IP to pass a TCP segment to TCP: */\r
+void             tcp_input   (struct pbuf *p, struct netif *inp);\r
+/* Used within the TCP code only: */\r
+err_t            tcp_output  (struct tcp_pcb *pcb);\r
+void             tcp_rexmit  (struct tcp_pcb *pcb);\r
+void             tcp_rexmit_rto  (struct tcp_pcb *pcb);\r
+\r
+\r
+\r
+#define TCP_SEQ_LT(a,b)     ((s32_t)((a)-(b)) < 0)\r
+#define TCP_SEQ_LEQ(a,b)    ((s32_t)((a)-(b)) <= 0)\r
+#define TCP_SEQ_GT(a,b)     ((s32_t)((a)-(b)) > 0)\r
+#define TCP_SEQ_GEQ(a,b)    ((s32_t)((a)-(b)) >= 0)\r
+/* is b<=a<=c? */\r
+#if 0 /* see bug #10548 */\r
+#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))\r
+#endif\r
+#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))\r
+#define TCP_FIN 0x01U\r
+#define TCP_SYN 0x02U\r
+#define TCP_RST 0x04U\r
+#define TCP_PSH 0x08U\r
+#define TCP_ACK 0x10U\r
+#define TCP_URG 0x20U\r
+#define TCP_ECE 0x40U\r
+#define TCP_CWR 0x80U\r
+\r
+#define TCP_FLAGS 0x3fU\r
+\r
+/* Length of the TCP header, excluding options. */\r
+#define TCP_HLEN 20\r
+\r
+#ifndef TCP_TMR_INTERVAL\r
+#define TCP_TMR_INTERVAL       250  /* The TCP timer interval in\r
+                                       milliseconds. */\r
+#endif /* TCP_TMR_INTERVAL */\r
+\r
+#ifndef TCP_FAST_INTERVAL\r
+#define TCP_FAST_INTERVAL      TCP_TMR_INTERVAL /* the fine grained timeout in\r
+                                       milliseconds */\r
+#endif /* TCP_FAST_INTERVAL */\r
+\r
+#ifndef TCP_SLOW_INTERVAL\r
+#define TCP_SLOW_INTERVAL      (2*TCP_TMR_INTERVAL)  /* the coarse grained timeout in\r
+                                       milliseconds */\r
+#endif /* TCP_SLOW_INTERVAL */\r
+\r
+#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */\r
+#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */\r
+\r
+#define TCP_OOSEQ_TIMEOUT        6U /* x RTO */\r
+\r
+#define TCP_MSL 60000  /* The maximum segment lifetime in microseconds */\r
+\r
+/*\r
+ * User-settable options (used with setsockopt).\r
+ */\r
+#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */\r
+#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keepalive miliseconds */\r
+\r
+/* Keepalive values */\r
+#define  TCP_KEEPDEFAULT   7200000                       /* KEEPALIVE timer in miliseconds */\r
+#define  TCP_KEEPINTVL     75000                         /* Time between KEEPALIVE probes in miliseconds */\r
+#define  TCP_KEEPCNT       9                             /* Counter for KEEPALIVE probes */\r
+#define  TCP_MAXIDLE       TCP_KEEPCNT * TCP_KEEPINTVL   /* Maximum KEEPALIVE probe time */\r
+\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct tcp_hdr {\r
+  PACK_STRUCT_FIELD(u16_t src);\r
+  PACK_STRUCT_FIELD(u16_t dest);\r
+  PACK_STRUCT_FIELD(u32_t seqno);\r
+  PACK_STRUCT_FIELD(u32_t ackno);\r
+  PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);\r
+  PACK_STRUCT_FIELD(u16_t wnd);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+  PACK_STRUCT_FIELD(u16_t urgp);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)\r
+#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)\r
+#define TCPH_FLAGS(phdr)  (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)\r
+\r
+#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))\r
+#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))\r
+#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags))\r
+#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags))\r
+#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )\r
+\r
+#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \\r
+          TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0))\r
+\r
+enum tcp_state {\r
+  CLOSED      = 0,\r
+  LISTEN      = 1,\r
+  SYN_SENT    = 2,\r
+  SYN_RCVD    = 3,\r
+  ESTABLISHED = 4,\r
+  FIN_WAIT_1  = 5,\r
+  FIN_WAIT_2  = 6,\r
+  CLOSE_WAIT  = 7,\r
+  CLOSING     = 8,\r
+  LAST_ACK    = 9,\r
+  TIME_WAIT   = 10\r
+};\r
+\r
+/* the TCP protocol control block */\r
+struct tcp_pcb {\r
+/** common PCB members */\r
+  IP_PCB;\r
+/** protocol specific PCB members */\r
+  struct tcp_pcb *next; /* for the linked list */\r
+  enum tcp_state state; /* TCP state */\r
+  u8_t prio;\r
+  void *callback_arg;\r
+\r
+  u16_t local_port;\r
+  u16_t remote_port;\r
+  \r
+  u8_t flags;\r
+#define TF_ACK_DELAY (u8_t)0x01U   /* Delayed ACK. */\r
+#define TF_ACK_NOW   (u8_t)0x02U   /* Immediate ACK. */\r
+#define TF_INFR      (u8_t)0x04U   /* In fast recovery. */\r
+#define TF_RESET     (u8_t)0x08U   /* Connection was reset. */\r
+#define TF_CLOSED    (u8_t)0x10U   /* Connection was sucessfully closed. */\r
+#define TF_GOT_FIN   (u8_t)0x20U   /* Connection was closed by the remote end. */\r
+#define TF_NODELAY   (u8_t)0x40U   /* Disable Nagle algorithm */\r
+\r
+  /* receiver variables */\r
+  u32_t rcv_nxt;   /* next seqno expected */\r
+  u16_t rcv_wnd;   /* receiver window */\r
+  \r
+  /* Timers */\r
+  u32_t tmr;\r
+  u8_t polltmr, pollinterval;\r
+  \r
+  /* Retransmission timer. */\r
+  u16_t rtime;\r
+  \r
+  u16_t mss;   /* maximum segment size */\r
+  \r
+  /* RTT (round trip time) estimation variables */\r
+  u32_t rttest; /* RTT estimate in 500ms ticks */\r
+  u32_t rtseq;  /* sequence number being timed */\r
+  s16_t sa, sv; /* @todo document this */\r
+\r
+  u16_t rto;    /* retransmission time-out */\r
+  u8_t nrtx;    /* number of retransmissions */\r
+\r
+  /* fast retransmit/recovery */\r
+  u32_t lastack; /* Highest acknowledged seqno. */\r
+  u8_t dupacks;\r
+  \r
+  /* congestion avoidance/control variables */\r
+  u16_t cwnd;  \r
+  u16_t ssthresh;\r
+\r
+  /* sender variables */\r
+  u32_t snd_nxt,       /* next seqno to be sent */\r
+    snd_max,       /* Highest seqno sent. */\r
+    snd_wnd,       /* sender window */\r
+    snd_wl1, snd_wl2, /* Sequence and acknowledgement numbers of last\r
+       window update. */\r
+    snd_lbb;       /* Sequence number of next byte to be buffered. */\r
+\r
+  u16_t acked;\r
+  \r
+  u16_t snd_buf;   /* Available buffer space for sending (in bytes). */\r
+  u8_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */\r
+  \r
+  \r
+  /* These are ordered by sequence number: */\r
+  struct tcp_seg *unsent;   /* Unsent (queued) segments. */\r
+  struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */\r
+#if TCP_QUEUE_OOSEQ  \r
+  struct tcp_seg *ooseq;    /* Received out of sequence segments. */\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+#if LWIP_CALLBACK_API\r
+  /* Function to be called when more send buffer space is available. */\r
+  err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space);\r
+  \r
+  /* Function to be called when (in-sequence) data has arrived. */\r
+  err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);\r
+\r
+  /* Function to be called when a connection has been set up. */\r
+  err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);\r
+\r
+  /* Function to call when a listener has been connected. */\r
+  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);\r
+\r
+  /* Function which is called periodically. */\r
+  err_t (* poll)(void *arg, struct tcp_pcb *pcb);\r
+\r
+  /* Function to be called whenever a fatal error occurs. */\r
+  void (* errf)(void *arg, err_t err);\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+  /* idle time before KEEPALIVE is sent */\r
+  u32_t keepalive;\r
+  \r
+  /* KEEPALIVE counter */\r
+  u8_t keep_cnt;\r
+};\r
+\r
+struct tcp_pcb_listen {  \r
+/* Common members of all PCB types */\r
+  IP_PCB;\r
+\r
+/* Protocol specific PCB members */\r
+  struct tcp_pcb_listen *next;   /* for the linked list */\r
+  \r
+  /* Even if state is obviously LISTEN this is here for\r
+   * field compatibility with tpc_pcb to which it is cast sometimes\r
+   * Until a cleaner solution emerges this is here.FIXME\r
+   */ \r
+  enum tcp_state state;   /* TCP state */\r
+\r
+  u8_t prio;\r
+  void *callback_arg;\r
+  \r
+  u16_t local_port; \r
+\r
+#if LWIP_CALLBACK_API\r
+  /* Function to call when a listener has been connected. */\r
+  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);\r
+#endif /* LWIP_CALLBACK_API */\r
+};\r
+\r
+#if LWIP_EVENT_API\r
+\r
+enum lwip_event {\r
+  LWIP_EVENT_ACCEPT,\r
+  LWIP_EVENT_SENT,\r
+  LWIP_EVENT_RECV,\r
+  LWIP_EVENT_CONNECTED,\r
+  LWIP_EVENT_POLL,\r
+  LWIP_EVENT_ERR\r
+};\r
+\r
+err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,\r
+         enum lwip_event,\r
+         struct pbuf *p,\r
+         u16_t size,\r
+         err_t err);\r
+\r
+#define TCP_EVENT_ACCEPT(pcb,err,ret)    ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                LWIP_EVENT_ACCEPT, NULL, 0, err)\r
+#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                   LWIP_EVENT_SENT, NULL, space, ERR_OK)\r
+#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                LWIP_EVENT_RECV, (p), 0, (err))\r
+#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                LWIP_EVENT_CONNECTED, NULL, 0, (err))\r
+#define TCP_EVENT_POLL(pcb,ret)       ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                LWIP_EVENT_POLL, NULL, 0, ERR_OK)\r
+#define TCP_EVENT_ERR(errf,arg,err)  lwip_tcp_event((arg), NULL, \\r
+                LWIP_EVENT_ERR, NULL, 0, (err))\r
+#else /* LWIP_EVENT_API */\r
+#define TCP_EVENT_ACCEPT(pcb,err,ret)     \\r
+                        if((pcb)->accept != NULL) \\r
+                        (ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err)))\r
+#define TCP_EVENT_SENT(pcb,space,ret) \\r
+                        if((pcb)->sent != NULL) \\r
+                        (ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space)))\r
+#define TCP_EVENT_RECV(pcb,p,err,ret) \\r
+                        if((pcb)->recv != NULL) \\r
+                        { ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \\r
+                          if (p) pbuf_free(p); }\r
+#define TCP_EVENT_CONNECTED(pcb,err,ret) \\r
+                        if((pcb)->connected != NULL) \\r
+                        (ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))\r
+#define TCP_EVENT_POLL(pcb,ret) \\r
+                        if((pcb)->poll != NULL) \\r
+                        (ret = (pcb)->poll((pcb)->callback_arg,(pcb)))\r
+#define TCP_EVENT_ERR(errf,arg,err) \\r
+                        if((errf) != NULL) \\r
+                        (errf)((arg),(err))\r
+#endif /* LWIP_EVENT_API */\r
+\r
+/* This structure represents a TCP segment on the unsent and unacked queues */\r
+struct tcp_seg {\r
+  struct tcp_seg *next;    /* used when putting segements on a queue */\r
+  struct pbuf *p;          /* buffer containing data + TCP header */\r
+  void *dataptr;           /* pointer to the TCP data in the pbuf */\r
+  u16_t len;               /* the TCP length of this segment */\r
+  struct tcp_hdr *tcphdr;  /* the TCP header */\r
+};\r
+\r
+/* Internal functions and global variables: */\r
+struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);\r
+void tcp_pcb_purge(struct tcp_pcb *pcb);\r
+void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);\r
+\r
+u8_t tcp_segs_free(struct tcp_seg *seg);\r
+u8_t tcp_seg_free(struct tcp_seg *seg);\r
+struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);\r
+\r
+#define tcp_ack(pcb)     if((pcb)->flags & TF_ACK_DELAY) { \\r
+                            (pcb)->flags &= ~TF_ACK_DELAY; \\r
+                            (pcb)->flags |= TF_ACK_NOW; \\r
+                            tcp_output(pcb); \\r
+                         } else { \\r
+                            (pcb)->flags |= TF_ACK_DELAY; \\r
+                         }\r
+\r
+#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \\r
+                         tcp_output(pcb)\r
+\r
+err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags);\r
+err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,\r
+    u8_t flags, u8_t copy,\r
+                u8_t *optdata, u8_t optlen);\r
+\r
+void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);\r
+\r
+void tcp_rst(u32_t seqno, u32_t ackno,\r
+       struct ip_addr *local_ip, struct ip_addr *remote_ip,\r
+       u16_t local_port, u16_t remote_port);\r
+\r
+u32_t tcp_next_iss(void);\r
+\r
+void tcp_keepalive(struct tcp_pcb *pcb);\r
+\r
+extern struct tcp_pcb *tcp_input_pcb;\r
+extern u32_t tcp_ticks;\r
+\r
+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG\r
+void tcp_debug_print(struct tcp_hdr *tcphdr);\r
+void tcp_debug_print_flags(u8_t flags);\r
+void tcp_debug_print_state(enum tcp_state s);\r
+void tcp_debug_print_pcbs(void);\r
+s16_t tcp_pcbs_sane(void);\r
+#else\r
+#  define tcp_debug_print(tcphdr)\r
+#  define tcp_debug_print_flags(flags)\r
+#  define tcp_debug_print_state(s)\r
+#  define tcp_debug_print_pcbs()\r
+#  define tcp_pcbs_sane() 1\r
+#endif /* TCP_DEBUG */\r
+\r
+#if NO_SYS\r
+#define tcp_timer_needed()\r
+#else\r
+void tcp_timer_needed(void);\r
+#endif\r
+\r
+/* The TCP PCB lists. */\r
+union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */\r
+  struct tcp_pcb_listen *listen_pcbs; \r
+  struct tcp_pcb *pcbs;\r
+};\r
+extern union tcp_listen_pcbs_t tcp_listen_pcbs;\r
+extern struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a\r
+              state in which they accept or send\r
+              data. */\r
+extern struct tcp_pcb *tcp_tw_pcbs;      /* List of all TCP PCBs in TIME-WAIT. */\r
+\r
+extern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */\r
+\r
+/* Axioms about the above lists:   \r
+   1) Every TCP PCB that is not CLOSED is in one of the lists.\r
+   2) A PCB is only in one of the lists.\r
+   3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.\r
+   4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.\r
+*/\r
+\r
+/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB\r
+   with a PCB list or removes a PCB from a list, respectively. */\r
+#if 0\r
+#define TCP_REG(pcbs, npcb) do {\\r
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \\r
+                            for(tcp_tmp_pcb = *pcbs; \\r
+          tcp_tmp_pcb != NULL; \\r
+        tcp_tmp_pcb = tcp_tmp_pcb->next) { \\r
+                                LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \\r
+                            } \\r
+                            LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \\r
+                            npcb->next = *pcbs; \\r
+                            LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \\r
+                            *(pcbs) = npcb; \\r
+                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \\r
+              tcp_timer_needed(); \\r
+                            } while(0)\r
+#define TCP_RMV(pcbs, npcb) do { \\r
+                            LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \\r
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \\r
+                            if(*pcbs == npcb) { \\r
+                               *pcbs = (*pcbs)->next; \\r
+                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \\r
+                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \\r
+                                  tcp_tmp_pcb->next = npcb->next; \\r
+                                  break; \\r
+                               } \\r
+                            } \\r
+                            npcb->next = NULL; \\r
+                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \\r
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \\r
+                            } while(0)\r
+\r
+#else /* LWIP_DEBUG */\r
+#define TCP_REG(pcbs, npcb) do { \\r
+                            npcb->next = *pcbs; \\r
+                            *(pcbs) = npcb; \\r
+              tcp_timer_needed(); \\r
+                            } while(0)\r
+#define TCP_RMV(pcbs, npcb) do { \\r
+                            if(*(pcbs) == npcb) { \\r
+                               (*(pcbs)) = (*pcbs)->next; \\r
+                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \\r
+                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \\r
+                                  tcp_tmp_pcb->next = npcb->next; \\r
+                                  break; \\r
+                               } \\r
+                            } \\r
+                            npcb->next = NULL; \\r
+                            } while(0)\r
+#endif /* LWIP_DEBUG */\r
+#endif /* __LWIP_TCP_H__ */\r
+\r
+\r
+\r
index 316ae4fc53659bed05a6696fe31c7fb94cab8de7..242664ef71aadce7fc2cca9f23129ad30d17d134 100644 (file)
@@ -1,68 +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__ */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_TCPIP_H__\r
+#define __LWIP_TCPIP_H__\r
+\r
+#include "lwip/api_msg.h"\r
+#include "lwip/pbuf.h"\r
+\r
+void tcpip_init(void (* tcpip_init_done)(void *), void *arg);\r
+void tcpip_apimsg(struct api_msg *apimsg);\r
+err_t tcpip_input(struct pbuf *p, struct netif *inp);\r
+err_t tcpip_callback(void (*f)(void *ctx), void *ctx);\r
+\r
+void tcpip_tcp_timer_needed(void);\r
+\r
+enum tcpip_msg_type {\r
+  TCPIP_MSG_API,\r
+  TCPIP_MSG_INPUT,\r
+  TCPIP_MSG_CALLBACK\r
+};\r
+\r
+struct tcpip_msg {\r
+  enum tcpip_msg_type type;\r
+  sys_sem_t *sem;\r
+  union {\r
+    struct api_msg *apimsg;\r
+    struct {\r
+      struct pbuf *p;\r
+      struct netif *netif;\r
+    } inp;\r
+    struct {\r
+      void (*f)(void *ctx);\r
+      void *ctx;\r
+    } cb;\r
+  } msg;\r
+};\r
+\r
+\r
+#endif /* __LWIP_TCPIP_H__ */\r
index 346898e84cb706b94f2badf57b3da6381e9d12a2..adefdc9ddc63d085a8f86e2d9bd26d3fe273beb5 100644 (file)
-/*
- * 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__ */
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_UDP_H__\r
+#define __LWIP_UDP_H__\r
+\r
+#include "lwip/arch.h"\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/ip.h"\r
+\r
+#define UDP_HLEN 8\r
+\r
+struct udp_hdr {\r
+  PACK_STRUCT_FIELD(u16_t src);\r
+  PACK_STRUCT_FIELD(u16_t dest);  /* src/dest UDP ports */\r
+  PACK_STRUCT_FIELD(u16_t len);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+} PACK_STRUCT_STRUCT;\r
+\r
+#define UDP_FLAGS_NOCHKSUM 0x01U\r
+#define UDP_FLAGS_UDPLITE  0x02U\r
+#define UDP_FLAGS_CONNECTED  0x04U\r
+\r
+struct udp_pcb {\r
+/* Common members of all PCB types */\r
+  IP_PCB;\r
+\r
+/* Protocol specific PCB members */\r
+\r
+  struct udp_pcb *next;\r
+\r
+  u8_t flags;\r
+  u16_t local_port, remote_port;\r
+  \r
+  u16_t chksum_len;\r
+  \r
+  void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p,\r
+    struct ip_addr *addr, u16_t port);\r
+  void *recv_arg;  \r
+};\r
+/* udp_pcbs export for exernal reference (e.g. SNMP agent) */\r
+extern struct udp_pcb *udp_pcbs;\r
+\r
+/* The following functions is the application layer interface to the\r
+   UDP code. */\r
+struct udp_pcb * udp_new        (void);\r
+void             udp_remove     (struct udp_pcb *pcb);\r
+err_t            udp_bind       (struct udp_pcb *pcb, struct ip_addr *ipaddr,\r
+                 u16_t port);\r
+err_t            udp_connect    (struct udp_pcb *pcb, struct ip_addr *ipaddr,\r
+                 u16_t port);\r
+void             udp_disconnect    (struct udp_pcb *pcb);\r
+void             udp_recv       (struct udp_pcb *pcb,\r
+         void (* recv)(void *arg, struct udp_pcb *upcb,\r
+                 struct pbuf *p,\r
+                 struct ip_addr *addr,\r
+                 u16_t port),\r
+         void *recv_arg);\r
+err_t            udp_sendto     (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port);\r
+err_t            udp_send       (struct udp_pcb *pcb, struct pbuf *p);\r
+\r
+#define          udp_flags(pcb)  ((pcb)->flags)\r
+#define          udp_setflags(pcb, f)  ((pcb)->flags = (f))\r
+\r
+/* The following functions are the lower layer interface to UDP. */\r
+void             udp_input      (struct pbuf *p, struct netif *inp);\r
+void             udp_init       (void);\r
+\r
+#if UDP_DEBUG\r
+void udp_debug_print(struct udp_hdr *udphdr);\r
+#else\r
+#define udp_debug_print(udphdr)\r
+#endif\r
+#endif /* __LWIP_UDP_H__ */\r
+\r
+\r
index d64f55e3961c4b5ca3286b77deabbc8c70d35ddb..cc0a35f4e91d6c4f7647b39a60dc3e760ca45bbd 100644 (file)
-/*
- * 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__ */
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>\r
+ * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#ifndef __NETIF_ETHARP_H__\r
+#define __NETIF_ETHARP_H__\r
+\r
+#ifndef ETH_PAD_SIZE\r
+#define ETH_PAD_SIZE 0\r
+#endif\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/ip.h"\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct eth_addr {\r
+  PACK_STRUCT_FIELD(u8_t addr[6]);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct eth_hdr {\r
+#if ETH_PAD_SIZE\r
+  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);\r
+#endif\r
+  PACK_STRUCT_FIELD(struct eth_addr dest);\r
+  PACK_STRUCT_FIELD(struct eth_addr src);\r
+  PACK_STRUCT_FIELD(u16_t type);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+/** the ARP message */\r
+struct etharp_hdr {\r
+  PACK_STRUCT_FIELD(struct eth_hdr ethhdr);\r
+  PACK_STRUCT_FIELD(u16_t hwtype);\r
+  PACK_STRUCT_FIELD(u16_t proto);\r
+  PACK_STRUCT_FIELD(u16_t _hwlen_protolen);\r
+  PACK_STRUCT_FIELD(u16_t opcode);\r
+  PACK_STRUCT_FIELD(struct eth_addr shwaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);\r
+  PACK_STRUCT_FIELD(struct eth_addr dhwaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ethip_hdr {\r
+  PACK_STRUCT_FIELD(struct eth_hdr eth);\r
+  PACK_STRUCT_FIELD(struct ip_hdr ip);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/** 5 seconds period */\r
+#define ARP_TMR_INTERVAL 5000\r
+\r
+#define ETHTYPE_ARP 0x0806\r
+#define ETHTYPE_IP  0x0800\r
+\r
+\r
+void etharp_init(void);\r
+void etharp_tmr(void);\r
+s8_t etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,\r
+         struct eth_addr **eth_ret, struct ip_addr **ip_ret);\r
+void etharp_ip_input(struct netif *netif, struct pbuf *p);\r
+void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,\r
+         struct pbuf *p);\r
+err_t etharp_output(struct netif *netif, struct ip_addr *ipaddr,\r
+         struct pbuf *q);\r
+err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);\r
+err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);\r
+\r
+#endif /* __NETIF_ARP_H__ */\r
index 97b3c67645badf25cf923eae628ab30480fa9202..7fd54873397e37e0425764881a10b30b15e2b505 100644 (file)
@@ -1,39 +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__ */
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __NETIF_LOOPIF_H__\r
+#define __NETIF_LOOPIF_H__\r
+\r
+#include "lwip/netif.h"\r
+\r
+err_t loopif_init(struct netif *netif);\r
+\r
+#endif /* __NETIF_LOOPIF_H__ */\r
index bf70046a9f6e8e8c020725f8fd3abe627cb63292..d9060fc9734231af45a4048d8108631ff491f3f9 100644 (file)
@@ -1,42 +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 
-
+/*\r
+ * Copyright (c) 2001, Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ *\r
+ * Redistribution and use in source and binary forms, with or without \r
+ * modification, are permitted provided that the following conditions \r
+ * are met: \r
+ * 1. Redistributions of source code must retain the above copyright \r
+ *    notice, this list of conditions and the following disclaimer. \r
+ * 2. Redistributions in binary form must reproduce the above copyright \r
+ *    notice, this list of conditions and the following disclaimer in the \r
+ *    documentation and/or other materials provided with the distribution. \r
+ * 3. Neither the name of the Institute nor the names of its contributors \r
+ *    may be used to endorse or promote products derived from this software \r
+ *    without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND \r
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE \r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \r
+ * SUCH DAMAGE. \r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __NETIF_SLIPIF_H__\r
+#define __NETIF_SLIPIF_H__\r
+\r
+#include "lwip/netif.h"\r
+\r
+err_t slipif_init(struct netif * netif);\r
\r
+#endif \r
+\r
index 9787f6d8d681950fa3da040f0134210ccdaff1bd..22eeb9a08846d80e9f23977ca51fb4577c209f91 100644 (file)
-/**
- * @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;
-}
+/**\r
+ * @file\r
+ * Address Resolution Protocol module for IP over Ethernet\r
+ *\r
+ * Functionally, ARP is divided into two parts. The first maps an IP address\r
+ * to a physical address when sending a packet, and the second part answers\r
+ * requests from other machines for our physical address.\r
+ *\r
+ * This implementation complies with RFC 826 (Ethernet ARP). It supports\r
+ * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6\r
+ * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon\r
+ * address change.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>\r
+ * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ */\r
+#include <string.h>\r
+#include "lwip/opt.h"\r
+#include "lwip/inet.h"\r
+#include "netif/etharp.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+\r
+/* ARP needs to inform DHCP of any ARP replies? */\r
+#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)\r
+#  include "lwip/dhcp.h"\r
+#endif\r
+\r
+/** the time an ARP entry stays valid after its last update,\r
+ * (240 * 5) seconds = 20 minutes.\r
+ */\r
+#define ARP_MAXAGE 240\r
+/** the time an ARP entry stays pending after first request,\r
+ * (2 * 5) seconds = 10 seconds.\r
+ * \r
+ * @internal Keep this number at least 2, otherwise it might\r
+ * run out instantly if the timeout occurs directly after a request.\r
+ */\r
+#define ARP_MAXPENDING 2\r
+\r
+#define HWTYPE_ETHERNET 1\r
+\r
+/** ARP message types */\r
+#define ARP_REQUEST 1\r
+#define ARP_REPLY 2\r
+\r
+#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)\r
+#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)\r
+\r
+#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))\r
+#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))\r
+\r
+enum etharp_state {\r
+  ETHARP_STATE_EMPTY,\r
+  ETHARP_STATE_PENDING,\r
+  ETHARP_STATE_STABLE,\r
+  /** @internal transitional state used in etharp_tmr() for convenience*/\r
+  ETHARP_STATE_EXPIRED\r
+};\r
+\r
+struct etharp_entry {\r
+#if ARP_QUEUEING\r
+  /** \r
+   * Pointer to queue of pending outgoing packets on this ARP entry.\r
+   */\r
+   struct pbuf *p;\r
+#endif\r
+  struct ip_addr ipaddr;\r
+  struct eth_addr ethaddr;\r
+  enum etharp_state state;\r
+  u8_t ctime;\r
+  struct netif *netif;\r
+};\r
+\r
+static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};\r
+static struct etharp_entry arp_table[ARP_TABLE_SIZE];\r
+\r
+/**\r
+ * Try hard to create a new entry - we want the IP address to appear in\r
+ * the cache (even if this means removing an active entry or so). */\r
+#define ETHARP_TRY_HARD 1\r
+\r
+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);\r
+static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);\r
+/**\r
+ * Initializes ARP module.\r
+ */\r
+void\r
+etharp_init(void)\r
+{\r
+  u8_t i;\r
+  /* clear ARP entries */\r
+  for(i = 0; i < ARP_TABLE_SIZE; ++i) {\r
+    arp_table[i].state = ETHARP_STATE_EMPTY;\r
+#if ARP_QUEUEING\r
+    arp_table[i].p = NULL;\r
+#endif\r
+    arp_table[i].ctime = 0;\r
+    arp_table[i].netif = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+ * Clears expired entries in the ARP table.\r
+ *\r
+ * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),\r
+ * in order to expire entries in the ARP table.\r
+ */\r
+void\r
+etharp_tmr(void)\r
+{\r
+  u8_t i;\r
+\r
+  LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));\r
+  /* remove expired entries from the ARP table */\r
+  for (i = 0; i < ARP_TABLE_SIZE; ++i) {\r
+    arp_table[i].ctime++;\r
+    /* stable entry? */\r
+    if ((arp_table[i].state == ETHARP_STATE_STABLE) &&\r
+         /* entry has become old? */\r
+        (arp_table[i].ctime >= ARP_MAXAGE)) {\r
+      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %"U16_F".\n", (u16_t)i));\r
+      arp_table[i].state = ETHARP_STATE_EXPIRED;\r
+    /* pending entry? */\r
+    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
+      /* entry unresolved/pending for too long? */\r
+      if (arp_table[i].ctime >= ARP_MAXPENDING) {\r
+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %"U16_F".\n", (u16_t)i));\r
+        arp_table[i].state = ETHARP_STATE_EXPIRED;\r
+#if ARP_QUEUEING\r
+      } else if (arp_table[i].p != NULL) {\r
+        /* resend an ARP query here */\r
+#endif\r
+      }\r
+    }\r
+    /* clean up entries that have just been expired */\r
+    if (arp_table[i].state == ETHARP_STATE_EXPIRED) {\r
+      /* remove from SNMP ARP index tree */\r
+      snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);\r
+#if ARP_QUEUEING\r
+      /* and empty packet queue */\r
+      if (arp_table[i].p != NULL) {\r
+        /* remove all queued packets */\r
+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].p)));\r
+        pbuf_free(arp_table[i].p);\r
+        arp_table[i].p = NULL;\r
+      }\r
+#endif\r
+      /* recycle entry for re-use */      \r
+      arp_table[i].state = ETHARP_STATE_EMPTY;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Search the ARP table for a matching or new entry.\r
+ * \r
+ * If an IP address is given, return a pending or stable ARP entry that matches\r
+ * the address. If no match is found, create a new entry with this address set,\r
+ * but in state ETHARP_EMPTY. The caller must check and possibly change the\r
+ * state of the returned entry.\r
+ * \r
+ * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.\r
+ * \r
+ * In all cases, attempt to create new entries from an empty entry. If no\r
+ * empty entries are available and ETHARP_TRY_HARD flag is set, recycle\r
+ * old entries. Heuristic choose the least important entry for recycling.\r
+ *\r
+ * @param ipaddr IP address to find in ARP cache, or to add if not found.\r
+ * @param flags\r
+ * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of\r
+ * active (stable or pending) entries.\r
+ *  \r
+ * @return The ARP entry index that matched or is created, ERR_MEM if no\r
+ * entry is found or could be recycled.\r
+ */\r
+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)\r
+{\r
+  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;\r
+  s8_t empty = ARP_TABLE_SIZE;\r
+  u8_t i = 0, age_pending = 0, age_stable = 0;\r
+#if ARP_QUEUEING\r
+  /* oldest entry with packets on queue */\r
+  s8_t old_queue = ARP_TABLE_SIZE;\r
+  /* its age */\r
+  u8_t age_queue = 0;\r
+#endif\r
+\r
+  /**\r
+   * a) do a search through the cache, remember candidates\r
+   * b) select candidate entry\r
+   * c) create new entry\r
+   */\r
+\r
+  /* a) in a single search sweep, do all of this\r
+   * 1) remember the first empty entry (if any)\r
+   * 2) remember the oldest stable entry (if any)\r
+   * 3) remember the oldest pending entry without queued packets (if any)\r
+   * 4) remember the oldest pending entry with queued packets (if any)\r
+   * 5) search for a matching IP entry, either pending or stable\r
+   *    until 5 matches, or all entries are searched for.\r
+   */\r
+\r
+  for (i = 0; i < ARP_TABLE_SIZE; ++i) {\r
+    /* no empty entry found yet and now we do find one? */\r
+    if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {\r
+      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));\r
+      /* remember first empty entry */\r
+      empty = i;\r
+    }\r
+    /* pending entry? */\r
+    else if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
+      /* if given, does IP address match IP address in ARP entry? */\r
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {\r
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));\r
+        /* found exact IP address match, simply bail out */\r
+        return i;\r
+#if ARP_QUEUEING\r
+      /* pending with queued packets? */\r
+      } else if (arp_table[i].p != NULL) {\r
+        if (arp_table[i].ctime >= age_queue) {\r
+          old_queue = i;\r
+          age_queue = arp_table[i].ctime;\r
+        }\r
+#endif\r
+      /* pending without queued packets? */\r
+      } else {\r
+        if (arp_table[i].ctime >= age_pending) {\r
+          old_pending = i;\r
+          age_pending = arp_table[i].ctime;\r
+        }\r
+      }        \r
+    }\r
+    /* stable entry? */\r
+    else if (arp_table[i].state == ETHARP_STATE_STABLE) {\r
+      /* if given, does IP address match IP address in ARP entry? */\r
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {\r
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));\r
+        /* found exact IP address match, simply bail out */\r
+        return i;\r
+      /* remember entry with oldest stable entry in oldest, its age in maxtime */\r
+      } else if (arp_table[i].ctime >= age_stable) {\r
+        old_stable = i;\r
+        age_stable = arp_table[i].ctime;\r
+      }\r
+    }\r
+  }\r
+  /* { we have no match } => try to create a new entry */\r
+   \r
+  /* no empty entry found and not allowed to recycle? */\r
+  if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))\r
+  {\r
+    return (s8_t)ERR_MEM;\r
+  }\r
+  \r
+  /* b) choose the least destructive entry to recycle:\r
+   * 1) empty entry\r
+   * 2) oldest stable entry\r
+   * 3) oldest pending entry without queued packets\r
+   * 4) oldest pending entry without queued packets\r
+   * \r
+   * { ETHARP_TRY_HARD is set at this point }\r
+   */ \r
+\r
+  /* 1) empty entry available? */\r
+  if (empty < ARP_TABLE_SIZE) {\r
+    i = empty;\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));\r
+  }\r
+  /* 2) found recyclable stable entry? */\r
+  else if (old_stable < ARP_TABLE_SIZE) {\r
+    /* recycle oldest stable*/\r
+    i = old_stable;\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));\r
+#if ARP_QUEUEING\r
+    /* no queued packets should exist on stable entries */\r
+    LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL);\r
+#endif\r
+  /* 3) found recyclable pending entry without queued packets? */\r
+  } else if (old_pending < ARP_TABLE_SIZE) {\r
+    /* recycle oldest pending */\r
+    i = old_pending;\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));\r
+#if ARP_QUEUEING\r
+  /* 4) found recyclable pending entry with queued packets? */\r
+  } else if (old_queue < ARP_TABLE_SIZE) {\r
+    /* recycle oldest pending */\r
+    i = old_queue;\r
+    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)));\r
+    pbuf_free(arp_table[i].p);\r
+    arp_table[i].p = NULL;\r
+#endif\r
+    /* no empty or recyclable entries found */\r
+  } else {\r
+    return (s8_t)ERR_MEM;\r
+  }\r
+\r
+  /* { empty or recyclable entry found } */\r
+  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);\r
+\r
+  if (arp_table[i].state != ETHARP_STATE_EMPTY)\r
+  {\r
+    snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);\r
+  }\r
+  /* recycle entry (no-op for an already empty entry) */\r
+  arp_table[i].state = ETHARP_STATE_EMPTY;\r
+\r
+  /* IP address given? */\r
+  if (ipaddr != NULL) {\r
+    /* set IP address */\r
+    ip_addr_set(&arp_table[i].ipaddr, ipaddr);\r
+  }\r
+  arp_table[i].ctime = 0;\r
+  return (err_t)i;\r
+}\r
+\r
+/**\r
+ * Update (or insert) a IP/MAC address pair in the ARP cache.\r
+ *\r
+ * If a pending entry is resolved, any queued packets will be sent\r
+ * at this point.\r
+ * \r
+ * @param ipaddr IP address of the inserted ARP entry.\r
+ * @param ethaddr Ethernet address of the inserted ARP entry.\r
+ * @param flags Defines behaviour:\r
+ * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,\r
+ * only existing ARP entries will be updated.\r
+ *\r
+ * @return\r
+ * - ERR_OK Succesfully updated ARP cache.\r
+ * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.\r
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.\r
+ *\r
+ * @see pbuf_free()\r
+ */\r
+static err_t\r
+update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)\r
+{\r
+  s8_t i;\r
+  u8_t k;\r
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n"));\r
+  LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0);\r
+  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",\r
+                                        ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), \r
+                                        ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],\r
+                                        ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));\r
+  /* non-unicast address? */\r
+  if (ip_addr_isany(ipaddr) ||\r
+      ip_addr_isbroadcast(ipaddr, netif) ||\r
+      ip_addr_ismulticast(ipaddr)) {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));\r
+    return ERR_ARG;\r
+  }\r
+  /* find or create ARP entry */\r
+  i = find_entry(ipaddr, flags);\r
+  /* bail out if no entry could be found */\r
+  if (i < 0) return (err_t)i;\r
+  \r
+  /* mark it stable */\r
+  arp_table[i].state = ETHARP_STATE_STABLE;\r
+  /* record network interface */\r
+  arp_table[i].netif = netif;\r
+\r
+  /* insert in SNMP ARP index tree */\r
+  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);\r
+\r
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));\r
+  /* update address */\r
+  k = netif->hwaddr_len;\r
+  while (k > 0) {\r
+    k--;\r
+    arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];\r
+  }\r
+  /* reset time stamp */\r
+  arp_table[i].ctime = 0;\r
+/* this is where we will send out queued packets! */\r
+#if ARP_QUEUEING\r
+  while (arp_table[i].p != NULL) {\r
+    /* get the first packet on the queue */\r
+    struct pbuf *p = arp_table[i].p;\r
+    /* Ethernet header */\r
+    struct eth_hdr *ethhdr = p->payload;\r
+    /* remember (and reference) remainder of queue */\r
+    /* note: this will also terminate the p pbuf chain */\r
+    arp_table[i].p = pbuf_dequeue(p);\r
+    /* fill-in Ethernet header */\r
+    k = netif->hwaddr_len;\r
+    while(k > 0) {\r
+      k--;\r
+      ethhdr->dest.addr[k] = ethaddr->addr[k];\r
+      ethhdr->src.addr[k] = netif->hwaddr[k];\r
+    }\r
+    ethhdr->type = htons(ETHTYPE_IP);\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));\r
+    /* send the queued IP packet */\r
+    netif->linkoutput(netif, p);\r
+    /* free the queued IP packet */\r
+    pbuf_free(p);\r
+  }\r
+#endif\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Finds (stable) ethernet/IP address pair from ARP table\r
+ * using interface and IP address index.\r
+ * @note the addresses in the ARP table are in network order!\r
+ *\r
+ * @param netif points to interface index\r
+ * @param ipaddr points to the (network order) IP address index\r
+ * @param eth_ret points to return pointer\r
+ * @param ip_ret points to return pointer\r
+ * @return table index if found, -1 otherwise\r
+ */\r
+s8_t\r
+etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,\r
+         struct eth_addr **eth_ret, struct ip_addr **ip_ret)\r
+{\r
+  s8_t i;\r
+\r
+  i = 0;\r
+  while (i < ARP_TABLE_SIZE)\r
+  {\r
+    if ((arp_table[i].state == ETHARP_STATE_STABLE) &&\r
+        (arp_table[i].netif == netif) && \r
+        ip_addr_cmp(ipaddr, &arp_table[i].ipaddr) )\r
+    {\r
+      *eth_ret = &arp_table[i].ethaddr;\r
+      *ip_ret = &arp_table[i].ipaddr;\r
+      return i;\r
+    }\r
+    i++;\r
+  }\r
+  return -1;\r
+}\r
+\r
+/**\r
+ * Updates the ARP table using the given IP packet.\r
+ *\r
+ * Uses the incoming IP packet's source address to update the\r
+ * ARP cache for the local network. The function does not alter\r
+ * or free the packet. This function must be called before the\r
+ * packet p is passed to the IP layer.\r
+ *\r
+ * @param netif The lwIP network interface on which the IP packet pbuf arrived.\r
+ * @param pbuf The IP packet that arrived on netif.\r
+ *\r
+ * @return NULL\r
+ *\r
+ * @see pbuf_free()\r
+ */\r
+void\r
+etharp_ip_input(struct netif *netif, struct pbuf *p)\r
+{\r
+  struct ethip_hdr *hdr;\r
+  LWIP_ASSERT("netif != NULL", netif != NULL);\r
+  /* Only insert an entry if the source IP address of the\r
+     incoming IP packet comes from a host on the local network. */\r
+  hdr = p->payload;\r
+  /* source is not on the local network? */\r
+  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {\r
+    /* do nothing */\r
+    return;\r
+  }\r
+\r
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));\r
+  /* update ARP table */\r
+  /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk\r
+   * back soon (for example, if the destination IP address is ours. */\r
+  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);\r
+}\r
+\r
+\r
+/**\r
+ * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache  \r
+ * send out queued IP packets. Updates cache with snooped address pairs.\r
+ *\r
+ * Should be called for incoming ARP packets. The pbuf in the argument\r
+ * is freed by this function.\r
+ *\r
+ * @param netif The lwIP network interface on which the ARP packet pbuf arrived.\r
+ * @param pbuf The ARP packet that arrived on netif. Is freed by this function.\r
+ * @param ethaddr Ethernet address of netif.\r
+ *\r
+ * @return NULL\r
+ *\r
+ * @see pbuf_free()\r
+ */\r
+void\r
+etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)\r
+{\r
+  struct etharp_hdr *hdr;\r
+  /* these are aligned properly, whereas the ARP header fields might not be */\r
+  struct ip_addr sipaddr, dipaddr;\r
+  u8_t i;\r
+  u8_t for_us;\r
+\r
+  LWIP_ASSERT("netif != NULL", netif != NULL);\r
+  \r
+  /* drop short ARP packets */\r
+  if (p->tot_len < sizeof(struct etharp_hdr)) {\r
+    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)));\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+  hdr = p->payload;\r
\r
+  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without\r
+   * structure packing (not using structure copy which breaks strict-aliasing rules). */\r
+  memcpy(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));\r
+  memcpy(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));\r
+\r
+  /* this interface is not configured? */\r
+  if (netif->ip_addr.addr == 0) {\r
+    for_us = 0;\r
+  } else {\r
+    /* ARP packet directed to us? */\r
+    for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));\r
+  }\r
+\r
+  /* ARP message directed to us? */\r
+  if (for_us) {\r
+    /* add IP address in ARP cache; assume requester wants to talk to us.\r
+     * can result in directly sending the queued packets for this host. */\r
+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);\r
+  /* ARP message not directed to us? */\r
+  } else {\r
+    /* update the source IP address in the cache, if present */\r
+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);\r
+  }\r
+\r
+  /* now act on the message itself */\r
+  switch (htons(hdr->opcode)) {\r
+  /* ARP request? */\r
+  case ARP_REQUEST:\r
+    /* ARP request. If it asked for our address, we send out a\r
+     * reply. In any case, we time-stamp any existing ARP entry,\r
+     * and possiby send out an IP packet that was queued on it. */\r
+\r
+    LWIP_DEBUGF (ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));\r
+    /* ARP request for our address? */\r
+    if (for_us) {\r
+\r
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));\r
+      /* re-use pbuf to send ARP reply */\r
+      hdr->opcode = htons(ARP_REPLY);\r
+\r
+      hdr->dipaddr = hdr->sipaddr;\r
+      hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;\r
+\r
+      i = netif->hwaddr_len;\r
+      while(i > 0) {\r
+        i--;\r
+        hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];\r
+        hdr->shwaddr.addr[i] = ethaddr->addr[i];\r
+        hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];\r
+        hdr->ethhdr.src.addr[i] = ethaddr->addr[i];\r
+      }\r
+\r
+      hdr->hwtype = htons(HWTYPE_ETHERNET);\r
+      ARPH_HWLEN_SET(hdr, netif->hwaddr_len);\r
+\r
+      hdr->proto = htons(ETHTYPE_IP);\r
+      ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));\r
+\r
+      hdr->ethhdr.type = htons(ETHTYPE_ARP);\r
+      /* return ARP reply */\r
+      netif->linkoutput(netif, p);\r
+    /* we are not configured? */\r
+    } else if (netif->ip_addr.addr == 0) {\r
+      /* { for_us == 0 and netif->ip_addr.addr == 0 } */\r
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));\r
+    /* request was not directed to us */\r
+    } else {\r
+      /* { for_us == 0 and netif->ip_addr.addr != 0 } */\r
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));\r
+    }\r
+    break;\r
+  case ARP_REPLY:\r
+    /* ARP reply. We already updated the ARP cache earlier. */\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));\r
+#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)\r
+    /* DHCP wants to know about ARP replies from any host with an\r
+     * IP address also offered to us by the DHCP server. We do not\r
+     * want to take a duplicate IP address on a single network.\r
+     * @todo How should we handle redundant (fail-over) interfaces?\r
+     * */\r
+    dhcp_arp_reply(netif, &sipaddr);\r
+#endif\r
+    break;\r
+  default:\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));\r
+    break;\r
+  }\r
+  /* free ARP packet */\r
+  pbuf_free(p);\r
+}\r
+\r
+/**\r
+ * Resolve and fill-in Ethernet address header for outgoing packet.\r
+ *\r
+ * For IP multicast and broadcast, corresponding Ethernet addresses\r
+ * are selected and the packet is transmitted on the link.\r
+ *\r
+ * For unicast addresses, the packet is submitted to etharp_query(). In\r
+ * case the IP address is outside the local network, the IP address of\r
+ * the gateway is used.\r
+ *\r
+ * @param netif The lwIP network interface which the IP packet will be sent on.\r
+ * @param ipaddr The IP address of the packet destination.\r
+ * @param pbuf The pbuf(s) containing the IP packet to be sent.\r
+ *\r
+ * @return\r
+ * - ERR_RTE No route to destination (no gateway to external networks),\r
+ * or the return type of either etharp_query() or netif->linkoutput().\r
+ */\r
+err_t\r
+etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)\r
+{\r
+  struct eth_addr *dest, *srcaddr, mcastaddr;\r
+  struct eth_hdr *ethhdr;\r
+  u8_t i;\r
+\r
+  /* make room for Ethernet header - should not fail */\r
+  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {\r
+    /* bail out */\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));\r
+    LINK_STATS_INC(link.lenerr);\r
+    return ERR_BUF;\r
+  }\r
+\r
+  /* assume unresolved Ethernet address */\r
+  dest = NULL;\r
+  /* Determine on destination hardware address. Broadcasts and multicasts\r
+   * are special, other IP addresses are looked up in the ARP table. */\r
+\r
+  /* broadcast destination IP address? */\r
+  if (ip_addr_isbroadcast(ipaddr, netif)) {\r
+    /* broadcast on Ethernet also */\r
+    dest = (struct eth_addr *)&ethbroadcast;\r
+  /* multicast destination IP address? */\r
+  } else if (ip_addr_ismulticast(ipaddr)) {\r
+    /* Hash IP multicast address to MAC address.*/\r
+    mcastaddr.addr[0] = 0x01;\r
+    mcastaddr.addr[1] = 0x00;\r
+    mcastaddr.addr[2] = 0x5e;\r
+    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;\r
+    mcastaddr.addr[4] = ip4_addr3(ipaddr);\r
+    mcastaddr.addr[5] = ip4_addr4(ipaddr);\r
+    /* destination Ethernet address is multicast */\r
+    dest = &mcastaddr;\r
+  /* unicast destination IP address? */\r
+  } else {\r
+    /* outside local network? */\r
+    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {\r
+      /* interface has default gateway? */\r
+      if (netif->gw.addr != 0) {\r
+        /* send to hardware address of default gateway IP address */\r
+        ipaddr = &(netif->gw);\r
+      /* no default gateway available */\r
+      } else {\r
+        /* no route to destination error (default gateway missing) */\r
+        return ERR_RTE;\r
+      }\r
+    }\r
+    /* queue on destination Ethernet address belonging to ipaddr */\r
+    return etharp_query(netif, ipaddr, q);\r
+  }\r
+\r
+  /* continuation for multicast/broadcast destinations */\r
+  /* obtain source Ethernet address of the given interface */\r
+  srcaddr = (struct eth_addr *)netif->hwaddr;\r
+  ethhdr = q->payload;\r
+  i = netif->hwaddr_len;\r
+  while(i > 0) {\r
+    i--;\r
+    ethhdr->dest.addr[i] = dest->addr[i];\r
+    ethhdr->src.addr[i] = srcaddr->addr[i];\r
+  }\r
+  ethhdr->type = htons(ETHTYPE_IP);\r
+  /* send packet directly on the link */\r
+  return netif->linkoutput(netif, q);\r
+}\r
+\r
+/**\r
+ * Send an ARP request for the given IP address and/or queue a packet.\r
+ *\r
+ * If the IP address was not yet in the cache, a pending ARP cache entry\r
+ * is added and an ARP request is sent for the given address. The packet\r
+ * is queued on this entry.\r
+ *\r
+ * If the IP address was already pending in the cache, a new ARP request\r
+ * is sent for the given address. The packet is queued on this entry.\r
+ *\r
+ * If the IP address was already stable in the cache, and a packet is\r
+ * given, it is directly sent and no ARP request is sent out. \r
+ * \r
+ * If the IP address was already stable in the cache, and no packet is\r
+ * given, an ARP request is sent out.\r
+ * \r
+ * @param netif The lwIP network interface on which ipaddr\r
+ * must be queried for.\r
+ * @param ipaddr The IP address to be resolved.\r
+ * @param q If non-NULL, a pbuf that must be delivered to the IP address.\r
+ * q is not freed by this function.\r
+ *\r
+ * @return\r
+ * - ERR_BUF Could not make room for Ethernet header.\r
+ * - ERR_MEM Hardware address unknown, and no more ARP entries available\r
+ *   to query for address or queue the packet.\r
+ * - ERR_MEM Could not queue packet due to memory shortage.\r
+ * - ERR_RTE No route to destination (no gateway to external networks).\r
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.\r
+ *\r
+ */\r
+err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)\r
+{\r
+  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;\r
+  err_t result = ERR_MEM;\r
+  s8_t i; /* ARP entry index */\r
+  u8_t k; /* Ethernet address octet index */\r
+\r
+  /* non-unicast address? */\r
+  if (ip_addr_isbroadcast(ipaddr, netif) ||\r
+      ip_addr_ismulticast(ipaddr) ||\r
+      ip_addr_isany(ipaddr)) {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));\r
+    return ERR_ARG;\r
+  }\r
+\r
+  /* find entry in ARP cache, ask to create entry if queueing packet */\r
+  i = find_entry(ipaddr, ETHARP_TRY_HARD);\r
+\r
+  /* could not find or create entry? */\r
+  if (i < 0)\r
+  {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));\r
+    if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));\r
+    return (err_t)i;\r
+  }\r
+\r
+  /* mark a fresh entry as pending (we just sent a request) */\r
+  if (arp_table[i].state == ETHARP_STATE_EMPTY) {\r
+    arp_table[i].state = ETHARP_STATE_PENDING;\r
+  }\r
+\r
+  /* { i is either a STABLE or (new or existing) PENDING entry } */\r
+  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",\r
+  ((arp_table[i].state == ETHARP_STATE_PENDING) ||\r
+   (arp_table[i].state == ETHARP_STATE_STABLE)));\r
+\r
+  /* do we have a pending entry? or an implicit query request? */\r
+  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {\r
+    /* try to resolve it; send out ARP request */\r
+    result = etharp_request(netif, ipaddr);\r
+  }\r
+  \r
+  /* packet given? */\r
+  if (q != NULL) {\r
+    /* stable entry? */\r
+    if (arp_table[i].state == ETHARP_STATE_STABLE) {\r
+      /* we have a valid IP->Ethernet address mapping,\r
+       * fill in the Ethernet header for the outgoing packet */\r
+      struct eth_hdr *ethhdr = q->payload;\r
+      k = netif->hwaddr_len;\r
+      while(k > 0) {\r
+        k--;\r
+        ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];\r
+        ethhdr->src.addr[k]  = srcaddr->addr[k];\r
+      }\r
+      ethhdr->type = htons(ETHTYPE_IP);\r
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));\r
+      /* send the packet */\r
+      result = netif->linkoutput(netif, q);\r
+    /* pending entry? (either just created or already pending */\r
+    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
+#if ARP_QUEUEING /* queue the given q packet */\r
+      struct pbuf *p;\r
+      /* copy any PBUF_REF referenced payloads into PBUF_RAM */\r
+      /* (the caller of lwIP assumes the referenced payload can be\r
+       * freed after it returns from the lwIP call that brought us here) */\r
+      p = pbuf_take(q);\r
+      /* packet could be taken over? */\r
+      if (p != NULL) {\r
+        /* queue packet ... */\r
+        if (arp_table[i].p == NULL) {\r
+          /* ... in the empty queue */\r
+          pbuf_ref(p);\r
+          arp_table[i].p = p;\r
+#if 0 /* multi-packet-queueing disabled, see bug #11400 */\r
+        } else {\r
+          /* ... at tail of non-empty queue */\r
+          pbuf_queue(arp_table[i].p, p);\r
+#endif\r
+        }\r
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));\r
+        result = ERR_OK;\r
+      } else {\r
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));\r
+        /* { result == ERR_MEM } through initialization */\r
+      }\r
+#else /* ARP_QUEUEING == 0 */\r
+      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */\r
+      /* { result == ERR_MEM } through initialization */\r
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));\r
+#endif\r
+    }\r
+  }\r
+  return result;\r
+}\r
+\r
+err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)\r
+{\r
+  struct pbuf *p;\r
+  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;\r
+  err_t result = ERR_OK;\r
+  u8_t k; /* ARP entry index */\r
+\r
+  /* allocate a pbuf for the outgoing ARP request packet */\r
+  p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);\r
+  /* could allocate a pbuf for an ARP request? */\r
+  if (p != NULL) {\r
+    struct etharp_hdr *hdr = p->payload;\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));\r
+    hdr->opcode = htons(ARP_REQUEST);\r
+    k = netif->hwaddr_len;\r
+    while(k > 0) {\r
+      k--;\r
+      hdr->shwaddr.addr[k] = srcaddr->addr[k];\r
+      /* the hardware address is what we ask for, in\r
+       * a request it is a don't-care value, we use zeroes */\r
+      hdr->dhwaddr.addr[k] = 0x00;\r
+    }\r
+    hdr->dipaddr = *(struct ip_addr2 *)ipaddr;\r
+    hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;\r
+\r
+    hdr->hwtype = htons(HWTYPE_ETHERNET);\r
+    ARPH_HWLEN_SET(hdr, netif->hwaddr_len);\r
+\r
+    hdr->proto = htons(ETHTYPE_IP);\r
+    ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));\r
+    k = netif->hwaddr_len;\r
+    while(k > 0) {\r
+      k--;\r
+      /* broadcast to all network interfaces on the local network */\r
+      hdr->ethhdr.dest.addr[k] = 0xff;\r
+      hdr->ethhdr.src.addr[k] = srcaddr->addr[k];\r
+    }\r
+    hdr->ethhdr.type = htons(ETHTYPE_ARP);\r
+    /* send ARP query */\r
+    result = netif->linkoutput(netif, p);\r
+    /* free ARP query packet */\r
+    pbuf_free(p);\r
+    p = NULL;\r
+  /* could not allocate pbuf for ARP request */\r
+  } else {\r
+    result = ERR_MEM;\r
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));\r
+  }\r
+  return result;\r
+}\r
index 87d591793e7b04c711f097e9d7cd4c07e36ff323..300775ffdb86e8b5a548c80b206a863c41281a2c 100644 (file)
-/*
- * 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;
-}
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/*\r
+ * This file is a skeleton for developing Ethernet network interface\r
+ * drivers for lwIP. Add code to the low_level functions and do a\r
+ * search-and-replace for the word "ethernetif" to replace it with\r
+ * something that better describes your network interface.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+#include <lwip/stats.h>\r
+\r
+#include "netif/etharp.h"\r
+\r
+/* Define those to better describe your network interface. */\r
+#define IFNAME0 'e'\r
+#define IFNAME1 'n'\r
+\r
+struct ethernetif {\r
+  struct eth_addr *ethaddr;\r
+  /* Add whatever per-interface state that is needed here. */\r
+};\r
+\r
+static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};\r
+\r
+/* Forward declarations. */\r
+static void  ethernetif_input(struct netif *netif);\r
+static err_t ethernetif_output(struct netif *netif, struct pbuf *p,\r
+             struct ip_addr *ipaddr);\r
+\r
+static void\r
+low_level_init(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif = netif->state;\r
+  \r
+  /* set MAC hardware address length */\r
+  netif->hwaddr_len = 6;\r
+\r
+  /* set MAC hardware address */\r
+  netif->hwaddr[0] = ;\r
+  ...\r
+  netif->hwaddr[5] = ;\r
+\r
+  /* maximum transfer unit */\r
+  netif->mtu = 1500;\r
+  \r
+  /* broadcast capability */\r
+  netif->flags = NETIF_FLAG_BROADCAST;\r
\r
+  /* Do whatever else is needed to initialize interface. */  \r
+}\r
+\r
+/*\r
+ * low_level_output():\r
+ *\r
+ * Should do the actual transmission of the packet. The packet is\r
+ * contained in the pbuf that is passed to the function. This pbuf\r
+ * might be chained.\r
+ *\r
+ */\r
+\r
+static err_t\r
+low_level_output(struct netif *netif, struct pbuf *p)\r
+{\r
+  struct ethernetif *ethernetif = netif->state;\r
+  struct pbuf *q;\r
+\r
+  initiate transfer();\r
+  \r
+#if ETH_PAD_SIZE\r
+  pbuf_header(p, -ETH_PAD_SIZE);                       /* drop the padding word */\r
+#endif\r
+\r
+  for(q = p; q != NULL; q = q->next) {\r
+    /* Send the data from the pbuf to the interface, one pbuf at a\r
+       time. The size of the data in each pbuf is kept in the ->len\r
+       variable. */\r
+    send data from(q->payload, q->len);\r
+  }\r
+\r
+  signal that packet should be sent();\r
+\r
+#if ETH_PAD_SIZE\r
+  pbuf_header(p, ETH_PAD_SIZE);                        /* reclaim the padding word */\r
+#endif\r
+  \r
+#if LINK_STATS\r
+  lwip_stats.link.xmit++;\r
+#endif /* LINK_STATS */      \r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/*\r
+ * low_level_input():\r
+ *\r
+ * Should allocate a pbuf and transfer the bytes of the incoming\r
+ * packet from the interface into the pbuf.\r
+ *\r
+ */\r
+\r
+static struct pbuf *\r
+low_level_input(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif = netif->state;\r
+  struct pbuf *p, *q;\r
+  u16_t len;\r
+\r
+  /* Obtain the size of the packet and put it into the "len"\r
+     variable. */\r
+  len = ;\r
+\r
+#if ETH_PAD_SIZE\r
+  len += ETH_PAD_SIZE;                                         /* allow room for Ethernet padding */\r
+#endif\r
+\r
+  /* We allocate a pbuf chain of pbufs from the pool. */\r
+  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);\r
+  \r
+  if (p != NULL) {\r
+\r
+#if ETH_PAD_SIZE\r
+    pbuf_header(p, -ETH_PAD_SIZE);                     /* drop the padding word */\r
+#endif\r
+\r
+    /* We iterate over the pbuf chain until we have read the entire\r
+     * packet into the pbuf. */\r
+    for(q = p; q != NULL; q = q->next) {\r
+      /* Read enough bytes to fill this pbuf in the chain. The\r
+       * available data in the pbuf is given by the q->len\r
+       * variable. */\r
+      read data into(q->payload, q->len);\r
+    }\r
+    acknowledge that packet has been read();\r
+\r
+#if ETH_PAD_SIZE\r
+    pbuf_header(p, ETH_PAD_SIZE);                      /* reclaim the padding word */\r
+#endif\r
+\r
+#if LINK_STATS\r
+    lwip_stats.link.recv++;\r
+#endif /* LINK_STATS */      \r
+  } else {\r
+    drop packet();\r
+#if LINK_STATS\r
+    lwip_stats.link.memerr++;\r
+    lwip_stats.link.drop++;\r
+#endif /* LINK_STATS */      \r
+  }\r
+\r
+  return p;  \r
+}\r
+\r
+/*\r
+ * ethernetif_output():\r
+ *\r
+ * This function is called by the TCP/IP stack when an IP packet\r
+ * should be sent. It calls the function called low_level_output() to\r
+ * do the actual transmission of the packet.\r
+ *\r
+ */\r
+\r
+static err_t\r
+ethernetif_output(struct netif *netif, struct pbuf *p,\r
+      struct ip_addr *ipaddr)\r
+{\r
+  \r
+ /* resolve hardware address, then send (or queue) packet */\r
+  return etharp_output(netif, ipaddr, p);\r
\r
+}\r
+\r
+/*\r
+ * ethernetif_input():\r
+ *\r
+ * This function should be called when a packet is ready to be read\r
+ * from the interface. It uses the function low_level_input() that\r
+ * should handle the actual reception of bytes from the network\r
+ * interface.\r
+ *\r
+ */\r
+\r
+static void\r
+ethernetif_input(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif;\r
+  struct eth_hdr *ethhdr;\r
+  struct pbuf *p;\r
+\r
+  ethernetif = netif->state;\r
+  \r
+  /* move received packet into a new pbuf */\r
+  p = low_level_input(netif);\r
+  /* no packet could be read, silently ignore this */\r
+  if (p == NULL) return;\r
+  /* points to packet payload, which starts with an Ethernet header */\r
+  ethhdr = p->payload;\r
+\r
+#if LINK_STATS\r
+  lwip_stats.link.recv++;\r
+#endif /* LINK_STATS */\r
+\r
+  ethhdr = p->payload;\r
+    \r
+  switch (htons(ethhdr->type)) {\r
+  /* IP packet? */\r
+  case ETHTYPE_IP:\r
+#if 0\r
+/* CSi disabled ARP table update on ingress IP packets.\r
+   This seems to work but needs thorough testing. */\r
+    /* update ARP table */\r
+    etharp_ip_input(netif, p);\r
+#endif\r
+    /* skip Ethernet header */\r
+    pbuf_header(p, -sizeof(struct eth_hdr));\r
+    /* pass to network layer */\r
+    netif->input(p, netif);\r
+    break;\r
+      \r
+    case ETHTYPE_ARP:\r
+      /* pass p to ARP module  */\r
+      etharp_arp_input(netif, ethernetif->ethaddr, p);\r
+      break;\r
+    default:\r
+      pbuf_free(p);\r
+      p = NULL;\r
+      break;\r
+  }\r
+}\r
+\r
+static void\r
+arp_timer(void *arg)\r
+{\r
+  etharp_tmr();\r
+  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);\r
+}\r
+\r
+/*\r
+ * ethernetif_init():\r
+ *\r
+ * Should be called at the beginning of the program to set up the\r
+ * network interface. It calls the function low_level_init() to do the\r
+ * actual setup of the hardware.\r
+ *\r
+ */\r
+\r
+err_t\r
+ethernetif_init(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif;\r
+    \r
+  ethernetif = mem_malloc(sizeof(struct ethernetif));\r
+  \r
+  if (ethernetif == NULL)\r
+  {\r
+       LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));\r
+       return ERR_MEM;\r
+  }\r
+\r
+#if LWIP_SNMP\r
+  /* ifType ethernetCsmacd(6) @see RFC1213 */\r
+  netif->link_type = 6;\r
+  /* your link speed here */\r
+  netif->link_speed = ;\r
+  netif->ts = 0;\r
+  netif->ifinoctets = 0;\r
+  netif->ifinucastpkts = 0;\r
+  netif->ifinnucastpkts = 0;\r
+  netif->ifindiscards = 0;\r
+  netif->ifoutoctets = 0;\r
+  netif->ifoutucastpkts = 0;\r
+  netif->ifoutnucastpkts = 0;\r
+  netif->ifoutdiscards = 0;\r
+#endif\r
+  \r
+  netif->state = ethernetif;\r
+  netif->name[0] = IFNAME0;\r
+  netif->name[1] = IFNAME1;\r
+  netif->output = ethernetif_output;\r
+  netif->linkoutput = low_level_output;\r
+  \r
+  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);\r
+  \r
+  low_level_init(netif);\r
+\r
+  etharp_init();\r
+\r
+  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);\r
+\r
+  return ERR_OK;\r
+}\r
+\r
index 0464cb8e80b6934ab451670f2f3a1aa18a97f069..cd523fb034b04c53601409f739e69a79217f1643 100644 (file)
-/*
- * 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 */
-
-
-
-
-
-
-
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_HAVE_LOOPIF\r
+\r
+#include "netif/loopif.h"\r
+#include "lwip/mem.h"\r
+\r
+#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)\r
+#include "netif/tcpdump.h"\r
+#endif /* LWIP_DEBUG && LWIP_TCPDUMP */\r
+\r
+#include "lwip/tcp.h"\r
+#include "lwip/ip.h"\r
+\r
+static void\r
+loopif_input( void * arg )\r
+{\r
+       struct netif *netif = (struct netif *)( ((void **)arg)[ 0 ] );\r
+       struct pbuf *r = (struct pbuf *)( ((void **)arg)[ 1 ] );\r
+\r
+       mem_free( arg );\r
+       netif -> input( r, netif );\r
+}\r
+\r
+static err_t\r
+loopif_output(struct netif *netif, struct pbuf *p,\r
+       struct ip_addr *ipaddr)\r
+{\r
+  struct pbuf *q, *r;\r
+  u8_t *ptr;\r
+  void **arg;\r
+\r
+#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)\r
+  tcpdump(p);\r
+#endif /* LWIP_DEBUG && LWIP_TCPDUMP */\r
+  \r
+  r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\r
+  if (r != NULL) {\r
+    ptr = r->payload;\r
+    \r
+    for(q = p; q != NULL; q = q->next) {\r
+      memcpy(ptr, q->payload, q->len);\r
+      ptr += q->len;\r
+    }\r
+\r
+    arg = mem_malloc( sizeof( void *[2]));\r
+       if( NULL == arg ) {\r
+               return ERR_MEM;\r
+       }\r
+       \r
+       arg[0] = netif;\r
+       arg[1] = r;\r
+       /**\r
+        * workaround (patch #1779) to try to prevent bug #2595:\r
+        * When connecting to "localhost" with the loopif interface,\r
+        * tcp_output doesn't get the opportunity to finnish sending the\r
+        * segment before tcp_process gets it, resulting in tcp_process\r
+        * referencing pcb->unacked-> which still is NULL.\r
+        * \r
+        * TODO: Is there still a race condition here? Leon\r
+        */\r
+       sys_timeout( 1, loopif_input, arg );\r
+       \r
+    return ERR_OK;    \r
+  }\r
+  return ERR_MEM;\r
+}\r
+\r
+err_t\r
+loopif_init(struct netif *netif)\r
+{\r
+  netif->name[0] = 'l';\r
+  netif->name[1] = 'o';\r
+#if 0 /** TODO: I think this should be enabled, or not? Leon */\r
+  netif->input = loopif_input;\r
+#endif\r
+  netif->output = loopif_output;\r
+  return ERR_OK;\r
+}\r
+\r
+#endif /* LWIP_HAVE_LOOPIF */\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
index 33349640223faa403d5428769cd757619300d80b..0786a2e81cf9a04537939e75d73a8ce44af5371e 100644 (file)
-/*****************************************************************************
-* 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 */
+/*****************************************************************************\r
+* auth.c - Network Authentication and Phase Control program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Ported from public pppd code.\r
+*****************************************************************************/\r
+/*\r
+ * auth.c - PPP authentication and phase control.\r
+ *\r
+ * Copyright (c) 1993 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the Australian National University.  The name of the University\r
+ * may not be used to endorse or promote products derived from this\r
+ * software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "ppp.h"\r
+#if PPP_SUPPORT > 0\r
+#include "fsm.h"\r
+#include "lcp.h"\r
+#include "pap.h"\r
+#include "chap.h"\r
+#include "auth.h"\r
+#include "ipcp.h"\r
+\r
+#if CBCP_SUPPORT > 0\r
+#include "cbcp.h"\r
+#endif\r
+\r
+#include "pppdebug.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+/* Bits in auth_pending[] */\r
+#define PAP_WITHPEER    1\r
+#define PAP_PEER    2\r
+#define CHAP_WITHPEER   4\r
+#define CHAP_PEER   8\r
+\r
+\r
+                                                                    \r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+/* Used for storing a sequence of words.  Usually malloced. */\r
+struct wordlist {\r
+    struct wordlist *next;\r
+    char        word[1];\r
+};\r
+\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+extern char *crypt (const char *, const char *);\r
+\r
+/* Prototypes for procedures local to this file. */\r
+\r
+static void network_phase (int);\r
+static void check_idle (void *);\r
+static void connect_time_expired (void *);\r
+#if 0\r
+static int  login (char *, char *, char **, int *);\r
+#endif\r
+static void logout (void);\r
+static int  null_login (int);\r
+static int  get_pap_passwd (int, char *, char *);\r
+static int  have_pap_secret (void);\r
+static int  have_chap_secret (char *, char *, u32_t);\r
+static int  ip_addr_check (u32_t, struct wordlist *);\r
+#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT > 0 */\r
+static void set_allowed_addrs(int unit, struct wordlist *addrs);\r
+static void free_wordlist (struct wordlist *);\r
+#endif\r
+#if CBCP_SUPPORT > 0\r
+static void callback_phase (int);\r
+#endif\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0\r
+/* The name by which the peer authenticated itself to us. */\r
+static char peer_authname[MAXNAMELEN];\r
+#endif\r
+\r
+/* Records which authentication operations haven't completed yet. */\r
+static int auth_pending[NUM_PPP];\r
+\r
+/* Set if we have successfully called login() */\r
+static int logged_in;\r
+\r
+/* Set if we have run the /etc/ppp/auth-up script. */\r
+static int did_authup;\r
+\r
+/* List of addresses which the peer may use. */\r
+static struct wordlist *addresses[NUM_PPP];\r
+\r
+/* Number of network protocols which we have opened. */\r
+static int num_np_open;\r
+\r
+/* Number of network protocols which have come up. */\r
+static int num_np_up;\r
+\r
+#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0\r
+/* Set if we got the contents of passwd[] from the pap-secrets file. */\r
+static int passwd_from_file;\r
+#endif\r
+\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * An Open on LCP has requested a change from Dead to Establish phase.\r
+ * Do what's necessary to bring the physical layer up.\r
+ */\r
+void link_required(int unit)\r
+{\r
+    AUTHDEBUG((LOG_INFO, "link_required: %d\n", unit));\r
+}\r
+\r
+/*\r
+ * LCP has terminated the link; go to the Dead phase and take the\r
+ * physical layer down.\r
+ */\r
+void link_terminated(int unit)\r
+{\r
+    AUTHDEBUG((LOG_INFO, "link_terminated: %d\n", unit));\r
+    \r
+    if (lcp_phase[unit] == PHASE_DEAD)\r
+        return;\r
+    if (logged_in)\r
+        logout();\r
+    lcp_phase[unit] = PHASE_DEAD;\r
+    AUTHDEBUG((LOG_NOTICE, "Connection terminated.\n"));\r
+       pppMainWakeup(unit);\r
+}\r
+\r
+/*\r
+ * LCP has gone down; it will either die or try to re-establish.\r
+ */\r
+void link_down(int unit)\r
+{\r
+    int i;\r
+    struct protent *protp;\r
+    \r
+    AUTHDEBUG((LOG_INFO, "link_down: %d\n", unit));\r
+    if (did_authup) {\r
+        /* XXX Do link down processing. */\r
+        did_authup = 0;\r
+    }\r
+    for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {\r
+        if (!protp->enabled_flag)\r
+            continue;\r
+        if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)\r
+            (*protp->lowerdown)(unit);\r
+        if (protp->protocol < 0xC000 && protp->close != NULL)\r
+            (*protp->close)(unit, "LCP down");\r
+    }\r
+    num_np_open = 0;\r
+    num_np_up = 0;\r
+    if (lcp_phase[unit] != PHASE_DEAD)\r
+        lcp_phase[unit] = PHASE_TERMINATE;\r
+       pppMainWakeup(unit);\r
+}\r
+\r
+/*\r
+ * The link is established.\r
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.\r
+ */\r
+void link_established(int unit)\r
+{\r
+    int auth;\r
+    int i;\r
+    struct protent *protp;\r
+    lcp_options *wo = &lcp_wantoptions[unit];\r
+    lcp_options *go = &lcp_gotoptions[unit];\r
+#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0\r
+    lcp_options *ho = &lcp_hisoptions[unit];\r
+#endif\r
+    \r
+    AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit));\r
+    /*\r
+     * Tell higher-level protocols that LCP is up.\r
+     */\r
+    for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i)\r
+        if (protp->protocol != PPP_LCP && protp->enabled_flag\r
+                && protp->lowerup != NULL)\r
+            (*protp->lowerup)(unit);\r
+    \r
+    if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) {\r
+        /*\r
+         * We wanted the peer to authenticate itself, and it refused:\r
+         * treat it as though it authenticated with PAP using a username\r
+         * of "" and a password of "".  If that's not OK, boot it out.\r
+         */\r
+        if (!wo->neg_upap || !null_login(unit)) {\r
+            AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n"));\r
+            lcp_close(unit, "peer refused to authenticate");\r
+            return;\r
+        }\r
+    }\r
+    \r
+    lcp_phase[unit] = PHASE_AUTHENTICATE;\r
+    auth = 0;\r
+#if CHAP_SUPPORT > 0\r
+    if (go->neg_chap) {\r
+        ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype);\r
+        auth |= CHAP_PEER;\r
+    } \r
+#endif\r
+#if PAP_SUPPORT > 0 && CHAP_SUPPORT > 0\r
+    else\r
+#endif\r
+#if PAP_SUPPORT > 0\r
+    if (go->neg_upap) {\r
+        upap_authpeer(unit);\r
+        auth |= PAP_PEER;\r
+    }\r
+#endif\r
+#if CHAP_SUPPORT > 0\r
+    if (ho->neg_chap) {\r
+        ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype);\r
+        auth |= CHAP_WITHPEER;\r
+    }\r
+#endif\r
+#if PAP_SUPPORT > 0 && CHAP_SUPPORT > 0\r
+    else\r
+#endif\r
+#if PAP_SUPPORT > 0\r
+    if (ho->neg_upap) {\r
+        if (ppp_settings.passwd[0] == 0) {\r
+            passwd_from_file = 1;\r
+            if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd))\r
+                AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n"));\r
+        }\r
+        upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd);\r
+        auth |= PAP_WITHPEER;\r
+    }\r
+#endif\r
+    auth_pending[unit] = auth;\r
+    \r
+    if (!auth)\r
+        network_phase(unit);\r
+}\r
+\r
+\r
+/*\r
+ * The peer has failed to authenticate himself using `protocol'.\r
+ */\r
+void auth_peer_fail(int unit, u16_t protocol)\r
+{\r
+    AUTHDEBUG((LOG_INFO, "auth_peer_fail: %d proto=%X\n", unit, protocol));\r
+    /*\r
+     * Authentication failure: take the link down\r
+     */\r
+    lcp_close(unit, "Authentication failed");\r
+}\r
+\r
+\r
+#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0\r
+/*\r
+ * The peer has been successfully authenticated using `protocol'.\r
+ */\r
+void auth_peer_success(int unit, u16_t protocol, char *name, int namelen)\r
+{\r
+    int pbit;\r
+    \r
+    AUTHDEBUG((LOG_INFO, "auth_peer_success: %d proto=%X\n", unit, protocol));\r
+    switch (protocol) {\r
+    case PPP_CHAP:\r
+        pbit = CHAP_PEER;\r
+        break;\r
+    case PPP_PAP:\r
+        pbit = PAP_PEER;\r
+        break;\r
+    default:\r
+        AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n",\r
+               protocol));\r
+        return;\r
+    }\r
+    \r
+    /*\r
+     * Save the authenticated name of the peer for later.\r
+     */\r
+    if (namelen > sizeof(peer_authname) - 1)\r
+        namelen = sizeof(peer_authname) - 1;\r
+    BCOPY(name, peer_authname, namelen);\r
+    peer_authname[namelen] = 0;\r
+    \r
+    /*\r
+     * If there is no more authentication still to be done,\r
+     * proceed to the network (or callback) phase.\r
+     */\r
+    if ((auth_pending[unit] &= ~pbit) == 0)\r
+        network_phase(unit);\r
+}\r
+\r
+/*\r
+ * We have failed to authenticate ourselves to the peer using `protocol'.\r
+ */\r
+void auth_withpeer_fail(int unit, u16_t protocol)\r
+{\r
+    int errCode = PPPERR_AUTHFAIL;\r
+    \r
+    AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol));\r
+    if (passwd_from_file)\r
+        BZERO(ppp_settings.passwd, MAXSECRETLEN);\r
+    /* \r
+     * XXX Warning: the unit number indicates the interface which is\r
+     * not necessarily the PPP connection.  It works here as long\r
+     * as we are only supporting PPP interfaces.\r
+     */\r
+    pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode);\r
+\r
+    /*\r
+     * We've failed to authenticate ourselves to our peer.\r
+     * He'll probably take the link down, and there's not much\r
+     * we can do except wait for that.\r
+     */\r
+}\r
+\r
+/*\r
+ * We have successfully authenticated ourselves with the peer using `protocol'.\r
+ */\r
+void auth_withpeer_success(int unit, u16_t protocol)\r
+{\r
+    int pbit;\r
+    \r
+    AUTHDEBUG((LOG_INFO, "auth_withpeer_success: %d proto=%X\n", unit, protocol));\r
+    switch (protocol) {\r
+    case PPP_CHAP:\r
+        pbit = CHAP_WITHPEER;\r
+        break;\r
+    case PPP_PAP:\r
+        if (passwd_from_file)\r
+            BZERO(ppp_settings.passwd, MAXSECRETLEN);\r
+        pbit = PAP_WITHPEER;\r
+        break;\r
+    default:\r
+        AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n",\r
+               protocol));\r
+        pbit = 0;\r
+    }\r
+    \r
+    /*\r
+     * If there is no more authentication still being done,\r
+     * proceed to the network (or callback) phase.\r
+     */\r
+    if ((auth_pending[unit] &= ~pbit) == 0)\r
+        network_phase(unit);\r
+}\r
+#endif\r
+\r
+\r
+/*\r
+ * np_up - a network protocol has come up.\r
+ */\r
+void np_up(int unit, u16_t proto)\r
+{\r
+    AUTHDEBUG((LOG_INFO, "np_up: %d proto=%X\n", unit, proto));\r
+    if (num_np_up == 0) {\r
+       AUTHDEBUG((LOG_INFO, "np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit));\r
+        /*\r
+         * At this point we consider that the link has come up successfully.\r
+         */\r
+        if (ppp_settings.idle_time_limit > 0)\r
+            TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit);\r
+        \r
+        /*\r
+         * Set a timeout to close the connection once the maximum\r
+         * connect time has expired.\r
+         */\r
+        if (ppp_settings.maxconnect > 0)\r
+            TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect);\r
+    }\r
+    ++num_np_up;\r
+}\r
+\r
+/*\r
+ * np_down - a network protocol has gone down.\r
+ */\r
+void np_down(int unit, u16_t proto)\r
+{\r
+    AUTHDEBUG((LOG_INFO, "np_down: %d proto=%X\n", unit, proto));\r
+    if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) {\r
+        UNTIMEOUT(check_idle, NULL);\r
+    }\r
+}\r
+\r
+/*\r
+ * np_finished - a network protocol has finished using the link.\r
+ */\r
+void np_finished(int unit, u16_t proto)\r
+{\r
+    AUTHDEBUG((LOG_INFO, "np_finished: %d proto=%X\n", unit, proto));\r
+    if (--num_np_open <= 0) {\r
+        /* no further use for the link: shut up shop. */\r
+        lcp_close(0, "No network protocols running");\r
+    }\r
+}\r
+\r
+/*\r
+ * auth_reset - called when LCP is starting negotiations to recheck\r
+ * authentication options, i.e. whether we have appropriate secrets\r
+ * to use for authenticating ourselves and/or the peer.\r
+ */\r
+void auth_reset(int unit)\r
+{\r
+    lcp_options *go = &lcp_gotoptions[unit];\r
+    lcp_options *ao = &lcp_allowoptions[0];\r
+    ipcp_options *ipwo = &ipcp_wantoptions[0];\r
+    u32_t remote;\r
+    \r
+    AUTHDEBUG((LOG_INFO, "auth_reset: %d\n", unit));\r
+    ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL));\r
+    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)*/;\r
+    \r
+    if (go->neg_upap && !have_pap_secret())\r
+        go->neg_upap = 0;\r
+    if (go->neg_chap) {\r
+        remote = ipwo->accept_remote? 0: ipwo->hisaddr;\r
+        if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote))\r
+            go->neg_chap = 0;\r
+    }\r
+}\r
+\r
+\r
+#if PAP_SUPPORT > 0\r
+/*\r
+ * check_passwd - Check the user name and passwd against the PAP secrets\r
+ * file.  If requested, also check against the system password database,\r
+ * and login the user if OK.\r
+ *\r
+ * returns:\r
+ *  UPAP_AUTHNAK: Authentication failed.\r
+ *  UPAP_AUTHACK: Authentication succeeded.\r
+ * In either case, msg points to an appropriate message.\r
+ */\r
+int check_passwd(\r
+       int unit,\r
+       char *auser,\r
+       int userlen,\r
+       char *apasswd,\r
+       int passwdlen,\r
+       char **msg,\r
+       int *msglen\r
+)\r
+{\r
+#if 1\r
+       *msg = (char *) 0;\r
+       return UPAP_AUTHACK;     /* XXX Assume all entries OK. */\r
+#else\r
+    int ret = 0;\r
+    struct wordlist *addrs = NULL;\r
+    char passwd[256], user[256];\r
+    char secret[MAXWORDLEN];\r
+    static u_short attempts = 0;\r
+    \r
+    /*\r
+     * Make copies of apasswd and auser, then null-terminate them.\r
+     */\r
+    BCOPY(apasswd, passwd, passwdlen);\r
+    passwd[passwdlen] = '\0';\r
+    BCOPY(auser, user, userlen);\r
+    user[userlen] = '\0';\r
+    *msg = (char *) 0;\r
+\r
+    /* XXX Validate user name and password. */\r
+    ret = UPAP_AUTHACK;     /* XXX Assume all entries OK. */\r
+        \r
+    if (ret == UPAP_AUTHNAK) {\r
+        if (*msg == (char *) 0)\r
+            *msg = "Login incorrect";\r
+        *msglen = strlen(*msg);\r
+        /*\r
+         * Frustrate passwd stealer programs.\r
+         * Allow 10 tries, but start backing off after 3 (stolen from login).\r
+         * On 10'th, drop the connection.\r
+         */\r
+        if (attempts++ >= 10) {\r
+            AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user));\r
+            /*ppp_panic("Excess Bad Logins");*/\r
+        }\r
+        if (attempts > 3) {\r
+            sys_msleep((attempts - 3) * 5);\r
+        }\r
+        if (addrs != NULL) {\r
+            free_wordlist(addrs);\r
+        }\r
+    } else {\r
+        attempts = 0;           /* Reset count */\r
+        if (*msg == (char *) 0)\r
+            *msg = "Login ok";\r
+        *msglen = strlen(*msg);\r
+        set_allowed_addrs(unit, addrs);\r
+    }\r
+    \r
+    BZERO(passwd, sizeof(passwd));\r
+    BZERO(secret, sizeof(secret));\r
+    \r
+    return ret;\r
+#endif\r
+}\r
+#endif\r
+\r
+\r
+/*\r
+ * auth_ip_addr - check whether the peer is authorized to use\r
+ * a given IP address.  Returns 1 if authorized, 0 otherwise.\r
+ */\r
+int auth_ip_addr(int unit, u32_t addr)\r
+{\r
+    return ip_addr_check(addr, addresses[unit]);\r
+}\r
+\r
+/*\r
+ * bad_ip_adrs - return 1 if the IP address is one we don't want\r
+ * to use, such as an address in the loopback net or a multicast address.\r
+ * addr is in network byte order.\r
+ */\r
+int bad_ip_adrs(u32_t addr)\r
+{\r
+    addr = ntohl(addr);\r
+    return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET\r
+        || IN_MULTICAST(addr) || IN_BADCLASS(addr);\r
+}\r
+\r
+\r
+#if CHAP_SUPPORT > 0\r
+/*\r
+ * get_secret - open the CHAP secret file and return the secret\r
+ * for authenticating the given client on the given server.\r
+ * (We could be either client or server).\r
+ */\r
+int get_secret(\r
+    int unit,\r
+    char *client,\r
+    char *server,\r
+    char *secret,\r
+    int *secret_len,\r
+    int save_addrs\r
+)\r
+{\r
+#if 1\r
+    int len;\r
+    struct wordlist *addrs;\r
+    \r
+    addrs = NULL;\r
+\r
+    if(!client || !client[0] || strcmp(client, ppp_settings.user)) {\r
+       return 0;\r
+    }\r
+\r
+    len = strlen(ppp_settings.passwd);\r
+    if (len > MAXSECRETLEN) {\r
+        AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));\r
+        len = MAXSECRETLEN;\r
+    }\r
+    BCOPY(ppp_settings.passwd, secret, len);\r
+    *secret_len = len;\r
+    \r
+    return 1;\r
+#else\r
+    int ret = 0, len;\r
+    struct wordlist *addrs;\r
+    char secbuf[MAXWORDLEN];\r
+    \r
+    addrs = NULL;\r
+    secbuf[0] = 0;\r
+\r
+    /* XXX Find secret. */  \r
+    if (ret < 0)\r
+        return 0;\r
+    \r
+    if (save_addrs)\r
+        set_allowed_addrs(unit, addrs);\r
+    \r
+    len = strlen(secbuf);\r
+    if (len > MAXSECRETLEN) {\r
+        AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));\r
+        len = MAXSECRETLEN;\r
+    }\r
+    BCOPY(secbuf, secret, len);\r
+    BZERO(secbuf, sizeof(secbuf));\r
+    *secret_len = len;\r
+    \r
+    return 1;\r
+#endif\r
+}\r
+#endif\r
+\r
+\r
+#if 0 /* UNUSED */\r
+/*\r
+ * auth_check_options - called to check authentication options.\r
+ */\r
+void auth_check_options(void)\r
+{\r
+    lcp_options *wo = &lcp_wantoptions[0];\r
+    int can_auth;\r
+    ipcp_options *ipwo = &ipcp_wantoptions[0];\r
+    u32_t remote;\r
+    \r
+    /* Default our_name to hostname, and user to our_name */\r
+    if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname)\r
+        strcpy(ppp_settings.our_name, ppp_settings.hostname);\r
+    if (ppp_settings.user[0] == 0)\r
+        strcpy(ppp_settings.user, ppp_settings.our_name);\r
+    \r
+    /* If authentication is required, ask peer for CHAP or PAP. */\r
+    if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) {\r
+        wo->neg_chap = 1;\r
+        wo->neg_upap = 1;\r
+    }\r
+    \r
+    /*\r
+     * Check whether we have appropriate secrets to use\r
+     * to authenticate the peer.\r
+     */\r
+    can_auth = wo->neg_upap && have_pap_secret();\r
+    if (!can_auth && wo->neg_chap) {\r
+        remote = ipwo->accept_remote? 0: ipwo->hisaddr;\r
+        can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote);\r
+    }\r
+    \r
+    if (ppp_settings.auth_required && !can_auth) {\r
+        ppp_panic("No auth secret");\r
+    }\r
+}\r
+#endif\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/*\r
+ * Proceed to the network phase.\r
+ */\r
+static void network_phase(int unit)\r
+{\r
+    int i;\r
+    struct protent *protp;\r
+    lcp_options *go = &lcp_gotoptions[unit];\r
+    \r
+    /*\r
+     * If the peer had to authenticate, run the auth-up script now.\r
+     */\r
+    if ((go->neg_chap || go->neg_upap) && !did_authup) {\r
+        /* XXX Do setup for peer authentication. */\r
+        did_authup = 1;\r
+    }\r
+    \r
+#if CBCP_SUPPORT > 0\r
+    /*\r
+     * If we negotiated callback, do it now.\r
+     */\r
+    if (go->neg_cbcp) {\r
+        lcp_phase[unit] = PHASE_CALLBACK;\r
+        (*cbcp_protent.open)(unit);\r
+        return;\r
+    }\r
+#endif\r
+    \r
+    lcp_phase[unit] = PHASE_NETWORK;\r
+    for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i)\r
+        if (protp->protocol < 0xC000 && protp->enabled_flag\r
+                && protp->open != NULL) {\r
+            (*protp->open)(unit);\r
+            if (protp->protocol != PPP_CCP)\r
+                ++num_np_open;\r
+        }\r
+    \r
+    if (num_np_open == 0)\r
+        /* nothing to do */\r
+        lcp_close(0, "No network protocols running");\r
+}\r
+\r
+/*\r
+ * check_idle - check whether the link has been idle for long\r
+ * enough that we can shut it down.\r
+ */\r
+static void check_idle(void *arg)\r
+{\r
+    struct ppp_idle idle;\r
+    u_short itime;\r
+    \r
+       (void)arg;\r
+    if (!get_idle_time(0, &idle))\r
+        return;\r
+    itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle);\r
+    if (itime >= ppp_settings.idle_time_limit) {\r
+        /* link is idle: shut it down. */\r
+        AUTHDEBUG((LOG_INFO, "Terminating connection due to lack of activity.\n"));\r
+        lcp_close(0, "Link inactive");\r
+    } else {\r
+        TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime);\r
+    }\r
+}\r
+\r
+/*\r
+ * connect_time_expired - log a message and close the connection.\r
+ */\r
+static void connect_time_expired(void *arg)\r
+{\r
+       (void)arg;\r
+\r
+    AUTHDEBUG((LOG_INFO, "Connect time expired\n"));\r
+    lcp_close(0, "Connect time expired");   /* Close connection */\r
+}\r
+\r
+#if 0\r
+/*\r
+ * login - Check the user name and password against the system\r
+ * password database, and login the user if OK.\r
+ *\r
+ * returns:\r
+ *  UPAP_AUTHNAK: Login failed.\r
+ *  UPAP_AUTHACK: Login succeeded.\r
+ * In either case, msg points to an appropriate message.\r
+ */\r
+static int login(char *user, char *passwd, char **msg, int *msglen)\r
+{\r
+    /* XXX Fail until we decide that we want to support logins. */\r
+    return (UPAP_AUTHNAK);\r
+}\r
+#endif\r
+\r
+/*\r
+ * logout - Logout the user.\r
+ */\r
+static void logout(void)\r
+{\r
+    logged_in = 0;\r
+}\r
+\r
+\r
+/*\r
+ * null_login - Check if a username of "" and a password of "" are\r
+ * acceptable, and iff so, set the list of acceptable IP addresses\r
+ * and return 1.\r
+ */\r
+static int null_login(int unit)\r
+{\r
+       (void)unit;\r
+    /* XXX Fail until we decide that we want to support logins. */\r
+    return 0;\r
+}\r
+\r
+\r
+/*\r
+ * get_pap_passwd - get a password for authenticating ourselves with\r
+ * our peer using PAP.  Returns 1 on success, 0 if no suitable password\r
+ * could be found.\r
+ */\r
+static int get_pap_passwd(int unit, char *user, char *passwd)\r
+{\r
+/* normally we would reject PAP if no password is provided,\r
+   but this causes problems with some providers (like CHT in Taiwan)\r
+   who incorrectly request PAP and expect a bogus/empty password, so\r
+   always provide a default user/passwd of "none"/"none"\r
+*/\r
+    if(user)\r
+       strcpy(user,   "none");\r
+    if(passwd)\r
+       strcpy(passwd, "none");\r
+\r
+    return 1;\r
+}\r
+\r
+\r
+/*\r
+ * have_pap_secret - check whether we have a PAP file with any\r
+ * secrets that we could possibly use for authenticating the peer.\r
+ */\r
+static int have_pap_secret(void)\r
+{\r
+    /* XXX Fail until we set up our passwords. */\r
+    return 0;\r
+}\r
+\r
+\r
+/*\r
+ * have_chap_secret - check whether we have a CHAP file with a\r
+ * secret that we could possibly use for authenticating `client'\r
+ * on `server'.  Either can be the null string, meaning we don't\r
+ * know the identity yet.\r
+ */\r
+static int have_chap_secret(char *client, char *server, u32_t remote)\r
+{\r
+       (void)client;\r
+       (void)server;\r
+       (void)remote;\r
+    /* XXX Fail until we set up our passwords. */\r
+    return 0;\r
+}\r
+\r
+\r
+#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT > 0 */\r
+/*\r
+ * set_allowed_addrs() - set the list of allowed addresses.\r
+ */\r
+static void set_allowed_addrs(int unit, struct wordlist *addrs)\r
+{\r
+    if (addresses[unit] != NULL)\r
+        free_wordlist(addresses[unit]);\r
+    addresses[unit] = addrs;\r
+\r
+#if 0\r
+    /*\r
+     * If there's only one authorized address we might as well\r
+     * ask our peer for that one right away\r
+     */\r
+    if (addrs != NULL && addrs->next == NULL) {\r
+        char *p = addrs->word;\r
+        struct ipcp_options *wo = &ipcp_wantoptions[unit];\r
+        u32_t a;\r
+        struct hostent *hp;\r
+        \r
+        if (wo->hisaddr == 0 && *p != '!' && *p != '-'\r
+                && strchr(p, '/') == NULL) {\r
+            hp = gethostbyname(p);\r
+            if (hp != NULL && hp->h_addrtype == AF_INET)\r
+                a = *(u32_t *)hp->h_addr;\r
+            else\r
+                a = inet_addr(p);\r
+            if (a != (u32_t) -1)\r
+                wo->hisaddr = a;\r
+        }\r
+    }\r
+#endif\r
+}\r
+#endif\r
+\r
+static int ip_addr_check(u32_t addr, struct wordlist *addrs)\r
+{\r
+    \r
+    /* don't allow loopback or multicast address */\r
+    if (bad_ip_adrs(addr))\r
+        return 0;\r
+    \r
+    if (addrs == NULL)\r
+        return !ppp_settings.auth_required;      /* no addresses authorized */\r
+    \r
+    /* XXX All other addresses allowed. */\r
+    return 1;\r
+}\r
+\r
+#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT */\r
+/*\r
+ * free_wordlist - release memory allocated for a wordlist.\r
+ */\r
+static void free_wordlist(struct wordlist *wp)\r
+{\r
+    struct wordlist *next;\r
+    \r
+    while (wp != NULL) {\r
+        next = wp->next;\r
+        free(wp);\r
+        wp = next;\r
+    }\r
+}\r
+#endif\r
+\r
+#endif /* PPP_SUPPORT */\r
index d6a5de5b79a6c6eec007a25a3bc139ad7db047bd..58174056c5bfd8a7aaa07d76a6a8cd1276be0f09 100644 (file)
@@ -1,94 +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 */
+/*****************************************************************************\r
+* auth.h -  PPP Authentication and phase control header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1998 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original derived from BSD pppd.h.\r
+*****************************************************************************/\r
+/*\r
+ * pppd.h - PPP daemon global declarations.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ */\r
+\r
+#ifndef AUTH_H\r
+#define AUTH_H\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+void link_required (int);              /* we are starting to use the link */\r
+void link_terminated (int);    /* we are finished with the link */\r
+void link_down (int);                  /* the LCP layer has left the Opened state */\r
+void link_established (int);   /* the link is up; authenticate now */\r
+void np_up (int, u16_t);                       /* a network protocol has come up */\r
+void np_down (int, u16_t);             /* a network protocol has gone down */\r
+void np_finished (int, u16_t); /* a network protocol no longer needs link */\r
+void auth_peer_fail (int, u16_t);/* peer failed to authenticate itself */\r
+\r
+/* peer successfully authenticated itself */\r
+void auth_peer_success (int, u16_t, char *, int);\r
+\r
+/* we failed to authenticate ourselves */\r
+void auth_withpeer_fail (int, u16_t);\r
+\r
+/* we successfully authenticated ourselves */\r
+void auth_withpeer_success (int, u16_t);\r
+\r
+/* check authentication options supplied */\r
+void auth_check_options (void);\r
+void auth_reset (int);                 /* check what secrets we have */\r
+\r
+/* Check peer-supplied username/password */\r
+int  check_passwd (int, char *, int, char *, int, char **, int *);\r
+\r
+/* get "secret" for chap */\r
+int  get_secret (int, char *, char *, char *, int *, int);\r
+\r
+/* check if IP address is authorized */\r
+int  auth_ip_addr (int, u32_t);\r
+\r
+/* check if IP address is unreasonable */\r
+int  bad_ip_adrs (u32_t);\r
+\r
+\r
+#endif /* AUTH_H */\r
index 4d1dc0d245b3d8203062baa358fe95cf5ca9d8f7..30441bdc8328b211a920f05e9932bee53c9dea83 100644 (file)
-/*** 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 */
+/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/\r
+/*****************************************************************************\r
+* chap.c - Network Challenge Handshake Authentication Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original based on BSD chap.c.\r
+*****************************************************************************/\r
+/*\r
+ * chap.c - Challenge Handshake Authentication Protocol.\r
+ *\r
+ * Copyright (c) 1993 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the Australian National University.  The name of the University\r
+ * may not be used to endorse or promote products derived from this\r
+ * software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * Copyright (c) 1991 Gregory M. Christy.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Gregory M. Christy.  The name of the author may not be used to\r
+ * endorse or promote products derived from this software without\r
+ * specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "ppp.h"\r
+#if PPP_SUPPORT > 0\r
+#include "magic.h"\r
+\r
+#if CHAP_SUPPORT > 0\r
+\r
+#include "randm.h"\r
+#include "auth.h"\r
+#include "md5.h"\r
+#include "chap.h"\r
+#include "chpms.h"\r
+#include "pppdebug.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+/*\r
+ * Protocol entry points.\r
+ */\r
+static void ChapInit (int);\r
+static void ChapLowerUp (int);\r
+static void ChapLowerDown (int);\r
+static void ChapInput (int, u_char *, int);\r
+static void ChapProtocolReject (int);\r
+static int  ChapPrintPkt (u_char *, int,\r
+                             void (*) (void *, char *, ...), void *);\r
+\r
+static void ChapChallengeTimeout (void *);\r
+static void ChapResponseTimeout (void *);\r
+static void ChapReceiveChallenge (chap_state *, u_char *, int, int);\r
+static void ChapRechallenge (void *);\r
+static void ChapReceiveResponse (chap_state *, u_char *, int, int);\r
+static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);\r
+static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);\r
+static void ChapSendStatus (chap_state *, int);\r
+static void ChapSendChallenge (chap_state *);\r
+static void ChapSendResponse (chap_state *);\r
+static void ChapGenChallenge (chap_state *);\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+chap_state chap[NUM_PPP];              /* CHAP state; one for each unit */\r
+\r
+struct protent chap_protent = {\r
+    PPP_CHAP,\r
+    ChapInit,\r
+    ChapInput,\r
+    ChapProtocolReject,\r
+    ChapLowerUp,\r
+    ChapLowerDown,\r
+    NULL,\r
+    NULL,\r
+#if 0\r
+    ChapPrintPkt,\r
+    NULL,\r
+#endif\r
+    1,\r
+    "CHAP",\r
+#if 0\r
+    NULL,\r
+    NULL,\r
+    NULL\r
+#endif\r
+};\r
+\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+static char *ChapCodenames[] = {\r
+       "Challenge", "Response", "Success", "Failure"\r
+};\r
+\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * ChapAuthWithPeer - Authenticate us with our peer (start client).\r
+ *\r
+ */\r
+void ChapAuthWithPeer(int unit, char *our_name, int digest)\r
+{\r
+       chap_state *cstate = &chap[unit];\r
+       \r
+       cstate->resp_name = our_name;\r
+       cstate->resp_type = digest;\r
+       \r
+       if (cstate->clientstate == CHAPCS_INITIAL ||\r
+                       cstate->clientstate == CHAPCS_PENDING) {\r
+               /* lower layer isn't up - wait until later */\r
+               cstate->clientstate = CHAPCS_PENDING;\r
+               return;\r
+       }\r
+       \r
+       /*\r
+        * We get here as a result of LCP coming up.\r
+        * So even if CHAP was open before, we will \r
+        * have to re-authenticate ourselves.\r
+        */\r
+       cstate->clientstate = CHAPCS_LISTEN;\r
+}\r
+\r
+\r
+/*\r
+ * ChapAuthPeer - Authenticate our peer (start server).\r
+ */\r
+void ChapAuthPeer(int unit, char *our_name, int digest)\r
+{\r
+       chap_state *cstate = &chap[unit];\r
+       \r
+       cstate->chal_name = our_name;\r
+       cstate->chal_type = digest;\r
+       \r
+       if (cstate->serverstate == CHAPSS_INITIAL ||\r
+                       cstate->serverstate == CHAPSS_PENDING) {\r
+               /* lower layer isn't up - wait until later */\r
+               cstate->serverstate = CHAPSS_PENDING;\r
+               return;\r
+       }\r
+       \r
+       ChapGenChallenge(cstate);\r
+       ChapSendChallenge(cstate);              /* crank it up dude! */\r
+       cstate->serverstate = CHAPSS_INITIAL_CHAL;\r
+}\r
+\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/*\r
+ * ChapInit - Initialize a CHAP unit.\r
+ */\r
+static void ChapInit(int unit)\r
+{\r
+       chap_state *cstate = &chap[unit];\r
+       \r
+       BZERO(cstate, sizeof(*cstate));\r
+       cstate->unit = unit;\r
+       cstate->clientstate = CHAPCS_INITIAL;\r
+       cstate->serverstate = CHAPSS_INITIAL;\r
+       cstate->timeouttime = CHAP_DEFTIMEOUT;\r
+       cstate->max_transmits = CHAP_DEFTRANSMITS;\r
+       /* random number generator is initialized in magic_init */\r
+}\r
+\r
+\r
+/*\r
+ * ChapChallengeTimeout - Timeout expired on sending challenge.\r
+ */\r
+static void ChapChallengeTimeout(void *arg)\r
+{\r
+       chap_state *cstate = (chap_state *) arg;\r
+       \r
+       /* if we aren't sending challenges, don't worry.  then again we */\r
+       /* probably shouldn't be here either */\r
+       if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&\r
+                       cstate->serverstate != CHAPSS_RECHALLENGE)\r
+               return;\r
+       \r
+       if (cstate->chal_transmits >= cstate->max_transmits) {\r
+               /* give up on peer */\r
+               CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));\r
+               cstate->serverstate = CHAPSS_BADAUTH;\r
+               auth_peer_fail(cstate->unit, PPP_CHAP);\r
+               return;\r
+       }\r
+       \r
+       ChapSendChallenge(cstate);              /* Re-send challenge */\r
+}\r
+\r
+\r
+/*\r
+ * ChapResponseTimeout - Timeout expired on sending response.\r
+ */\r
+static void ChapResponseTimeout(void *arg)\r
+{\r
+       chap_state *cstate = (chap_state *) arg;\r
+       \r
+       /* if we aren't sending a response, don't worry. */\r
+       if (cstate->clientstate != CHAPCS_RESPONSE)\r
+               return;\r
+       \r
+       ChapSendResponse(cstate);               /* re-send response */\r
+}\r
+\r
+\r
+/*\r
+ * ChapRechallenge - Time to challenge the peer again.\r
+ */\r
+static void ChapRechallenge(void *arg)\r
+{\r
+       chap_state *cstate = (chap_state *) arg;\r
+       \r
+       /* if we aren't sending a response, don't worry. */\r
+       if (cstate->serverstate != CHAPSS_OPEN)\r
+               return;\r
+       \r
+       ChapGenChallenge(cstate);\r
+       ChapSendChallenge(cstate);\r
+       cstate->serverstate = CHAPSS_RECHALLENGE;\r
+}\r
+\r
+\r
+/*\r
+ * ChapLowerUp - The lower layer is up.\r
+ *\r
+ * Start up if we have pending requests.\r
+ */\r
+static void ChapLowerUp(int unit)\r
+{\r
+       chap_state *cstate = &chap[unit];\r
+       \r
+       if (cstate->clientstate == CHAPCS_INITIAL)\r
+               cstate->clientstate = CHAPCS_CLOSED;\r
+       else if (cstate->clientstate == CHAPCS_PENDING)\r
+               cstate->clientstate = CHAPCS_LISTEN;\r
+       \r
+       if (cstate->serverstate == CHAPSS_INITIAL)\r
+               cstate->serverstate = CHAPSS_CLOSED;\r
+       else if (cstate->serverstate == CHAPSS_PENDING) {\r
+               ChapGenChallenge(cstate);\r
+               ChapSendChallenge(cstate);\r
+               cstate->serverstate = CHAPSS_INITIAL_CHAL;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * ChapLowerDown - The lower layer is down.\r
+ *\r
+ * Cancel all timeouts.\r
+ */\r
+static void ChapLowerDown(int unit)\r
+{\r
+       chap_state *cstate = &chap[unit];\r
+       \r
+       /* Timeout(s) pending?  Cancel if so. */\r
+       if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||\r
+                       cstate->serverstate == CHAPSS_RECHALLENGE)\r
+               UNTIMEOUT(ChapChallengeTimeout, cstate);\r
+       else if (cstate->serverstate == CHAPSS_OPEN\r
+                       && cstate->chal_interval != 0)\r
+               UNTIMEOUT(ChapRechallenge, cstate);\r
+       if (cstate->clientstate == CHAPCS_RESPONSE)\r
+               UNTIMEOUT(ChapResponseTimeout, cstate);\r
+       \r
+       cstate->clientstate = CHAPCS_INITIAL;\r
+       cstate->serverstate = CHAPSS_INITIAL;\r
+}\r
+\r
+\r
+/*\r
+ * ChapProtocolReject - Peer doesn't grok CHAP.\r
+ */\r
+static void ChapProtocolReject(int unit)\r
+{\r
+       chap_state *cstate = &chap[unit];\r
+       \r
+       if (cstate->serverstate != CHAPSS_INITIAL &&\r
+                       cstate->serverstate != CHAPSS_CLOSED)\r
+               auth_peer_fail(unit, PPP_CHAP);\r
+       if (cstate->clientstate != CHAPCS_INITIAL &&\r
+                       cstate->clientstate != CHAPCS_CLOSED)\r
+               auth_withpeer_fail(unit, PPP_CHAP);\r
+       ChapLowerDown(unit);            /* shutdown chap */\r
+}\r
+\r
+\r
+/*\r
+ * ChapInput - Input CHAP packet.\r
+ */\r
+static void ChapInput(int unit, u_char *inpacket, int packet_len)\r
+{\r
+       chap_state *cstate = &chap[unit];\r
+       u_char *inp;\r
+       u_char code, id;\r
+       int len;\r
+       \r
+       /*\r
+        * Parse header (code, id and length).\r
+        * If packet too short, drop it.\r
+        */\r
+       inp = inpacket;\r
+       if (packet_len < CHAP_HEADERLEN) {\r
+               CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));\r
+               return;\r
+       }\r
+       GETCHAR(code, inp);\r
+       GETCHAR(id, inp);\r
+       GETSHORT(len, inp);\r
+       if (len < CHAP_HEADERLEN) {\r
+               CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));\r
+               return;\r
+       }\r
+       if (len > packet_len) {\r
+               CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       len -= CHAP_HEADERLEN;\r
+       \r
+       /*\r
+        * Action depends on code (as in fact it usually does :-).\r
+        */\r
+       switch (code) {\r
+       case CHAP_CHALLENGE:\r
+               ChapReceiveChallenge(cstate, inp, id, len);\r
+               break;\r
+       \r
+       case CHAP_RESPONSE:\r
+               ChapReceiveResponse(cstate, inp, id, len);\r
+               break;\r
+       \r
+       case CHAP_FAILURE:\r
+               ChapReceiveFailure(cstate, inp, id, len);\r
+               break;\r
+       \r
+       case CHAP_SUCCESS:\r
+               ChapReceiveSuccess(cstate, inp, id, len);\r
+               break;\r
+       \r
+       default:                                /* Need code reject? */\r
+               CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * ChapReceiveChallenge - Receive Challenge and send Response.\r
+ */\r
+static void ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)\r
+{\r
+       int rchallenge_len;\r
+       u_char *rchallenge;\r
+       int secret_len;\r
+       char secret[MAXSECRETLEN];\r
+       char rhostname[256];\r
+       MD5_CTX mdContext;\r
+       u_char hash[MD5_SIGNATURE_SIZE];\r
+       \r
+       CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));\r
+       if (cstate->clientstate == CHAPCS_CLOSED ||\r
+               cstate->clientstate == CHAPCS_PENDING) {\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",\r
+                          cstate->clientstate));\r
+               return;\r
+       }\r
+       \r
+       if (len < 2) {\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       \r
+       GETCHAR(rchallenge_len, inp);\r
+       len -= sizeof (u_char) + rchallenge_len;        /* now name field length */\r
+       if (len < 0) {\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       rchallenge = inp;\r
+       INCPTR(rchallenge_len, inp);\r
+       \r
+       if (len >= sizeof(rhostname))\r
+               len = sizeof(rhostname) - 1;\r
+       BCOPY(inp, rhostname, len);\r
+       rhostname[len] = '\000';\r
+       \r
+       CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n",\r
+              rhostname));\r
+       \r
+       /* Microsoft doesn't send their name back in the PPP packet */\r
+       if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {\r
+               strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));\r
+               rhostname[sizeof(rhostname) - 1] = 0;\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n",\r
+                          rhostname));\r
+       }\r
+       \r
+       /* get secret for authenticating ourselves with the specified host */\r
+       if (!get_secret(cstate->unit, cstate->resp_name, rhostname,\r
+                           secret, &secret_len, 0)) {\r
+               secret_len = 0;         /* assume null secret if can't find one */\r
+               CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));\r
+       }\r
+       \r
+       /* cancel response send timeout if necessary */\r
+       if (cstate->clientstate == CHAPCS_RESPONSE)\r
+               UNTIMEOUT(ChapResponseTimeout, cstate);\r
+       \r
+       cstate->resp_id = id;\r
+       cstate->resp_transmits = 0;\r
+       \r
+       /*  generate MD based on negotiated type */\r
+       switch (cstate->resp_type) { \r
+       \r
+       case CHAP_DIGEST_MD5:\r
+               MD5Init(&mdContext);\r
+               MD5Update(&mdContext, &cstate->resp_id, 1);\r
+               MD5Update(&mdContext, (u_char*)secret, secret_len);\r
+               MD5Update(&mdContext, rchallenge, rchallenge_len);\r
+               MD5Final(hash, &mdContext);\r
+               BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);\r
+               cstate->resp_length = MD5_SIGNATURE_SIZE;\r
+               break;\r
+       \r
+#ifdef CHAPMS\r
+       case CHAP_MICROSOFT:\r
+               ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);\r
+               break;\r
+#endif\r
+       \r
+       default:\r
+               CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));\r
+               return;\r
+       }\r
+       \r
+       BZERO(secret, sizeof(secret));\r
+       ChapSendResponse(cstate);\r
+}\r
+\r
+\r
+/*\r
+ * ChapReceiveResponse - Receive and process response.\r
+ */\r
+static void ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)\r
+{\r
+       u_char *remmd, remmd_len;\r
+       int secret_len, old_state;\r
+       int code;\r
+       char rhostname[256];\r
+       MD5_CTX mdContext;\r
+       char secret[MAXSECRETLEN];\r
+       u_char hash[MD5_SIGNATURE_SIZE];\r
+       \r
+       CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));\r
+       \r
+       if (cstate->serverstate == CHAPSS_CLOSED ||\r
+                       cstate->serverstate == CHAPSS_PENDING) {\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",\r
+               cstate->serverstate));\r
+               return;\r
+       }\r
+       \r
+       if (id != cstate->chal_id)\r
+               return;                 /* doesn't match ID of last challenge */\r
+       \r
+       /*\r
+       * If we have received a duplicate or bogus Response,\r
+       * we have to send the same answer (Success/Failure)\r
+       * as we did for the first Response we saw.\r
+       */\r
+       if (cstate->serverstate == CHAPSS_OPEN) {\r
+               ChapSendStatus(cstate, CHAP_SUCCESS);\r
+               return;\r
+       }\r
+       if (cstate->serverstate == CHAPSS_BADAUTH) {\r
+               ChapSendStatus(cstate, CHAP_FAILURE);\r
+               return;\r
+       }\r
+       \r
+       if (len < 2) {\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       GETCHAR(remmd_len, inp);                /* get length of MD */\r
+       remmd = inp;                    /* get pointer to MD */\r
+       INCPTR(remmd_len, inp);\r
+       \r
+       len -= sizeof (u_char) + remmd_len;\r
+       if (len < 0) {\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       \r
+       UNTIMEOUT(ChapChallengeTimeout, cstate);\r
+       \r
+       if (len >= sizeof(rhostname))\r
+               len = sizeof(rhostname) - 1;\r
+       BCOPY(inp, rhostname, len);\r
+       rhostname[len] = '\000';\r
+       \r
+       CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n",\r
+                               rhostname));\r
+       \r
+       /*\r
+       * Get secret for authenticating them with us,\r
+       * do the hash ourselves, and compare the result.\r
+       */\r
+       code = CHAP_FAILURE;\r
+       if (!get_secret(cstate->unit, rhostname, cstate->chal_name,\r
+       secret, &secret_len, 1)) {\r
+/*        CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */\r
+               CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",\r
+               rhostname));\r
+       } else {\r
+       \r
+               /*  generate MD based on negotiated type */\r
+               switch (cstate->chal_type) { \r
+               \r
+               case CHAP_DIGEST_MD5:           /* only MD5 is defined for now */\r
+                       if (remmd_len != MD5_SIGNATURE_SIZE)\r
+                               break;                  /* it's not even the right length */\r
+                       MD5Init(&mdContext);\r
+                       MD5Update(&mdContext, &cstate->chal_id, 1);\r
+                       MD5Update(&mdContext, (u_char*)secret, secret_len);\r
+                       MD5Update(&mdContext, cstate->challenge, cstate->chal_len);\r
+                       MD5Final(hash, &mdContext); \r
+                       \r
+                       /* compare local and remote MDs and send the appropriate status */\r
+                       if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)\r
+                               code = CHAP_SUCCESS;    /* they are the same! */\r
+                       break;\r
+               \r
+               default:\r
+                       CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));\r
+               }\r
+       }\r
+       \r
+       BZERO(secret, sizeof(secret));\r
+       ChapSendStatus(cstate, code);\r
+       \r
+       if (code == CHAP_SUCCESS) {\r
+               old_state = cstate->serverstate;\r
+               cstate->serverstate = CHAPSS_OPEN;\r
+               if (old_state == CHAPSS_INITIAL_CHAL) {\r
+                       auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);\r
+               }\r
+               if (cstate->chal_interval != 0)\r
+                       TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);\r
+       } else {\r
+               CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));\r
+               cstate->serverstate = CHAPSS_BADAUTH;\r
+               auth_peer_fail(cstate->unit, PPP_CHAP);\r
+       }\r
+}\r
+\r
+/*\r
+ * ChapReceiveSuccess - Receive Success\r
+ */\r
+static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)\r
+{\r
+\r
+       CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));\r
+       \r
+       if (cstate->clientstate == CHAPCS_OPEN)\r
+               /* presumably an answer to a duplicate response */\r
+               return;\r
+       \r
+       if (cstate->clientstate != CHAPCS_RESPONSE) {\r
+               /* don't know what this is */\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",\r
+                          cstate->clientstate));\r
+               return;\r
+       }\r
+       \r
+       UNTIMEOUT(ChapResponseTimeout, cstate);\r
+       \r
+       /*\r
+        * Print message.\r
+        */\r
+       if (len > 0)\r
+               PRINTMSG(inp, len);\r
+       \r
+       cstate->clientstate = CHAPCS_OPEN;\r
+       \r
+       auth_withpeer_success(cstate->unit, PPP_CHAP);\r
+}\r
+\r
+\r
+/*\r
+ * ChapReceiveFailure - Receive failure.\r
+ */\r
+static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)\r
+{\r
+       CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));\r
+       \r
+       if (cstate->clientstate != CHAPCS_RESPONSE) {\r
+               /* don't know what this is */\r
+               CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",\r
+                          cstate->clientstate));\r
+               return;\r
+       }\r
+       \r
+       UNTIMEOUT(ChapResponseTimeout, cstate);\r
+       \r
+       /*\r
+        * Print message.\r
+        */\r
+       if (len > 0)\r
+               PRINTMSG(inp, len);\r
+       \r
+       CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));\r
+       auth_withpeer_fail(cstate->unit, PPP_CHAP);\r
+}\r
+\r
+\r
+/*\r
+ * ChapSendChallenge - Send an Authenticate challenge.\r
+ */\r
+static void ChapSendChallenge(chap_state *cstate)\r
+{\r
+       u_char *outp;\r
+       int chal_len, name_len;\r
+       int outlen;\r
+       \r
+       chal_len = cstate->chal_len;\r
+       name_len = strlen(cstate->chal_name);\r
+       outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;\r
+       outp = outpacket_buf[cstate->unit];\r
+       \r
+       MAKEHEADER(outp, PPP_CHAP);             /* paste in a CHAP header */\r
+       \r
+       PUTCHAR(CHAP_CHALLENGE, outp);\r
+       PUTCHAR(cstate->chal_id, outp);\r
+       PUTSHORT(outlen, outp);\r
+       \r
+       PUTCHAR(chal_len, outp);                /* put length of challenge */\r
+       BCOPY(cstate->challenge, outp, chal_len);\r
+       INCPTR(chal_len, outp);\r
+       \r
+       BCOPY(cstate->chal_name, outp, name_len);       /* append hostname */\r
+       \r
+       pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);\r
+       \r
+       CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));\r
+       \r
+       TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);\r
+       ++cstate->chal_transmits;\r
+}\r
+\r
+\r
+/*\r
+ * ChapSendStatus - Send a status response (ack or nak).\r
+ */\r
+static void ChapSendStatus(chap_state *cstate, int code)\r
+{\r
+       u_char *outp;\r
+       int outlen, msglen;\r
+       char msg[256];\r
+       \r
+       if (code == CHAP_SUCCESS)\r
+               strcpy(msg, "Welcome!");\r
+       else\r
+               strcpy(msg, "I don't like you.  Go 'way.");\r
+       msglen = strlen(msg);\r
+       \r
+       outlen = CHAP_HEADERLEN + msglen;\r
+       outp = outpacket_buf[cstate->unit];\r
+       \r
+       MAKEHEADER(outp, PPP_CHAP);             /* paste in a header */\r
+       \r
+       PUTCHAR(code, outp);\r
+       PUTCHAR(cstate->chal_id, outp);\r
+       PUTSHORT(outlen, outp);\r
+       BCOPY(msg, outp, msglen);\r
+       pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);\r
+       \r
+       CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code,\r
+              cstate->chal_id));\r
+}\r
+\r
+/*\r
+ * ChapGenChallenge is used to generate a pseudo-random challenge string of\r
+ * a pseudo-random length between min_len and max_len.  The challenge\r
+ * string and its length are stored in *cstate, and various other fields of\r
+ * *cstate are initialized.\r
+ */\r
+\r
+static void ChapGenChallenge(chap_state *cstate)\r
+{\r
+       int chal_len;\r
+       u_char *ptr = cstate->challenge;\r
+       int i;\r
+       \r
+       /* pick a random challenge length between MIN_CHALLENGE_LENGTH and \r
+          MAX_CHALLENGE_LENGTH */  \r
+       chal_len = (unsigned)\r
+                               ((((magic() >> 16) *\r
+                               (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)\r
+                            + MIN_CHALLENGE_LENGTH);\r
+       cstate->chal_len = chal_len;\r
+       cstate->chal_id = ++cstate->id;\r
+       cstate->chal_transmits = 0;\r
+       \r
+       /* generate a random string */\r
+       for (i = 0; i < chal_len; i++ )\r
+               *ptr++ = (char) (magic() & 0xff);\r
+}\r
+\r
+/*\r
+ * ChapSendResponse - send a response packet with values as specified\r
+ * in *cstate.\r
+ */\r
+/* ARGSUSED */\r
+static void ChapSendResponse(chap_state *cstate)\r
+{\r
+       u_char *outp;\r
+       int outlen, md_len, name_len;\r
+       \r
+       md_len = cstate->resp_length;\r
+       name_len = strlen(cstate->resp_name);\r
+       outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;\r
+       outp = outpacket_buf[cstate->unit];\r
+       \r
+       MAKEHEADER(outp, PPP_CHAP);\r
+       \r
+       PUTCHAR(CHAP_RESPONSE, outp);   /* we are a response */\r
+       PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */\r
+       PUTSHORT(outlen, outp);                 /* packet length */\r
+       \r
+       PUTCHAR(md_len, outp);                  /* length of MD */\r
+       BCOPY(cstate->response, outp, md_len);          /* copy MD to buffer */\r
+       INCPTR(md_len, outp);\r
+       \r
+       BCOPY(cstate->resp_name, outp, name_len);       /* append our name */\r
+       \r
+       /* send the packet */\r
+       pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);\r
+       \r
+       cstate->clientstate = CHAPCS_RESPONSE;\r
+       TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);\r
+       ++cstate->resp_transmits;\r
+}\r
+\r
+/*\r
+ * ChapPrintPkt - print the contents of a CHAP packet.\r
+ */\r
+static int ChapPrintPkt(\r
+       u_char *p,\r
+       int plen,\r
+       void (*printer) (void *, char *, ...),\r
+       void *arg\r
+)\r
+{\r
+       int code, id, len;\r
+       int clen, nlen;\r
+       u_char x;\r
+       \r
+       if (plen < CHAP_HEADERLEN)\r
+               return 0;\r
+       GETCHAR(code, p);\r
+       GETCHAR(id, p);\r
+       GETSHORT(len, p);\r
+       if (len < CHAP_HEADERLEN || len > plen)\r
+               return 0;\r
+       \r
+       if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))\r
+               printer(arg, " %s", ChapCodenames[code-1]);\r
+       else\r
+               printer(arg, " code=0x%x", code);\r
+       printer(arg, " id=0x%x", id);\r
+       len -= CHAP_HEADERLEN;\r
+       switch (code) {\r
+       case CHAP_CHALLENGE:\r
+       case CHAP_RESPONSE:\r
+               if (len < 1)\r
+                       break;\r
+               clen = p[0];\r
+               if (len < clen + 1)\r
+                       break;\r
+               ++p;\r
+               nlen = len - clen - 1;\r
+               printer(arg, " <");\r
+               for (; clen > 0; --clen) {\r
+                       GETCHAR(x, p);\r
+                       printer(arg, "%.2x", x);\r
+               }\r
+               printer(arg, ">, name = %.*Z", nlen, p);\r
+               break;\r
+       case CHAP_FAILURE:\r
+       case CHAP_SUCCESS:\r
+               printer(arg, " %.*Z", len, p);\r
+               break;\r
+       default:\r
+               for (clen = len; clen > 0; --clen) {\r
+                       GETCHAR(x, p);\r
+                       printer(arg, " %.2x", x);\r
+               }\r
+       }\r
+       \r
+       return len + CHAP_HEADERLEN;\r
+}\r
+\r
+#endif\r
+\r
+#endif /* PPP_SUPPORT */\r
index 6fd9727525a3fe6691512616fcb9a8c37bb38d6c..1aca13414fe13816e9cbc67f83e1c43e1e766893 100644 (file)
-/*****************************************************************************
-* 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 */
-
+/*****************************************************************************\r
+* chap.h - Network Challenge Handshake Authentication Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1998 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original built from BSD network code.\r
+******************************************************************************/\r
+/*\r
+ * chap.h - Challenge Handshake Authentication Protocol definitions.\r
+ *\r
+ * Copyright (c) 1993 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the Australian National University.  The name of the University\r
+ * may not be used to endorse or promote products derived from this\r
+ * software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * Copyright (c) 1991 Gregory M. Christy\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the author.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: chap.h,v 1.1 2003/05/27 14:37:56 jani Exp $\r
+ */\r
+\r
+#ifndef CHAP_H\r
+#define CHAP_H\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+\r
+/* Code + ID + length */\r
+#define CHAP_HEADERLEN         4\r
+\r
+/*\r
+ * CHAP codes.\r
+ */\r
+\r
+#define CHAP_DIGEST_MD5                5       /* use MD5 algorithm */\r
+#define MD5_SIGNATURE_SIZE     16      /* 16 bytes in a MD5 message digest */\r
+#define CHAP_MICROSOFT         0x80    /* use Microsoft-compatible alg. */\r
+#define MS_CHAP_RESPONSE_LEN   49      /* Response length for MS-CHAP */\r
+\r
+#define CHAP_CHALLENGE         1\r
+#define CHAP_RESPONSE          2\r
+#define CHAP_SUCCESS           3\r
+#define CHAP_FAILURE           4\r
+\r
+/*\r
+ *  Challenge lengths (for challenges we send) and other limits.\r
+ */\r
+#define MIN_CHALLENGE_LENGTH   32\r
+#define MAX_CHALLENGE_LENGTH   64\r
+#define MAX_RESPONSE_LENGTH    64      /* sufficient for MD5 or MS-CHAP */\r
+\r
+/*\r
+ * Client (peer) states.\r
+ */\r
+#define CHAPCS_INITIAL         0       /* Lower layer down, not opened */\r
+#define CHAPCS_CLOSED          1       /* Lower layer up, not opened */\r
+#define CHAPCS_PENDING         2       /* Auth us to peer when lower up */\r
+#define CHAPCS_LISTEN          3       /* Listening for a challenge */\r
+#define CHAPCS_RESPONSE                4       /* Sent response, waiting for status */\r
+#define CHAPCS_OPEN            5       /* We've received Success */\r
+\r
+/*\r
+ * Server (authenticator) states.\r
+ */\r
+#define CHAPSS_INITIAL         0       /* Lower layer down, not opened */\r
+#define CHAPSS_CLOSED          1       /* Lower layer up, not opened */\r
+#define CHAPSS_PENDING         2       /* Auth peer when lower up */\r
+#define CHAPSS_INITIAL_CHAL    3       /* We've sent the first challenge */\r
+#define CHAPSS_OPEN            4       /* We've sent a Success msg */\r
+#define CHAPSS_RECHALLENGE     5       /* We've sent another challenge */\r
+#define CHAPSS_BADAUTH         6       /* We've sent a Failure msg */\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+/*\r
+ * Each interface is described by a chap structure.\r
+ */\r
+\r
+typedef struct chap_state {\r
+    int unit;                  /* Interface unit number */\r
+    int clientstate;           /* Client state */\r
+    int serverstate;           /* Server state */\r
+    u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */\r
+    u_char chal_len;           /* challenge length */\r
+    u_char chal_id;            /* ID of last challenge */\r
+    u_char chal_type;          /* hash algorithm for challenges */\r
+    u_char id;                 /* Current id */\r
+    char *chal_name;           /* Our name to use with challenge */\r
+    int chal_interval;         /* Time until we challenge peer again */\r
+    int timeouttime;           /* Timeout time in seconds */\r
+    int max_transmits;         /* Maximum # of challenge transmissions */\r
+    int chal_transmits;                /* Number of transmissions of challenge */\r
+    int resp_transmits;                /* Number of transmissions of response */\r
+    u_char response[MAX_RESPONSE_LENGTH];      /* Response to send */\r
+    u_char resp_length;                /* length of response */\r
+    u_char resp_id;            /* ID for response messages */\r
+    u_char resp_type;          /* hash algorithm for responses */\r
+    char *resp_name;           /* Our name to send with response */\r
+} chap_state;\r
+\r
+\r
+/******************\r
+*** PUBLIC DATA ***\r
+******************/\r
+extern chap_state chap[];\r
+\r
+extern struct protent chap_protent;\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+void ChapAuthWithPeer (int, char *, int);\r
+void ChapAuthPeer (int, char *, int);\r
+\r
+#endif /* CHAP_H */\r
+\r
index 01755ba39ca6e3afaeb58ca69870348a93da0ec8..30643446034382f722681c0f0f59d58a425a4fb7 100644 (file)
-/*** 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 */
-
+/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/\r
+/*****************************************************************************\r
+* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original based on BSD chap_ms.c.\r
+*****************************************************************************/\r
+/*\r
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.\r
+ *\r
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.\r
+ * http://www.strataware.com/\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Eric Rosenquist.  The name of the author may not be used to\r
+ * endorse or promote products derived from this software without\r
+ * specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+/*\r
+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997\r
+ *\r
+ *   Implemented LANManager type password response to MS-CHAP challenges.\r
+ *   Now pppd provides both NT style and LANMan style blocks, and the\r
+ *   prefered is set by option "ms-lanman". Default is to use NT.\r
+ *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.\r
+ *\r
+ *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80\r
+ */\r
+\r
+#define USE_CRYPT\r
+\r
+\r
+#include "ppp.h"\r
+\r
+#if MSCHAP_SUPPORT > 0\r
+\r
+#include "md4.h"\r
+#ifndef USE_CRYPT\r
+#include "des.h"\r
+#endif\r
+#include "chap.h"\r
+#include "chpms.h"\r
+#include "pppdebug.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+typedef struct {\r
+    u_char LANManResp[24];\r
+    u_char NTResp[24];\r
+    u_char UseNT;              /* If 1, ignore the LANMan response field */\r
+} MS_ChapResponse;\r
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),\r
+   in case this struct gets padded. */\r
+\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+\r
+/* XXX Don't know what to do with these. */\r
+extern void setkey(const char *);\r
+extern void encrypt(char *, int);\r
+\r
+static void    DesEncrypt (u_char *, u_char *, u_char *);\r
+static void    MakeKey (u_char *, u_char *);\r
+\r
+#ifdef USE_CRYPT\r
+static void    Expand (u_char *, u_char *);\r
+static void    Collapse (u_char *, u_char *);\r
+#endif\r
+\r
+static void ChallengeResponse(\r
+       u_char *challenge,      /* IN   8 octets */\r
+       u_char *pwHash,         /* IN  16 octets */\r
+       u_char *response        /* OUT 24 octets */\r
+);\r
+static void ChapMS_NT(\r
+       char *rchallenge,\r
+       int rchallenge_len,\r
+       char *secret,\r
+       int secret_len,\r
+       MS_ChapResponse *response\r
+);\r
+static u_char Get7Bits(\r
+       u_char *input,\r
+       int startBit\r
+);\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+void ChapMS(\r
+       chap_state *cstate,\r
+       char *rchallenge,\r
+       int rchallenge_len,\r
+       char *secret,\r
+       int secret_len\r
+)\r
+{\r
+       MS_ChapResponse response;\r
+#ifdef MSLANMAN\r
+       extern int ms_lanman;\r
+#endif\r
+       \r
+#if 0\r
+       CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));\r
+#endif\r
+       BZERO(&response, sizeof(response));\r
+       \r
+       /* Calculate both always */\r
+       ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);\r
+       \r
+#ifdef MSLANMAN\r
+       ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);\r
+       \r
+       /* prefered method is set by option  */\r
+       response.UseNT = !ms_lanman;\r
+#else\r
+       response.UseNT = 1;\r
+#endif\r
+       \r
+       BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);\r
+       cstate->resp_length = MS_CHAP_RESPONSE_LEN;\r
+}\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+static void ChallengeResponse(\r
+       u_char *challenge,      /* IN   8 octets */\r
+       u_char *pwHash,         /* IN  16 octets */\r
+       u_char *response        /* OUT 24 octets */\r
+)\r
+{\r
+       char    ZPasswordHash[21];\r
+       \r
+       BZERO(ZPasswordHash, sizeof(ZPasswordHash));\r
+       BCOPY(pwHash, ZPasswordHash, 16);\r
+       \r
+#if 0\r
+       log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);\r
+#endif\r
+       \r
+       DesEncrypt(challenge, ZPasswordHash +  0, response + 0);\r
+       DesEncrypt(challenge, ZPasswordHash +  7, response + 8);\r
+       DesEncrypt(challenge, ZPasswordHash + 14, response + 16);\r
+       \r
+#if 0\r
+       log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);\r
+#endif\r
+}\r
+\r
+\r
+#ifdef USE_CRYPT\r
+static void DesEncrypt(\r
+       u_char *clear,  /* IN  8 octets */\r
+       u_char *key,    /* IN  7 octets */\r
+       u_char *cipher  /* OUT 8 octets */\r
+)\r
+{\r
+       u_char des_key[8];\r
+       u_char crypt_key[66];\r
+       u_char des_input[66];\r
+       \r
+       MakeKey(key, des_key);\r
+       \r
+       Expand(des_key, crypt_key);\r
+       setkey(crypt_key);\r
+       \r
+#if 0\r
+       CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));\r
+#endif\r
+       \r
+       Expand(clear, des_input);\r
+       encrypt(des_input, 0);\r
+       Collapse(des_input, cipher);\r
+       \r
+#if 0\r
+       CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));\r
+#endif\r
+}\r
+\r
+#else /* USE_CRYPT */\r
+\r
+static void DesEncrypt(\r
+       u_char *clear,  /* IN  8 octets */\r
+       u_char *key,    /* IN  7 octets */\r
+       u_char *cipher  /* OUT 8 octets */\r
+)\r
+{\r
+       des_cblock              des_key;\r
+       des_key_schedule        key_schedule;\r
+       \r
+       MakeKey(key, des_key);\r
+       \r
+       des_set_key(&des_key, key_schedule);\r
+       \r
+#if 0\r
+       CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));\r
+#endif\r
+       \r
+       des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);\r
+       \r
+#if 0\r
+       CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));\r
+#endif\r
+}\r
+\r
+#endif /* USE_CRYPT */\r
+\r
+\r
+static u_char Get7Bits(\r
+       u_char *input,\r
+       int startBit\r
+)\r
+{\r
+       register unsigned int   word;\r
+       \r
+       word  = (unsigned)input[startBit / 8] << 8;\r
+       word |= (unsigned)input[startBit / 8 + 1];\r
+       \r
+       word >>= 15 - (startBit % 8 + 7);\r
+       \r
+       return word & 0xFE;\r
+}\r
+\r
+#ifdef USE_CRYPT\r
+\r
+/* in == 8-byte string (expanded version of the 56-bit key)\r
+ * out == 64-byte string where each byte is either 1 or 0\r
+ * Note that the low-order "bit" is always ignored by by setkey()\r
+ */\r
+static void Expand(u_char *in, u_char *out)\r
+{\r
+       int j, c;\r
+       int i;\r
+       \r
+       for(i = 0; i < 64; in++){\r
+               c = *in;\r
+               for(j = 7; j >= 0; j--)\r
+                       *out++ = (c >> j) & 01;\r
+               i += 8;\r
+       }\r
+}\r
+\r
+/* The inverse of Expand\r
+ */\r
+static void Collapse(u_char *in, u_char *out)\r
+{\r
+       int j;\r
+       int i;\r
+       unsigned int c;\r
+       \r
+       for (i = 0; i < 64; i += 8, out++) {\r
+               c = 0;\r
+               for (j = 7; j >= 0; j--, in++)\r
+                       c |= *in << j;\r
+               *out = c & 0xff;\r
+       }\r
+}\r
+#endif\r
+\r
+static void MakeKey(\r
+       u_char *key,            /* IN  56 bit DES key missing parity bits */\r
+       u_char *des_key         /* OUT 64 bit DES key with parity bits added */\r
+)\r
+{\r
+       des_key[0] = Get7Bits(key,  0);\r
+       des_key[1] = Get7Bits(key,  7);\r
+       des_key[2] = Get7Bits(key, 14);\r
+       des_key[3] = Get7Bits(key, 21);\r
+       des_key[4] = Get7Bits(key, 28);\r
+       des_key[5] = Get7Bits(key, 35);\r
+       des_key[6] = Get7Bits(key, 42);\r
+       des_key[7] = Get7Bits(key, 49);\r
+       \r
+#ifndef USE_CRYPT\r
+       des_set_odd_parity((des_cblock *)des_key);\r
+#endif\r
+       \r
+#if 0\r
+       CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",\r
+              key[0], key[1], key[2], key[3], key[4], key[5], key[6]));\r
+       CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+              des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));\r
+#endif\r
+}\r
+\r
+static void ChapMS_NT(\r
+       char *rchallenge,\r
+       int rchallenge_len,\r
+       char *secret,\r
+       int secret_len,\r
+       MS_ChapResponse *response\r
+)\r
+{\r
+       int                     i;\r
+       MDstruct        md4Context;\r
+       u_char          unicodePassword[MAX_NT_PASSWORD * 2];\r
+       static int      low_byte_first = -1;\r
+       \r
+       /* Initialize the Unicode version of the secret (== password). */\r
+       /* This implicitly supports 8-bit ISO8859/1 characters. */\r
+       BZERO(unicodePassword, sizeof(unicodePassword));\r
+       for (i = 0; i < secret_len; i++)\r
+               unicodePassword[i * 2] = (u_char)secret[i];\r
+       \r
+       MDbegin(&md4Context);\r
+       MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);     /* Unicode is 2 bytes/char, *8 for bit count */\r
+       \r
+       if (low_byte_first == -1)\r
+               low_byte_first = (htons((unsigned short int)1) != 1);\r
+       if (low_byte_first == 0)\r
+               MDreverse((u_long *)&md4Context);  /*  sfb 961105 */\r
+       \r
+       MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */\r
+       \r
+       ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);\r
+}\r
+\r
+#ifdef MSLANMAN\r
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */\r
+\r
+static ChapMS_LANMan(\r
+       char *rchallenge,\r
+       int rchallenge_len,\r
+       char *secret,\r
+       int secret_len,\r
+       MS_ChapResponse *response\r
+)\r
+{\r
+       int                     i;\r
+       u_char          UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */\r
+       u_char          PasswordHash[16];\r
+       \r
+       /* LANMan password is case insensitive */\r
+       BZERO(UcasePassword, sizeof(UcasePassword));\r
+       for (i = 0; i < secret_len; i++)\r
+               UcasePassword[i] = (u_char)toupper(secret[i]);\r
+       DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );\r
+       DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );\r
+       ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);\r
+}\r
+#endif\r
+\r
+#endif /* MSCHAP_SUPPORT */\r
+\r
index c58447215a7b3aef8e7b754b3cc01c00243eb489..0b30c6554b5fbbc52482e089713e5681d943fa06 100644 (file)
@@ -1,64 +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 */
+/*****************************************************************************\r
+* chpms.h - Network Microsoft Challenge Handshake Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1998 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 98-01-30 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original built from BSD network code.\r
+******************************************************************************/\r
+/*\r
+ * chap.h - Challenge Handshake Authentication Protocol definitions.\r
+ *\r
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.\r
+ * http://www.strataware.com/\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Eric Rosenquist.  The name of the author may not be used to\r
+ * endorse or promote products derived from this software without\r
+ * specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: chpms.h,v 1.3 2004/02/07 00:30:03 likewise Exp $\r
+ */\r
+\r
+#ifndef CHPMS_H\r
+#define CHPMS_H\r
+\r
+#define MAX_NT_PASSWORD        256     /* Maximum number of (Unicode) chars in an NT password */\r
+\r
+void ChapMS (chap_state *, char *, int, char *, int);\r
+\r
+#endif /* CHPMS_H */\r
index fe8b38a93596226f2f71f563461786b42b54da37..6cad71525e004e0bac5a94d99b8eb3617d2ab5ee 100644 (file)
-/*****************************************************************************
-* 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 */
+/*****************************************************************************\r
+* fsm.c - Network Control Protocol Finite State Machine program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original based on BSD fsm.c.\r
+*****************************************************************************/\r
+/*\r
+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+\r
+/*\r
+ * TODO:\r
+ * Randomize fsm id on link/init.\r
+ * Deal with variable outgoing MTU.\r
+ */\r
+\r
+#include "ppp.h"\r
+#if PPP_SUPPORT > 0\r
+#include "fsm.h"\r
+#include "pppdebug.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+static void fsm_timeout (void *);\r
+static void fsm_rconfreq (fsm *, u_char, u_char *, int);\r
+static void fsm_rconfack (fsm *, int, u_char *, int);\r
+static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);\r
+static void fsm_rtermreq (fsm *, int, u_char *, int);\r
+static void fsm_rtermack (fsm *);\r
+static void fsm_rcoderej (fsm *, u_char *, int);\r
+static void fsm_sconfreq (fsm *, int);\r
+\r
+#define PROTO_NAME(f)  ((f)->callbacks->proto_name)\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+int peer_mru[NUM_PPP];\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+\r
+/*\r
+ * fsm_init - Initialize fsm.\r
+ *\r
+ * Initialize fsm state.\r
+ */\r
+void fsm_init(fsm *f)\r
+{\r
+       f->state = INITIAL;\r
+       f->flags = 0;\r
+       f->id = 0;                              /* XXX Start with random id? */\r
+       f->timeouttime = FSM_DEFTIMEOUT;\r
+       f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;\r
+       f->maxtermtransmits = FSM_DEFMAXTERMREQS;\r
+       f->maxnakloops = FSM_DEFMAXNAKLOOPS;\r
+       f->term_reason_len = 0;\r
+}\r
+\r
+\r
+/*\r
+ * fsm_lowerup - The lower layer is up.\r
+ */\r
+void fsm_lowerup(fsm *f)\r
+{\r
+       int oldState = f->state;\r
+\r
+       switch( f->state ){\r
+       case INITIAL:\r
+               f->state = CLOSED;\r
+               break;\r
+       \r
+       case STARTING:\r
+               if( f->flags & OPT_SILENT )\r
+                       f->state = STOPPED;\r
+               else {\r
+                       /* Send an initial configure-request */\r
+                       fsm_sconfreq(f, 0);\r
+                       f->state = REQSENT;\r
+               }\r
+       break;\r
+       \r
+       default:\r
+               FSMDEBUG((LOG_INFO, "%s: Up event in state %d!\n",\r
+                               PROTO_NAME(f), f->state));\r
+       }\r
+       \r
+       FSMDEBUG((LOG_INFO, "%s: lowerup state %d -> %d\n",\r
+                       PROTO_NAME(f), oldState, f->state));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_lowerdown - The lower layer is down.\r
+ *\r
+ * Cancel all timeouts and inform upper layers.\r
+ */\r
+void fsm_lowerdown(fsm *f)\r
+{\r
+       int oldState = f->state;\r
+       \r
+       switch( f->state ){\r
+       case CLOSED:\r
+               f->state = INITIAL;\r
+               break;\r
+       \r
+       case STOPPED:\r
+               f->state = STARTING;\r
+               if( f->callbacks->starting )\r
+                       (*f->callbacks->starting)(f);\r
+               break;\r
+       \r
+       case CLOSING:\r
+               f->state = INITIAL;\r
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               break;\r
+       \r
+       case STOPPING:\r
+       case REQSENT:\r
+       case ACKRCVD:\r
+       case ACKSENT:\r
+               f->state = STARTING;\r
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               break;\r
+       \r
+       case OPENED:\r
+               if( f->callbacks->down )\r
+                       (*f->callbacks->down)(f);\r
+               f->state = STARTING;\r
+               break;\r
+       \r
+       default:\r
+               FSMDEBUG((LOG_INFO, "%s: Down event in state %d!\n",\r
+                               PROTO_NAME(f), f->state));\r
+       }\r
+       \r
+       FSMDEBUG((LOG_INFO, "%s: lowerdown state %d -> %d\n",\r
+                       PROTO_NAME(f), oldState, f->state));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_open - Link is allowed to come up.\r
+ */\r
+void fsm_open(fsm *f)\r
+{\r
+       int oldState = f->state;\r
+       \r
+       switch( f->state ){\r
+               case INITIAL:\r
+                       f->state = STARTING;\r
+                       if( f->callbacks->starting )\r
+                               (*f->callbacks->starting)(f);\r
+                       break;\r
+               \r
+               case CLOSED:\r
+               if( f->flags & OPT_SILENT )\r
+                       f->state = STOPPED;\r
+               else {\r
+                       /* Send an initial configure-request */\r
+                       fsm_sconfreq(f, 0);\r
+                       f->state = REQSENT;\r
+               }\r
+               break;\r
+       \r
+       case CLOSING:\r
+               f->state = STOPPING;\r
+               /* fall through */\r
+       case STOPPED:\r
+       case OPENED:\r
+               if( f->flags & OPT_RESTART ){\r
+                       fsm_lowerdown(f);\r
+                       fsm_lowerup(f);\r
+               }\r
+               break;\r
+       }\r
+       \r
+       FSMDEBUG((LOG_INFO, "%s: open state %d -> %d\n",\r
+                       PROTO_NAME(f), oldState, f->state));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_close - Start closing connection.\r
+ *\r
+ * Cancel timeouts and either initiate close or possibly go directly to\r
+ * the CLOSED state.\r
+ */\r
+void fsm_close(fsm *f, char *reason)\r
+{\r
+       int oldState = f->state;\r
+       \r
+       f->term_reason = reason;\r
+       f->term_reason_len = (reason == NULL? 0: strlen(reason));\r
+       switch( f->state ){\r
+       case STARTING:\r
+               f->state = INITIAL;\r
+               break;\r
+       case STOPPED:\r
+               f->state = CLOSED;\r
+               break;\r
+       case STOPPING:\r
+               f->state = CLOSING;\r
+               break;\r
+       \r
+       case REQSENT:\r
+       case ACKRCVD:\r
+       case ACKSENT:\r
+       case OPENED:\r
+               if( f->state != OPENED )\r
+                       UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               else if( f->callbacks->down )\r
+                       (*f->callbacks->down)(f);       /* Inform upper layers we're down */\r
+               \r
+               /* Init restart counter, send Terminate-Request */\r
+               f->retransmits = f->maxtermtransmits;\r
+               fsm_sdata(f, TERMREQ, f->reqid = ++f->id,\r
+                                       (u_char *) f->term_reason, f->term_reason_len);\r
+               TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+               --f->retransmits;\r
+               \r
+               f->state = CLOSING;\r
+               break;\r
+       }\r
+       \r
+       FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d -> %d\n",\r
+                       PROTO_NAME(f), reason, oldState, f->state));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_sdata - Send some data.\r
+ *\r
+ * Used for all packets sent to our peer by this module.\r
+ */\r
+void fsm_sdata(\r
+       fsm *f,\r
+       u_char code, \r
+       u_char id,\r
+       u_char *data,\r
+       int datalen\r
+)\r
+{\r
+       u_char *outp;\r
+       int outlen;\r
+       \r
+       /* Adjust length to be smaller than MTU */\r
+       outp = outpacket_buf[f->unit];\r
+       if (datalen > peer_mru[f->unit] - (int)HEADERLEN)\r
+               datalen = peer_mru[f->unit] - HEADERLEN;\r
+       if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)\r
+               BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);\r
+       outlen = datalen + HEADERLEN;\r
+       MAKEHEADER(outp, f->protocol);\r
+       PUTCHAR(code, outp);\r
+       PUTCHAR(id, outp);\r
+       PUTSHORT(outlen, outp);\r
+       pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);\r
+       FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n",\r
+                               PROTO_NAME(f), code, id, outlen));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_input - Input packet.\r
+ */\r
+void fsm_input(fsm *f, u_char *inpacket, int l)\r
+{\r
+       u_char *inp = inpacket;\r
+       u_char code, id;\r
+       int len;\r
+       \r
+       /*\r
+       * Parse header (code, id and length).\r
+       * If packet too short, drop it.\r
+       */\r
+       if (l < HEADERLEN) {\r
+               FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n",\r
+                                       f->protocol));\r
+               return;\r
+       }\r
+       GETCHAR(code, inp);\r
+       GETCHAR(id, inp);\r
+       GETSHORT(len, inp);\r
+       if (len < HEADERLEN) {\r
+               FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n",\r
+                               f->protocol));\r
+               return;\r
+       }\r
+       if (len > l) {\r
+               FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n",\r
+                               f->protocol));\r
+               return;\r
+       }\r
+       len -= HEADERLEN;               /* subtract header length */\r
+       \r
+       if( f->state == INITIAL || f->state == STARTING ){\r
+               FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.\n",\r
+                               f->protocol, f->state));\r
+               return;\r
+       }\r
+       FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));\r
+       /*\r
+        * Action depends on code.\r
+        */\r
+       switch (code) {\r
+       case CONFREQ:\r
+               fsm_rconfreq(f, id, inp, len);\r
+               break;\r
+       \r
+       case CONFACK:\r
+               fsm_rconfack(f, id, inp, len);\r
+               break;\r
+       \r
+       case CONFNAK:\r
+       case CONFREJ:\r
+               fsm_rconfnakrej(f, code, id, inp, len);\r
+               break;\r
+       \r
+       case TERMREQ:\r
+               fsm_rtermreq(f, id, inp, len);\r
+               break;\r
+       \r
+       case TERMACK:\r
+               fsm_rtermack(f);\r
+               break;\r
+       \r
+       case CODEREJ:\r
+               fsm_rcoderej(f, inp, len);\r
+               break;\r
+       \r
+       default:\r
+               if( !f->callbacks->extcode\r
+                               || !(*f->callbacks->extcode)(f, code, id, inp, len) )\r
+                       fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_protreject - Peer doesn't speak this protocol.\r
+ *\r
+ * Treat this as a catastrophic error (RXJ-).\r
+ */\r
+void fsm_protreject(fsm *f)\r
+{\r
+       switch( f->state ){\r
+       case CLOSING:\r
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               /* fall through */\r
+       case CLOSED:\r
+               f->state = CLOSED;\r
+               if( f->callbacks->finished )\r
+                       (*f->callbacks->finished)(f);\r
+               break;\r
+       \r
+       case STOPPING:\r
+       case REQSENT:\r
+       case ACKRCVD:\r
+       case ACKSENT:\r
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               /* fall through */\r
+       case STOPPED:\r
+               f->state = STOPPED;\r
+               if( f->callbacks->finished )\r
+                       (*f->callbacks->finished)(f);\r
+               break;\r
+       \r
+       case OPENED:\r
+               if( f->callbacks->down )\r
+                       (*f->callbacks->down)(f);\r
+               \r
+               /* Init restart counter, send Terminate-Request */\r
+               f->retransmits = f->maxtermtransmits;\r
+               fsm_sdata(f, TERMREQ, f->reqid = ++f->id,\r
+                                       (u_char *) f->term_reason, f->term_reason_len);\r
+               TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+               --f->retransmits;\r
+               \r
+               f->state = STOPPING;\r
+               break;\r
+       \r
+       default:\r
+               FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!\n",\r
+                                       PROTO_NAME(f), f->state));\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+\r
+/*\r
+ * fsm_timeout - Timeout expired.\r
+ */\r
+static void fsm_timeout(void *arg)\r
+{\r
+    fsm *f = (fsm *) arg;\r
+\r
+    switch (f->state) {\r
+    case CLOSING:\r
+    case STOPPING:\r
+               if( f->retransmits <= 0 ){\r
+                   FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d\n",\r
+                                          PROTO_NAME(f), f->state));\r
+                   /*\r
+                    * We've waited for an ack long enough.  Peer probably heard us.\r
+                    */\r
+                   f->state = (f->state == CLOSING)? CLOSED: STOPPED;\r
+                   if( f->callbacks->finished )\r
+                       (*f->callbacks->finished)(f);\r
+               } else {\r
+                   FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d\n",\r
+                                          PROTO_NAME(f), f->state));\r
+                   /* Send Terminate-Request */\r
+                   fsm_sdata(f, TERMREQ, f->reqid = ++f->id,\r
+                             (u_char *) f->term_reason, f->term_reason_len);\r
+                   TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+                   --f->retransmits;\r
+               }\r
+               break;\r
+\r
+    case REQSENT:\r
+    case ACKRCVD:\r
+    case ACKSENT:\r
+               if (f->retransmits <= 0) {\r
+                   FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d\n",\r
+                          PROTO_NAME(f), f->state));\r
+                   f->state = STOPPED;\r
+                   if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )\r
+                               (*f->callbacks->finished)(f);\r
+       \r
+               } else {\r
+                   FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d\n",\r
+                          PROTO_NAME(f), f->state));\r
+                   /* Retransmit the configure-request */\r
+                   if (f->callbacks->retransmit)\r
+                               (*f->callbacks->retransmit)(f);\r
+                   fsm_sconfreq(f, 1);         /* Re-send Configure-Request */\r
+                   if( f->state == ACKRCVD )\r
+                               f->state = REQSENT;\r
+               }\r
+               break;\r
+\r
+    default:\r
+               FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!\n",\r
+                                 PROTO_NAME(f), f->state));\r
+           }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rconfreq - Receive Configure-Request.\r
+ */\r
+static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)\r
+{\r
+       int code, reject_if_disagree;\r
+       \r
+       FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d\n", \r
+                               PROTO_NAME(f), id, f->state));\r
+       switch( f->state ){\r
+       case CLOSED:\r
+               /* Go away, we're closed */\r
+               fsm_sdata(f, TERMACK, id, NULL, 0);\r
+               return;\r
+       case CLOSING:\r
+       case STOPPING:\r
+               return;\r
+       \r
+       case OPENED:\r
+               /* Go down and restart negotiation */\r
+               if( f->callbacks->down )\r
+                       (*f->callbacks->down)(f);       /* Inform upper layers */\r
+               fsm_sconfreq(f, 0);             /* Send initial Configure-Request */\r
+               break;\r
+       \r
+       case STOPPED:\r
+               /* Negotiation started by our peer */\r
+               fsm_sconfreq(f, 0);             /* Send initial Configure-Request */\r
+               f->state = REQSENT;\r
+               break;\r
+       }\r
+       \r
+       /*\r
+       * Pass the requested configuration options\r
+       * to protocol-specific code for checking.\r
+       */\r
+       if (f->callbacks->reqci){               /* Check CI */\r
+               reject_if_disagree = (f->nakloops >= f->maxnakloops);\r
+               code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);\r
+       } \r
+       else if (len)\r
+               code = CONFREJ;                 /* Reject all CI */\r
+       else\r
+               code = CONFACK;\r
+       \r
+       /* send the Ack, Nak or Rej to the peer */\r
+       fsm_sdata(f, (u_char)code, id, inp, len);\r
+       \r
+       if (code == CONFACK) {\r
+               if (f->state == ACKRCVD) {\r
+                       UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+                       f->state = OPENED;\r
+                       if (f->callbacks->up)\r
+                               (*f->callbacks->up)(f); /* Inform upper layers */\r
+               } \r
+               else\r
+                       f->state = ACKSENT;\r
+               f->nakloops = 0;\r
+       } \r
+       else {\r
+               /* we sent CONFACK or CONFREJ */\r
+               if (f->state != ACKRCVD)\r
+                       f->state = REQSENT;\r
+               if( code == CONFNAK )\r
+                       ++f->nakloops;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rconfack - Receive Configure-Ack.\r
+ */\r
+static void fsm_rconfack(fsm *f, int id, u_char *inp, int len)\r
+{\r
+       FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d\n",\r
+                               PROTO_NAME(f), id, f->state));\r
+       \r
+       if (id != f->reqid || f->seen_ack)              /* Expected id? */\r
+               return;                                 /* Nope, toss... */\r
+       if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):\r
+                                                               (len == 0)) ){\r
+               /* Ack is bad - ignore it */\r
+               FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n",\r
+                                       PROTO_NAME(f), len));\r
+               return;\r
+       }\r
+       f->seen_ack = 1;\r
+       \r
+       switch (f->state) {\r
+       case CLOSED:\r
+       case STOPPED:\r
+               fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);\r
+               break;\r
+       \r
+       case REQSENT:\r
+               f->state = ACKRCVD;\r
+               f->retransmits = f->maxconfreqtransmits;\r
+               break;\r
+       \r
+       case ACKRCVD:\r
+               /* Huh? an extra valid Ack? oh well... */\r
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               fsm_sconfreq(f, 0);\r
+               f->state = REQSENT;\r
+               break;\r
+       \r
+       case ACKSENT:\r
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               f->state = OPENED;\r
+               f->retransmits = f->maxconfreqtransmits;\r
+               if (f->callbacks->up)\r
+                       (*f->callbacks->up)(f); /* Inform upper layers */\r
+               break;\r
+       \r
+       case OPENED:\r
+               /* Go down and restart negotiation */\r
+               if (f->callbacks->down)\r
+                       (*f->callbacks->down)(f);       /* Inform upper layers */\r
+               fsm_sconfreq(f, 0);             /* Send initial Configure-Request */\r
+               f->state = REQSENT;\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.\r
+ */\r
+static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)\r
+{\r
+       int (*proc) (fsm *, u_char *, int);\r
+       int ret;\r
+       \r
+       FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d\n",\r
+                               PROTO_NAME(f), id, f->state));\r
+       \r
+       if (id != f->reqid || f->seen_ack)      /* Expected id? */\r
+               return;                         /* Nope, toss... */\r
+       proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;\r
+       if (!proc || !(ret = proc(f, inp, len))) {\r
+               /* Nak/reject is bad - ignore it */\r
+               FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n",\r
+                                       PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));\r
+               return;\r
+       }\r
+       f->seen_ack = 1;\r
+       \r
+       switch (f->state) {\r
+       case CLOSED:\r
+       case STOPPED:\r
+               fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);\r
+               break;\r
+       \r
+       case REQSENT:\r
+       case ACKSENT:\r
+               /* They didn't agree to what we wanted - try another request */\r
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               if (ret < 0)\r
+                       f->state = STOPPED;             /* kludge for stopping CCP */\r
+               else\r
+                       fsm_sconfreq(f, 0);             /* Send Configure-Request */\r
+               break;\r
+       \r
+       case ACKRCVD:\r
+               /* Got a Nak/reject when we had already had an Ack?? oh well... */\r
+               UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */\r
+               fsm_sconfreq(f, 0);\r
+               f->state = REQSENT;\r
+               break;\r
+       \r
+       case OPENED:\r
+               /* Go down and restart negotiation */\r
+               if (f->callbacks->down)\r
+                       (*f->callbacks->down)(f);       /* Inform upper layers */\r
+               fsm_sconfreq(f, 0);             /* Send initial Configure-Request */\r
+               f->state = REQSENT;\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rtermreq - Receive Terminate-Req.\r
+ */\r
+static void fsm_rtermreq(fsm *f, int id, u_char *p, int len)\r
+{\r
+       FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d\n",\r
+                               PROTO_NAME(f), id, f->state));\r
+       \r
+       switch (f->state) {\r
+       case ACKRCVD:\r
+       case ACKSENT:\r
+               f->state = REQSENT;             /* Start over but keep trying */\r
+               break;\r
+       \r
+       case OPENED:\r
+               if (len > 0) {\r
+                       FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p));\r
+               } else {\r
+                       FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f)));\r
+               }\r
+               if (f->callbacks->down)\r
+                       (*f->callbacks->down)(f);       /* Inform upper layers */\r
+               f->retransmits = 0;\r
+               f->state = STOPPING;\r
+               TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+               break;\r
+       }\r
+       \r
+       fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rtermack - Receive Terminate-Ack.\r
+ */\r
+static void fsm_rtermack(fsm *f)\r
+{\r
+       FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d\n", \r
+                               PROTO_NAME(f), f->state));\r
+       \r
+       switch (f->state) {\r
+       case CLOSING:\r
+               UNTIMEOUT(fsm_timeout, f);\r
+               f->state = CLOSED;\r
+               if( f->callbacks->finished )\r
+                       (*f->callbacks->finished)(f);\r
+               break;\r
+       case STOPPING:\r
+               UNTIMEOUT(fsm_timeout, f);\r
+               f->state = STOPPED;\r
+               if( f->callbacks->finished )\r
+                       (*f->callbacks->finished)(f);\r
+               break;\r
+       \r
+       case ACKRCVD:\r
+               f->state = REQSENT;\r
+               break;\r
+       \r
+       case OPENED:\r
+               if (f->callbacks->down)\r
+                       (*f->callbacks->down)(f);       /* Inform upper layers */\r
+               fsm_sconfreq(f, 0);\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rcoderej - Receive an Code-Reject.\r
+ */\r
+static void fsm_rcoderej(fsm *f, u_char *inp, int len)\r
+{\r
+       u_char code, id;\r
+       \r
+       FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d\n", \r
+                               PROTO_NAME(f), f->state));\r
+       \r
+       if (len < HEADERLEN) {\r
+               FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n"));\r
+               return;\r
+       }\r
+       GETCHAR(code, inp);\r
+       GETCHAR(id, inp);\r
+       FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n",\r
+                               PROTO_NAME(f), code, id));\r
+       \r
+       if( f->state == ACKRCVD )\r
+               f->state = REQSENT;\r
+}\r
+\r
+\r
+/*\r
+ * fsm_sconfreq - Send a Configure-Request.\r
+ */\r
+static void fsm_sconfreq(fsm *f, int retransmit)\r
+{\r
+       u_char *outp;\r
+       int cilen;\r
+       \r
+       if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){\r
+               /* Not currently negotiating - reset options */\r
+               if( f->callbacks->resetci )\r
+                       (*f->callbacks->resetci)(f);\r
+               f->nakloops = 0;\r
+               }\r
+       \r
+       if( !retransmit ){\r
+               /* New request - reset retransmission counter, use new ID */\r
+               f->retransmits = f->maxconfreqtransmits;\r
+               f->reqid = ++f->id;\r
+       }\r
+       \r
+       f->seen_ack = 0;\r
+       \r
+       /*\r
+        * Make up the request packet\r
+        */\r
+       outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;\r
+       if( f->callbacks->cilen && f->callbacks->addci ){\r
+               cilen = (*f->callbacks->cilen)(f);\r
+               if( cilen > peer_mru[f->unit] - (int)HEADERLEN )\r
+                       cilen = peer_mru[f->unit] - HEADERLEN;\r
+               if (f->callbacks->addci)\r
+                       (*f->callbacks->addci)(f, outp, &cilen);\r
+       } else\r
+               cilen = 0;\r
+       \r
+       /* send the request to our peer */\r
+       fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);\r
+       \r
+       /* start the retransmit timer */\r
+       --f->retransmits;\r
+       TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+       \r
+       FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n",\r
+                               PROTO_NAME(f), f->reqid));\r
+}\r
+\r
+#endif /* PPP_SUPPORT */\r
index 0e1d9f61a6739eb3b71aba52df4cafdb0cad065f..4cca402e02d3d460a94775fd453e083d2ce59ef2 100644 (file)
-/*****************************************************************************
-* 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 */
-
+/*****************************************************************************\r
+* fsm.h - Network Control Protocol Finite State Machine header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*      Original based on BSD code.\r
+*****************************************************************************/\r
+/*\r
+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: fsm.h,v 1.1 2003/05/27 14:37:56 jani Exp $\r
+ */\r
+\r
+#ifndef FSM_H\r
+#define FSM_H\r
+\r
+\r
+/*****************************************************************************\r
+************************* PUBLIC DEFINITIONS *********************************\r
+*****************************************************************************/\r
+/*\r
+ * LCP Packet header = Code, id, length.\r
+ */\r
+#define HEADERLEN      (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))\r
+\r
+\r
+/*\r
+ *  CP (LCP, IPCP, etc.) codes.\r
+ */\r
+#define CONFREQ                1               /* Configuration Request */\r
+#define CONFACK                2               /* Configuration Ack */\r
+#define CONFNAK                3               /* Configuration Nak */\r
+#define CONFREJ                4               /* Configuration Reject */\r
+#define TERMREQ                5               /* Termination Request */\r
+#define TERMACK                6               /* Termination Ack */\r
+#define CODEREJ                7               /* Code Reject */\r
+\r
+/*\r
+ * Link states.\r
+ */\r
+#define INITIAL                0               /* Down, hasn't been opened */\r
+#define STARTING       1               /* Down, been opened */\r
+#define CLOSED         2               /* Up, hasn't been opened */\r
+#define STOPPED                3               /* Open, waiting for down event */\r
+#define CLOSING                4               /* Terminating the connection, not open */\r
+#define STOPPING       5               /* Terminating, but open */\r
+#define REQSENT                6               /* We've sent a Config Request */\r
+#define ACKRCVD                7               /* We've received a Config Ack */\r
+#define ACKSENT                8               /* We've sent a Config Ack */\r
+#define OPENED         9               /* Connection available */\r
+\r
+\r
+/*\r
+ * Flags - indicate options controlling FSM operation\r
+ */\r
+#define OPT_PASSIVE    1               /* Don't die if we don't get a response */\r
+#define OPT_RESTART    2               /* Treat 2nd OPEN as DOWN, UP */\r
+#define OPT_SILENT     4               /* Wait for peer to speak first */\r
+\r
+\r
+/*****************************************************************************\r
+************************* PUBLIC DATA TYPES **********************************\r
+*****************************************************************************/\r
+/*\r
+ * Each FSM is described by an fsm structure and fsm callbacks.\r
+ */\r
+typedef struct fsm {\r
+    int unit;                          /* Interface unit number */\r
+    u_short protocol;          /* Data Link Layer Protocol field value */\r
+    int state;                         /* State */\r
+    int flags;                         /* Contains option bits */\r
+    u_char id;                         /* Current id */\r
+    u_char reqid;                      /* Current request id */\r
+    u_char seen_ack;           /* Have received valid Ack/Nak/Rej to Req */\r
+    int timeouttime;           /* Timeout time in milliseconds */\r
+    int maxconfreqtransmits;/* Maximum Configure-Request transmissions */\r
+    int retransmits;           /* Number of retransmissions left */\r
+    int maxtermtransmits;      /* Maximum Terminate-Request transmissions */\r
+    int nakloops;                      /* Number of nak loops since last ack */\r
+    int maxnakloops;           /* Maximum number of nak loops tolerated */\r
+    struct fsm_callbacks* callbacks;/* Callback routines */\r
+    char* term_reason;         /* Reason for closing protocol */\r
+    int term_reason_len;       /* Length of term_reason */\r
+} fsm;\r
+\r
+\r
+typedef struct fsm_callbacks {\r
+    void (*resetci)                    /* Reset our Configuration Information */\r
+               (fsm*);\r
+    int  (*cilen)                      /* Length of our Configuration Information */\r
+               (fsm*);\r
+    void (*addci)                      /* Add our Configuration Information */\r
+               (fsm*, u_char*, int*);\r
+    int  (*ackci)                      /* ACK our Configuration Information */\r
+               (fsm*, u_char*, int);\r
+    int  (*nakci)                      /* NAK our Configuration Information */\r
+               (fsm*, u_char*, int);\r
+    int  (*rejci)                      /* Reject our Configuration Information */\r
+               (fsm*, u_char*, int);\r
+    int  (*reqci)                      /* Request peer's Configuration Information */\r
+               (fsm*, u_char*, int*, int);\r
+    void (*up)                         /* Called when fsm reaches OPENED state */\r
+               (fsm*);\r
+    void (*down)                       /* Called when fsm leaves OPENED state */\r
+               (fsm*);\r
+    void (*starting)           /* Called when we want the lower layer */\r
+               (fsm*);\r
+    void (*finished)           /* Called when we don't want the lower layer */\r
+               (fsm*);\r
+    void (*protreject)         /* Called when Protocol-Reject received */\r
+               (int);\r
+    void (*retransmit)         /* Retransmission is necessary */\r
+               (fsm*);\r
+    int  (*extcode)                    /* Called when unknown code received */\r
+               (fsm*, int, u_char, u_char*, int);\r
+    char *proto_name;          /* String name for protocol (for messages) */\r
+} fsm_callbacks;\r
+\r
+\r
+/*****************************************************************************\r
+*********************** PUBLIC DATA STRUCTURES *******************************\r
+*****************************************************************************/\r
+/*\r
+ * Variables\r
+ */\r
+extern int peer_mru[];         /* currently negotiated peer MRU (per unit) */\r
+\r
+\r
+/*****************************************************************************\r
+************************** PUBLIC FUNCTIONS **********************************\r
+*****************************************************************************/\r
+\r
+/*\r
+ * Prototypes\r
+ */\r
+void fsm_init (fsm*);\r
+void fsm_lowerup (fsm*);\r
+void fsm_lowerdown (fsm*);\r
+void fsm_open (fsm*);\r
+void fsm_close (fsm*, char*);\r
+void fsm_input (fsm*, u_char*, int);\r
+void fsm_protreject (fsm*);\r
+void fsm_sdata (fsm*, u_char, u_char, u_char*, int);\r
+\r
+\r
+#endif /* FSM_H */\r
+\r
index d5b251880997bba95b0036f161107d8c246af9da..ec3207a0c43fd9f39f135f4b95437e425eb375ec 100644 (file)
-/*****************************************************************************
-* 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 */
+/*****************************************************************************\r
+* ipcp.c - Network PPP IP Control Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original.\r
+*****************************************************************************/\r
+/*\r
+ * ipcp.c - PPP IP Control Protocol.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "ppp.h"\r
+#if PPP_SUPPORT > 0\r
+#include "auth.h"\r
+#include "fsm.h"\r
+#include "vj.h"\r
+#include "ipcp.h"\r
+#include "pppdebug.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+/* #define OLD_CI_ADDRS 1 */   /* Support deprecated address negotiation. */\r
+\r
+/*\r
+ * Lengths of configuration options.\r
+ */\r
+#define CILEN_VOID     2\r
+#define CILEN_COMPRESS 4       /* min length for compression protocol opt. */\r
+#define CILEN_VJ       6       /* length for RFC1332 Van-Jacobson opt. */\r
+#define CILEN_ADDR     6       /* new-style single address option */\r
+#define CILEN_ADDRS    10      /* old-style dual address option */\r
+\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+/*\r
+ * Callbacks for fsm code.  (CI = Configuration Information)\r
+ */\r
+static void ipcp_resetci (fsm *);      /* Reset our CI */\r
+static int  ipcp_cilen (fsm *);                /* Return length of our CI */\r
+static void ipcp_addci (fsm *, u_char *, int *); /* Add our CI */\r
+static int  ipcp_ackci (fsm *, u_char *, int); /* Peer ack'd our CI */\r
+static int  ipcp_nakci (fsm *, u_char *, int); /* Peer nak'd our CI */\r
+static int  ipcp_rejci (fsm *, u_char *, int); /* Peer rej'd our CI */\r
+static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */\r
+static void ipcp_up (fsm *);           /* We're UP */\r
+static void ipcp_down (fsm *);         /* We're DOWN */\r
+#if 0\r
+static void ipcp_script (fsm *, char *); /* Run an up/down script */\r
+#endif\r
+static void ipcp_finished (fsm *);     /* Don't need lower layer */\r
+\r
+/*\r
+ * Protocol entry points from main code.\r
+ */\r
+static void ipcp_init (int);\r
+static void ipcp_open (int);\r
+static void ipcp_close (int, char *);\r
+static void ipcp_lowerup (int);\r
+static void ipcp_lowerdown (int);\r
+static void ipcp_input (int, u_char *, int);\r
+static void ipcp_protrej (int);\r
+\r
+static void ipcp_clear_addrs (int);\r
+\r
+#define CODENAME(x)    ((x) == CONFACK ? "ACK" : \\r
+                        (x) == CONFNAK ? "NAK" : "REJ")\r
+\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+/* global vars */\r
+ipcp_options ipcp_wantoptions[NUM_PPP];        /* Options that we want to request */\r
+ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */\r
+ipcp_options ipcp_allowoptions[NUM_PPP];       /* Options we allow peer to request */\r
+ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */\r
+\r
+fsm ipcp_fsm[NUM_PPP];         /* IPCP fsm structure */\r
+\r
+struct protent ipcp_protent = {\r
+    PPP_IPCP,\r
+    ipcp_init,\r
+    ipcp_input,\r
+    ipcp_protrej,\r
+    ipcp_lowerup,\r
+    ipcp_lowerdown,\r
+    ipcp_open,\r
+    ipcp_close,\r
+#if 0\r
+    ipcp_printpkt,\r
+    NULL,\r
+#endif\r
+    1,\r
+    "IPCP",\r
+#if 0\r
+    ip_check_options,\r
+    NULL,\r
+    ip_active_pkt\r
+#endif\r
+};\r
+\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+/* local vars */\r
+static int cis_received[NUM_PPP];              /* # Conf-Reqs received */\r
+static int default_route_set[NUM_PPP]; /* Have set up a default route */\r
+\r
+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */\r
+    ipcp_resetci,              /* Reset our Configuration Information */\r
+    ipcp_cilen,                        /* Length of our Configuration Information */\r
+    ipcp_addci,                        /* Add our Configuration Information */\r
+    ipcp_ackci,                        /* ACK our Configuration Information */\r
+    ipcp_nakci,                        /* NAK our Configuration Information */\r
+    ipcp_rejci,                        /* Reject our Configuration Information */\r
+    ipcp_reqci,                        /* Request peer's Configuration Information */\r
+    ipcp_up,                   /* Called when fsm reaches OPENED state */\r
+    ipcp_down,                 /* Called when fsm leaves OPENED state */\r
+    NULL,                              /* Called when we want the lower layer up */\r
+    ipcp_finished,             /* Called when we want the lower layer down */\r
+    NULL,                              /* Called when Protocol-Reject received */\r
+    NULL,                              /* Retransmission is necessary */\r
+    NULL,                              /* Called to handle protocol-specific codes */\r
+    "IPCP"                             /* String name of protocol */\r
+};\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+\r
+/*\r
+ * Non-standard inet_ntoa left here for compat with original ppp\r
+ * sources. Assumes u32_t instead of struct in_addr.\r
+ */ \r
+\r
+char * _inet_ntoa(u32_t n)\r
+{\r
+       struct in_addr ia;\r
+       ia.s_addr = n;\r
+       return inet_ntoa(ia);\r
+}\r
+\r
+#define inet_ntoa _inet_ntoa\r
+\r
+/*\r
+ * ipcp_init - Initialize IPCP.\r
+ */\r
+static void ipcp_init(int unit)\r
+{\r
+       fsm *f = &ipcp_fsm[unit];\r
+       ipcp_options *wo = &ipcp_wantoptions[unit];\r
+       ipcp_options *ao = &ipcp_allowoptions[unit];\r
+       \r
+       f->unit = unit;\r
+       f->protocol = PPP_IPCP;\r
+       f->callbacks = &ipcp_callbacks;\r
+       fsm_init(&ipcp_fsm[unit]);\r
+       \r
+       memset(wo, 0, sizeof(*wo));\r
+       memset(ao, 0, sizeof(*ao));\r
+       \r
+       wo->neg_addr = 1;\r
+       wo->ouraddr = 0;\r
+#if VJ_SUPPORT > 0\r
+       wo->neg_vj = 1;\r
+#else\r
+       wo->neg_vj = 0;\r
+#endif\r
+       wo->vj_protocol = IPCP_VJ_COMP;\r
+       wo->maxslotindex = MAX_SLOTS - 1;\r
+       wo->cflag = 0;\r
+       \r
+       wo->default_route = 1;\r
+       \r
+       ao->neg_addr = 1;\r
+#if VJ_SUPPORT > 0\r
+       ao->neg_vj = 1;\r
+#else\r
+       ao->neg_vj = 0;\r
+#endif\r
+       ao->maxslotindex = MAX_SLOTS - 1;\r
+       ao->cflag = 1;\r
+       \r
+       ao->default_route = 1;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_open - IPCP is allowed to come up.\r
+ */\r
+static void ipcp_open(int unit)\r
+{\r
+       fsm_open(&ipcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_close - Take IPCP down.\r
+ */\r
+static void ipcp_close(int unit, char *reason)\r
+{\r
+       fsm_close(&ipcp_fsm[unit], reason);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_lowerup - The lower layer is up.\r
+ */\r
+static void ipcp_lowerup(int unit)\r
+{\r
+       fsm_lowerup(&ipcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_lowerdown - The lower layer is down.\r
+ */\r
+static void ipcp_lowerdown(int unit)\r
+{\r
+       fsm_lowerdown(&ipcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_input - Input IPCP packet.\r
+ */\r
+static void ipcp_input(int unit, u_char *p, int len)\r
+{\r
+       fsm_input(&ipcp_fsm[unit], p, len);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_protrej - A Protocol-Reject was received for IPCP.\r
+ *\r
+ * Pretend the lower layer went down, so we shut up.\r
+ */\r
+static void ipcp_protrej(int unit)\r
+{\r
+       fsm_lowerdown(&ipcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_resetci - Reset our CI.\r
+ */\r
+static void ipcp_resetci(fsm *f)\r
+{\r
+       ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
+       \r
+       wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;\r
+       if (wo->ouraddr == 0)\r
+               wo->accept_local = 1;\r
+       if (wo->hisaddr == 0)\r
+               wo->accept_remote = 1;\r
+       /* Request DNS addresses from the peer */\r
+       wo->req_dns1 = ppp_settings.usepeerdns;\r
+       wo->req_dns2 = ppp_settings.usepeerdns;\r
+       ipcp_gotoptions[f->unit] = *wo;\r
+       cis_received[f->unit] = 0;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_cilen - Return length of our CI.\r
+ */\r
+static int ipcp_cilen(fsm *f)\r
+{\r
+       ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+       ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
+       ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
+       \r
+#define LENCIVJ(neg, old)      (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)\r
+#define LENCIADDR(neg, old)    (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)\r
+#define LENCIDNS(neg)          (neg ? (CILEN_ADDR) : 0)\r
+       \r
+       /*\r
+        * First see if we want to change our options to the old\r
+        * forms because we have received old forms from the peer.\r
+        */\r
+       if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {\r
+               /* use the old style of address negotiation */\r
+               go->neg_addr = 1;\r
+               go->old_addrs = 1;\r
+       }\r
+       if (wo->neg_vj && !go->neg_vj && !go->old_vj) {\r
+               /* try an older style of VJ negotiation */\r
+               if (cis_received[f->unit] == 0) {\r
+                       /* keep trying the new style until we see some CI from the peer */\r
+                       go->neg_vj = 1;\r
+               } else {\r
+                       /* use the old style only if the peer did */\r
+                       if (ho->neg_vj && ho->old_vj) {\r
+                               go->neg_vj = 1;\r
+                               go->old_vj = 1;\r
+                               go->vj_protocol = ho->vj_protocol;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       return (LENCIADDR(go->neg_addr, go->old_addrs)\r
+                       + LENCIVJ(go->neg_vj, go->old_vj) +\r
+                       LENCIDNS(go->req_dns1) +\r
+                       LENCIDNS(go->req_dns2));\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_addci - Add our desired CIs to a packet.\r
+ */\r
+static void ipcp_addci(fsm *f, u_char *ucp, int *lenp)\r
+{\r
+       ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+       int len = *lenp;\r
+       \r
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \\r
+       if (neg) { \\r
+               int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \\r
+               if (len >= vjlen) { \\r
+                       PUTCHAR(opt, ucp); \\r
+                       PUTCHAR(vjlen, ucp); \\r
+                       PUTSHORT(val, ucp); \\r
+                       if (!old) { \\r
+                               PUTCHAR(maxslotindex, ucp); \\r
+                               PUTCHAR(cflag, ucp); \\r
+                       } \\r
+                       len -= vjlen; \\r
+               } else \\r
+                       neg = 0; \\r
+       }\r
+       \r
+#define ADDCIADDR(opt, neg, old, val1, val2) \\r
+       if (neg) { \\r
+               int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \\r
+               if (len >= addrlen) { \\r
+                       u32_t l; \\r
+                       PUTCHAR(opt, ucp); \\r
+                       PUTCHAR(addrlen, ucp); \\r
+                       l = ntohl(val1); \\r
+                       PUTLONG(l, ucp); \\r
+                       if (old) { \\r
+                               l = ntohl(val2); \\r
+                               PUTLONG(l, ucp); \\r
+                       } \\r
+                       len -= addrlen; \\r
+               } else \\r
+                       neg = 0; \\r
+       }\r
+\r
+#define ADDCIDNS(opt, neg, addr) \\r
+       if (neg) { \\r
+               if (len >= CILEN_ADDR) { \\r
+                       u32_t l; \\r
+                       PUTCHAR(opt, ucp); \\r
+                       PUTCHAR(CILEN_ADDR, ucp); \\r
+                       l = ntohl(addr); \\r
+                       PUTLONG(l, ucp); \\r
+                       len -= CILEN_ADDR; \\r
+               } else \\r
+                       neg = 0; \\r
+       }\r
+       \r
+       ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,\r
+                         go->old_addrs, go->ouraddr, go->hisaddr);\r
+       \r
+       ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,\r
+                       go->maxslotindex, go->cflag);\r
+       \r
+       ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);\r
+\r
+       ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);\r
+\r
+       *lenp -= len;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_ackci - Ack our CIs.\r
+ *\r
+ * Returns:\r
+ *     0 - Ack was bad.\r
+ *     1 - Ack was good.\r
+ */\r
+static int ipcp_ackci(fsm *f, u_char *p, int len)\r
+{\r
+       ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+       u_short cilen, citype, cishort;\r
+       u32_t cilong;\r
+       u_char cimaxslotindex, cicflag;\r
+       \r
+       /*\r
+        * CIs must be in exactly the same order that we sent...\r
+        * Check packet length and CI length at each step.\r
+        * If we find any deviations, then this packet is bad.\r
+        */\r
+       \r
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \\r
+       if (neg) { \\r
+               int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \\r
+               if ((len -= vjlen) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != vjlen || \\r
+                               citype != opt)  \\r
+                       goto bad; \\r
+               GETSHORT(cishort, p); \\r
+               if (cishort != val) \\r
+                       goto bad; \\r
+               if (!old) { \\r
+                       GETCHAR(cimaxslotindex, p); \\r
+                       if (cimaxslotindex != maxslotindex) \\r
+                               goto bad; \\r
+                       GETCHAR(cicflag, p); \\r
+                       if (cicflag != cflag) \\r
+                               goto bad; \\r
+               } \\r
+       }\r
+       \r
+#define ACKCIADDR(opt, neg, old, val1, val2) \\r
+       if (neg) { \\r
+               int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \\r
+               u32_t l; \\r
+               if ((len -= addrlen) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != addrlen || \\r
+                               citype != opt) \\r
+                       goto bad; \\r
+               GETLONG(l, p); \\r
+               cilong = htonl(l); \\r
+               if (val1 != cilong) \\r
+                       goto bad; \\r
+               if (old) { \\r
+                       GETLONG(l, p); \\r
+                       cilong = htonl(l); \\r
+                       if (val2 != cilong) \\r
+                               goto bad; \\r
+               } \\r
+       }\r
+\r
+#define ACKCIDNS(opt, neg, addr) \\r
+       if (neg) { \\r
+               u32_t l; \\r
+               if ((len -= CILEN_ADDR) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != CILEN_ADDR || \\r
+                               citype != opt) \\r
+                       goto bad; \\r
+               GETLONG(l, p); \\r
+               cilong = htonl(l); \\r
+               if (addr != cilong) \\r
+                       goto bad; \\r
+       }\r
+       \r
+       ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,\r
+                         go->old_addrs, go->ouraddr, go->hisaddr);\r
+       \r
+       ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,\r
+                       go->maxslotindex, go->cflag);\r
+       \r
+       ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);\r
+\r
+       ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);\r
+\r
+       /*\r
+        * If there are any remaining CIs, then this packet is bad.\r
+        */\r
+       if (len != 0)\r
+               goto bad;\r
+       return (1);\r
+       \r
+bad:\r
+       IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!\n"));\r
+       return (0);\r
+}\r
+\r
+/*\r
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.\r
+ * This should not modify any state if the Nak is bad\r
+ * or if IPCP is in the OPENED state.\r
+ *\r
+ * Returns:\r
+ *     0 - Nak was bad.\r
+ *     1 - Nak was good.\r
+ */\r
+static int ipcp_nakci(fsm *f, u_char *p, int len)\r
+{\r
+       ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+       u_char cimaxslotindex, cicflag;\r
+       u_char citype, cilen, *next;\r
+       u_short cishort;\r
+       u32_t ciaddr1, ciaddr2, l, cidnsaddr;\r
+       ipcp_options no;                /* options we've seen Naks for */\r
+       ipcp_options try;               /* options to request next time */\r
+       \r
+       BZERO(&no, sizeof(no));\r
+       try = *go;\r
+       \r
+       /*\r
+        * Any Nak'd CIs must be in exactly the same order that we sent.\r
+        * Check packet length and CI length at each step.\r
+        * If we find any deviations, then this packet is bad.\r
+        */\r
+#define NAKCIADDR(opt, neg, old, code) \\r
+       if (go->neg && \\r
+                       len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \\r
+                       p[1] == cilen && \\r
+                       p[0] == opt) { \\r
+               len -= cilen; \\r
+               INCPTR(2, p); \\r
+               GETLONG(l, p); \\r
+               ciaddr1 = htonl(l); \\r
+               if (old) { \\r
+                       GETLONG(l, p); \\r
+                       ciaddr2 = htonl(l); \\r
+                       no.old_addrs = 1; \\r
+               } else \\r
+                       ciaddr2 = 0; \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+       \r
+#define NAKCIVJ(opt, neg, code) \\r
+       if (go->neg && \\r
+                       ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \\r
+                       len >= cilen && \\r
+                       p[0] == opt) { \\r
+               len -= cilen; \\r
+               INCPTR(2, p); \\r
+               GETSHORT(cishort, p); \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+       \r
+#define NAKCIDNS(opt, neg, code) \\r
+       if (go->neg && \\r
+                       ((cilen = p[1]) == CILEN_ADDR) && \\r
+                       len >= cilen && \\r
+                       p[0] == opt) { \\r
+               len -= cilen; \\r
+               INCPTR(2, p); \\r
+               GETLONG(l, p); \\r
+               cidnsaddr = htonl(l); \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+       \r
+       /*\r
+        * Accept the peer's idea of {our,his} address, if different\r
+        * from our idea, only if the accept_{local,remote} flag is set.\r
+        */\r
+       NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,\r
+         if (go->accept_local && ciaddr1) { /* Do we know our address? */\r
+                 try.ouraddr = ciaddr1;\r
+                 IPCPDEBUG((LOG_INFO, "local IP address %s\n",\r
+                            inet_ntoa(ciaddr1)));\r
+         }\r
+         if (go->accept_remote && ciaddr2) { /* Does he know his? */\r
+                 try.hisaddr = ciaddr2;\r
+                 IPCPDEBUG((LOG_INFO, "remote IP address %s\n",\r
+                            inet_ntoa(ciaddr2)));\r
+         }\r
+       );\r
+       \r
+       /*\r
+        * Accept the peer's value of maxslotindex provided that it\r
+        * is less than what we asked for.  Turn off slot-ID compression\r
+        * if the peer wants.  Send old-style compress-type option if\r
+        * the peer wants.\r
+        */\r
+       NAKCIVJ(CI_COMPRESSTYPE, neg_vj,\r
+               if (cilen == CILEN_VJ) {\r
+                       GETCHAR(cimaxslotindex, p);\r
+                       GETCHAR(cicflag, p);\r
+                       if (cishort == IPCP_VJ_COMP) {\r
+                               try.old_vj = 0;\r
+                               if (cimaxslotindex < go->maxslotindex)\r
+                                       try.maxslotindex = cimaxslotindex;\r
+                               if (!cicflag)\r
+                                       try.cflag = 0;\r
+                       } else {\r
+                               try.neg_vj = 0;\r
+                       }\r
+               } else {\r
+                       if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {\r
+                               try.old_vj = 1;\r
+                               try.vj_protocol = cishort;\r
+                       } else {\r
+                               try.neg_vj = 0;\r
+                       }\r
+               }\r
+       );\r
+       \r
+       NAKCIDNS(CI_MS_DNS1, req_dns1,\r
+                       try.dnsaddr[0] = cidnsaddr;\r
+                       IPCPDEBUG((LOG_INFO, "primary DNS address %s\n", inet_ntoa(cidnsaddr)));\r
+                       );\r
+\r
+       NAKCIDNS(CI_MS_DNS2, req_dns2,\r
+                       try.dnsaddr[1] = cidnsaddr;\r
+                       IPCPDEBUG((LOG_INFO, "secondary DNS address %s\n", inet_ntoa(cidnsaddr)));\r
+                       );\r
+\r
+       /*\r
+       * There may be remaining CIs, if the peer is requesting negotiation\r
+       * on an option that we didn't include in our request packet.\r
+       * If they want to negotiate about IP addresses, we comply.\r
+       * If they want us to ask for compression, we refuse.\r
+       */\r
+       while (len > CILEN_VOID) {\r
+               GETCHAR(citype, p);\r
+               GETCHAR(cilen, p);\r
+               if( (len -= cilen) < 0 )\r
+                       goto bad;\r
+               next = p + cilen - 2;\r
+               \r
+               switch (citype) {\r
+               case CI_COMPRESSTYPE:\r
+                       if (go->neg_vj || no.neg_vj ||\r
+                                       (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))\r
+                               goto bad;\r
+                       no.neg_vj = 1;\r
+                       break;\r
+               case CI_ADDRS:\r
+                       if ((go->neg_addr && go->old_addrs) || no.old_addrs\r
+                                       || cilen != CILEN_ADDRS)\r
+                               goto bad;\r
+                       try.neg_addr = 1;\r
+                       try.old_addrs = 1;\r
+                       GETLONG(l, p);\r
+                       ciaddr1 = htonl(l);\r
+                       if (ciaddr1 && go->accept_local)\r
+                               try.ouraddr = ciaddr1;\r
+                       GETLONG(l, p);\r
+                       ciaddr2 = htonl(l);\r
+                       if (ciaddr2 && go->accept_remote)\r
+                               try.hisaddr = ciaddr2;\r
+                       no.old_addrs = 1;\r
+                       break;\r
+               case CI_ADDR:\r
+                       if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)\r
+                               goto bad;\r
+                       try.old_addrs = 0;\r
+                       GETLONG(l, p);\r
+                       ciaddr1 = htonl(l);\r
+                       if (ciaddr1 && go->accept_local)\r
+                               try.ouraddr = ciaddr1;\r
+                       if (try.ouraddr != 0)\r
+                               try.neg_addr = 1;\r
+                       no.neg_addr = 1;\r
+                       break;\r
+               }\r
+               p = next;\r
+       }\r
+       \r
+       /* If there is still anything left, this packet is bad. */\r
+       if (len != 0)\r
+               goto bad;\r
+       \r
+       /*\r
+        * OK, the Nak is good.  Now we can update state.\r
+        */\r
+       if (f->state != OPENED)\r
+               *go = try;\r
+       \r
+       return 1;\r
+       \r
+bad:\r
+       IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!\n"));\r
+       return 0;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_rejci - Reject some of our CIs.\r
+ */\r
+static int ipcp_rejci(fsm *f, u_char *p, int len)\r
+{\r
+       ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+       u_char cimaxslotindex, ciflag, cilen;\r
+       u_short cishort;\r
+       u32_t cilong;\r
+       ipcp_options try;               /* options to request next time */\r
+       \r
+       try = *go;\r
+       /*\r
+        * Any Rejected CIs must be in exactly the same order that we sent.\r
+        * Check packet length and CI length at each step.\r
+        * If we find any deviations, then this packet is bad.\r
+        */\r
+#define REJCIADDR(opt, neg, old, val1, val2) \\r
+       if (go->neg && \\r
+                       len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \\r
+                       p[1] == cilen && \\r
+                       p[0] == opt) { \\r
+               u32_t l; \\r
+               len -= cilen; \\r
+               INCPTR(2, p); \\r
+               GETLONG(l, p); \\r
+               cilong = htonl(l); \\r
+               /* Check rejected value. */ \\r
+               if (cilong != val1) \\r
+                       goto bad; \\r
+               if (old) { \\r
+                       GETLONG(l, p); \\r
+                       cilong = htonl(l); \\r
+                       /* Check rejected value. */ \\r
+                       if (cilong != val2) \\r
+                               goto bad; \\r
+               } \\r
+               try.neg = 0; \\r
+       }\r
+       \r
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \\r
+       if (go->neg && \\r
+                       p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \\r
+                       len >= p[1] && \\r
+                       p[0] == opt) { \\r
+               len -= p[1]; \\r
+               INCPTR(2, p); \\r
+               GETSHORT(cishort, p); \\r
+               /* Check rejected value. */  \\r
+               if (cishort != val) \\r
+                       goto bad; \\r
+               if (!old) { \\r
+                       GETCHAR(cimaxslotindex, p); \\r
+                       if (cimaxslotindex != maxslot) \\r
+                               goto bad; \\r
+                       GETCHAR(ciflag, p); \\r
+                       if (ciflag != cflag) \\r
+                               goto bad; \\r
+               } \\r
+               try.neg = 0; \\r
+       }\r
+       \r
+#define REJCIDNS(opt, neg, dnsaddr) \\r
+       if (go->neg && \\r
+                       ((cilen = p[1]) == CILEN_ADDR) && \\r
+                       len >= cilen && \\r
+                       p[0] == opt) { \\r
+               u32_t l; \\r
+               len -= cilen; \\r
+               INCPTR(2, p); \\r
+               GETLONG(l, p); \\r
+               cilong = htonl(l); \\r
+               /* Check rejected value. */ \\r
+               if (cilong != dnsaddr) \\r
+                       goto bad; \\r
+               try.neg = 0; \\r
+       }\r
+\r
+       REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,\r
+                         go->old_addrs, go->ouraddr, go->hisaddr);\r
+       \r
+       REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,\r
+                       go->maxslotindex, go->cflag);\r
+       \r
+       REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);\r
+\r
+       REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);\r
+\r
+       /*\r
+        * If there are any remaining CIs, then this packet is bad.\r
+        */\r
+       if (len != 0)\r
+               goto bad;\r
+       /*\r
+        * Now we can update state.\r
+        */\r
+       if (f->state != OPENED)\r
+               *go = try;\r
+       return 1;\r
+       \r
+bad:\r
+       IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!\n"));\r
+       return 0;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.\r
+ *\r
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified\r
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return\r
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.\r
+ */\r
+static int ipcp_reqci(\r
+       fsm *f,\r
+       u_char *inp,            /* Requested CIs */\r
+       int *len,                       /* Length of requested CIs */\r
+       int reject_if_disagree\r
+)\r
+{\r
+       ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
+       ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
+       ipcp_options *ao = &ipcp_allowoptions[f->unit];\r
+#ifdef OLD_CI_ADDRS\r
+       ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+#endif\r
+       u_char *cip, *next;                             /* Pointer to current and next CIs */\r
+       u_short cilen, citype;                  /* Parsed len, type */\r
+       u_short cishort;                                /* Parsed short value */\r
+       u32_t tl, ciaddr1;                      /* Parsed address values */\r
+#ifdef OLD_CI_ADDRS\r
+       u32_t ciaddr2;                          /* Parsed address values */\r
+#endif\r
+       int rc = CONFACK;                               /* Final packet return code */\r
+       int orc;                                                /* Individual option return code */\r
+       u_char *p;                                              /* Pointer to next char to parse */\r
+       u_char *ucp = inp;                              /* Pointer to current output char */\r
+       int l = *len;                                   /* Length left */\r
+       u_char maxslotindex, cflag;\r
+       int d;\r
+       \r
+       cis_received[f->unit] = 1;\r
+       \r
+       /*\r
+        * Reset all his options.\r
+        */\r
+       BZERO(ho, sizeof(*ho));\r
+       \r
+       /*\r
+        * Process all his options.\r
+        */\r
+       next = inp;\r
+       while (l) {\r
+               orc = CONFACK;                          /* Assume success */\r
+               cip = p = next;                         /* Remember begining of CI */\r
+               if (l < 2 ||                            /* Not enough data for CI header or */\r
+                               p[1] < 2 ||                     /*  CI length too small or */\r
+                               p[1] > l) {                     /*  CI length too big? */\r
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!\n"));\r
+                       orc = CONFREJ;                  /* Reject bad CI */\r
+                       cilen = l;                              /* Reject till end of packet */\r
+                       l = 0;                                  /* Don't loop again */\r
+                       goto endswitch;\r
+               }\r
+               GETCHAR(citype, p);                     /* Parse CI type */\r
+               GETCHAR(cilen, p);                      /* Parse CI length */\r
+               l -= cilen;                                     /* Adjust remaining length */\r
+               next += cilen;                          /* Step to next CI */\r
+\r
+               switch (citype) {                       /* Check CI type */\r
+#ifdef OLD_CI_ADDRS /* Need to save space... */\r
+               case CI_ADDRS:\r
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS\n"));\r
+                       if (!ao->neg_addr ||\r
+                                       cilen != CILEN_ADDRS) { /* Check CI length */\r
+                               orc = CONFREJ;          /* Reject CI */\r
+                               break;\r
+                       }\r
+                       \r
+                       /*\r
+                        * If he has no address, or if we both have his address but\r
+                        * disagree about it, then NAK it with our idea.\r
+                        * In particular, if we don't know his address, but he does,\r
+                        * then accept it.\r
+                        */\r
+                       GETLONG(tl, p);         /* Parse source address (his) */\r
+                       ciaddr1 = htonl(tl);\r
+                       IPCPDEBUG((LOG_INFO, "his addr %s\n", inet_ntoa(ciaddr1)));\r
+                       if (ciaddr1 != wo->hisaddr\r
+                                       && (ciaddr1 == 0 || !wo->accept_remote)) {\r
+                               orc = CONFNAK;\r
+                               if (!reject_if_disagree) {\r
+                                       DECPTR(sizeof(u32_t), p);\r
+                                       tl = ntohl(wo->hisaddr);\r
+                                       PUTLONG(tl, p);\r
+                               }\r
+                       } else if (ciaddr1 == 0 && wo->hisaddr == 0) {\r
+                               /*\r
+                                * If neither we nor he knows his address, reject the option.\r
+                                */\r
+                               orc = CONFREJ;\r
+                               wo->req_addr = 0;       /* don't NAK with 0.0.0.0 later */\r
+                               break;\r
+                       }\r
+                       \r
+                       /*\r
+                        * If he doesn't know our address, or if we both have our address\r
+                        * but disagree about it, then NAK it with our idea.\r
+                        */\r
+                       GETLONG(tl, p);         /* Parse desination address (ours) */\r
+                       ciaddr2 = htonl(tl);\r
+                       IPCPDEBUG((LOG_INFO, "our addr %s\n", inet_ntoa(ciaddr2)));\r
+                       if (ciaddr2 != wo->ouraddr) {\r
+                               if (ciaddr2 == 0 || !wo->accept_local) {\r
+                                       orc = CONFNAK;\r
+                                       if (!reject_if_disagree) {\r
+                                               DECPTR(sizeof(u32_t), p);\r
+                                               tl = ntohl(wo->ouraddr);\r
+                                               PUTLONG(tl, p);\r
+                                       }\r
+                               } else {\r
+                                       go->ouraddr = ciaddr2;  /* accept peer's idea */\r
+                               }\r
+                       }\r
+                       \r
+                       ho->neg_addr = 1;\r
+                       ho->old_addrs = 1;\r
+                       ho->hisaddr = ciaddr1;\r
+                       ho->ouraddr = ciaddr2;\r
+                       break;\r
+#endif\r
+               \r
+               case CI_ADDR:\r
+                       if (!ao->neg_addr) {\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR not allowed\n"));\r
+                               orc = CONFREJ;                          /* Reject CI */\r
+                               break;\r
+                       } else if (cilen != CILEN_ADDR) {       /* Check CI length */\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR bad len\n"));\r
+                               orc = CONFREJ;                          /* Reject CI */\r
+                               break;\r
+                       }\r
+                       \r
+                       /*\r
+                        * If he has no address, or if we both have his address but\r
+                        * disagree about it, then NAK it with our idea.\r
+                        * In particular, if we don't know his address, but he does,\r
+                        * then accept it.\r
+                        */\r
+                       GETLONG(tl, p); /* Parse source address (his) */\r
+                       ciaddr1 = htonl(tl);\r
+                       if (ciaddr1 != wo->hisaddr\r
+                                       && (ciaddr1 == 0 || !wo->accept_remote)) {\r
+                               orc = CONFNAK;\r
+                               if (!reject_if_disagree) {\r
+                                       DECPTR(sizeof(u32_t), p);\r
+                                       tl = ntohl(wo->hisaddr);\r
+                                       PUTLONG(tl, p);\r
+                               }\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1)));\r
+                       } else if (ciaddr1 == 0 && wo->hisaddr == 0) {\r
+                               /*\r
+                                * Don't ACK an address of 0.0.0.0 - reject it instead.\r
+                                */\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1)));\r
+                               orc = CONFREJ;\r
+                               wo->req_addr = 0;       /* don't NAK with 0.0.0.0 later */\r
+                               break;\r
+                       }\r
+                       \r
+                       ho->neg_addr = 1;\r
+                       ho->hisaddr = ciaddr1;\r
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1)));\r
+                       break;\r
+               \r
+               case CI_MS_DNS1:\r
+               case CI_MS_DNS2:\r
+                       /* Microsoft primary or secondary DNS request */\r
+                       d = citype == CI_MS_DNS2;\r
+                       \r
+                       /* If we do not have a DNS address then we cannot send it */\r
+                       if (ao->dnsaddr[d] == 0 ||\r
+                                       cilen != CILEN_ADDR) {  /* Check CI length */\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting DNS%d Request\n", d+1));\r
+                               orc = CONFREJ;                          /* Reject CI */\r
+                               break;\r
+                       }\r
+                       GETLONG(tl, p);\r
+                       if (htonl(tl) != ao->dnsaddr[d]) {\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking DNS%d Request %d\n",\r
+                                                       d+1, inet_ntoa(tl)));\r
+                               DECPTR(sizeof(u32_t), p);\r
+                               tl = ntohl(ao->dnsaddr[d]);\r
+                               PUTLONG(tl, p);\r
+                               orc = CONFNAK;\r
+                       }\r
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: received DNS%d Request\n", d+1));\r
+                       break;\r
+               \r
+               case CI_MS_WINS1:\r
+               case CI_MS_WINS2:\r
+                       /* Microsoft primary or secondary WINS request */\r
+                       d = citype == CI_MS_WINS2;\r
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: received WINS%d Request\n", d+1));\r
+                       \r
+                       /* If we do not have a DNS address then we cannot send it */\r
+                       if (ao->winsaddr[d] == 0 ||\r
+                               cilen != CILEN_ADDR) {  /* Check CI length */\r
+                               orc = CONFREJ;                  /* Reject CI */\r
+                               break;\r
+                       }\r
+                       GETLONG(tl, p);\r
+                       if (htonl(tl) != ao->winsaddr[d]) {\r
+                               DECPTR(sizeof(u32_t), p);\r
+                               tl = ntohl(ao->winsaddr[d]);\r
+                               PUTLONG(tl, p);\r
+                               orc = CONFNAK;\r
+                       }\r
+                       break;\r
+               \r
+               case CI_COMPRESSTYPE:\r
+                       if (!ao->neg_vj) {\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n"));\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) {\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen));\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       }\r
+                       GETSHORT(cishort, p);\r
+                       \r
+                       if (!(cishort == IPCP_VJ_COMP ||\r
+                                       (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort));\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       }\r
+                       \r
+                       ho->neg_vj = 1;\r
+                       ho->vj_protocol = cishort;\r
+                       if (cilen == CILEN_VJ) {\r
+                               GETCHAR(maxslotindex, p);\r
+                               if (maxslotindex > ao->maxslotindex) { \r
+                                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ max slot %d\n", maxslotindex));\r
+                                       orc = CONFNAK;\r
+                                       if (!reject_if_disagree){\r
+                                               DECPTR(1, p);\r
+                                               PUTCHAR(ao->maxslotindex, p);\r
+                                       }\r
+                               }\r
+                               GETCHAR(cflag, p);\r
+                               if (cflag && !ao->cflag) {\r
+                                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ cflag %d\n", cflag));\r
+                                       orc = CONFNAK;\r
+                                       if (!reject_if_disagree){\r
+                                               DECPTR(1, p);\r
+                                               PUTCHAR(wo->cflag, p);\r
+                                       }\r
+                               }\r
+                               ho->maxslotindex = maxslotindex;\r
+                               ho->cflag = cflag;\r
+                       } else {\r
+                               ho->old_vj = 1;\r
+                               ho->maxslotindex = MAX_SLOTS - 1;\r
+                               ho->cflag = 1;\r
+                       }\r
+                       IPCPDEBUG((LOG_INFO, \r
+                                               "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n",\r
+                                               ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag));\r
+                       break;\r
+                       \r
+               default:\r
+                       IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting unknown CI type %d\n", citype));\r
+                       orc = CONFREJ;\r
+                       break;\r
+               }\r
+               \r
+endswitch:\r
+               if (orc == CONFACK &&           /* Good CI */\r
+                               rc != CONFACK)          /*  but prior CI wasnt? */\r
+                       continue;                               /* Don't send this one */\r
+               \r
+               if (orc == CONFNAK) {           /* Nak this CI? */\r
+                       if (reject_if_disagree) {       /* Getting fed up with sending NAKs? */\r
+                               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting too many naks\n"));\r
+                               orc = CONFREJ;          /* Get tough if so */\r
+                       } else {\r
+                               if (rc == CONFREJ)      /* Rejecting prior CI? */\r
+                                       continue;               /* Don't send this one */\r
+                               if (rc == CONFACK) {    /* Ack'd all prior CIs? */\r
+                                       rc = CONFNAK;   /* Not anymore... */\r
+                                       ucp = inp;              /* Backup */\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               if (orc == CONFREJ &&           /* Reject this CI */\r
+                               rc != CONFREJ) {        /*  but no prior ones? */\r
+                       rc = CONFREJ;\r
+                       ucp = inp;                              /* Backup */\r
+               }\r
+               \r
+               /* Need to move CI? */\r
+               if (ucp != cip)\r
+                       BCOPY(cip, ucp, cilen); /* Move it */\r
+               \r
+               /* Update output pointer */\r
+               INCPTR(cilen, ucp);\r
+       }\r
+       \r
+       /*\r
+        * If we aren't rejecting this packet, and we want to negotiate\r
+        * their address, and they didn't send their address, then we\r
+        * send a NAK with a CI_ADDR option appended.  We assume the\r
+        * input buffer is long enough that we can append the extra\r
+        * option safely.\r
+        */\r
+       if (rc != CONFREJ && !ho->neg_addr &&\r
+                       wo->req_addr && !reject_if_disagree) {\r
+               IPCPDEBUG((LOG_INFO, "ipcp_reqci: Requesting peer address\n"));\r
+               if (rc == CONFACK) {\r
+                       rc = CONFNAK;\r
+                       ucp = inp;                              /* reset pointer */\r
+                       wo->req_addr = 0;               /* don't ask again */\r
+               }\r
+               PUTCHAR(CI_ADDR, ucp);\r
+               PUTCHAR(CILEN_ADDR, ucp);\r
+               tl = ntohl(wo->hisaddr);\r
+               PUTLONG(tl, ucp);\r
+       }\r
+       \r
+       *len = (int)(ucp - inp);                /* Compute output length */\r
+       IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning Configure-%s\n", CODENAME(rc)));\r
+       return (rc);                    /* Return final code */\r
+}\r
+\r
+\r
+#if 0\r
+/*\r
+ * ip_check_options - check that any IP-related options are OK,\r
+ * and assign appropriate defaults.\r
+ */\r
+static void ip_check_options(u_long localAddr)\r
+{\r
+       ipcp_options *wo = &ipcp_wantoptions[0];\r
+\r
+       /*\r
+        * Load our default IP address but allow the remote host to give us\r
+        * a new address.\r
+        */\r
+       if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) {\r
+               wo->accept_local = 1;   /* don't insist on this default value */\r
+               wo->ouraddr = htonl(localAddr);\r
+       }\r
+}\r
+#endif\r
+\r
+\r
+/*\r
+ * ipcp_up - IPCP has come UP.\r
+ *\r
+ * Configure the IP network interface appropriately and bring it up.\r
+ */\r
+static void ipcp_up(fsm *f)\r
+{\r
+       u32_t mask;\r
+       ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
+       ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+       ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
+       \r
+       np_up(f->unit, PPP_IP);\r
+       IPCPDEBUG((LOG_INFO, "ipcp: up\n"));\r
+       \r
+       /*\r
+        * We must have a non-zero IP address for both ends of the link.\r
+        */\r
+       if (!ho->neg_addr)\r
+               ho->hisaddr = wo->hisaddr;\r
+       \r
+       if (ho->hisaddr == 0) {\r
+               IPCPDEBUG((LOG_ERR, "Could not determine remote IP address\n"));\r
+               ipcp_close(f->unit, "Could not determine remote IP address");\r
+               return;\r
+       }\r
+       if (go->ouraddr == 0) {\r
+               IPCPDEBUG((LOG_ERR, "Could not determine local IP address\n"));\r
+               ipcp_close(f->unit, "Could not determine local IP address");\r
+               return;\r
+       }\r
+       \r
+       if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {\r
+               /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/\r
+       }\r
+\r
+       /*\r
+        * Check that the peer is allowed to use the IP address it wants.\r
+        */\r
+       if (!auth_ip_addr(f->unit, ho->hisaddr)) {\r
+               IPCPDEBUG((LOG_ERR, "Peer is not authorized to use remote address %s\n",\r
+                               inet_ntoa(ho->hisaddr)));\r
+               ipcp_close(f->unit, "Unauthorized remote IP address");\r
+               return;\r
+       }\r
+       \r
+       /* set tcp compression */\r
+       sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);\r
+       \r
+       /*\r
+        * Set IP addresses and (if specified) netmask.\r
+        */\r
+       mask = GetMask(go->ouraddr);\r
+       \r
+       if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {\r
+               IPCPDEBUG((LOG_WARNING, "sifaddr failed\n"));\r
+               ipcp_close(f->unit, "Interface configuration failed");\r
+               return;\r
+       }\r
+       \r
+       /* bring the interface up for IP */\r
+       if (!sifup(f->unit)) {\r
+               IPCPDEBUG((LOG_WARNING, "sifup failed\n"));\r
+               ipcp_close(f->unit, "Interface configuration failed");\r
+               return;\r
+       }\r
+       \r
+       sifnpmode(f->unit, PPP_IP, NPMODE_PASS);\r
+       \r
+       /* assign a default route through the interface if required */\r
+       if (ipcp_wantoptions[f->unit].default_route) \r
+               if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))\r
+                       default_route_set[f->unit] = 1;\r
+       \r
+       IPCPDEBUG((LOG_NOTICE, "local  IP address %s\n", inet_ntoa(go->ouraddr)));\r
+       IPCPDEBUG((LOG_NOTICE, "remote IP address %s\n", inet_ntoa(ho->hisaddr)));\r
+       if (go->dnsaddr[0]) {\r
+               IPCPDEBUG((LOG_NOTICE, "primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0])));\r
+       }\r
+       if (go->dnsaddr[1]) {\r
+               IPCPDEBUG((LOG_NOTICE, "secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_down - IPCP has gone DOWN.\r
+ *\r
+ * Take the IP network interface down, clear its addresses\r
+ * and delete routes through it.\r
+ */\r
+static void ipcp_down(fsm *f)\r
+{\r
+       IPCPDEBUG((LOG_INFO, "ipcp: down\n"));\r
+       np_down(f->unit, PPP_IP);\r
+       sifvjcomp(f->unit, 0, 0, 0);\r
+       \r
+       sifdown(f->unit);\r
+       ipcp_clear_addrs(f->unit);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_clear_addrs() - clear the interface addresses, routes, etc.\r
+ */\r
+static void ipcp_clear_addrs(int unit)\r
+{\r
+       u32_t ouraddr, hisaddr;\r
+       \r
+       ouraddr = ipcp_gotoptions[unit].ouraddr;\r
+       hisaddr = ipcp_hisoptions[unit].hisaddr;\r
+       if (default_route_set[unit]) {\r
+               cifdefaultroute(unit, ouraddr, hisaddr);\r
+               default_route_set[unit] = 0;\r
+       }\r
+       cifaddr(unit, ouraddr, hisaddr);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_finished - possibly shut down the lower layers.\r
+ */\r
+static void ipcp_finished(fsm *f)\r
+{\r
+       np_finished(f->unit, PPP_IP);\r
+}\r
+\r
+#if 0\r
+static int ipcp_printpkt(\r
+       u_char *p,\r
+       int plen,\r
+       void (*printer) (void *, char *, ...),\r
+       void *arg\r
+)\r
+{\r
+       (void)p;\r
+       (void)plen;\r
+       (void)printer;\r
+       (void)arg;\r
+       return 0;\r
+}\r
+\r
+/*\r
+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.\r
+ * We don't bring the link up for IP fragments or for TCP FIN packets\r
+ * with no data.\r
+ */\r
+#define IP_HDRLEN      20      /* bytes */\r
+#define IP_OFFMASK     0x1fff\r
+#define IPPROTO_TCP    6\r
+#define TCP_HDRLEN     20\r
+#define TH_FIN         0x01\r
+\r
+/*\r
+ * We use these macros because the IP header may be at an odd address,\r
+ * and some compilers might use word loads to get th_off or ip_hl.\r
+ */\r
+\r
+#define net_short(x)   (((x)[0] << 8) + (x)[1])\r
+#define get_iphl(x)    (((unsigned char *)(x))[0] & 0xF)\r
+#define get_ipoff(x)   net_short((unsigned char *)(x) + 6)\r
+#define get_ipproto(x) (((unsigned char *)(x))[9])\r
+#define get_tcpoff(x)  (((unsigned char *)(x))[12] >> 4)\r
+#define get_tcpflags(x)        (((unsigned char *)(x))[13])\r
+\r
+static int ip_active_pkt(u_char *pkt, int len)\r
+{\r
+       u_char *tcp;\r
+       int hlen;\r
+       \r
+       len -= PPP_HDRLEN;\r
+       pkt += PPP_HDRLEN;\r
+       if (len < IP_HDRLEN)\r
+               return 0;\r
+       if ((get_ipoff(pkt) & IP_OFFMASK) != 0)\r
+               return 0;\r
+       if (get_ipproto(pkt) != IPPROTO_TCP)\r
+               return 1;\r
+       hlen = get_iphl(pkt) * 4;\r
+       if (len < hlen + TCP_HDRLEN)\r
+               return 0;\r
+       tcp = pkt + hlen;\r
+       if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)\r
+               return 0;\r
+       return 1;\r
+}\r
+#endif\r
+\r
+#endif /* PPP_SUPPORT */\r
index 416aa79a2e1cd212d90fc8209c19b098de966038..28fc36ed8c20f3431babae0efad64c10b419d5b4 100644 (file)
-/*****************************************************************************
-* 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 */
-
+/*****************************************************************************\r
+* ipcp.h -  PPP IP NCP: Internet Protocol Network Control Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*      Original derived from BSD codes.\r
+*****************************************************************************/\r
+/*\r
+ * ipcp.h - IP Control Protocol definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: ipcp.h,v 1.1 2003/05/27 14:37:56 jani Exp $\r
+ */\r
+\r
+#ifndef IPCP_H\r
+#define IPCP_H\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+/*\r
+ * Options.\r
+ */\r
+#define CI_ADDRS       1                       /* IP Addresses */\r
+#define CI_COMPRESSTYPE        2               /* Compression Type */\r
+#define        CI_ADDR         3\r
+\r
+#define CI_MS_WINS1    128                     /* Primary WINS value */\r
+#define CI_MS_DNS1     129                     /* Primary DNS value */\r
+#define CI_MS_WINS2    130                     /* Secondary WINS value */\r
+#define CI_MS_DNS2     131                     /* Secondary DNS value */\r
+\r
+#define IPCP_VJMODE_OLD 1              /* "old" mode (option # = 0x0037) */\r
+#define IPCP_VJMODE_RFC1172 2  /* "old-rfc"mode (option # = 0x002d) */\r
+#define IPCP_VJMODE_RFC1332 3  /* "new-rfc"mode (option # = 0x002d, */\r
+                                /*  maxslot and slot number compression) */\r
+\r
+#define IPCP_VJ_COMP 0x002d            /* current value for VJ compression option*/\r
+#define IPCP_VJ_COMP_OLD 0x0037        /* "old" (i.e, broken) value for VJ */\r
+                                                               /* compression option*/ \r
+\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+typedef struct ipcp_options {\r
+    u_int neg_addr : 1;                        /* Negotiate IP Address? */\r
+    u_int old_addrs : 1;                       /* Use old (IP-Addresses) option? */\r
+    u_int req_addr : 1;                        /* Ask peer to send IP address? */\r
+    u_int default_route : 1;           /* Assign default route through interface? */\r
+    u_int proxy_arp : 1;                       /* Make proxy ARP entry for peer? */\r
+    u_int neg_vj : 1;                          /* Van Jacobson Compression? */\r
+    u_int old_vj : 1;                          /* use old (short) form of VJ option? */\r
+    u_int accept_local : 1;            /* accept peer's value for ouraddr */\r
+    u_int accept_remote : 1;           /* accept peer's value for hisaddr */\r
+    u_int req_dns1 : 1;                        /* Ask peer to send primary DNS address? */\r
+    u_int req_dns2 : 1;                        /* Ask peer to send secondary DNS address? */\r
+    u_short vj_protocol;               /* protocol value to use in VJ option */\r
+    u_char maxslotindex;               /* VJ slots - 1. */\r
+    u_char cflag;                              /* VJ slot compression flag. */\r
+    u32_t ouraddr, hisaddr;    /* Addresses in NETWORK BYTE ORDER */\r
+    u32_t dnsaddr[2];          /* Primary and secondary MS DNS entries */\r
+    u32_t winsaddr[2];         /* Primary and secondary MS WINS entries */\r
+} ipcp_options;\r
+\r
+\r
+/*****************************\r
+*** PUBLIC DATA STRUCTURES ***\r
+*****************************/\r
+\r
+extern fsm ipcp_fsm[];\r
+extern ipcp_options ipcp_wantoptions[];\r
+extern ipcp_options ipcp_gotoptions[];\r
+extern ipcp_options ipcp_allowoptions[];\r
+extern ipcp_options ipcp_hisoptions[];\r
+\r
+extern struct protent ipcp_protent;\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+\r
+#endif /* IPCP_H */\r
+\r
index 6a988d6df6e16784a3351984e34255b3aaa24e48..41dbc5dd21b9ad19177c1bd033334f0986fe349e 100644 (file)
-/*****************************************************************************
-* 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 */
+/*****************************************************************************\r
+* lcp.c - Network Link Control Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original.\r
+*****************************************************************************/\r
+\r
+/*\r
+ * lcp.c - PPP Link Control Protocol.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
\r
+#include <string.h>\r
\r
+#include "ppp.h"\r
+#if PPP_SUPPORT > 0\r
+#include "fsm.h"\r
+#include "chap.h"\r
+#include "magic.h"\r
+#include "auth.h"\r
+#include "lcp.h"\r
+#include "pppdebug.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+/*\r
+ * Length of each type of configuration option (in octets)\r
+ */\r
+#define CILEN_VOID     2\r
+#define CILEN_CHAR     3\r
+#define CILEN_SHORT    4       /* CILEN_VOID + sizeof(short) */\r
+#define CILEN_CHAP     5       /* CILEN_VOID + sizeof(short) + 1 */\r
+#define CILEN_LONG     6       /* CILEN_VOID + sizeof(long) */\r
+#define CILEN_LQR      8       /* CILEN_VOID + sizeof(short) + sizeof(long) */\r
+#define CILEN_CBCP     3\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+/*\r
+ * Callbacks for fsm code.  (CI = Configuration Information)\r
+ */\r
+static void lcp_resetci (fsm*);                /* Reset our CI */\r
+static int  lcp_cilen (fsm*);                  /* Return length of our CI */\r
+static void lcp_addci (fsm*, u_char*, int*);       /* Add our CI to pkt */\r
+static int  lcp_ackci (fsm*, u_char*, int);/* Peer ack'd our CI */\r
+static int  lcp_nakci (fsm*, u_char*, int);/* Peer nak'd our CI */\r
+static int  lcp_rejci (fsm*, u_char*, int);/* Peer rej'd our CI */\r
+static int  lcp_reqci (fsm*, u_char*, int*, int);  /* Rcv peer CI */\r
+static void lcp_up (fsm*);                         /* We're UP */\r
+static void lcp_down (fsm*);               /* We're DOWN */\r
+static void lcp_starting (fsm*);           /* We need lower layer up */\r
+static void lcp_finished (fsm*);               /* We need lower layer down */\r
+static int  lcp_extcode (fsm*, int, u_char, u_char*, int);\r
+\r
+static void lcp_rprotrej (fsm*, u_char*, int);\r
+\r
+/*\r
+ * routines to send LCP echos to peer\r
+ */\r
+static void lcp_echo_lowerup (int);\r
+static void lcp_echo_lowerdown (int);\r
+static void LcpEchoTimeout (void*);\r
+static void lcp_received_echo_reply (fsm*, int, u_char*, int);\r
+static void LcpSendEchoRequest (fsm*);\r
+static void LcpLinkFailure (fsm*);\r
+static void LcpEchoCheck (fsm*);\r
+\r
+/*\r
+ * Protocol entry points.\r
+ * Some of these are called directly.\r
+ */\r
+static void lcp_input (int, u_char *, int);\r
+static void lcp_protrej (int);\r
+\r
+#define CODENAME(x)    ((x) == CONFACK ? "ACK" : \\r
+                        (x) == CONFNAK ? "NAK" : "REJ")\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+/* global vars */\r
+LinkPhase lcp_phase[NUM_PPP];                  /* Phase of link session (RFC 1661) */\r
+lcp_options lcp_wantoptions[NUM_PPP];  /* Options that we want to request */\r
+lcp_options lcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */\r
+lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */\r
+lcp_options lcp_hisoptions[NUM_PPP];   /* Options that we ack'd */\r
+ext_accm xmit_accm[NUM_PPP];                   /* extended transmit ACCM */\r
+\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+static fsm lcp_fsm[NUM_PPP];                   /* LCP fsm structure (global)*/\r
+static u_int    lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */\r
+static u_int    lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */\r
+static u32_t lcp_echos_pending = 0;    /* Number of outstanding echo msgs */\r
+static u32_t lcp_echo_number   = 0;    /* ID number of next echo frame */\r
+static u32_t lcp_echo_timer_running = 0;  /* TRUE if a timer is running */\r
+\r
+static u_char nak_buffer[PPP_MRU];     /* where we construct a nak packet */\r
+\r
+static fsm_callbacks lcp_callbacks = { /* LCP callback routines */\r
+    lcp_resetci,               /* Reset our Configuration Information */\r
+    lcp_cilen,                 /* Length of our Configuration Information */\r
+    lcp_addci,                 /* Add our Configuration Information */\r
+    lcp_ackci,                 /* ACK our Configuration Information */\r
+    lcp_nakci,                 /* NAK our Configuration Information */\r
+    lcp_rejci,                 /* Reject our Configuration Information */\r
+    lcp_reqci,                 /* Request peer's Configuration Information */\r
+    lcp_up,                            /* Called when fsm reaches OPENED state */\r
+    lcp_down,                  /* Called when fsm leaves OPENED state */\r
+    lcp_starting,              /* Called when we want the lower layer up */\r
+    lcp_finished,              /* Called when we want the lower layer down */\r
+    NULL,                              /* Called when Protocol-Reject received */\r
+    NULL,                              /* Retransmission is necessary */\r
+    lcp_extcode,               /* Called to handle LCP-specific codes */\r
+    "LCP"                              /* String name of protocol */\r
+};\r
+\r
+struct protent lcp_protent = {\r
+    PPP_LCP,\r
+    lcp_init,\r
+    lcp_input,\r
+    lcp_protrej,\r
+    lcp_lowerup,\r
+    lcp_lowerdown,\r
+    lcp_open,\r
+    lcp_close,\r
+#if 0\r
+    lcp_printpkt,\r
+    NULL,\r
+#endif\r
+    1,\r
+    "LCP",\r
+#if 0\r
+    NULL,\r
+    NULL,\r
+    NULL\r
+#endif\r
+};\r
+\r
+int lcp_loopbackfail = DEFLOOPBACKFAIL;\r
+\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * lcp_init - Initialize LCP.\r
+ */\r
+void lcp_init(int unit)\r
+{\r
+       fsm *f = &lcp_fsm[unit];\r
+       lcp_options *wo = &lcp_wantoptions[unit];\r
+       lcp_options *ao = &lcp_allowoptions[unit];\r
+       \r
+       f->unit = unit;\r
+       f->protocol = PPP_LCP;\r
+       f->callbacks = &lcp_callbacks;\r
+       \r
+       fsm_init(f);\r
+       \r
+       wo->passive = 0;\r
+       wo->silent = 0;\r
+       wo->restart = 0;                        /* Set to 1 in kernels or multi-line\r
+                                                                * implementations */\r
+       wo->neg_mru = 1;\r
+       wo->mru = PPP_DEFMRU;\r
+       wo->neg_asyncmap = 1;\r
+       wo->asyncmap = 0x00000000l;     /* Assume don't need to escape any ctl chars. */\r
+       wo->neg_chap = 0;                       /* Set to 1 on server */\r
+       wo->neg_upap = 0;                       /* Set to 1 on server */\r
+       wo->chap_mdtype = CHAP_DIGEST_MD5;\r
+       wo->neg_magicnumber = 1;\r
+       wo->neg_pcompression = 1;\r
+       wo->neg_accompression = 1;\r
+       wo->neg_lqr = 0;                        /* no LQR implementation yet */\r
+       wo->neg_cbcp = 0;\r
+       \r
+       ao->neg_mru = 1;\r
+       ao->mru = PPP_MAXMRU;\r
+       ao->neg_asyncmap = 1;\r
+       ao->asyncmap = 0x00000000l;     /* Assume don't need to escape any ctl chars. */\r
+       ao->neg_chap = (CHAP_SUPPORT != 0);\r
+       ao->chap_mdtype = CHAP_DIGEST_MD5;\r
+       ao->neg_upap = (PAP_SUPPORT != 0);\r
+       ao->neg_magicnumber = 1;\r
+       ao->neg_pcompression = 1;\r
+       ao->neg_accompression = 1;\r
+       ao->neg_lqr = 0;                        /* no LQR implementation yet */\r
+       ao->neg_cbcp = (CBCP_SUPPORT != 0);\r
+\r
+       /* \r
+        * Set transmit escape for the flag and escape characters plus anything\r
+        * set for the allowable options.\r
+        */\r
+       memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));\r
+       xmit_accm[unit][15] = 0x60;\r
+       xmit_accm[unit][0] = (u_char)(ao->asyncmap & 0xFF);\r
+       xmit_accm[unit][1] = (u_char)((ao->asyncmap >> 8) & 0xFF);\r
+       xmit_accm[unit][2] = (u_char)((ao->asyncmap >> 16) & 0xFF);\r
+       xmit_accm[unit][3] = (u_char)((ao->asyncmap >> 24) & 0xFF);\r
+       LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n",\r
+                               xmit_accm[unit][0],\r
+                               xmit_accm[unit][1],\r
+                               xmit_accm[unit][2],\r
+                               xmit_accm[unit][3]));\r
+       \r
+       lcp_phase[unit] = PHASE_INITIALIZE;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_open - LCP is allowed to come up.\r
+ */\r
+void lcp_open(int unit)\r
+{\r
+       fsm *f = &lcp_fsm[unit];\r
+       lcp_options *wo = &lcp_wantoptions[unit];\r
+       \r
+       f->flags = 0;\r
+       if (wo->passive)\r
+               f->flags |= OPT_PASSIVE;\r
+       if (wo->silent)\r
+               f->flags |= OPT_SILENT;\r
+       fsm_open(f);\r
+       \r
+       lcp_phase[unit] = PHASE_ESTABLISH; \r
+}\r
+\r
+\r
+/*\r
+ * lcp_close - Take LCP down.\r
+ */\r
+void lcp_close(int unit, char *reason)\r
+{\r
+       fsm *f = &lcp_fsm[unit];\r
+       \r
+       if (lcp_phase[unit] != PHASE_DEAD)\r
+               lcp_phase[unit] = PHASE_TERMINATE;\r
+       if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {\r
+               /*\r
+                * This action is not strictly according to the FSM in RFC1548,\r
+                * but it does mean that the program terminates if you do an\r
+                * lcp_close() in passive/silent mode when a connection hasn't\r
+                * been established.\r
+                */\r
+               f->state = CLOSED;\r
+               lcp_finished(f);\r
+       }\r
+       else\r
+               fsm_close(&lcp_fsm[unit], reason);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_lowerup - The lower layer is up.\r
+ */\r
+void lcp_lowerup(int unit)\r
+{\r
+       lcp_options *wo = &lcp_wantoptions[unit];\r
+       \r
+       /*\r
+       * Don't use A/C or protocol compression on transmission,\r
+       * but accept A/C and protocol compressed packets\r
+       * if we are going to ask for A/C and protocol compression.\r
+       */\r
+       ppp_set_xaccm(unit, &xmit_accm[unit]);\r
+       ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0);\r
+       ppp_recv_config(unit, PPP_MRU, 0x00000000l,\r
+                                       wo->neg_pcompression, wo->neg_accompression);\r
+       peer_mru[unit] = PPP_MRU;\r
+       lcp_allowoptions[unit].asyncmap \r
+               = (u_long)xmit_accm[unit][0]\r
+                       | ((u_long)xmit_accm[unit][1] << 8)\r
+                       | ((u_long)xmit_accm[unit][2] << 16)\r
+                       | ((u_long)xmit_accm[unit][3] << 24);\r
+       LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n",\r
+                               xmit_accm[unit][3],\r
+                               xmit_accm[unit][2],\r
+                               xmit_accm[unit][1],\r
+                               xmit_accm[unit][0]));\r
+       \r
+       fsm_lowerup(&lcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_lowerdown - The lower layer is down.\r
+ */\r
+void lcp_lowerdown(int unit)\r
+{\r
+       fsm_lowerdown(&lcp_fsm[unit]);\r
+}\r
+\r
+/*\r
+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.\r
+ */\r
+void lcp_sprotrej(int unit, u_char *p, int len)\r
+{\r
+       /*\r
+       * Send back the protocol and the information field of the\r
+       * rejected packet.  We only get here if LCP is in the OPENED state.\r
+       */\r
+\r
+       fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id,\r
+                               p, len);\r
+}\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/*\r
+ * lcp_input - Input LCP packet.\r
+ */\r
+static void lcp_input(int unit, u_char *p, int len)\r
+{\r
+       fsm *f = &lcp_fsm[unit];\r
+       \r
+       fsm_input(f, p, len);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_extcode - Handle a LCP-specific code.\r
+ */\r
+static int lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len)\r
+{\r
+       u_char *magp;\r
+       \r
+       switch( code ){\r
+       case PROTREJ:\r
+               lcp_rprotrej(f, inp, len);\r
+               break;\r
+       \r
+       case ECHOREQ:\r
+               if (f->state != OPENED)\r
+                       break;\r
+               LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id));\r
+               magp = inp;\r
+               PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);\r
+               fsm_sdata(f, ECHOREP, id, inp, len);\r
+               break;\r
+       \r
+       case ECHOREP:\r
+               lcp_received_echo_reply(f, id, inp, len);\r
+               break;\r
+       \r
+       case DISCREQ:\r
+               break;\r
+       \r
+       default:\r
+               return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+    \r
+/*\r
+ * lcp_rprotrej - Receive an Protocol-Reject.\r
+ *\r
+ * Figure out which protocol is rejected and inform it.\r
+ */\r
+static void lcp_rprotrej(fsm *f, u_char *inp, int len)\r
+{\r
+       int i;\r
+       struct protent *protp;\r
+       u_short prot;\r
+       \r
+       if (len < sizeof (u_short)) {\r
+               LCPDEBUG((LOG_INFO,\r
+                               "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n"));\r
+               return;\r
+       }\r
+       \r
+       GETSHORT(prot, inp);\r
+       \r
+       LCPDEBUG((LOG_INFO,\r
+                       "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n",\r
+                       prot));\r
+       \r
+       /*\r
+       * Protocol-Reject packets received in any state other than the LCP\r
+       * OPENED state SHOULD be silently discarded.\r
+       */\r
+       if( f->state != OPENED ){\r
+               LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n",\r
+                               f->state));\r
+               return;\r
+       }\r
+       \r
+       /*\r
+       * Upcall the proper Protocol-Reject routine.\r
+       */\r
+       for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i)\r
+               if (protp->protocol == prot && protp->enabled_flag) {\r
+                       (*protp->protrej)(f->unit);\r
+                       return;\r
+               }\r
+       \r
+       LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n",\r
+                       prot));\r
+}\r
+\r
+\r
+/*\r
+ * lcp_protrej - A Protocol-Reject was received.\r
+ */\r
+static void lcp_protrej(int unit)\r
+{\r
+       (void)unit;\r
+       /*\r
+       * Can't reject LCP!\r
+       */\r
+       LCPDEBUG((LOG_WARNING,\r
+                       "lcp_protrej: Received Protocol-Reject for LCP!\n"));\r
+       fsm_protreject(&lcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_resetci - Reset our CI.\r
+ */\r
+static void lcp_resetci(fsm *f)\r
+{\r
+       lcp_wantoptions[f->unit].magicnumber = magic();\r
+       lcp_wantoptions[f->unit].numloops = 0;\r
+       lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];\r
+       peer_mru[f->unit] = PPP_MRU;\r
+       auth_reset(f->unit);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_cilen - Return length of our CI.\r
+ */\r
+static int lcp_cilen(fsm *f)\r
+{\r
+       lcp_options *go = &lcp_gotoptions[f->unit];\r
+\r
+#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0)\r
+#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0)\r
+#define LENCISHORT(neg)        ((neg) ? CILEN_SHORT : 0)\r
+#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0)\r
+#define LENCILQR(neg)  ((neg) ? CILEN_LQR: 0)\r
+#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0)\r
+       /*\r
+       * NB: we only ask for one of CHAP and UPAP, even if we will\r
+       * accept either.\r
+       */\r
+       return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +\r
+               LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +\r
+               LENCICHAP(go->neg_chap) +\r
+               LENCISHORT(!go->neg_chap && go->neg_upap) +\r
+               LENCILQR(go->neg_lqr) +\r
+               LENCICBCP(go->neg_cbcp) +\r
+               LENCILONG(go->neg_magicnumber) +\r
+               LENCIVOID(go->neg_pcompression) +\r
+               LENCIVOID(go->neg_accompression));\r
+}\r
+\r
+\r
+/*\r
+ * lcp_addci - Add our desired CIs to a packet.\r
+ */\r
+static void lcp_addci(fsm *f, u_char *ucp, int *lenp)\r
+{\r
+       lcp_options *go = &lcp_gotoptions[f->unit];\r
+       u_char *start_ucp = ucp;\r
+       \r
+#define ADDCIVOID(opt, neg) \\r
+       if (neg) { \\r
+           LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \\r
+               PUTCHAR(opt, ucp); \\r
+               PUTCHAR(CILEN_VOID, ucp); \\r
+       }\r
+#define ADDCISHORT(opt, neg, val) \\r
+       if (neg) { \\r
+           LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \\r
+               PUTCHAR(opt, ucp); \\r
+               PUTCHAR(CILEN_SHORT, ucp); \\r
+               PUTSHORT(val, ucp); \\r
+       }\r
+#define ADDCICHAP(opt, neg, val, digest) \\r
+       if (neg) { \\r
+           LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \\r
+               PUTCHAR(opt, ucp); \\r
+               PUTCHAR(CILEN_CHAP, ucp); \\r
+               PUTSHORT(val, ucp); \\r
+               PUTCHAR(digest, ucp); \\r
+       }\r
+#define ADDCILONG(opt, neg, val) \\r
+       if (neg) { \\r
+           LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \\r
+               PUTCHAR(opt, ucp); \\r
+               PUTCHAR(CILEN_LONG, ucp); \\r
+               PUTLONG(val, ucp); \\r
+       }\r
+#define ADDCILQR(opt, neg, val) \\r
+       if (neg) { \\r
+           LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \\r
+               PUTCHAR(opt, ucp); \\r
+               PUTCHAR(CILEN_LQR, ucp); \\r
+               PUTSHORT(PPP_LQR, ucp); \\r
+               PUTLONG(val, ucp); \\r
+       }\r
+#define ADDCICHAR(opt, neg, val) \\r
+       if (neg) { \\r
+           LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \\r
+               PUTCHAR(opt, ucp); \\r
+               PUTCHAR(CILEN_CHAR, ucp); \\r
+               PUTCHAR(val, ucp); \\r
+       }\r
+       \r
+       ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);\r
+       ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl,\r
+                       go->asyncmap);\r
+       ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);\r
+       ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);\r
+       ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);\r
+       ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);\r
+       ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);\r
+       ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);\r
+       ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);\r
+       \r
+       if (ucp - start_ucp != *lenp) {\r
+               /* this should never happen, because peer_mtu should be 1500 */\r
+               LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n"));\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * lcp_ackci - Ack our CIs.\r
+ * This should not modify any state if the Ack is bad.\r
+ *\r
+ * Returns:\r
+ *     0 - Ack was bad.\r
+ *     1 - Ack was good.\r
+ */\r
+static int lcp_ackci(fsm *f, u_char *p, int len)\r
+{\r
+       lcp_options *go = &lcp_gotoptions[f->unit];\r
+       u_char cilen, citype, cichar;\r
+       u_short cishort;\r
+       u32_t cilong;\r
+       \r
+       /*\r
+       * CIs must be in exactly the same order that we sent.\r
+       * Check packet length and CI length at each step.\r
+       * If we find any deviations, then this packet is bad.\r
+       */\r
+#define ACKCIVOID(opt, neg) \\r
+       if (neg) { \\r
+               if ((len -= CILEN_VOID) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != CILEN_VOID || \\r
+                               citype != opt) \\r
+                       goto bad; \\r
+       }\r
+#define ACKCISHORT(opt, neg, val) \\r
+       if (neg) { \\r
+               if ((len -= CILEN_SHORT) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != CILEN_SHORT || \\r
+                               citype != opt) \\r
+                       goto bad; \\r
+               GETSHORT(cishort, p); \\r
+               if (cishort != val) \\r
+                       goto bad; \\r
+       }\r
+#define ACKCICHAR(opt, neg, val) \\r
+       if (neg) { \\r
+               if ((len -= CILEN_CHAR) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != CILEN_CHAR || \\r
+                               citype != opt) \\r
+                       goto bad; \\r
+               GETCHAR(cichar, p); \\r
+               if (cichar != val) \\r
+                       goto bad; \\r
+       }\r
+#define ACKCICHAP(opt, neg, val, digest) \\r
+       if (neg) { \\r
+               if ((len -= CILEN_CHAP) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != CILEN_CHAP || \\r
+                               citype != opt) \\r
+                       goto bad; \\r
+               GETSHORT(cishort, p); \\r
+               if (cishort != val) \\r
+                       goto bad; \\r
+               GETCHAR(cichar, p); \\r
+               if (cichar != digest) \\r
+                       goto bad; \\r
+       }\r
+#define ACKCILONG(opt, neg, val) \\r
+       if (neg) { \\r
+               if ((len -= CILEN_LONG) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != CILEN_LONG || \\r
+                               citype != opt) \\r
+                       goto bad; \\r
+               GETLONG(cilong, p); \\r
+               if (cilong != val) \\r
+                       goto bad; \\r
+       }\r
+#define ACKCILQR(opt, neg, val) \\r
+       if (neg) { \\r
+               if ((len -= CILEN_LQR) < 0) \\r
+                       goto bad; \\r
+               GETCHAR(citype, p); \\r
+               GETCHAR(cilen, p); \\r
+               if (cilen != CILEN_LQR || \\r
+                               citype != opt) \\r
+                       goto bad; \\r
+               GETSHORT(cishort, p); \\r
+               if (cishort != PPP_LQR) \\r
+                       goto bad; \\r
+               GETLONG(cilong, p); \\r
+               if (cilong != val) \\r
+                       goto bad; \\r
+       }\r
+       \r
+       ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);\r
+       ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl,\r
+                       go->asyncmap);\r
+       ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);\r
+       ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);\r
+       ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);\r
+       ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);\r
+       ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);\r
+       ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);\r
+       ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);\r
+       \r
+       /*\r
+        * If there are any remaining CIs, then this packet is bad.\r
+        */\r
+       if (len != 0)\r
+               goto bad;\r
+       LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n"));\r
+       return (1);\r
+bad:\r
+       LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n"));\r
+       return (0);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.\r
+ * This should not modify any state if the Nak is bad\r
+ * or if LCP is in the OPENED state.\r
+ *\r
+ * Returns:\r
+ *     0 - Nak was bad.\r
+ *     1 - Nak was good.\r
+ */\r
+static int lcp_nakci(fsm *f, u_char *p, int len)\r
+{\r
+       lcp_options *go = &lcp_gotoptions[f->unit];\r
+       lcp_options *wo = &lcp_wantoptions[f->unit];\r
+       u_char citype, cichar, *next;\r
+       u_short cishort;\r
+       u32_t cilong;\r
+       lcp_options no;         /* options we've seen Naks for */\r
+       lcp_options try;                /* options to request next time */\r
+       int looped_back = 0;\r
+       int cilen;\r
+       \r
+       BZERO(&no, sizeof(no));\r
+       try = *go;\r
+       \r
+       /*\r
+       * Any Nak'd CIs must be in exactly the same order that we sent.\r
+       * Check packet length and CI length at each step.\r
+       * If we find any deviations, then this packet is bad.\r
+       */\r
+#define NAKCIVOID(opt, neg, code) \\r
+       if (go->neg && \\r
+                       len >= CILEN_VOID && \\r
+                       p[1] == CILEN_VOID && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_VOID; \\r
+               INCPTR(CILEN_VOID, p); \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+#define NAKCICHAP(opt, neg, code) \\r
+       if (go->neg && \\r
+                       len >= CILEN_CHAP && \\r
+                       p[1] == CILEN_CHAP && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_CHAP; \\r
+               INCPTR(2, p); \\r
+               GETSHORT(cishort, p); \\r
+               GETCHAR(cichar, p); \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+#define NAKCICHAR(opt, neg, code) \\r
+       if (go->neg && \\r
+                       len >= CILEN_CHAR && \\r
+                       p[1] == CILEN_CHAR && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_CHAR; \\r
+               INCPTR(2, p); \\r
+               GETCHAR(cichar, p); \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+#define NAKCISHORT(opt, neg, code) \\r
+       if (go->neg && \\r
+                       len >= CILEN_SHORT && \\r
+                       p[1] == CILEN_SHORT && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_SHORT; \\r
+               INCPTR(2, p); \\r
+               GETSHORT(cishort, p); \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+#define NAKCILONG(opt, neg, code) \\r
+       if (go->neg && \\r
+                       len >= CILEN_LONG && \\r
+                       p[1] == CILEN_LONG && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_LONG; \\r
+               INCPTR(2, p); \\r
+               GETLONG(cilong, p); \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+#define NAKCILQR(opt, neg, code) \\r
+       if (go->neg && \\r
+                       len >= CILEN_LQR && \\r
+                       p[1] == CILEN_LQR && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_LQR; \\r
+               INCPTR(2, p); \\r
+               GETSHORT(cishort, p); \\r
+               GETLONG(cilong, p); \\r
+               no.neg = 1; \\r
+               code \\r
+       }\r
+       \r
+       /*\r
+       * We don't care if they want to send us smaller packets than\r
+       * we want.  Therefore, accept any MRU less than what we asked for,\r
+       * but then ignore the new value when setting the MRU in the kernel.\r
+       * If they send us a bigger MRU than what we asked, accept it, up to\r
+       * the limit of the default MRU we'd get if we didn't negotiate.\r
+       */\r
+       if (go->neg_mru && go->mru != PPP_DEFMRU) {\r
+               NAKCISHORT(CI_MRU, neg_mru,\r
+                       if (cishort <= wo->mru || cishort < PPP_DEFMRU)\r
+                               try.mru = cishort;\r
+               );\r
+       }\r
+       \r
+       /*\r
+       * Add any characters they want to our (receive-side) asyncmap.\r
+       */\r
+       if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) {\r
+               NAKCILONG(CI_ASYNCMAP, neg_asyncmap,\r
+                       try.asyncmap = go->asyncmap | cilong;\r
+               );\r
+       }\r
+       \r
+       /*\r
+       * If they've nak'd our authentication-protocol, check whether\r
+       * they are proposing a different protocol, or a different\r
+       * hash algorithm for CHAP.\r
+       */\r
+       if ((go->neg_chap || go->neg_upap)\r
+                       && len >= CILEN_SHORT\r
+                       && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {\r
+               cilen = p[1];\r
+       len -= cilen;\r
+       no.neg_chap = go->neg_chap;\r
+       no.neg_upap = go->neg_upap;\r
+       INCPTR(2, p);\r
+       GETSHORT(cishort, p);\r
+       if (cishort == PPP_PAP && cilen == CILEN_SHORT) {\r
+               /*\r
+                * If we were asking for CHAP, they obviously don't want to do it.\r
+                * If we weren't asking for CHAP, then we were asking for PAP,\r
+                * in which case this Nak is bad.\r
+                */\r
+               if (!go->neg_chap)\r
+                       goto bad;\r
+               try.neg_chap = 0;\r
+       \r
+       } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {\r
+               GETCHAR(cichar, p);\r
+               if (go->neg_chap) {\r
+                       /*\r
+                        * We were asking for CHAP/MD5; they must want a different\r
+                        * algorithm.  If they can't do MD5, we'll have to stop\r
+                        * asking for CHAP.\r
+                        */\r
+                       if (cichar != go->chap_mdtype)\r
+                               try.neg_chap = 0;\r
+               } else {\r
+                       /*\r
+                        * Stop asking for PAP if we were asking for it.\r
+                        */\r
+                       try.neg_upap = 0;\r
+               }\r
+       \r
+       } else {\r
+               /*\r
+                * We don't recognize what they're suggesting.\r
+                * Stop asking for what we were asking for.\r
+                */\r
+               if (go->neg_chap)\r
+                       try.neg_chap = 0;\r
+               else\r
+                       try.neg_upap = 0;\r
+               p += cilen - CILEN_SHORT;\r
+       }\r
+       }\r
+       \r
+       /*\r
+       * If they can't cope with our link quality protocol, we'll have\r
+       * to stop asking for LQR.  We haven't got any other protocol.\r
+       * If they Nak the reporting period, take their value XXX ?\r
+       */\r
+       NAKCILQR(CI_QUALITY, neg_lqr,\r
+               if (cishort != PPP_LQR)\r
+                       try.neg_lqr = 0;\r
+               else\r
+                       try.lqr_period = cilong;\r
+       );\r
+       \r
+       /*\r
+       * Only implementing CBCP...not the rest of the callback options\r
+       */\r
+       NAKCICHAR(CI_CALLBACK, neg_cbcp,\r
+               try.neg_cbcp = 0;\r
+       );\r
+       \r
+       /*\r
+       * Check for a looped-back line.\r
+       */\r
+       NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,\r
+               try.magicnumber = magic();\r
+               looped_back = 1;\r
+       );\r
+       \r
+       /*\r
+       * Peer shouldn't send Nak for protocol compression or\r
+       * address/control compression requests; they should send\r
+       * a Reject instead.  If they send a Nak, treat it as a Reject.\r
+       */\r
+       NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,\r
+               try.neg_pcompression = 0;\r
+       );\r
+       NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,\r
+               try.neg_accompression = 0;\r
+       );\r
+       \r
+       /*\r
+       * There may be remaining CIs, if the peer is requesting negotiation\r
+       * on an option that we didn't include in our request packet.\r
+       * If we see an option that we requested, or one we've already seen\r
+       * in this packet, then this packet is bad.\r
+       * If we wanted to respond by starting to negotiate on the requested\r
+       * option(s), we could, but we don't, because except for the\r
+       * authentication type and quality protocol, if we are not negotiating\r
+       * an option, it is because we were told not to.\r
+       * For the authentication type, the Nak from the peer means\r
+       * `let me authenticate myself with you' which is a bit pointless.\r
+       * For the quality protocol, the Nak means `ask me to send you quality\r
+       * reports', but if we didn't ask for them, we don't want them.\r
+       * An option we don't recognize represents the peer asking to\r
+       * negotiate some option we don't support, so ignore it.\r
+       */\r
+       while (len > CILEN_VOID) {\r
+               GETCHAR(citype, p);\r
+               GETCHAR(cilen, p);\r
+               if (cilen < CILEN_VOID || (len -= cilen) < 0)\r
+                       goto bad;\r
+               next = p + cilen - 2;\r
+               \r
+               switch (citype) {\r
+               case CI_MRU:\r
+                       if ((go->neg_mru && go->mru != PPP_DEFMRU)\r
+                                       || no.neg_mru || cilen != CILEN_SHORT)\r
+                               goto bad;\r
+                       GETSHORT(cishort, p);\r
+                       if (cishort < PPP_DEFMRU)\r
+                               try.mru = cishort;\r
+                       break;\r
+               case CI_ASYNCMAP:\r
+                       if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl)\r
+                                       || no.neg_asyncmap || cilen != CILEN_LONG)\r
+                               goto bad;\r
+                       break;\r
+               case CI_AUTHTYPE:\r
+                       if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)\r
+                               goto bad;\r
+                       break;\r
+               case CI_MAGICNUMBER:\r
+                       if (go->neg_magicnumber || no.neg_magicnumber ||\r
+                                       cilen != CILEN_LONG)\r
+                               goto bad;\r
+                       break;\r
+               case CI_PCOMPRESSION:\r
+                       if (go->neg_pcompression || no.neg_pcompression\r
+                                       || cilen != CILEN_VOID)\r
+                               goto bad;\r
+                       break;\r
+               case CI_ACCOMPRESSION:\r
+                       if (go->neg_accompression || no.neg_accompression\r
+                                       || cilen != CILEN_VOID)\r
+                               goto bad;\r
+                       break;\r
+               case CI_QUALITY:\r
+                       if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)\r
+                               goto bad;\r
+                       break;\r
+               }\r
+               p = next;\r
+       }\r
+       \r
+       /* If there is still anything left, this packet is bad. */\r
+       if (len != 0)\r
+               goto bad;\r
+       \r
+       /*\r
+       * OK, the Nak is good.  Now we can update state.\r
+       */\r
+       if (f->state != OPENED) {\r
+               if (looped_back) {\r
+                       if (++try.numloops >= lcp_loopbackfail) {\r
+                               LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n"));\r
+                               lcp_close(f->unit, "Loopback detected");\r
+                       }\r
+               } \r
+               else\r
+                       try.numloops = 0;\r
+               *go = try;\r
+       }\r
+       \r
+       return 1;\r
+       \r
+bad:\r
+       LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n"));\r
+       return 0;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_rejci - Peer has Rejected some of our CIs.\r
+ * This should not modify any state if the Reject is bad\r
+ * or if LCP is in the OPENED state.\r
+ *\r
+ * Returns:\r
+ *     0 - Reject was bad.\r
+ *     1 - Reject was good.\r
+ */\r
+static int lcp_rejci(fsm *f, u_char *p, int len)\r
+{\r
+       lcp_options *go = &lcp_gotoptions[f->unit];\r
+       u_char cichar;\r
+       u_short cishort;\r
+       u32_t cilong;\r
+       lcp_options try;                /* options to request next time */\r
+       \r
+       try = *go;\r
+       \r
+       /*\r
+       * Any Rejected CIs must be in exactly the same order that we sent.\r
+       * Check packet length and CI length at each step.\r
+       * If we find any deviations, then this packet is bad.\r
+       */\r
+#define REJCIVOID(opt, neg) \\r
+       if (go->neg && \\r
+                       len >= CILEN_VOID && \\r
+                       p[1] == CILEN_VOID && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_VOID; \\r
+               INCPTR(CILEN_VOID, p); \\r
+               try.neg = 0; \\r
+               LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \\r
+       }\r
+#define REJCISHORT(opt, neg, val) \\r
+       if (go->neg && \\r
+                       len >= CILEN_SHORT && \\r
+                       p[1] == CILEN_SHORT && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_SHORT; \\r
+               INCPTR(2, p); \\r
+               GETSHORT(cishort, p); \\r
+               /* Check rejected value. */ \\r
+               if (cishort != val) \\r
+                       goto bad; \\r
+               try.neg = 0; \\r
+               LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \\r
+       }\r
+#define REJCICHAP(opt, neg, val, digest) \\r
+       if (go->neg && \\r
+                       len >= CILEN_CHAP && \\r
+                       p[1] == CILEN_CHAP && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_CHAP; \\r
+               INCPTR(2, p); \\r
+               GETSHORT(cishort, p); \\r
+               GETCHAR(cichar, p); \\r
+               /* Check rejected value. */ \\r
+               if (cishort != val || cichar != digest) \\r
+                       goto bad; \\r
+               try.neg = 0; \\r
+               try.neg_upap = 0; \\r
+               LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \\r
+       }\r
+#define REJCILONG(opt, neg, val) \\r
+       if (go->neg && \\r
+                       len >= CILEN_LONG && \\r
+                       p[1] == CILEN_LONG && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_LONG; \\r
+               INCPTR(2, p); \\r
+               GETLONG(cilong, p); \\r
+               /* Check rejected value. */ \\r
+               if (cilong != val) \\r
+                       goto bad; \\r
+               try.neg = 0; \\r
+               LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \\r
+       }\r
+#define REJCILQR(opt, neg, val) \\r
+       if (go->neg && \\r
+                       len >= CILEN_LQR && \\r
+                       p[1] == CILEN_LQR && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_LQR; \\r
+               INCPTR(2, p); \\r
+               GETSHORT(cishort, p); \\r
+               GETLONG(cilong, p); \\r
+               /* Check rejected value. */ \\r
+               if (cishort != PPP_LQR || cilong != val) \\r
+                       goto bad; \\r
+               try.neg = 0; \\r
+               LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \\r
+       }\r
+#define REJCICBCP(opt, neg, val) \\r
+       if (go->neg && \\r
+                       len >= CILEN_CBCP && \\r
+                       p[1] == CILEN_CBCP && \\r
+                       p[0] == opt) { \\r
+               len -= CILEN_CBCP; \\r
+               INCPTR(2, p); \\r
+               GETCHAR(cichar, p); \\r
+               /* Check rejected value. */ \\r
+               if (cichar != val) \\r
+                       goto bad; \\r
+               try.neg = 0; \\r
+               LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \\r
+       }\r
+       \r
+       REJCISHORT(CI_MRU, neg_mru, go->mru);\r
+       REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);\r
+       REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);\r
+       if (!go->neg_chap) {\r
+               REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);\r
+       }\r
+       REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);\r
+       REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);\r
+       REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);\r
+       REJCIVOID(CI_PCOMPRESSION, neg_pcompression);\r
+       REJCIVOID(CI_ACCOMPRESSION, neg_accompression);\r
+       \r
+       /*\r
+       * If there are any remaining CIs, then this packet is bad.\r
+       */\r
+       if (len != 0)\r
+               goto bad;\r
+       /*\r
+       * Now we can update state.\r
+       */\r
+       if (f->state != OPENED)\r
+               *go = try;\r
+       return 1;\r
+       \r
+bad:\r
+       LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n"));\r
+       return 0;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.\r
+ *\r
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified\r
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return\r
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.\r
+ */\r
+static int lcp_reqci(fsm *f, \r
+                                               u_char *inp,            /* Requested CIs */\r
+                                               int *lenp,                      /* Length of requested CIs */\r
+                                               int reject_if_disagree)\r
+{\r
+       lcp_options *go = &lcp_gotoptions[f->unit];\r
+       lcp_options *ho = &lcp_hisoptions[f->unit];\r
+       lcp_options *ao = &lcp_allowoptions[f->unit];\r
+       u_char *cip, *next;                     /* Pointer to current and next CIs */\r
+       int cilen, citype, cichar;      /* Parsed len, type, char value */\r
+       u_short cishort;                        /* Parsed short value */\r
+       u32_t cilong;                   /* Parse long value */\r
+       int rc = CONFACK;                       /* Final packet return code */\r
+       int orc;                                        /* Individual option return code */\r
+       u_char *p;                                      /* Pointer to next char to parse */\r
+       u_char *rejp;                           /* Pointer to next char in reject frame */\r
+       u_char *nakp;                           /* Pointer to next char in Nak frame */\r
+       int l = *lenp;                          /* Length left */\r
+#if TRACELCP > 0\r
+       char traceBuf[80];\r
+       int traceNdx = 0;\r
+#endif\r
+       \r
+       /*\r
+        * Reset all his options.\r
+        */\r
+       BZERO(ho, sizeof(*ho));\r
+       \r
+       /*\r
+        * Process all his options.\r
+        */\r
+       next = inp;\r
+       nakp = nak_buffer;\r
+       rejp = inp;\r
+       while (l) {\r
+               orc = CONFACK;                  /* Assume success */\r
+               cip = p = next;                 /* Remember begining of CI */\r
+               if (l < 2 ||                    /* Not enough data for CI header or */\r
+                               p[1] < 2 ||                     /*  CI length too small or */\r
+                               p[1] > l) {                     /*  CI length too big? */\r
+                       LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n"));\r
+                       orc = CONFREJ;          /* Reject bad CI */\r
+                       cilen = l;                      /* Reject till end of packet */\r
+                       l = 0;                  /* Don't loop again */\r
+                       citype = 0;\r
+                       goto endswitch;\r
+               }\r
+               GETCHAR(citype, p);             /* Parse CI type */\r
+               GETCHAR(cilen, p);              /* Parse CI length */\r
+               l -= cilen;                     /* Adjust remaining length */\r
+               next += cilen;                  /* Step to next CI */\r
+               \r
+               switch (citype) {               /* Check CI type */\r
+               case CI_MRU:\r
+                       if (!ao->neg_mru) {             /* Allow option? */\r
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n"));\r
+                               orc = CONFREJ;          /* Reject CI */\r
+                               break;\r
+                       } else if (cilen != CILEN_SHORT) {      /* Check CI length */\r
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n"));\r
+                               orc = CONFREJ;          /* Reject CI */\r
+                               break;\r
+                       }\r
+                       GETSHORT(cishort, p);   /* Parse MRU */\r
+                       \r
+                       /*\r
+                        * He must be able to receive at least our minimum.\r
+                        * No need to check a maximum.  If he sends a large number,\r
+                        * we'll just ignore it.\r
+                        */\r
+                       if (cishort < PPP_MINMRU) {\r
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n"));\r
+                               orc = CONFNAK;          /* Nak CI */\r
+                               PUTCHAR(CI_MRU, nakp);\r
+                               PUTCHAR(CILEN_SHORT, nakp);\r
+                               PUTSHORT(PPP_MINMRU, nakp);     /* Give him a hint */\r
+                               break;\r
+                       }\r
+                       ho->neg_mru = 1;                /* Remember he sent MRU */\r
+                       ho->mru = cishort;              /* And remember value */\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort);\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+                       break;\r
+               \r
+               case CI_ASYNCMAP:\r
+                       if (!ao->neg_asyncmap) {\r
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n"));\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       } else if (cilen != CILEN_LONG) {\r
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n"));\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       }\r
+                       GETLONG(cilong, p);\r
+                       \r
+                       /*\r
+                        * Asyncmap must have set at least the bits\r
+                        * which are set in lcp_allowoptions[unit].asyncmap.\r
+                        */\r
+                       if ((ao->asyncmap & ~cilong) != 0) {\r
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", \r
+                                                       cilong, ao->asyncmap));\r
+                               orc = CONFNAK;\r
+                               PUTCHAR(CI_ASYNCMAP, nakp);\r
+                               PUTCHAR(CILEN_LONG, nakp);\r
+                               PUTLONG(ao->asyncmap | cilong, nakp);\r
+                               break;\r
+                       }\r
+                       ho->neg_asyncmap = 1;\r
+                       ho->asyncmap = cilong;\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong);\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+                       break;\r
+               \r
+               case CI_AUTHTYPE:\r
+                       if (cilen < CILEN_SHORT) {\r
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n"));\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       } else if (!(ao->neg_upap || ao->neg_chap)) {\r
+                               /*\r
+                                * Reject the option if we're not willing to authenticate.\r
+                                */\r
+                               LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n"));\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       }\r
+                       GETSHORT(cishort, p);\r
+                       \r
+                       /*\r
+                        * Authtype must be UPAP or CHAP.\r
+                        *\r
+                        * Note: if both ao->neg_upap and ao->neg_chap are set,\r
+                        * and the peer sends a Configure-Request with two\r
+                        * authenticate-protocol requests, one for CHAP and one\r
+                        * for UPAP, then we will reject the second request.\r
+                        * Whether we end up doing CHAP or UPAP depends then on\r
+                        * the ordering of the CIs in the peer's Configure-Request.\r
+                        */\r
+                       \r
+                       if (cishort == PPP_PAP) {\r
+                               if (ho->neg_chap) {     /* we've already accepted CHAP */\r
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n"));\r
+                                       orc = CONFREJ;\r
+                                       break;\r
+                               } else if (cilen != CILEN_SHORT) {\r
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n"));\r
+                                       orc = CONFREJ;\r
+                                       break;\r
+                               }\r
+                               if (!ao->neg_upap) {    /* we don't want to do PAP */\r
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n"));\r
+                                       orc = CONFNAK;  /* NAK it and suggest CHAP */\r
+                                       PUTCHAR(CI_AUTHTYPE, nakp);\r
+                                       PUTCHAR(CILEN_CHAP, nakp);\r
+                                       PUTSHORT(PPP_CHAP, nakp);\r
+                                       PUTCHAR(ao->chap_mdtype, nakp);\r
+                                       break;\r
+                               }\r
+                               ho->neg_upap = 1;\r
+#if TRACELCP > 0\r
+                               snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort);\r
+                               traceNdx = strlen(traceBuf);\r
+#endif\r
+                               break;\r
+                       }\r
+                       if (cishort == PPP_CHAP) {\r
+                               if (ho->neg_upap) {     /* we've already accepted PAP */\r
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n"));\r
+                                       orc = CONFREJ;\r
+                                       break;\r
+                               } else if (cilen != CILEN_CHAP) {\r
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n"));\r
+                                       orc = CONFREJ;\r
+                                       break;\r
+                               }\r
+                               if (!ao->neg_chap) {    /* we don't want to do CHAP */\r
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n"));\r
+                                       orc = CONFNAK;  /* NAK it and suggest PAP */\r
+                                       PUTCHAR(CI_AUTHTYPE, nakp);\r
+                                       PUTCHAR(CILEN_SHORT, nakp);\r
+                                       PUTSHORT(PPP_PAP, nakp);\r
+                                       break;\r
+                               }\r
+                               GETCHAR(cichar, p);     /* get digest type*/\r
+                               if (cichar != CHAP_DIGEST_MD5\r
+#ifdef CHAPMS\r
+                                               && cichar != CHAP_MICROSOFT\r
+#endif\r
+                               ) {\r
+                                       LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar));\r
+                                       orc = CONFNAK;\r
+                                       PUTCHAR(CI_AUTHTYPE, nakp);\r
+                                       PUTCHAR(CILEN_CHAP, nakp);\r
+                                       PUTSHORT(PPP_CHAP, nakp);\r
+                                       PUTCHAR(ao->chap_mdtype, nakp);\r
+                                       break;\r
+                               }\r
+#if TRACELCP > 0\r
+                               snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar);\r
+                               traceNdx = strlen(traceBuf);\r
+#endif\r
+                               ho->chap_mdtype = cichar; /* save md type */\r
+                               ho->neg_chap = 1;\r
+                               break;\r
+                       }\r
+                       \r
+                       /*\r
+                        * We don't recognize the protocol they're asking for.\r
+                        * Nak it with something we're willing to do.\r
+                        * (At this point we know ao->neg_upap || ao->neg_chap.)\r
+                        */\r
+                       orc = CONFNAK;\r
+                       PUTCHAR(CI_AUTHTYPE, nakp);\r
+                       if (ao->neg_chap) {\r
+                               LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort));\r
+                               PUTCHAR(CILEN_CHAP, nakp);\r
+                               PUTSHORT(PPP_CHAP, nakp);\r
+                               PUTCHAR(ao->chap_mdtype, nakp);\r
+                       } \r
+                       else {\r
+                               LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort));\r
+                               PUTCHAR(CILEN_SHORT, nakp);\r
+                               PUTSHORT(PPP_PAP, nakp);\r
+                       }\r
+                       break;\r
+               \r
+               case CI_QUALITY:\r
+                       GETSHORT(cishort, p);\r
+                       GETLONG(cilong, p);\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong);\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+\r
+                       if (!ao->neg_lqr ||\r
+                                       cilen != CILEN_LQR) {\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       }\r
+                       \r
+                       /*\r
+                        * Check the protocol and the reporting period.\r
+                        * XXX When should we Nak this, and what with?\r
+                        */\r
+                       if (cishort != PPP_LQR) {\r
+                               orc = CONFNAK;\r
+                               PUTCHAR(CI_QUALITY, nakp);\r
+                               PUTCHAR(CILEN_LQR, nakp);\r
+                               PUTSHORT(PPP_LQR, nakp);\r
+                               PUTLONG(ao->lqr_period, nakp);\r
+                               break;\r
+                       }\r
+                       break;\r
+               \r
+               case CI_MAGICNUMBER:\r
+                       if (!(ao->neg_magicnumber || go->neg_magicnumber) ||\r
+                                       cilen != CILEN_LONG) {\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       }\r
+                       GETLONG(cilong, p);\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong);\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+\r
+                       /*\r
+                        * He must have a different magic number.\r
+                        */\r
+                       if (go->neg_magicnumber &&\r
+                                       cilong == go->magicnumber) {\r
+                               cilong = magic();       /* Don't put magic() inside macro! */\r
+                               orc = CONFNAK;\r
+                               PUTCHAR(CI_MAGICNUMBER, nakp);\r
+                               PUTCHAR(CILEN_LONG, nakp);\r
+                               PUTLONG(cilong, nakp);\r
+                               break;\r
+                       }\r
+                       ho->neg_magicnumber = 1;\r
+                       ho->magicnumber = cilong;\r
+                       break;\r
+               \r
+               \r
+               case CI_PCOMPRESSION:\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION");\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+                       if (!ao->neg_pcompression ||\r
+                                       cilen != CILEN_VOID) {\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       }\r
+                       ho->neg_pcompression = 1;\r
+                       break;\r
+               \r
+               case CI_ACCOMPRESSION:\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION");\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+                       if (!ao->neg_accompression ||\r
+                                       cilen != CILEN_VOID) {\r
+                               orc = CONFREJ;\r
+                               break;\r
+                       }\r
+                       ho->neg_accompression = 1;\r
+                       break;\r
+               \r
+               case CI_MRRU:\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU");\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+                       orc = CONFREJ;\r
+                       break;\r
+               \r
+               case CI_SSNHF:\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF");\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+                       orc = CONFREJ;\r
+                       break;\r
+               \r
+               case CI_EPDISC:\r
+#if TRACELCP > 0\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC");\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+                       orc = CONFREJ;\r
+                       break;\r
+               \r
+               default:\r
+#if TRACELCP\r
+                       snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype);\r
+                       traceNdx = strlen(traceBuf);\r
+#endif\r
+                       orc = CONFREJ;\r
+                       break;\r
+               }\r
+               \r
+       endswitch:\r
+#if TRACELCP\r
+               if (traceNdx >= 80 - 32) {\r
+                       LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf));\r
+                       traceNdx = 0;\r
+               }\r
+#endif\r
+               if (orc == CONFACK &&           /* Good CI */\r
+                               rc != CONFACK)          /*  but prior CI wasnt? */\r
+                       continue;                       /* Don't send this one */\r
+               \r
+               if (orc == CONFNAK) {           /* Nak this CI? */\r
+                       if (reject_if_disagree  /* Getting fed up with sending NAKs? */\r
+                                       && citype != CI_MAGICNUMBER) {\r
+                               orc = CONFREJ;          /* Get tough if so */\r
+                       } \r
+                       else {\r
+                               if (rc == CONFREJ)      /* Rejecting prior CI? */\r
+                                       continue;               /* Don't send this one */\r
+                               rc = CONFNAK;\r
+                       }\r
+               }\r
+               if (orc == CONFREJ) {           /* Reject this CI */\r
+                       rc = CONFREJ;\r
+                       if (cip != rejp)                /* Need to move rejected CI? */\r
+                               BCOPY(cip, rejp, cilen); /* Move it */\r
+                       INCPTR(cilen, rejp);    /* Update output pointer */\r
+               }\r
+       }\r
+       \r
+       /*\r
+        * If we wanted to send additional NAKs (for unsent CIs), the\r
+        * code would go here.  The extra NAKs would go at *nakp.\r
+        * At present there are no cases where we want to ask the\r
+        * peer to negotiate an option.\r
+        */\r
+       \r
+       switch (rc) {\r
+       case CONFACK:\r
+               *lenp = (int)(next - inp);\r
+               break;\r
+       case CONFNAK:\r
+               /*\r
+                * Copy the Nak'd options from the nak_buffer to the caller's buffer.\r
+                */\r
+               *lenp = (int)(nakp - nak_buffer);\r
+               BCOPY(nak_buffer, inp, *lenp);\r
+               break;\r
+       case CONFREJ:\r
+               *lenp = (int)(rejp - inp);\r
+               break;\r
+       }\r
+       \r
+#if TRACELCP > 0\r
+       if (traceNdx > 0) {\r
+               LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf));\r
+       }\r
+#endif\r
+       LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc)));\r
+       return (rc);                    /* Return final code */\r
+}\r
+\r
+\r
+/*\r
+ * lcp_up - LCP has come UP.\r
+ */\r
+static void lcp_up(fsm *f)\r
+{\r
+       lcp_options *wo = &lcp_wantoptions[f->unit];\r
+       lcp_options *ho = &lcp_hisoptions[f->unit];\r
+       lcp_options *go = &lcp_gotoptions[f->unit];\r
+       lcp_options *ao = &lcp_allowoptions[f->unit];\r
+       \r
+       if (!go->neg_magicnumber)\r
+               go->magicnumber = 0;\r
+       if (!ho->neg_magicnumber)\r
+               ho->magicnumber = 0;\r
+       \r
+       /*\r
+       * Set our MTU to the smaller of the MTU we wanted and\r
+       * the MRU our peer wanted.  If we negotiated an MRU,\r
+       * set our MRU to the larger of value we wanted and\r
+       * the value we got in the negotiation.\r
+       */\r
+       ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),\r
+                               (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl),\r
+                               ho->neg_pcompression, ho->neg_accompression);\r
+       /*\r
+       * If the asyncmap hasn't been negotiated, we really should\r
+       * set the receive asyncmap to ffffffff, but we set it to 0\r
+       * for backwards contemptibility.\r
+       */\r
+       ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU),\r
+                               (go->neg_asyncmap? go->asyncmap: 0x00000000),\r
+                               go->neg_pcompression, go->neg_accompression);\r
+       \r
+       if (ho->neg_mru)\r
+               peer_mru[f->unit] = ho->mru;\r
+       \r
+       lcp_echo_lowerup(f->unit);  /* Enable echo messages */\r
+       \r
+       link_established(f->unit);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_down - LCP has gone DOWN.\r
+ *\r
+ * Alert other protocols.\r
+ */\r
+static void lcp_down(fsm *f)\r
+{\r
+       lcp_options *go = &lcp_gotoptions[f->unit];\r
+       \r
+       lcp_echo_lowerdown(f->unit);\r
+       \r
+       link_down(f->unit);\r
+       \r
+       ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0);\r
+       ppp_recv_config(f->unit, PPP_MRU,\r
+                               (go->neg_asyncmap? go->asyncmap: 0x00000000),\r
+                               go->neg_pcompression, go->neg_accompression);\r
+       peer_mru[f->unit] = PPP_MRU;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_starting - LCP needs the lower layer up.\r
+ */\r
+static void lcp_starting(fsm *f)\r
+{\r
+       link_required(f->unit);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_finished - LCP has finished with the lower layer.\r
+ */\r
+static void lcp_finished(fsm *f)\r
+{\r
+       link_terminated(f->unit);\r
+}\r
+\r
+\r
+#if 0\r
+/*\r
+ * print_string - print a readable representation of a string using\r
+ * printer.\r
+ */\r
+static void print_string(\r
+    char *p,\r
+    int len,\r
+    void (*printer) (void *, char *, ...),\r
+    void *arg\r
+)\r
+{\r
+    int c;\r
+    \r
+    printer(arg, "\"");\r
+    for (; len > 0; --len) {\r
+        c = *p++;\r
+        if (' ' <= c && c <= '~') {\r
+            if (c == '\\' || c == '"')\r
+                printer(arg, "\\");\r
+            printer(arg, "%c", c);\r
+        } else {\r
+            switch (c) {\r
+            case '\n':\r
+                printer(arg, "\\n");\r
+                break;\r
+            case '\r':\r
+                printer(arg, "\\r");\r
+                break;\r
+            case '\t':\r
+                printer(arg, "\\t");\r
+                break;\r
+            default:\r
+                printer(arg, "\\%.3o", c);\r
+            }\r
+        }\r
+    }\r
+    printer(arg, "\"");\r
+}\r
+\r
+\r
+/*\r
+ * lcp_printpkt - print the contents of an LCP packet.\r
+ */\r
+static char *lcp_codenames[] = {\r
+       "ConfReq", "ConfAck", "ConfNak", "ConfRej",\r
+       "TermReq", "TermAck", "CodeRej", "ProtRej",\r
+       "EchoReq", "EchoRep", "DiscReq"\r
+};\r
+\r
+static int lcp_printpkt(\r
+       u_char *p,\r
+       int plen,\r
+       void (*printer) (void *, char *, ...),\r
+       void *arg\r
+)\r
+{\r
+       int code, id, len, olen;\r
+       u_char *pstart, *optend;\r
+       u_short cishort;\r
+       u32_t cilong;\r
+       \r
+       if (plen < HEADERLEN)\r
+               return 0;\r
+       pstart = p;\r
+       GETCHAR(code, p);\r
+       GETCHAR(id, p);\r
+       GETSHORT(len, p);\r
+       if (len < HEADERLEN || len > plen)\r
+               return 0;\r
+       \r
+       if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *))\r
+               printer(arg, " %s", lcp_codenames[code-1]);\r
+       else\r
+               printer(arg, " code=0x%x", code);\r
+       printer(arg, " id=0x%x", id);\r
+       len -= HEADERLEN;\r
+       switch (code) {\r
+       case CONFREQ:\r
+       case CONFACK:\r
+       case CONFNAK:\r
+       case CONFREJ:\r
+               /* print option list */\r
+               while (len >= 2) {\r
+                       GETCHAR(code, p);\r
+                       GETCHAR(olen, p);\r
+                       p -= 2;\r
+                       if (olen < 2 || olen > len) {\r
+                               break;\r
+                       }\r
+                       printer(arg, " <");\r
+                       len -= olen;\r
+                       optend = p + olen;\r
+                       switch (code) {\r
+                       case CI_MRU:\r
+                               if (olen == CILEN_SHORT) {\r
+                                       p += 2;\r
+                                       GETSHORT(cishort, p);\r
+                                       printer(arg, "mru %d", cishort);\r
+                               }\r
+                               break;\r
+                       case CI_ASYNCMAP:\r
+                               if (olen == CILEN_LONG) {\r
+                                       p += 2;\r
+                                       GETLONG(cilong, p);\r
+                                       printer(arg, "asyncmap 0x%lx", cilong);\r
+                               }\r
+                               break;\r
+                       case CI_AUTHTYPE:\r
+                               if (olen >= CILEN_SHORT) {\r
+                                       p += 2;\r
+                                       printer(arg, "auth ");\r
+                                       GETSHORT(cishort, p);\r
+                                       switch (cishort) {\r
+                                       case PPP_PAP:\r
+                                               printer(arg, "pap");\r
+                                               break;\r
+                                       case PPP_CHAP:\r
+                                               printer(arg, "chap");\r
+                                               break;\r
+                                       default:\r
+                                               printer(arg, "0x%x", cishort);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case CI_QUALITY:\r
+                               if (olen >= CILEN_SHORT) {\r
+                                       p += 2;\r
+                                       printer(arg, "quality ");\r
+                                       GETSHORT(cishort, p);\r
+                                       switch (cishort) {\r
+                                       case PPP_LQR:\r
+                                               printer(arg, "lqr");\r
+                                               break;\r
+                                       default:\r
+                                               printer(arg, "0x%x", cishort);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case CI_CALLBACK:\r
+                               if (olen >= CILEN_CHAR) {\r
+                                       p += 2;\r
+                                       printer(arg, "callback ");\r
+                                       GETSHORT(cishort, p);\r
+                                       switch (cishort) {\r
+                                       case CBCP_OPT:\r
+                                               printer(arg, "CBCP");\r
+                                               break;\r
+                                       default:\r
+                                               printer(arg, "0x%x", cishort);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case CI_MAGICNUMBER:\r
+                               if (olen == CILEN_LONG) {\r
+                                       p += 2;\r
+                                       GETLONG(cilong, p);\r
+                                       printer(arg, "magic 0x%x", cilong);\r
+                               }\r
+                               break;\r
+                       case CI_PCOMPRESSION:\r
+                               if (olen == CILEN_VOID) {\r
+                                       p += 2;\r
+                                       printer(arg, "pcomp");\r
+                               }\r
+                               break;\r
+                       case CI_ACCOMPRESSION:\r
+                               if (olen == CILEN_VOID) {\r
+                                       p += 2;\r
+                                       printer(arg, "accomp");\r
+                               }\r
+                               break;\r
+                       }\r
+                       while (p < optend) {\r
+                               GETCHAR(code, p);\r
+                               printer(arg, " %.2x", code);\r
+                       }\r
+                       printer(arg, ">");\r
+               }\r
+               break;\r
+       \r
+       case TERMACK:\r
+       case TERMREQ:\r
+               if (len > 0 && *p >= ' ' && *p < 0x7f) {\r
+                       printer(arg, " ");\r
+                       print_string((char*)p, len, printer, arg);\r
+                       p += len;\r
+                       len = 0;\r
+               }\r
+               break;\r
+       \r
+       case ECHOREQ:\r
+       case ECHOREP:\r
+       case DISCREQ:\r
+               if (len >= 4) {\r
+                       GETLONG(cilong, p);\r
+                       printer(arg, " magic=0x%x", cilong);\r
+                       p += 4;\r
+                       len -= 4;\r
+               }\r
+               break;\r
+       }\r
+       \r
+       /* print the rest of the bytes in the packet */\r
+       for (; len > 0; --len) {\r
+               GETCHAR(code, p);\r
+               printer(arg, " %.2x", code);\r
+       }\r
+       \r
+       return (int)(p - pstart);\r
+}\r
+#endif\r
+\r
+/*\r
+ * Time to shut down the link because there is nothing out there.\r
+ */\r
+\r
+static void LcpLinkFailure (fsm *f)\r
+{\r
+       if (f->state == OPENED) {\r
+               LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending));\r
+               LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n"));\r
+               lcp_close(f->unit, "Peer not responding");\r
+       }\r
+}\r
+\r
+/*\r
+ * Timer expired for the LCP echo requests from this process.\r
+ */\r
+\r
+static void LcpEchoCheck (fsm *f)\r
+{\r
+       LcpSendEchoRequest (f);\r
+       \r
+       /*\r
+        * Start the timer for the next interval.\r
+        */\r
+       LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0);\r
+\r
+       TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);\r
+       lcp_echo_timer_running = 1;\r
+}\r
+\r
+/*\r
+ * LcpEchoTimeout - Timer expired on the LCP echo\r
+ */\r
+\r
+static void LcpEchoTimeout (void *arg)\r
+{\r
+       if (lcp_echo_timer_running != 0) {\r
+               lcp_echo_timer_running = 0;\r
+               LcpEchoCheck ((fsm *) arg);\r
+       }\r
+}\r
+\r
+/*\r
+ * LcpEchoReply - LCP has received a reply to the echo\r
+ */\r
+static void lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len)\r
+{\r
+       u32_t magic;\r
+       \r
+       (void)id;\r
+\r
+       /* Check the magic number - don't count replies from ourselves. */\r
+       if (len < 4) {\r
+               LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len));\r
+               return;\r
+       }\r
+       GETLONG(magic, inp);\r
+       if (lcp_gotoptions[f->unit].neg_magicnumber\r
+                       && magic == lcp_gotoptions[f->unit].magicnumber) {\r
+               LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n"));\r
+               return;\r
+       }\r
+       \r
+       /* Reset the number of outstanding echo frames */\r
+       lcp_echos_pending = 0;\r
+}\r
+\r
+/*\r
+ * LcpSendEchoRequest - Send an echo request frame to the peer\r
+ */\r
+\r
+static void LcpSendEchoRequest (fsm *f)\r
+{\r
+       u32_t lcp_magic;\r
+       u_char pkt[4], *pktp;\r
+       \r
+       /*\r
+       * Detect the failure of the peer at this point.\r
+       */\r
+       if (lcp_echo_fails != 0) {\r
+               if (lcp_echos_pending++ >= lcp_echo_fails) {\r
+                       LcpLinkFailure(f);\r
+                       lcp_echos_pending = 0;\r
+               }\r
+       }\r
+       \r
+       /*\r
+       * Make and send the echo request frame.\r
+       */\r
+       if (f->state == OPENED) {\r
+               lcp_magic = lcp_gotoptions[f->unit].magicnumber;\r
+               pktp = pkt;\r
+               PUTLONG(lcp_magic, pktp);\r
+               fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt));\r
+       }\r
+}\r
+\r
+/*\r
+ * lcp_echo_lowerup - Start the timer for the LCP frame\r
+ */\r
+\r
+static void lcp_echo_lowerup (int unit)\r
+{\r
+       fsm *f = &lcp_fsm[unit];\r
+       \r
+       /* Clear the parameters for generating echo frames */\r
+       lcp_echos_pending      = 0;\r
+       lcp_echo_number        = 0;\r
+       lcp_echo_timer_running = 0;\r
+       \r
+       /* If a timeout interval is specified then start the timer */\r
+       if (lcp_echo_interval != 0)\r
+               LcpEchoCheck (f);\r
+}\r
+\r
+/*\r
+ * lcp_echo_lowerdown - Stop the timer for the LCP frame\r
+ */\r
+\r
+static void lcp_echo_lowerdown (int unit)\r
+{\r
+       fsm *f = &lcp_fsm[unit];\r
+       \r
+       if (lcp_echo_timer_running != 0) {\r
+               UNTIMEOUT (LcpEchoTimeout, f);\r
+               lcp_echo_timer_running = 0;\r
+       }\r
+}\r
+\r
+#endif /* PPP_SUPPORT */\r
index 3876d39ae890439c4c3878c4de91d97ce7d5b492..2c0c34007762eb73afd05c4f6f19dbaf67b100fd 100644 (file)
-/*****************************************************************************
-* 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 */
-
+/*****************************************************************************\r
+* lcp.h - Network Link Control Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*      Original derived from BSD codes.\r
+*****************************************************************************/\r
+/*\r
+ * lcp.h - Link Control Protocol definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: lcp.h,v 1.1 2003/05/27 14:37:56 jani Exp $\r
+ */\r
+\r
+#ifndef LCP_H\r
+#define LCP_H\r
+\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+/*\r
+ * Options.\r
+ */\r
+#define CI_MRU         1       /* Maximum Receive Unit */\r
+#define CI_ASYNCMAP    2       /* Async Control Character Map */\r
+#define CI_AUTHTYPE    3       /* Authentication Type */\r
+#define CI_QUALITY     4       /* Quality Protocol */\r
+#define CI_MAGICNUMBER 5       /* Magic Number */\r
+#define CI_PCOMPRESSION        7       /* Protocol Field Compression */\r
+#define CI_ACCOMPRESSION 8     /* Address/Control Field Compression */\r
+#define CI_CALLBACK    13      /* callback */\r
+#define CI_MRRU                17      /* max reconstructed receive unit; multilink */\r
+#define CI_SSNHF       18      /* short sequence numbers for multilink */\r
+#define CI_EPDISC      19      /* endpoint discriminator */\r
+\r
+/*\r
+ * LCP-specific packet types.\r
+ */\r
+#define PROTREJ                8       /* Protocol Reject */\r
+#define ECHOREQ                9       /* Echo Request */\r
+#define ECHOREP                10      /* Echo Reply */\r
+#define DISCREQ                11      /* Discard Request */\r
+#define CBCP_OPT       6       /* Use callback control protocol */\r
+\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+/*\r
+ * The state of options is described by an lcp_options structure.\r
+ */\r
+typedef struct lcp_options {\r
+    u_int passive : 1;                 /* Don't die if we don't get a response */\r
+    u_int silent : 1;                          /* Wait for the other end to start first */\r
+    u_int restart : 1;                 /* Restart vs. exit after close */\r
+    u_int neg_mru : 1;                 /* Negotiate the MRU? */\r
+    u_int neg_asyncmap : 1;            /* Negotiate the async map? */\r
+    u_int neg_upap : 1;                        /* Ask for UPAP authentication? */\r
+    u_int neg_chap : 1;                        /* Ask for CHAP authentication? */\r
+    u_int neg_magicnumber : 1; /* Ask for magic number? */\r
+    u_int neg_pcompression : 1;        /* HDLC Protocol Field Compression? */\r
+    u_int neg_accompression : 1;       /* HDLC Address/Control Field Compression? */\r
+    u_int neg_lqr : 1;                 /* Negotiate use of Link Quality Reports */\r
+    u_int neg_cbcp : 1;                        /* Negotiate use of CBCP */\r
+#ifdef PPP_MULTILINK\r
+    u_int neg_mrru : 1;                        /* Negotiate multilink MRRU */\r
+    u_int neg_ssnhf : 1;               /* Negotiate short sequence numbers */\r
+    u_int neg_endpoint : 1;            /* Negotiate endpoint discriminator */\r
+#endif\r
+    u_short mru;                       /* Value of MRU */\r
+#ifdef PPP_MULTILINK\r
+    u_short mrru;                      /* Value of MRRU, and multilink enable */\r
+#endif\r
+    u_char chap_mdtype;                        /* which MD type (hashing algorithm) */\r
+    u32_t asyncmap;                    /* Value of async map */\r
+    u32_t magicnumber;\r
+    int numloops;                              /* Number of loops during magic number neg. */\r
+    u32_t lqr_period;          /* Reporting period for LQR 1/100ths second */\r
+#ifdef PPP_MULTILINK\r
+    struct epdisc endpoint;    /* endpoint discriminator */\r
+#endif\r
+} lcp_options;\r
+\r
+/*\r
+ * Values for phase from BSD pppd.h based on RFC 1661.\r
+ */\r
+typedef enum {\r
+       PHASE_DEAD = 0,\r
+       PHASE_INITIALIZE,\r
+       PHASE_ESTABLISH,\r
+       PHASE_AUTHENTICATE,\r
+       PHASE_CALLBACK,\r
+       PHASE_NETWORK,\r
+       PHASE_TERMINATE\r
+} LinkPhase;\r
+\r
+\r
+/*****************************\r
+*** PUBLIC DATA STRUCTURES ***\r
+*****************************/\r
+\r
+extern LinkPhase lcp_phase[NUM_PPP];   /* Phase of link session (RFC 1661) */\r
+extern lcp_options lcp_wantoptions[];\r
+extern lcp_options lcp_gotoptions[];\r
+extern lcp_options lcp_allowoptions[];\r
+extern lcp_options lcp_hisoptions[];\r
+extern ext_accm xmit_accm[];\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+void lcp_init (int);\r
+void lcp_open (int);\r
+void lcp_close (int, char *);\r
+void lcp_lowerup (int);\r
+void lcp_lowerdown (int);\r
+void lcp_sprotrej (int, u_char *, int);        /* send protocol reject */\r
+\r
+extern struct protent lcp_protent;\r
+\r
+/* Default number of times we receive our magic number from the peer\r
+   before deciding the link is looped-back. */\r
+#define DEFLOOPBACKFAIL        10\r
+\r
+#endif /* LCP_H */\r
+\r
index 427401691296a2bf56926fde59faf768e2127bf8..6e9d4753867a89cee2b0682ec0f549d8429410f4 100644 (file)
@@ -1,79 +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();
-}
-
-
+/*****************************************************************************\r
+* magic.c - Network Random Number Generator program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original based on BSD magic.c.\r
+*****************************************************************************/\r
+/*\r
+ * magic.c - PPP Magic Number routines.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "ppp.h"\r
+#include "randm.h"\r
+#include "magic.h"\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * magicInit - Initialize the magic number generator.\r
+ *\r
+ * Since we use another random number generator that has its own\r
+ * initialization, we do nothing here.\r
+ */\r
+void magicInit()\r
+{\r
+       return;\r
+}\r
+\r
+/*\r
+ * magic - Returns the next magic number.\r
+ */\r
+u32_t magic()\r
+{\r
+    return avRandom();\r
+}\r
+\r
+\r
index 7574f32b9f63cb57d7ceb71e1b61efe7049f4dae..6e9b10b58b956b8a263a2198fc4ea8abf9caa71f 100644 (file)
@@ -1,64 +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 */
+/*****************************************************************************\r
+* magic.h - Network Random Number Generator header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*   Original derived from BSD codes.\r
+*****************************************************************************/\r
+/*\r
+ * magic.h - PPP Magic Number definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: magic.h,v 1.1 2003/05/27 14:37:56 jani Exp $\r
+ */\r
+\r
+#ifndef MAGIC_H\r
+#define MAGIC_H\r
+\r
+/*****************************************************************************\r
+************************** PUBLIC FUNCTIONS **********************************\r
+*****************************************************************************/\r
+\r
+void magicInit(void);   /* Initialize the magic number generator */\r
+u32_t magic(void);  /* Returns the next magic number */\r
+\r
+#endif /* MAGIC_H */\r
index e077cdea5f922dd3a5ba8aa8d2f84abaeb65bb55..488d64af56d57900b263e183150ececd739d0e93 100644 (file)
-/*
- ***********************************************************************
- ** 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
-
+/*\r
+ ***********************************************************************\r
+ ** md5.c -- the source code for MD5 routines                         **\r
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **\r
+ ** Created: 2/17/90 RLR                                              **\r
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **\r
+ ***********************************************************************\r
+ */\r
+\r
+/*\r
+ ***********************************************************************\r
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **\r
+ **                                                                   **\r
+ ** License to copy and use this software is granted provided that    **\r
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **\r
+ ** Digest Algorithm" in all material mentioning or referencing this  **\r
+ ** software or this function.                                        **\r
+ **                                                                   **\r
+ ** License is also granted to make and use derivative works          **\r
+ ** provided that such works are identified as "derived from the RSA  **\r
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **\r
+ ** material mentioning or referencing the derived work.              **\r
+ **                                                                   **\r
+ ** RSA Data Security, Inc. makes no representations concerning       **\r
+ ** either the merchantability of this software or the suitability    **\r
+ ** of this software for any particular purpose.  It is provided "as  **\r
+ ** is" without express or implied warranty of any kind.              **\r
+ **                                                                   **\r
+ ** These notices must be retained in any copies of any part of this  **\r
+ ** documentation and/or software.                                    **\r
+ ***********************************************************************\r
+ */\r
+\r
+#include "ppp.h"\r
+#include "md5.h"\r
+#include "pppdebug.h"\r
+\r
+#if CHAP_SUPPORT > 0 || MD5_SUPPORT > 0\r
+\r
+/*\r
+ ***********************************************************************\r
+ **  Message-digest routines:                                         **\r
+ **  To form the message digest for a message M                       **\r
+ **    (1) Initialize a context buffer mdContext using MD5Init        **\r
+ **    (2) Call MD5Update on mdContext and M                          **\r
+ **    (3) Call MD5Final on mdContext                                 **\r
+ **  The message digest is now in mdContext->digest[0...15]           **\r
+ ***********************************************************************\r
+ */\r
+\r
+/* forward declaration */\r
+static void Transform (u32_t *buf, u32_t *in);\r
+\r
+static unsigned char PADDING[64] = {\r
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r
+};\r
+\r
+/* F, G, H and I are basic MD5 functions */\r
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))\r
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))\r
+#define H(x, y, z) ((x) ^ (y) ^ (z))\r
+#define I(x, y, z) ((y) ^ ((x) | (~z)))\r
+\r
+/* ROTATE_LEFT rotates x left n bits */\r
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))\r
+\r
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */\r
+/* Rotation is separate from addition to prevent recomputation */\r
+#define FF(a, b, c, d, x, s, ac) \\r
+  {(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \\r
+   (a) = ROTATE_LEFT ((a), (s)); \\r
+   (a) += (b); \\r
+  }\r
+#define GG(a, b, c, d, x, s, ac) \\r
+  {(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \\r
+   (a) = ROTATE_LEFT ((a), (s)); \\r
+   (a) += (b); \\r
+  }\r
+#define HH(a, b, c, d, x, s, ac) \\r
+  {(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \\r
+   (a) = ROTATE_LEFT ((a), (s)); \\r
+   (a) += (b); \\r
+  }\r
+#define II(a, b, c, d, x, s, ac) \\r
+  {(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \\r
+   (a) = ROTATE_LEFT ((a), (s)); \\r
+   (a) += (b); \\r
+  }\r
+\r
+#ifdef __STDC__\r
+#define UL(x)  x##UL\r
+#else\r
+#ifdef WIN32\r
+#define UL(x)  x##UL\r
+#else\r
+#define UL(x)  x\r
+#endif\r
+#endif\r
+\r
+/* The routine MD5Init initializes the message-digest context\r
+   mdContext. All fields are set to zero.\r
+ */\r
+void MD5Init (MD5_CTX *mdContext)\r
+{\r
+  mdContext->i[0] = mdContext->i[1] = (u32_t)0;\r
+\r
+  /* Load magic initialization constants.\r
+   */\r
+  mdContext->buf[0] = (u32_t)0x67452301UL;\r
+  mdContext->buf[1] = (u32_t)0xefcdab89UL;\r
+  mdContext->buf[2] = (u32_t)0x98badcfeUL;\r
+  mdContext->buf[3] = (u32_t)0x10325476UL;\r
+}\r
+\r
+/* The routine MD5Update updates the message-digest context to\r
+   account for the presence of each of the characters inBuf[0..inLen-1]\r
+   in the message whose digest is being computed.\r
+ */\r
+void MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)\r
+{\r
+  u32_t in[16];\r
+  int mdi;\r
+  unsigned int i, ii;\r
+\r
+#if 0\r
+  ppp_trace(LOG_INFO, "MD5Update: %u:%.*H\n", inLen, MIN(inLen, 20) * 2, inBuf);\r
+  ppp_trace(LOG_INFO, "MD5Update: %u:%s\n", inLen, inBuf);\r
+#endif\r
+  \r
+  /* compute number of bytes mod 64 */\r
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);\r
+\r
+  /* update number of bits */\r
+  if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0])\r
+    mdContext->i[1]++;\r
+  mdContext->i[0] += ((u32_t)inLen << 3);\r
+  mdContext->i[1] += ((u32_t)inLen >> 29);\r
+\r
+  while (inLen--) {\r
+    /* add new character to buffer, increment mdi */\r
+    mdContext->in[mdi++] = *inBuf++;\r
+\r
+    /* transform if necessary */\r
+    if (mdi == 0x40) {\r
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)\r
+        in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |\r
+                (((u32_t)mdContext->in[ii+2]) << 16) |\r
+                               (((u32_t)mdContext->in[ii+1]) << 8) |\r
+                ((u32_t)mdContext->in[ii]);\r
+      Transform (mdContext->buf, in);\r
+      mdi = 0;\r
+    }\r
+  }\r
+}\r
+\r
+/* The routine MD5Final terminates the message-digest computation and\r
+   ends with the desired message digest in mdContext->digest[0...15].\r
+ */\r
+void MD5Final (unsigned char hash[], MD5_CTX *mdContext)\r
+{\r
+  u32_t in[16];\r
+  int mdi;\r
+  unsigned int i, ii;\r
+  unsigned int padLen;\r
+\r
+  /* save number of bits */\r
+  in[14] = mdContext->i[0];\r
+  in[15] = mdContext->i[1];\r
+\r
+  /* compute number of bytes mod 64 */\r
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);\r
+\r
+  /* pad out to 56 mod 64 */\r
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);\r
+  MD5Update (mdContext, PADDING, padLen);\r
+\r
+  /* append length in bits and transform */\r
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)\r
+    in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |\r
+            (((u32_t)mdContext->in[ii+2]) << 16) |\r
+            (((u32_t)mdContext->in[ii+1]) << 8) |\r
+            ((u32_t)mdContext->in[ii]);\r
+  Transform (mdContext->buf, in);\r
+\r
+  /* store buffer in digest */\r
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {\r
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);\r
+       mdContext->digest[ii+1] =\r
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);\r
+    mdContext->digest[ii+2] =\r
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);\r
+    mdContext->digest[ii+3] =\r
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);\r
+  }\r
+  memcpy(hash, mdContext->digest, 16);\r
+}\r
+\r
+/* Basic MD5 step. Transforms buf based on in.\r
+ */\r
+static void Transform (u32_t *buf, u32_t *in)\r
+{\r
+  u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];\r
+\r
+  /* Round 1 */\r
+#define S11 7\r
+#define S12 12\r
+#define S13 17\r
+#define S14 22\r
+  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */\r
+  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */\r
+  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */\r
+  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */\r
+  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */\r
+  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */\r
+  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */\r
+  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */\r
+  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */\r
+  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */\r
+  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */\r
+  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */\r
+  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */\r
+  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */\r
+  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */\r
+  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */\r
+\r
+  /* Round 2 */\r
+#define S21 5\r
+#define S22 9\r
+#define S23 14\r
+#define S24 20\r
+  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */\r
+  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */\r
+  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */\r
+  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */\r
+  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */\r
+  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */\r
+  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */\r
+  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */\r
+  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */\r
+  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */\r
+  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */\r
+  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */\r
+  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */\r
+  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */\r
+  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */\r
+  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */\r
+\r
+  /* Round 3 */\r
+#define S31 4\r
+#define S32 11\r
+#define S33 16\r
+#define S34 23\r
+  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */\r
+  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */\r
+  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */\r
+  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */\r
+  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */\r
+  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */\r
+  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */\r
+  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */\r
+  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */\r
+  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */\r
+  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */\r
+  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */\r
+  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */\r
+  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */\r
+  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */\r
+  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */\r
+\r
+  /* Round 4 */\r
+#define S41 6\r
+#define S42 10\r
+#define S43 15\r
+#define S44 21\r
+  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */\r
+  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */\r
+  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */\r
+  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */\r
+  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */\r
+  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */\r
+  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */\r
+  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */\r
+  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */\r
+  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */\r
+  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */\r
+  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */\r
+  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */\r
+  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */\r
+  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */\r
+  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */\r
+\r
+  buf[0] += a;\r
+  buf[1] += b;\r
+  buf[2] += c;\r
+  buf[3] += d;\r
+}\r
+\r
+#endif\r
+\r
index 0e81cdc34bd8e7d6874fd853ade7e61a92871432..83d318cfba42f35ca6332d17cd3d9d5f9cf542b9 100644 (file)
@@ -1,55 +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 */
+/*\r
+ ***********************************************************************\r
+ ** md5.h -- header file for implementation of MD5                    **\r
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **\r
+ ** Created: 2/17/90 RLR                                              **\r
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **\r
+ ** Revised (for MD5): RLR 4/27/91                                    **\r
+ **   -- G modified to have y&~z instead of y&z                       **\r
+ **   -- FF, GG, HH modified to add in last register done             **\r
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **\r
+ **   -- distinct additive constant for each step                     **\r
+ **   -- round 4 added, working mod 7                                 **\r
+ ***********************************************************************\r
+ */\r
+\r
+/*\r
+ ***********************************************************************\r
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **\r
+ **                                                                   **\r
+ ** License to copy and use this software is granted provided that    **\r
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **\r
+ ** Digest Algorithm" in all material mentioning or referencing this  **\r
+ ** software or this function.                                        **\r
+ **                                                                   **\r
+ ** License is also granted to make and use derivative works          **\r
+ ** provided that such works are identified as "derived from the RSA  **\r
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **\r
+ ** material mentioning or referencing the derived work.              **\r
+ **                                                                   **\r
+ ** RSA Data Security, Inc. makes no representations concerning       **\r
+ ** either the merchantability of this software or the suitability    **\r
+ ** of this software for any particular purpose.  It is provided "as  **\r
+ ** is" without express or implied warranty of any kind.              **\r
+ **                                                                   **\r
+ ** These notices must be retained in any copies of any part of this  **\r
+ ** documentation and/or software.                                    **\r
+ ***********************************************************************\r
+ */\r
+\r
+#ifndef MD5_H\r
+#define MD5_H\r
+\r
+/* Data structure for MD5 (Message-Digest) computation */\r
+typedef struct {\r
+  u32_t i[2];                   /* number of _bits_ handled mod 2^64 */\r
+  u32_t buf[4];                                    /* scratch buffer */\r
+  unsigned char in[64];                              /* input buffer */\r
+  unsigned char digest[16];     /* actual digest after MD5Final call */\r
+} MD5_CTX;\r
+\r
+void MD5Init (MD5_CTX *mdContext);\r
+void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);\r
+void MD5Final (unsigned char hash[], MD5_CTX *mdContext);\r
+\r
+#endif /* MD5_H */\r
index 23e438ff2901b6b5cd397d44f3cdb06801875396..4b105ef3ecb5f55e28e774ed5e0bf850ad50cec9 100644 (file)
-/*****************************************************************************
-* 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 */
-
+/*****************************************************************************\r
+* pap.c - Network Password Authentication Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original.\r
+*****************************************************************************/\r
+/*\r
+ * upap.c - User/Password Authentication Protocol.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "ppp.h"\r
+#include "auth.h"\r
+#include "pap.h"\r
+#include "pppdebug.h"\r
+\r
+\r
+#if PAP_SUPPORT > 0\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+/*\r
+ * Protocol entry points.\r
+ */\r
+static void upap_init (int);\r
+static void upap_lowerup (int);\r
+static void upap_lowerdown (int);\r
+static void upap_input (int, u_char *, int);\r
+static void upap_protrej (int);\r
+\r
+static void upap_timeout (void *);\r
+static void upap_reqtimeout (void *);\r
+static void upap_rauthreq (upap_state *, u_char *, int, int);\r
+static void upap_rauthack (upap_state *, u_char *, int, int);\r
+static void upap_rauthnak (upap_state *, u_char *, int, int);\r
+static void upap_sauthreq (upap_state *);\r
+static void upap_sresp (upap_state *, u_char, u_char, char *, int);\r
+\r
+\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+struct protent pap_protent = {\r
+    PPP_PAP,\r
+    upap_init,\r
+    upap_input,\r
+    upap_protrej,\r
+    upap_lowerup,\r
+    upap_lowerdown,\r
+    NULL,\r
+    NULL,\r
+#if 0\r
+    upap_printpkt,\r
+    NULL,\r
+#endif\r
+    1,\r
+    "PAP",\r
+#if 0\r
+    NULL,\r
+    NULL,\r
+    NULL\r
+#endif\r
+};\r
+\r
+upap_state upap[NUM_PPP];              /* UPAP state; one for each unit */\r
+\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ *  Set the default login name and password for the pap sessions\r
+ */\r
+void upap_setloginpasswd(int unit, const char *luser, const char *lpassword)\r
+{\r
+       upap_state *u = &upap[unit];\r
+       \r
+       /* Save the username and password we're given */\r
+       u->us_user = luser;\r
+       u->us_userlen = strlen(luser);\r
+       u->us_passwd = lpassword;\r
+       u->us_passwdlen = strlen(lpassword);\r
+}\r
+\r
+\r
+/*\r
+ * upap_authwithpeer - Authenticate us with our peer (start client).\r
+ *\r
+ * Set new state and send authenticate's.\r
+ */\r
+void upap_authwithpeer(int unit, char *user, char *password)\r
+{\r
+       upap_state *u = &upap[unit];\r
+       \r
+       UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n",\r
+                               unit, user, password, u->us_clientstate));\r
+       \r
+       upap_setloginpasswd(unit, user, password);\r
+\r
+       u->us_transmits = 0;\r
+       \r
+       /* Lower layer up yet? */\r
+       if (u->us_clientstate == UPAPCS_INITIAL ||\r
+                       u->us_clientstate == UPAPCS_PENDING) {\r
+               u->us_clientstate = UPAPCS_PENDING;\r
+               return;\r
+       }\r
+       \r
+       upap_sauthreq(u);                       /* Start protocol */\r
+}\r
+\r
+\r
+/*\r
+ * upap_authpeer - Authenticate our peer (start server).\r
+ *\r
+ * Set new state.\r
+ */\r
+void upap_authpeer(int unit)\r
+{\r
+       upap_state *u = &upap[unit];\r
+       \r
+       /* Lower layer up yet? */\r
+       if (u->us_serverstate == UPAPSS_INITIAL ||\r
+                       u->us_serverstate == UPAPSS_PENDING) {\r
+               u->us_serverstate = UPAPSS_PENDING;\r
+               return;\r
+       }\r
+       \r
+       u->us_serverstate = UPAPSS_LISTEN;\r
+       if (u->us_reqtimeout > 0)\r
+               TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);\r
+}\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/*\r
+ * upap_init - Initialize a UPAP unit.\r
+ */\r
+static void upap_init(int unit)\r
+{\r
+       upap_state *u = &upap[unit];\r
+\r
+       UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit)); \r
+       u->us_unit = unit;\r
+       u->us_user = NULL;\r
+       u->us_userlen = 0;\r
+       u->us_passwd = NULL;\r
+       u->us_passwdlen = 0;\r
+       u->us_clientstate = UPAPCS_INITIAL;\r
+       u->us_serverstate = UPAPSS_INITIAL;\r
+       u->us_id = 0;\r
+       u->us_timeouttime = UPAP_DEFTIMEOUT;\r
+       u->us_maxtransmits = 10;\r
+       u->us_reqtimeout = UPAP_DEFREQTIME;\r
+}\r
+\r
+/*\r
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.\r
+ */\r
+static void upap_timeout(void *arg)\r
+{\r
+       upap_state *u = (upap_state *) arg;\r
+       \r
+       UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n", \r
+                               u->us_unit, u->us_timeouttime, u->us_clientstate));\r
+       \r
+       if (u->us_clientstate != UPAPCS_AUTHREQ)\r
+               return;\r
+       \r
+       if (u->us_transmits >= u->us_maxtransmits) {\r
+               /* give up in disgust */\r
+               UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n"));\r
+               u->us_clientstate = UPAPCS_BADAUTH;\r
+               auth_withpeer_fail(u->us_unit, PPP_PAP);\r
+               return;\r
+       }\r
+       \r
+       upap_sauthreq(u);               /* Send Authenticate-Request */\r
+}\r
+\r
+\r
+/*\r
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.\r
+ */\r
+static void upap_reqtimeout(void *arg)\r
+{\r
+       upap_state *u = (upap_state *) arg;\r
+       \r
+       if (u->us_serverstate != UPAPSS_LISTEN)\r
+               return;                 /* huh?? */\r
+       \r
+       auth_peer_fail(u->us_unit, PPP_PAP);\r
+       u->us_serverstate = UPAPSS_BADAUTH;\r
+}\r
+\r
+\r
+/*\r
+ * upap_lowerup - The lower layer is up.\r
+ *\r
+ * Start authenticating if pending.\r
+ */\r
+static void upap_lowerup(int unit)\r
+{\r
+       upap_state *u = &upap[unit];\r
+       \r
+       UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate));\r
+       \r
+       if (u->us_clientstate == UPAPCS_INITIAL)\r
+               u->us_clientstate = UPAPCS_CLOSED;\r
+       else if (u->us_clientstate == UPAPCS_PENDING) {\r
+               upap_sauthreq(u);       /* send an auth-request */\r
+       }\r
+       \r
+       if (u->us_serverstate == UPAPSS_INITIAL)\r
+               u->us_serverstate = UPAPSS_CLOSED;\r
+       else if (u->us_serverstate == UPAPSS_PENDING) {\r
+               u->us_serverstate = UPAPSS_LISTEN;\r
+               if (u->us_reqtimeout > 0)\r
+                       TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * upap_lowerdown - The lower layer is down.\r
+ *\r
+ * Cancel all timeouts.\r
+ */\r
+static void upap_lowerdown(int unit)\r
+{\r
+       upap_state *u = &upap[unit];\r
+       \r
+       UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate));\r
+       \r
+       if (u->us_clientstate == UPAPCS_AUTHREQ)        /* Timeout pending? */\r
+               UNTIMEOUT(upap_timeout, u);             /* Cancel timeout */\r
+       if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)\r
+               UNTIMEOUT(upap_reqtimeout, u);\r
+       \r
+       u->us_clientstate = UPAPCS_INITIAL;\r
+       u->us_serverstate = UPAPSS_INITIAL;\r
+}\r
+\r
+\r
+/*\r
+ * upap_protrej - Peer doesn't speak this protocol.\r
+ *\r
+ * This shouldn't happen.  In any case, pretend lower layer went down.\r
+ */\r
+static void upap_protrej(int unit)\r
+{\r
+       upap_state *u = &upap[unit];\r
+       \r
+       if (u->us_clientstate == UPAPCS_AUTHREQ) {\r
+               UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n"));\r
+               auth_withpeer_fail(unit, PPP_PAP);\r
+       }\r
+       if (u->us_serverstate == UPAPSS_LISTEN) {\r
+               UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n"));\r
+               auth_peer_fail(unit, PPP_PAP);\r
+       }\r
+       upap_lowerdown(unit);\r
+}\r
+\r
+\r
+/*\r
+ * upap_input - Input UPAP packet.\r
+ */\r
+static void upap_input(int unit, u_char *inpacket, int l)\r
+{\r
+       upap_state *u = &upap[unit];\r
+       u_char *inp;\r
+       u_char code, id;\r
+       int len;\r
+       \r
+       /*\r
+        * Parse header (code, id and length).\r
+        * If packet too short, drop it.\r
+        */\r
+       inp = inpacket;\r
+       if (l < UPAP_HEADERLEN) {\r
+               UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n"));\r
+               return;\r
+       }\r
+       GETCHAR(code, inp);\r
+       GETCHAR(id, inp);\r
+       GETSHORT(len, inp);\r
+       if (len < UPAP_HEADERLEN) {\r
+               UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n"));\r
+               return;\r
+       }\r
+       if (len > l) {\r
+               UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       len -= UPAP_HEADERLEN;\r
+       \r
+       /*\r
+        * Action depends on code.\r
+        */\r
+       switch (code) {\r
+       case UPAP_AUTHREQ:\r
+               upap_rauthreq(u, inp, id, len);\r
+               break;\r
+       \r
+       case UPAP_AUTHACK:\r
+               upap_rauthack(u, inp, id, len);\r
+               break;\r
+       \r
+       case UPAP_AUTHNAK:\r
+               upap_rauthnak(u, inp, id, len);\r
+               break;\r
+       \r
+       default:                                /* XXX Need code reject */\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * upap_rauth - Receive Authenticate.\r
+ */\r
+static void upap_rauthreq(\r
+       upap_state *u, \r
+       u_char *inp, \r
+       int id,\r
+       int len\r
+)\r
+{\r
+       u_char ruserlen, rpasswdlen;\r
+       char *ruser, *rpasswd;\r
+       int retcode;\r
+       char *msg;\r
+       int msglen;\r
+       \r
+       UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id));\r
+       \r
+       if (u->us_serverstate < UPAPSS_LISTEN)\r
+               return;\r
+       \r
+       /*\r
+        * If we receive a duplicate authenticate-request, we are\r
+        * supposed to return the same status as for the first request.\r
+        */\r
+       if (u->us_serverstate == UPAPSS_OPEN) {\r
+               upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */\r
+               return;\r
+       }\r
+       if (u->us_serverstate == UPAPSS_BADAUTH) {\r
+               upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */\r
+               return;\r
+       }\r
+       \r
+       /*\r
+        * Parse user/passwd.\r
+        */\r
+       if (len < sizeof (u_char)) {\r
+               UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       GETCHAR(ruserlen, inp);\r
+       len -= sizeof (u_char) + ruserlen + sizeof (u_char);\r
+       if (len < 0) {\r
+               UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       ruser = (char *) inp;\r
+       INCPTR(ruserlen, inp);\r
+       GETCHAR(rpasswdlen, inp);\r
+       if (len < rpasswdlen) {\r
+               UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       rpasswd = (char *) inp;\r
+       \r
+       /*\r
+        * Check the username and password given.\r
+        */\r
+       retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,\r
+                          rpasswdlen, &msg, &msglen);\r
+       BZERO(rpasswd, rpasswdlen);\r
+       \r
+       upap_sresp(u, retcode, id, msg, msglen);\r
+       \r
+       if (retcode == UPAP_AUTHACK) {\r
+               u->us_serverstate = UPAPSS_OPEN;\r
+               auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);\r
+       } else {\r
+               u->us_serverstate = UPAPSS_BADAUTH;\r
+               auth_peer_fail(u->us_unit, PPP_PAP);\r
+       }\r
+       \r
+       if (u->us_reqtimeout > 0)\r
+               UNTIMEOUT(upap_reqtimeout, u);\r
+}\r
+\r
+\r
+/*\r
+ * upap_rauthack - Receive Authenticate-Ack.\r
+ */\r
+static void upap_rauthack(\r
+       upap_state *u,\r
+       u_char *inp,\r
+       int id,\r
+       int len\r
+)\r
+{\r
+       u_char msglen;\r
+       char *msg;\r
+       \r
+       UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate));\r
+       \r
+       if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */\r
+               return;\r
+       \r
+       /*\r
+        * Parse message.\r
+        */\r
+       if (len < sizeof (u_char)) {\r
+               UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       GETCHAR(msglen, inp);\r
+       len -= sizeof (u_char);\r
+       if (len < msglen) {\r
+               UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       msg = (char *) inp;\r
+       PRINTMSG(msg, msglen);\r
+       \r
+       u->us_clientstate = UPAPCS_OPEN;\r
+       \r
+       auth_withpeer_success(u->us_unit, PPP_PAP);\r
+}\r
+\r
+\r
+/*\r
+ * upap_rauthnak - Receive Authenticate-Nakk.\r
+ */\r
+static void upap_rauthnak(\r
+       upap_state *u,\r
+       u_char *inp,\r
+       int id,\r
+       int len\r
+)\r
+{\r
+       u_char msglen;\r
+       char *msg;\r
+       \r
+       UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));\r
+       \r
+       if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */\r
+               return;\r
+       \r
+       /*\r
+        * Parse message.\r
+        */\r
+       if (len < sizeof (u_char)) {\r
+               UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       GETCHAR(msglen, inp);\r
+       len -= sizeof (u_char);\r
+       if (len < msglen) {\r
+               UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));\r
+               return;\r
+       }\r
+       msg = (char *) inp;\r
+       PRINTMSG(msg, msglen);\r
+       \r
+       u->us_clientstate = UPAPCS_BADAUTH;\r
+       \r
+       UPAPDEBUG((LOG_ERR, "PAP authentication failed\n"));\r
+       auth_withpeer_fail(u->us_unit, PPP_PAP);\r
+}\r
+\r
+\r
+/*\r
+ * upap_sauthreq - Send an Authenticate-Request.\r
+ */\r
+static void upap_sauthreq(upap_state *u)\r
+{\r
+       u_char *outp;\r
+       int outlen;\r
+       \r
+       outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) \r
+                       + u->us_userlen + u->us_passwdlen;\r
+       outp = outpacket_buf[u->us_unit];\r
+       \r
+       MAKEHEADER(outp, PPP_PAP);\r
+       \r
+       PUTCHAR(UPAP_AUTHREQ, outp);\r
+       PUTCHAR(++u->us_id, outp);\r
+       PUTSHORT(outlen, outp);\r
+       PUTCHAR(u->us_userlen, outp);\r
+       BCOPY(u->us_user, outp, u->us_userlen);\r
+       INCPTR(u->us_userlen, outp);\r
+       PUTCHAR(u->us_passwdlen, outp);\r
+       BCOPY(u->us_passwd, outp, u->us_passwdlen);\r
+       \r
+       pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);\r
+       \r
+       UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id));\r
+       \r
+       TIMEOUT(upap_timeout, u, u->us_timeouttime);\r
+       ++u->us_transmits;\r
+       u->us_clientstate = UPAPCS_AUTHREQ;\r
+}\r
+\r
+\r
+/*\r
+ * upap_sresp - Send a response (ack or nak).\r
+ */\r
+static void upap_sresp(\r
+       upap_state *u,\r
+       u_char code, \r
+       u_char id,\r
+       char *msg,\r
+       int msglen\r
+)\r
+{\r
+       u_char *outp;\r
+       int outlen;\r
+       \r
+       outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;\r
+       outp = outpacket_buf[u->us_unit];\r
+       MAKEHEADER(outp, PPP_PAP);\r
+       \r
+       PUTCHAR(code, outp);\r
+       PUTCHAR(id, outp);\r
+       PUTSHORT(outlen, outp);\r
+       PUTCHAR(msglen, outp);\r
+       BCOPY(msg, outp, msglen);\r
+       pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);\r
+       \r
+       UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n", \r
+                               code, id, u->us_clientstate));\r
+}\r
+\r
+#if 0\r
+/*\r
+ * upap_printpkt - print the contents of a PAP packet.\r
+ */\r
+static int upap_printpkt(\r
+       u_char *p,\r
+       int plen,\r
+       void (*printer) (void *, char *, ...),\r
+       void *arg\r
+)\r
+{\r
+       (void)p;\r
+       (void)plen;\r
+       (void)printer;\r
+       (void)arg;\r
+       return 0;\r
+}\r
+#endif\r
+\r
+#endif /* PAP_SUPPORT */\r
+\r
index 5295f6a0310b70f57e213d273a8f27ea17c156fa..afd4116bc78f96a1232fe14f7b9a7a228c716f4e 100644 (file)
-/*****************************************************************************
-* 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 */
+/*****************************************************************************\r
+* ppp.c - Network Point to Point Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original.\r
+*****************************************************************************/\r
+\r
+/*\r
+ * ppp_defs.h - PPP definitions.\r
+ *\r
+ * if_pppvar.h - private structures and declarations for PPP.\r
+ *\r
+ * Copyright (c) 1994 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software and its\r
+ * documentation is hereby granted, provided that the above copyright\r
+ * notice appears in all copies.  This software is provided without any\r
+ * warranty, express or implied. The Australian National University\r
+ * makes no representations about the suitability of this software for\r
+ * any purpose.\r
+ *\r
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY\r
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\r
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF\r
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,\r
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\r
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS\r
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO\r
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,\r
+ * OR MODIFICATIONS.\r
+ */\r
+\r
+/*\r
+ * if_ppp.h - Point-to-Point Protocol definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
\r
+#include <string.h>\r
\r
+#include "ppp.h"\r
+#if PPP_SUPPORT > 0\r
+#include "randm.h"\r
+#include "fsm.h"\r
+#if PAP_SUPPORT > 0\r
+#include "pap.h"\r
+#endif\r
+#if CHAP_SUPPORT > 0\r
+#include "chap.h"\r
+#endif\r
+#include "ipcp.h"\r
+#include "lcp.h"\r
+#include "magic.h"\r
+#include "auth.h"\r
+#if VJ_SUPPORT > 0\r
+#include "vj.h"\r
+#endif\r
+\r
+#include "pppdebug.h"\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+/*\r
+ * The basic PPP frame.\r
+ */\r
+#define PPP_ADDRESS(p)  (((u_char *)(p))[0])\r
+#define PPP_CONTROL(p)  (((u_char *)(p))[1])\r
+#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])\r
+\r
+/* PPP packet parser states.  Current state indicates operation yet to be\r
+ * completed. */\r
+typedef enum {\r
+    PDIDLE = 0,                 /* Idle state - waiting. */\r
+    PDSTART,                    /* Process start flag. */\r
+    PDADDRESS,                  /* Process address field. */\r
+    PDCONTROL,                  /* Process control field. */\r
+    PDPROTOCOL1,                /* Process protocol field 1. */\r
+    PDPROTOCOL2,                /* Process protocol field 2. */\r
+    PDDATA                      /* Process data byte. */\r
+} PPPDevStates;\r
+\r
+#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+/*\r
+ * PPP interface control block.\r
+ */\r
+typedef struct PPPControl_s {\r
+    char openFlag;                      /* True when in use. */\r
+    char oldFrame;                      /* Old framing character for fd. */\r
+    sio_fd_t fd;                    /* File device ID of port. */\r
+    int  kill_link;                     /* Shut the link down. */\r
+    int  sig_hup;                       /* Carrier lost. */\r
+    int  if_up;                         /* True when the interface is up. */\r
+    int  errCode;                       /* Code indicating why interface is down. */\r
+    struct pbuf *inHead, *inTail;       /* The input packet. */\r
+    PPPDevStates inState;               /* The input process state. */\r
+    char inEscaped;                     /* Escape next character. */\r
+    u16_t inProtocol;                   /* The input protocol code. */\r
+    u16_t inFCS;                        /* Input Frame Check Sequence value. */\r
+    int  mtu;                           /* Peer's mru */\r
+    int  pcomp;                         /* Does peer accept protocol compression? */\r
+    int  accomp;                        /* Does peer accept addr/ctl compression? */\r
+    u_long lastXMit;                    /* Time of last transmission. */\r
+    ext_accm inACCM;                    /* Async-Ctl-Char-Map for input. */\r
+    ext_accm outACCM;                   /* Async-Ctl-Char-Map for output. */\r
+#if VJ_SUPPORT > 0\r
+    int  vjEnabled;                     /* Flag indicating VJ compression enabled. */\r
+    struct vjcompress vjComp;           /* Van Jabobsen compression header. */\r
+#endif\r
+\r
+    struct netif netif;\r
+\r
+    struct ppp_addrs addrs;\r
+\r
+    void (*linkStatusCB)(void *ctx, int errCode, void *arg);\r
+    void *linkStatusCtx;\r
+\r
+} PPPControl;\r
+\r
+\r
+/*\r
+ * Ioctl definitions.\r
+ */\r
+\r
+struct npioctl {\r
+    int     protocol;           /* PPP procotol, e.g. PPP_IP */\r
+    enum NPmode mode;\r
+};\r
+\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+static void pppMain(void *pd);\r
+static void pppDrop(PPPControl *pc);\r
+static void pppInProc(int pd, u_char *s, int l);\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+u_long subnetMask;\r
+\r
+static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */\r
+\r
+/*\r
+ * PPP Data Link Layer "protocol" table.\r
+ * One entry per supported protocol.\r
+ * The last entry must be NULL.\r
+ */\r
+struct protent *ppp_protocols[] = {\r
+    &lcp_protent,\r
+#if PAP_SUPPORT > 0\r
+    &pap_protent,\r
+#endif\r
+#if CHAP_SUPPORT > 0\r
+    &chap_protent,\r
+#endif\r
+#if CBCP_SUPPORT > 0\r
+    &cbcp_protent,\r
+#endif\r
+    &ipcp_protent,\r
+#if CCP_SUPPORT > 0\r
+    &ccp_protent,\r
+#endif\r
+    NULL\r
+};\r
+\r
+\r
+/*\r
+ * Buffers for outgoing packets.  This must be accessed only from the appropriate\r
+ * PPP task so that it doesn't need to be protected to avoid collisions.\r
+ */\r
+u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];  \r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+\r
+/*\r
+ * FCS lookup table as calculated by genfcstab.\r
+ */\r
+static const u_short fcstab[256] = {\r
+    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,\r
+    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,\r
+    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,\r
+    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,\r
+    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,\r
+    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,\r
+    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,\r
+    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,\r
+    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,\r
+    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,\r
+    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,\r
+    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,\r
+    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,\r
+    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,\r
+    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,\r
+    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,\r
+    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,\r
+    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,\r
+    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,\r
+    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,\r
+    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,\r
+    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,\r
+    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,\r
+    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,\r
+    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,\r
+    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,\r
+    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,\r
+    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,\r
+    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,\r
+    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,\r
+    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,\r
+    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78\r
+};\r
+\r
+/* PPP's Asynchronous-Control-Character-Map.  The mask array is used\r
+ * to select the specific bit for a character. */\r
+static u_char pppACCMMask[] = {\r
+    0x01,\r
+    0x02,\r
+    0x04,\r
+    0x08,\r
+    0x10,\r
+    0x20,\r
+    0x40,\r
+    0x80\r
+};\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/* Initialize the PPP subsystem. */\r
+\r
+struct ppp_settings ppp_settings;\r
+\r
+void pppInit(void)\r
+{\r
+    struct protent *protp;\r
+    int i, j;\r
+    \r
+       memset(&ppp_settings, 0, sizeof(ppp_settings));\r
+       ppp_settings.usepeerdns = 1;\r
+       pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);\r
+\r
+       magicInit();\r
+\r
+    for (i = 0; i < NUM_PPP; i++) {\r
+        pppControl[i].openFlag = 0;\r
+\r
+               subnetMask = htonl(0xffffff00);\r
+    \r
+        /*\r
+         * Initialize to the standard option set.\r
+         */\r
+        for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j)\r
+            (*protp->init)(i);\r
+    }\r
+\r
+#if LINK_STATS\r
+    /* Clear the statistics. */\r
+    memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));\r
+#endif\r
+}\r
+\r
+void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)\r
+{\r
+    switch(authType) {\r
+       case PPPAUTHTYPE_NONE:\r
+       default:\r
+#ifdef LWIP_PPP_STRICT_PAP_REJECT\r
+           ppp_settings.refuse_pap = 1;\r
+#else\r
+           /* some providers request pap and accept an empty login/pw */\r
+           ppp_settings.refuse_pap = 0;\r
+#endif\r
+           ppp_settings.refuse_chap = 1;\r
+           break;\r
+       case PPPAUTHTYPE_ANY:\r
+/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.\r
+ * RFC 1994 says:\r
+ *\r
+ * In practice, within or associated with each PPP server, there is a\r
+ * database which associates "user" names with authentication\r
+ * information ("secrets").  It is not anticipated that a particular\r
+ * named user would be authenticated by multiple methods.  This would\r
+ * make the user vulnerable to attacks which negotiate the least secure\r
+ * method from among a set (such as PAP rather than CHAP).  If the same\r
+ * secret was used, PAP would reveal the secret to be used later with\r
+ * CHAP.\r
+ *\r
+ * Instead, for each user name there should be an indication of exactly\r
+ * one method used to authenticate that user name.  If a user needs to\r
+ * make use of different authentication methods under different\r
+ * circumstances, then distinct user names SHOULD be employed, each of\r
+ * which identifies exactly one authentication method.\r
+ *\r
+ */\r
+           ppp_settings.refuse_pap = 0;\r
+           ppp_settings.refuse_chap = 0;\r
+           break;\r
+       case PPPAUTHTYPE_PAP:\r
+           ppp_settings.refuse_pap = 0;\r
+           ppp_settings.refuse_chap = 1;\r
+           break;\r
+       case PPPAUTHTYPE_CHAP:\r
+           ppp_settings.refuse_pap = 1;\r
+           ppp_settings.refuse_chap = 0;\r
+           break;\r
+    }\r
+\r
+    if(user) {\r
+       strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);\r
+       ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';\r
+    } else\r
+       ppp_settings.user[0] = '\0';\r
+\r
+    if(passwd) {\r
+       strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);\r
+       ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';\r
+    } else\r
+       ppp_settings.passwd[0] = '\0';\r
+}\r
+\r
+/* Open a new PPP connection using the given I/O device.\r
+ * This initializes the PPP control block but does not\r
+ * attempt to negotiate the LCP session.  If this port\r
+ * connects to a modem, the modem connection must be\r
+ * established before calling this.\r
+ * Return a new PPP connection descriptor on success or\r
+ * an error code (negative) on failure. */\r
+int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)\r
+{\r
+    PPPControl *pc;\r
+    int pd;\r
+\r
+    /* Find a free PPP session descriptor. Critical region? */\r
+    for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);\r
+    if (pd >= NUM_PPP)\r
+        pd = PPPERR_OPEN;\r
+    else\r
+        pppControl[pd].openFlag = !0;\r
+\r
+    /* Launch a deamon thread. */\r
+    if (pd >= 0) {\r
+\r
+        pppControl[pd].openFlag = 1;\r
+\r
+        lcp_init(pd);\r
+        pc = &pppControl[pd];\r
+        pc->fd = fd;\r
+        pc->kill_link = 0;\r
+        pc->sig_hup = 0;\r
+        pc->if_up = 0;\r
+        pc->errCode = 0;\r
+        pc->inState = PDIDLE;\r
+        pc->inHead = NULL;\r
+        pc->inTail = NULL;\r
+        pc->inEscaped = 0;\r
+        pc->lastXMit = 0;\r
+\r
+#if VJ_SUPPORT > 0\r
+        pc->vjEnabled = 0;\r
+        vj_compress_init(&pc->vjComp);\r
+#endif\r
+\r
+        /* \r
+         * Default the in and out accm so that escape and flag characters\r
+         * are always escaped. \r
+         */\r
+        memset(pc->inACCM, 0, sizeof(ext_accm));\r
+        pc->inACCM[15] = 0x60;\r
+        memset(pc->outACCM, 0, sizeof(ext_accm));\r
+        pc->outACCM[15] = 0x60;\r
+\r
+       pc->linkStatusCB = linkStatusCB;\r
+       pc->linkStatusCtx = linkStatusCtx;\r
+\r
+       sys_thread_new(pppMain, (void*)pd, PPP_THREAD_PRIO);\r
+       if(!linkStatusCB) {\r
+               while(pd >= 0 && !pc->if_up) {\r
+                       sys_msleep(500);\r
+                       if (lcp_phase[pd] == PHASE_DEAD) {\r
+                               pppClose(pd);\r
+                               if (pc->errCode)\r
+                                       pd = pc->errCode;\r
+                               else\r
+                                       pd = PPPERR_CONNECT;\r
+                       }\r
+               }\r
+       }\r
+    }\r
+    return pd;\r
+}\r
+\r
+/* Close a PPP connection and release the descriptor. \r
+ * Any outstanding packets in the queues are dropped.\r
+ * Return 0 on success, an error code on failure. */\r
+int pppClose(int pd)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    int st = 0;\r
+\r
+    /* Disconnect */\r
+    pc->kill_link = !0;\r
+    pppMainWakeup(pd);\r
+    \r
+    if(!pc->linkStatusCB) {\r
+           while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {\r
+                   sys_msleep(500);\r
+                   break;\r
+           }\r
+    }\r
+    return st;\r
+}\r
+\r
+/* This function is called when carrier is lost on the PPP channel. */\r
+void pppSigHUP(int pd)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+\r
+    pc->sig_hup = 1;\r
+    pppMainWakeup(pd);\r
+}\r
+\r
+static void nPut(PPPControl *pc, struct pbuf *nb)\r
+{\r
+       struct pbuf *b;\r
+       int c;\r
+\r
+       for(b = nb; b != NULL; b = b->next) {\r
+           if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {\r
+               PPPDEBUG((LOG_WARNING,\r
+                           "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c));\r
+#if LINK_STATS\r
+               lwip_stats.link.err++;\r
+#endif /* LINK_STATS */\r
+               pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */\r
+               break;\r
+           }\r
+       }\r
+       pbuf_free(nb);\r
+\r
+#if LINK_STATS\r
+       lwip_stats.link.xmit++;\r
+#endif /* LINK_STATS */\r
+}\r
+\r
+/* \r
+ * pppAppend - append given character to end of given pbuf.  If outACCM\r
+ * is not NULL and the character needs to be escaped, do so.\r
+ * If pbuf is full, append another.\r
+ * Return the current pbuf.\r
+ */\r
+static struct pbuf *pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)\r
+{\r
+    struct pbuf *tb = nb;\r
+    \r
+    /* Make sure there is room for the character and an escape code.\r
+     * Sure we don't quite fill the buffer if the character doesn't\r
+     * get escaped but is one character worth complicating this? */\r
+    /* Note: We assume no packet header. */\r
+    if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {\r
+       tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);\r
+       if (tb) {\r
+           nb->next = tb;\r
+        }\r
+#if LINK_STATS\r
+       else {\r
+           lwip_stats.link.memerr++;\r
+       }\r
+#endif /* LINK_STATS */\r
+       nb = tb;\r
+    }\r
+    if (nb) {\r
+       if (outACCM && ESCAPE_P(*outACCM, c)) {\r
+            *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;\r
+            *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;\r
+        }\r
+        else\r
+            *((u_char*)nb->payload + nb->len++) = c;\r
+    }\r
+        \r
+    return tb;\r
+}\r
+\r
+/* Send a packet on the given connection. */\r
+static err_t pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)\r
+{\r
+    int pd = (int)netif->state;\r
+    u_short protocol = PPP_IP;\r
+    PPPControl *pc = &pppControl[pd];\r
+    u_int fcsOut = PPP_INITFCS;\r
+    struct pbuf *headMB = NULL, *tailMB = NULL, *p;\r
+    u_char c;\r
+\r
+    (void)ipaddr;\r
+\r
+    /* Validate parameters. */\r
+    /* We let any protocol value go through - it can't hurt us\r
+     * and the peer will just drop it if it's not accepting it. */\r
+       if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {\r
+        PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",\r
+                    pd, protocol, pb));\r
+#if LINK_STATS\r
+               lwip_stats.link.opterr++;\r
+               lwip_stats.link.drop++;\r
+#endif\r
+               return ERR_ARG;\r
+       }\r
+\r
+    /* Check that the link is up. */\r
+       if (lcp_phase[pd] == PHASE_DEAD) {\r
+        PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd));\r
+#if LINK_STATS\r
+               lwip_stats.link.rterr++;\r
+               lwip_stats.link.drop++;\r
+#endif\r
+               return ERR_RTE;\r
+       }\r
+\r
+    /* Grab an output buffer. */\r
+       headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);\r
+    if (headMB == NULL) {\r
+        PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd));\r
+#if LINK_STATS\r
+               lwip_stats.link.memerr++;\r
+               lwip_stats.link.drop++;\r
+#endif /* LINK_STATS */\r
+        return ERR_MEM;\r
+    }\r
+        \r
+#if VJ_SUPPORT > 0\r
+    /* \r
+     * Attempt Van Jacobson header compression if VJ is configured and\r
+     * this is an IP packet. \r
+     */\r
+    if (protocol == PPP_IP && pc->vjEnabled) {\r
+        switch (vj_compress_tcp(&pc->vjComp, pb)) {\r
+        case TYPE_IP:\r
+            /* No change...\r
+            protocol = PPP_IP_PROTOCOL;\r
+             */\r
+            break;\r
+        case TYPE_COMPRESSED_TCP:\r
+            protocol = PPP_VJC_COMP;\r
+            break;\r
+        case TYPE_UNCOMPRESSED_TCP:\r
+            protocol = PPP_VJC_UNCOMP;\r
+            break;\r
+        default:\r
+            PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));\r
+#if LINK_STATS\r
+                       lwip_stats.link.proterr++;\r
+                       lwip_stats.link.drop++;\r
+#endif\r
+               pbuf_free(headMB);\r
+            return ERR_VAL;\r
+        }\r
+    }\r
+#endif\r
+        \r
+    tailMB = headMB;\r
+        \r
+    /* Build the PPP header. */\r
+    if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)\r
+        tailMB = pppAppend(PPP_FLAG, tailMB, NULL);\r
+    pc->lastXMit = sys_jiffies();\r
+    if (!pc->accomp) {\r
+        fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);\r
+        tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);\r
+        fcsOut = PPP_FCS(fcsOut, PPP_UI);\r
+        tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);\r
+    }\r
+    if (!pc->pcomp || protocol > 0xFF) {\r
+        c = (protocol >> 8) & 0xFF;\r
+        fcsOut = PPP_FCS(fcsOut, c);\r
+        tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+    }\r
+    c = protocol & 0xFF;\r
+    fcsOut = PPP_FCS(fcsOut, c);\r
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+    \r
+    /* Load packet. */\r
+       for(p = pb; p; p = p->next) {\r
+       int n;\r
+       u_char *sPtr;\r
+\r
+        sPtr = (u_char*)p->payload;\r
+        n = p->len;\r
+        while (n-- > 0) {\r
+            c = *sPtr++;\r
+            \r
+            /* Update FCS before checking for special characters. */\r
+            fcsOut = PPP_FCS(fcsOut, c);\r
+            \r
+            /* Copy to output buffer escaping special characters. */\r
+            tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+        }\r
+    }\r
+\r
+    /* Add FCS and trailing flag. */\r
+    c = ~fcsOut & 0xFF;\r
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+    c = (~fcsOut >> 8) & 0xFF;\r
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+    tailMB = pppAppend(PPP_FLAG, tailMB, NULL);\r
+        \r
+    /* If we failed to complete the packet, throw it away. */\r
+    if (!tailMB) {\r
+        PPPDEBUG((LOG_WARNING,\r
+                    "pppifOutput[%d]: Alloc err - dropping proto=%d\n", \r
+                    pd, protocol));\r
+        pbuf_free(headMB);\r
+#if LINK_STATS\r
+               lwip_stats.link.memerr++;\r
+               lwip_stats.link.drop++;\r
+#endif\r
+        return ERR_MEM;\r
+    }\r
+\r
+       /* Send it. */\r
+    PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));\r
+\r
+    nPut(pc, headMB);\r
+\r
+    return ERR_OK;\r
+}\r
+\r
+/* Get and set parameters for the given connection.\r
+ * Return 0 on success, an error code on failure. */\r
+int  pppIOCtl(int pd, int cmd, void *arg)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    int st = 0;\r
+\r
+    if (pd < 0 || pd >= NUM_PPP)\r
+        st = PPPERR_PARAM;\r
+    else {\r
+        switch(cmd) {\r
+        case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */\r
+            if (arg) \r
+                *(int *)arg = (int)(pc->if_up);\r
+            else\r
+                st = PPPERR_PARAM;\r
+            break;\r
+        case PPPCTLS_ERRCODE:       /* Set the PPP error code. */\r
+            if (arg) \r
+                pc->errCode = *(int *)arg;\r
+            else\r
+                st = PPPERR_PARAM;\r
+            break;\r
+        case PPPCTLG_ERRCODE:       /* Get the PPP error code. */\r
+            if (arg) \r
+                *(int *)arg = (int)(pc->errCode);\r
+            else\r
+                st = PPPERR_PARAM;\r
+            break;\r
+        case PPPCTLG_FD:\r
+            if (arg) \r
+                *(sio_fd_t *)arg = pc->fd;\r
+            else\r
+                st = PPPERR_PARAM;\r
+            break;\r
+        default:\r
+            st = PPPERR_PARAM;\r
+            break;\r
+        }\r
+    }\r
+    \r
+    return st;\r
+}\r
+\r
+/*\r
+ * Return the Maximum Transmission Unit for the given PPP connection.\r
+ */\r
+u_int pppMTU(int pd)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    u_int st;\r
+    \r
+    /* Validate parameters. */\r
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag)\r
+        st = 0;\r
+    else\r
+        st = pc->mtu;\r
+        \r
+    return st;\r
+}\r
+\r
+/*\r
+ * Write n characters to a ppp link.\r
+ *  RETURN: >= 0 Number of characters written\r
+ *           -1 Failed to write to device\r
+ */\r
+int pppWrite(int pd, const u_char *s, int n)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    u_char c;\r
+    u_int fcsOut = PPP_INITFCS;\r
+    struct pbuf *headMB = NULL, *tailMB;\r
+       headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);\r
+    if (headMB == NULL) {\r
+#if LINK_STATS\r
+               lwip_stats.link.memerr++;\r
+               lwip_stats.link.proterr++;\r
+#endif /* LINK_STATS */\r
+               return PPPERR_ALLOC;\r
+    }\r
+\r
+    tailMB = headMB;\r
+        \r
+    /* If the link has been idle, we'll send a fresh flag character to\r
+     * flush any noise. */\r
+    if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)\r
+        tailMB = pppAppend(PPP_FLAG, tailMB, NULL);\r
+    pc->lastXMit = sys_jiffies();\r
+     \r
+    /* Load output buffer. */\r
+    while (n-- > 0) {\r
+        c = *s++;\r
+        \r
+        /* Update FCS before checking for special characters. */\r
+        fcsOut = PPP_FCS(fcsOut, c);\r
+        \r
+        /* Copy to output buffer escaping special characters. */\r
+        tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+    }\r
+    \r
+    /* Add FCS and trailing flag. */\r
+    c = ~fcsOut & 0xFF;\r
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+    c = (~fcsOut >> 8) & 0xFF;\r
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+    tailMB = pppAppend(PPP_FLAG, tailMB, NULL);\r
+        \r
+    /* If we failed to complete the packet, throw it away.\r
+     * Otherwise send it. */\r
+    if (!tailMB) {\r
+               PPPDEBUG((LOG_WARNING,\r
+                "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));\r
+/*                "pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */\r
+               pbuf_free(headMB);\r
+#if LINK_STATS\r
+               lwip_stats.link.memerr++;\r
+               lwip_stats.link.proterr++;\r
+#endif /* LINK_STATS */\r
+               return PPPERR_ALLOC;\r
+       }\r
+\r
+    PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len));\r
+/*     "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */\r
+    nPut(pc, headMB);\r
+\r
+    return PPPERR_NONE;\r
+}\r
+\r
+/*\r
+ * ppp_send_config - configure the transmit characteristics of\r
+ * the ppp interface.\r
+ */\r
+void ppp_send_config(\r
+    int unit, \r
+    int mtu,\r
+    u32_t asyncmap,\r
+    int pcomp, \r
+    int accomp\r
+)\r
+{\r
+    PPPControl *pc = &pppControl[unit];\r
+    int i;\r
+    \r
+    pc->mtu = mtu;\r
+    pc->pcomp = pcomp;\r
+    pc->accomp = accomp;\r
+    \r
+    /* Load the ACCM bits for the 32 control codes. */\r
+    for (i = 0; i < 32/8; i++)\r
+        pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);\r
+    PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n",\r
+                unit,\r
+                pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));\r
+}\r
+\r
+\r
+/*\r
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.\r
+ */\r
+void ppp_set_xaccm(int unit, ext_accm *accm)\r
+{\r
+    memcpy(pppControl[unit].outACCM, accm, sizeof(ext_accm));\r
+    PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",\r
+                unit,\r
+                pppControl[unit].outACCM[0],\r
+                pppControl[unit].outACCM[1],\r
+                pppControl[unit].outACCM[2],\r
+                pppControl[unit].outACCM[3]));\r
+}\r
+\r
+\r
+/*\r
+ * ppp_recv_config - configure the receive-side characteristics of\r
+ * the ppp interface.\r
+ */\r
+void ppp_recv_config(\r
+    int unit, \r
+    int mru,\r
+    u32_t asyncmap,\r
+    int pcomp, \r
+    int accomp\r
+)\r
+{\r
+    PPPControl *pc = &pppControl[unit];\r
+    int i;\r
+    \r
+       (void)accomp;\r
+       (void)pcomp;\r
+       (void)mru;\r
+\r
+    /* Load the ACCM bits for the 32 control codes. */\r
+    for (i = 0; i < 32 / 8; i++)\r
+        pc->inACCM[i] = (u_char)(asyncmap >> (i * 8));\r
+    PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n",\r
+                unit,\r
+                pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));\r
+}\r
+\r
+#if 0\r
+/*\r
+ * ccp_test - ask kernel whether a given compression method\r
+ * is acceptable for use.  Returns 1 if the method and parameters\r
+ * are OK, 0 if the method is known but the parameters are not OK\r
+ * (e.g. code size should be reduced), or -1 if the method is unknown.\r
+ */\r
+int ccp_test(\r
+    int unit, \r
+    int opt_len, \r
+    int for_transmit,\r
+    u_char *opt_ptr\r
+)\r
+{\r
+    return 0;   /* XXX Currently no compression. */\r
+}\r
+\r
+/*\r
+ * ccp_flags_set - inform kernel about the current state of CCP.\r
+ */\r
+void ccp_flags_set(int unit, int isopen, int isup)\r
+{\r
+    /* XXX */\r
+}\r
+\r
+/*\r
+ * ccp_fatal_error - returns 1 if decompression was disabled as a\r
+ * result of an error detected after decompression of a packet,\r
+ * 0 otherwise.  This is necessary because of patent nonsense.\r
+ */\r
+int ccp_fatal_error(int unit)\r
+{\r
+    /* XXX */\r
+    return 0;\r
+}\r
+#endif\r
+\r
+/*\r
+ * get_idle_time - return how long the link has been idle.\r
+ */\r
+int get_idle_time(int u, struct ppp_idle *ip)\r
+{   \r
+    /* XXX */\r
+       (void)u;\r
+       (void)ip;\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+/*\r
+ * Return user specified netmask, modified by any mask we might determine\r
+ * for address `addr' (in network byte order).\r
+ * Here we scan through the system's list of interfaces, looking for\r
+ * any non-point-to-point interfaces which might appear to be on the same\r
+ * network as `addr'.  If we find any, we OR in their netmask to the\r
+ * user-specified netmask.\r
+ */\r
+u32_t GetMask(u32_t addr)\r
+{\r
+    u32_t mask, nmask;\r
+    \r
+    htonl(addr);\r
+    if (IN_CLASSA(addr))    /* determine network mask for address class */\r
+        nmask = IN_CLASSA_NET;\r
+    else if (IN_CLASSB(addr))\r
+        nmask = IN_CLASSB_NET;\r
+    else\r
+        nmask = IN_CLASSC_NET;\r
+    /* class D nets are disallowed by bad_ip_adrs */\r
+    mask = subnetMask | htonl(nmask);\r
+    \r
+    /* XXX\r
+     * Scan through the system's network interfaces.\r
+     * Get each netmask and OR them into our mask.\r
+     */\r
+    \r
+    return mask;\r
+}\r
+\r
+/*\r
+ * sifvjcomp - config tcp header compression\r
+ */\r
+int sifvjcomp(\r
+    int pd, \r
+    int vjcomp, \r
+    int cidcomp, \r
+    int maxcid\r
+)\r
+{\r
+#if VJ_SUPPORT > 0\r
+    PPPControl *pc = &pppControl[pd];\r
+    \r
+    pc->vjEnabled = vjcomp;\r
+    pc->vjComp.compressSlot = cidcomp;\r
+    pc->vjComp.maxSlotIndex = maxcid;\r
+    PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",\r
+                vjcomp, cidcomp, maxcid));\r
+#endif\r
+\r
+    return 0;\r
+}\r
+\r
+/*\r
+ * pppifNetifInit - netif init callback\r
+ */\r
+static err_t pppifNetifInit(struct netif *netif)\r
+{\r
+       netif->name[0] = 'p';\r
+       netif->name[1] = 'p';\r
+       netif->output = pppifOutput;\r
+       netif->mtu = pppMTU((int)netif->state);\r
+       return ERR_OK;\r
+}\r
+\r
+\r
+/*\r
+ * sifup - Config the interface up and enable IP packets to pass.\r
+ */\r
+int sifup(int pd)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    int st = 1;\r
+    \r
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+        st = 0;\r
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+    } else {\r
+               netif_remove(&pc->netif);\r
+               if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) {\r
+               \r
+               netif_set_up(&pc->netif);\r
+               pc->if_up = 1;\r
+               pc->errCode = PPPERR_NONE;\r
+\r
+                       PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));\r
+                       if(pc->linkStatusCB)\r
+                               pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);\r
+               } else {\r
+               st = 0;\r
+               PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));\r
+               }\r
+    }\r
+\r
+    return st;\r
+}\r
+\r
+/*\r
+ * sifnpmode - Set the mode for handling packets for a given NP.\r
+ */\r
+int sifnpmode(int u, int proto, enum NPmode mode)\r
+{\r
+       (void)u;\r
+       (void)proto;\r
+       (void)mode;\r
+    return 0;\r
+}\r
+\r
+/*\r
+ * sifdown - Config the interface down and disable IP.\r
+ */\r
+int sifdown(int pd)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    int st = 1;\r
+    \r
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+        st = 0;\r
+        PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));\r
+    } else {\r
+        pc->if_up = 0;\r
+       netif_remove(&pc->netif);\r
+       PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));\r
+       if(pc->linkStatusCB)\r
+               pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);\r
+       }\r
+    return st;\r
+}\r
+\r
+/*\r
+ * sifaddr - Config the interface IP addresses and netmask.\r
+ */\r
+int sifaddr(\r
+    int pd,             /* Interface unit ??? */\r
+    u32_t o,        /* Our IP address ??? */\r
+    u32_t h,        /* His IP address ??? */\r
+    u32_t m,        /* IP subnet mask ??? */\r
+    u32_t ns1,      /* Primary DNS */\r
+    u32_t ns2       /* Secondary DNS */\r
+)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    int st = 1;\r
+    \r
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+        st = 0;\r
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+    } else {\r
+               memcpy(&pc->addrs.our_ipaddr, &o, sizeof(o));\r
+               memcpy(&pc->addrs.his_ipaddr, &h, sizeof(h));\r
+               memcpy(&pc->addrs.netmask, &m, sizeof(m));\r
+               memcpy(&pc->addrs.dns1, &ns1, sizeof(ns1));\r
+               memcpy(&pc->addrs.dns2, &ns2, sizeof(ns2));\r
+    }\r
+    return st;\r
+}\r
+\r
+/*\r
+ * cifaddr - Clear the interface IP addresses, and delete routes\r
+ * through the interface if possible.\r
+ */\r
+int cifaddr(\r
+    int pd,         /* Interface unit ??? */\r
+    u32_t o,    /* Our IP address ??? */\r
+    u32_t h     /* IP broadcast address ??? */\r
+)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    int st = 1;\r
+    \r
+       (void)o;\r
+       (void)h;\r
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+        st = 0;\r
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+    } else {\r
+               IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);\r
+               IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);\r
+               IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);\r
+               IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);\r
+               IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);\r
+    }\r
+    return st;\r
+}\r
+\r
+/*\r
+ * sifdefaultroute - assign a default route through the address given.\r
+ */\r
+int sifdefaultroute(int pd, u32_t l, u32_t g)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    int st = 1;\r
+    \r
+       (void)l;\r
+       (void)g;\r
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+        st = 0;\r
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+    } else {\r
+               netif_set_default(&pc->netif);\r
+    }\r
+\r
+    /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */\r
+\r
+    return st;\r
+}\r
+\r
+/*\r
+ * cifdefaultroute - delete a default route through the address given.\r
+ */\r
+int cifdefaultroute(int pd, u32_t l, u32_t g)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    int st = 1;\r
+    \r
+       (void)l;\r
+       (void)g;\r
+    if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+        st = 0;\r
+        PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+    } else {\r
+               netif_set_default(NULL);\r
+    }\r
+\r
+    return st;\r
+}\r
+\r
+void\r
+pppMainWakeup(int pd)\r
+{\r
+       PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));\r
+       sio_read_abort(pppControl[pd].fd);\r
+}\r
+\r
+/* these callbacks are necessary because lcp_* functions\r
+   must be called in the same context as pppInput(),\r
+   namely the tcpip_thread(), essentially because\r
+   they manipulate timeouts which are thread-private\r
+*/\r
+\r
+static void\r
+pppStartCB(void *arg)\r
+{\r
+    int pd = (int)arg;\r
+\r
+       PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));\r
+    lcp_lowerup(pd);\r
+    lcp_open(pd);      /* Start protocol */\r
+}\r
+\r
+static void\r
+pppStopCB(void *arg)\r
+{\r
+    int pd = (int)arg;\r
+\r
+       PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));\r
+    lcp_close(pd, "User request");\r
+}\r
+\r
+static void\r
+pppHupCB(void *arg)\r
+{\r
+    int pd = (int)arg;\r
+\r
+       PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));\r
+    lcp_lowerdown(pd);\r
+    link_terminated(pd);\r
+}\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/* The main PPP process function.  This implements the state machine according\r
+ * to section 4 of RFC 1661: The Point-To-Point Protocol. */\r
+static void pppMain(void *arg)\r
+{\r
+    int pd = (int)arg;\r
+    struct pbuf *p;\r
+    PPPControl* pc;\r
+\r
+    pc = &pppControl[pd];\r
+\r
+    p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);\r
+    if(!p) {\r
+               LWIP_ASSERT("p != NULL", p);\r
+               pc->errCode = PPPERR_ALLOC;\r
+               goto out;\r
+    }\r
+\r
+    /*\r
+     * Start the connection and handle incoming events (packet or timeout).\r
+     */\r
+       PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));\r
+    tcpip_callback(pppStartCB, arg);\r
+    while (lcp_phase[pd] != PHASE_DEAD) {\r
+        if (pc->kill_link) {\r
+               PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d kill_link -> pppStopCB\n", pd));\r
+               pc->errCode = PPPERR_USER;\r
+               /* This will leave us at PHASE_DEAD. */\r
+               tcpip_callback(pppStopCB, arg);\r
+               pc->kill_link = 0;\r
+        }\r
+        else if (pc->sig_hup) {\r
+               PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sig_hup -> pppHupCB\n", pd));\r
+               pc->sig_hup = 0;\r
+               tcpip_callback(pppHupCB, arg);\r
+        } else {\r
+               int c = sio_read(pc->fd, p->payload, p->len);\r
+               if(c > 0) {\r
+                       pppInProc(pd, p->payload, c);\r
+               } else {\r
+                   PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sio_read len=%d returned %d\n", pd, p->len, c));\r
+                   sys_msleep(1); /* give other tasks a chance to run */\r
+               }\r
+        }\r
+    }\r
+       PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));\r
+    pbuf_free(p);\r
+\r
+out:\r
+       PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));\r
+    if(pc->linkStatusCB)\r
+           pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);\r
+\r
+    pc->openFlag = 0;\r
+}\r
+\r
+static struct pbuf *pppSingleBuf(struct pbuf *p)\r
+{\r
+       struct pbuf *q, *b;\r
+       u_char *pl;\r
+\r
+       if(p->tot_len == p->len)\r
+               return p;\r
+\r
+       q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\r
+       if(!q) {\r
+               PPPDEBUG((LOG_ERR,\r
+                        "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));\r
+               return p; /* live dangerously */\r
+       }\r
+\r
+       for(b = p, pl = q->payload; b != NULL; b = b->next) {\r
+               memcpy(pl, b->payload, b->len);\r
+               pl += b->len;\r
+       }\r
+\r
+       pbuf_free(p);\r
+\r
+       return q;\r
+}\r
+\r
+struct pppInputHeader {\r
+       int unit;\r
+       u16_t proto;\r
+};\r
+\r
+/*\r
+ * Pass the processed input packet to the appropriate handler.\r
+ * This function and all handlers run in the context of the tcpip_thread\r
+ */\r
+static void pppInput(void *arg)\r
+{\r
+       struct pbuf *nb = (struct pbuf *)arg;\r
+    u16_t protocol;\r
+    int pd;\r
+\r
+       pd = ((struct pppInputHeader *)nb->payload)->unit;\r
+       protocol = ((struct pppInputHeader *)nb->payload)->proto;\r
+\r
+    pbuf_header(nb, -(int)sizeof(struct pppInputHeader));\r
+\r
+#if LINK_STATS\r
+    lwip_stats.link.recv++;\r
+#endif /* LINK_STATS */\r
+\r
+    /*\r
+     * Toss all non-LCP packets unless LCP is OPEN.\r
+     * Until we get past the authentication phase, toss all packets\r
+     * except LCP, LQR and authentication packets.\r
+     */\r
+    if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {\r
+           if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||\r
+                       (lcp_phase[pd] != PHASE_AUTHENTICATE)) {\r
+               PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd]));\r
+               goto drop;\r
+           }\r
+    }\r
+\r
+    switch(protocol) {\r
+    case PPP_VJC_COMP:      /* VJ compressed TCP */\r
+#if VJ_SUPPORT > 0\r
+        PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));\r
+        /*\r
+         * Clip off the VJ header and prepend the rebuilt TCP/IP header and\r
+         * pass the result to IP.\r
+         */\r
+        if (vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) {\r
+            if (pppControl[pd].netif.input != NULL) {\r
+              pppControl[pd].netif.input(nb, &pppControl[pd].netif);\r
+            }\r
+                       return;\r
+        }\r
+       /* Something's wrong so drop it. */\r
+       PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));\r
+#else\r
+        /* No handler for this protocol so drop the packet. */\r
+        PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));\r
+#endif /* VJ_SUPPORT > 0 */\r
+       break;\r
+    case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */\r
+#if VJ_SUPPORT > 0\r
+        PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));\r
+        /*\r
+         * Process the TCP/IP header for VJ header compression and then pass\r
+         * the packet to IP.\r
+         */\r
+        if (vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) {\r
+            if (pppControl[pd].netif.input != NULL) {\r
+              pppControl[pd].netif.input(nb, &pppControl[pd].netif);\r
+            }\r
+                       return;\r
+        }\r
+       /* Something's wrong so drop it. */\r
+       PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));\r
+#else\r
+        /* No handler for this protocol so drop the packet. */\r
+        PPPDEBUG((LOG_INFO,\r
+                    "pppInput[%d]: drop VJ UnComp in %d:.*H\n", \r
+                    pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));\r
+#endif /* VJ_SUPPORT > 0 */\r
+       break;\r
+    case PPP_IP:            /* Internet Protocol */\r
+        PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));\r
+        if (pppControl[pd].netif.input != NULL) {\r
+          pppControl[pd].netif.input(nb, &pppControl[pd].netif);\r
+        }\r
+               return;\r
+    default:\r
+       {\r
+               struct protent *protp;\r
+               int i;\r
+\r
+               /*\r
+                * Upcall the proper protocol input routine.\r
+                */\r
+               for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {\r
+                       if (protp->protocol == protocol && protp->enabled_flag) {\r
+                               PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));\r
+                               nb = pppSingleBuf(nb);\r
+                               (*protp->input)(pd, nb->payload, nb->len);\r
+                               goto out;\r
+                       }\r
+               }\r
+\r
+               /* No handler for this protocol so reject the packet. */\r
+               PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len));\r
+               pbuf_header(nb, sizeof(protocol));\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+               protocol = htons(protocol);\r
+               memcpy(nb->payload, &protocol, sizeof(protocol));\r
+#endif\r
+               lcp_sprotrej(pd, nb->payload, nb->len);\r
+       }\r
+       break;\r
+    }\r
+\r
+drop:\r
+#if LINK_STATS\r
+    lwip_stats.link.drop++;\r
+#endif\r
+\r
+out:\r
+    pbuf_free(nb);\r
+    return;\r
+}\r
+\r
+\r
+/*\r
+ * Drop the input packet.\r
+ */\r
+static void pppDrop(PPPControl *pc)\r
+{\r
+    if (pc->inHead != NULL) {\r
+#if 0      \r
+        PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));\r
+#endif \r
+        PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len));\r
+       if (pc->inTail && (pc->inTail != pc->inHead))\r
+           pbuf_free(pc->inTail);\r
+        pbuf_free(pc->inHead);\r
+        pc->inHead = NULL;\r
+        pc->inTail = NULL;\r
+    }\r
+#if VJ_SUPPORT > 0\r
+    vj_uncompress_err(&pc->vjComp);\r
+#endif\r
+\r
+#if LINK_STATS\r
+    lwip_stats.link.drop++;\r
+#endif /* LINK_STATS */\r
+}\r
+\r
+\r
+/*\r
+ * Process a received octet string.\r
+ */\r
+static void pppInProc(int pd, u_char *s, int l)\r
+{\r
+    PPPControl *pc = &pppControl[pd];\r
+    struct pbuf *nextNBuf;\r
+    u_char curChar;\r
+\r
+    PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));\r
+    while (l-- > 0) {\r
+        curChar = *s++;\r
+        \r
+        /* Handle special characters. */\r
+        if (ESCAPE_P(pc->inACCM, curChar)) {\r
+            /* Check for escape sequences. */\r
+            /* XXX Note that this does not handle an escaped 0x5d character which\r
+             * would appear as an escape character.  Since this is an ASCII ']'\r
+             * and there is no reason that I know of to escape it, I won't complicate\r
+             * the code to handle this case. GLL */\r
+            if (curChar == PPP_ESCAPE)\r
+                pc->inEscaped = 1;\r
+            /* Check for the flag character. */\r
+            else if (curChar == PPP_FLAG) {\r
+                /* If this is just an extra flag character, ignore it. */\r
+                if (pc->inState <= PDADDRESS)\r
+                    ;\r
+                /* If we haven't received the packet header, drop what has come in. */\r
+                else if (pc->inState < PDDATA) {\r
+                    PPPDEBUG((LOG_WARNING,\r
+                                "pppInProc[%d]: Dropping incomplete packet %d\n", \r
+                                pd, pc->inState));\r
+#if LINK_STATS\r
+                                       lwip_stats.link.lenerr++;\r
+#endif\r
+                    pppDrop(pc);\r
+                }\r
+                /* If the fcs is invalid, drop the packet. */\r
+                else if (pc->inFCS != PPP_GOODFCS) {\r
+                    PPPDEBUG((LOG_INFO,\r
+                                "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n", \r
+                                pd, pc->inFCS, pc->inProtocol));\r
+#if LINK_STATS\r
+                                       lwip_stats.link.chkerr++;\r
+#endif\r
+                    pppDrop(pc);\r
+                }\r
+                /* Otherwise it's a good packet so pass it on. */\r
+                else {\r
+                    \r
+                    /* Trim off the checksum. */\r
+                   if(pc->inTail->len >= 2) {\r
+                       pc->inTail->len -= 2;\r
+\r
+                       pc->inTail->tot_len = pc->inTail->len;\r
+                       if (pc->inTail != pc->inHead) {\r
+                           pbuf_cat(pc->inHead, pc->inTail);\r
+                       }\r
+                   } else {\r
+                       pc->inTail->tot_len = pc->inTail->len;\r
+                       if (pc->inTail != pc->inHead) {\r
+                           pbuf_cat(pc->inHead, pc->inTail);\r
+                       }\r
+\r
+                       pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);\r
+                   }\r
+\r
+                    /* Dispatch the packet thereby consuming it. */\r
+                   if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) {\r
+                       PPPDEBUG((LOG_ERR,\r
+                                   "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd));\r
+                       pbuf_free(pc->inHead);\r
+#if LINK_STATS\r
+                       lwip_stats.link.drop++;\r
+#endif\r
+                   }\r
+                    pc->inHead = NULL;\r
+                    pc->inTail = NULL;\r
+                }\r
+                    \r
+                /* Prepare for a new packet. */\r
+                pc->inFCS = PPP_INITFCS;\r
+                pc->inState = PDADDRESS;\r
+                pc->inEscaped = 0;\r
+            }\r
+            /* Other characters are usually control characters that may have\r
+             * been inserted by the physical layer so here we just drop them. */\r
+            else {\r
+                PPPDEBUG((LOG_WARNING,\r
+                            "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));\r
+            }\r
+        }\r
+        /* Process other characters. */\r
+        else {\r
+            /* Unencode escaped characters. */\r
+            if (pc->inEscaped) {\r
+                pc->inEscaped = 0;\r
+                curChar ^= PPP_TRANS;\r
+            }\r
+            \r
+            /* Process character relative to current state. */\r
+            switch(pc->inState) {\r
+            case PDIDLE:                    /* Idle state - waiting. */\r
+                /* Drop the character if it's not 0xff\r
+                 * we would have processed a flag character above. */\r
+                if (curChar != PPP_ALLSTATIONS) {\r
+                       break;\r
+                               }\r
+\r
+                               /* Fall through */\r
+            case PDSTART:                   /* Process start flag. */\r
+                /* Prepare for a new packet. */\r
+                pc->inFCS = PPP_INITFCS;\r
+\r
+                               /* Fall through */\r
+            case PDADDRESS:                 /* Process address field. */\r
+                if (curChar == PPP_ALLSTATIONS) {\r
+                    pc->inState = PDCONTROL;\r
+                    break;\r
+                }\r
+                /* Else assume compressed address and control fields so\r
+                 * fall through to get the protocol... */\r
+            case PDCONTROL:                 /* Process control field. */\r
+                /* If we don't get a valid control code, restart. */\r
+                if (curChar == PPP_UI) {\r
+                    pc->inState = PDPROTOCOL1;\r
+                       break;\r
+                }\r
+#if 0\r
+                else {\r
+                    PPPDEBUG((LOG_WARNING,\r
+                                "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));\r
+                    pc->inState = PDSTART;\r
+                }\r
+#endif\r
+            case PDPROTOCOL1:               /* Process protocol field 1. */\r
+                /* If the lower bit is set, this is the end of the protocol\r
+                 * field. */\r
+                if (curChar & 1) {\r
+                    pc->inProtocol = curChar;\r
+                    pc->inState = PDDATA;\r
+                }\r
+                else {\r
+                    pc->inProtocol = (u_int)curChar << 8;\r
+                    pc->inState = PDPROTOCOL2;\r
+                }\r
+                break;\r
+            case PDPROTOCOL2:               /* Process protocol field 2. */\r
+                pc->inProtocol |= curChar;\r
+                pc->inState = PDDATA;\r
+                break;\r
+            case PDDATA:                    /* Process data byte. */\r
+                /* Make space to receive processed data. */\r
+                if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) {\r
+                   if(pc->inTail) {\r
+                       pc->inTail->tot_len = pc->inTail->len;\r
+                       if (pc->inTail != pc->inHead) {\r
+                           pbuf_cat(pc->inHead, pc->inTail);\r
+                       }\r
+                   }\r
+                    /* If we haven't started a packet, we need a packet header. */\r
+                    nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);\r
+                    if (nextNBuf == NULL) {\r
+                        /* No free buffers.  Drop the input packet and let the\r
+                         * higher layers deal with it.  Continue processing\r
+                         * the received pbuf chain in case a new packet starts. */\r
+                        PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd));\r
+#if LINK_STATS\r
+                                               lwip_stats.link.memerr++;\r
+#endif /* LINK_STATS */\r
+                        pppDrop(pc);\r
+                        pc->inState = PDSTART;  /* Wait for flag sequence. */\r
+                       break;\r
+                    }\r
+                   if (pc->inHead == NULL) {\r
+                       struct pppInputHeader *pih = nextNBuf->payload;\r
+\r
+                       pih->unit = pd;\r
+                       pih->proto = pc->inProtocol;\r
+\r
+                       nextNBuf->len += sizeof(*pih);\r
+\r
+                       pc->inHead = nextNBuf;\r
+                   }\r
+                   pc->inTail = nextNBuf;\r
+                }\r
+                /* Load character into buffer. */\r
+                ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;\r
+                break;\r
+            }\r
+\r
+            /* update the frame check sequence number. */\r
+            pc->inFCS = PPP_FCS(pc->inFCS, curChar);\r
+        }\r
+    }\r
+       avRandomize();\r
+}\r
+\r
+#endif /* PPP_SUPPORT */\r
index 25cea83f2b2721265bbe947473d7379c777a67d2..094324813c8e209f8195adfd4e15d6b312faeee9 100644 (file)
-/*****************************************************************************
-* 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 */
+/*****************************************************************************\r
+* ppp.h - Network Point to Point Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*      Original derived from BSD codes.\r
+*****************************************************************************/\r
+\r
+#ifndef PPP_H\r
+#define PPP_H\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT > 0\r
+#include "lwip/sio.h"\r
+#include "lwip/api.h"\r
+#include "lwip/sockets.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/tcpip.h"\r
+#include "lwip/netif.h"\r
+\r
+/*\r
+ * pppd.h - PPP daemon global declarations.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ */\r
+/*\r
+ * ppp_defs.h - PPP definitions.\r
+ *\r
+ * Copyright (c) 1994 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software and its\r
+ * documentation is hereby granted, provided that the above copyright\r
+ * notice appears in all copies.  This software is provided without any\r
+ * warranty, express or implied. The Australian National University\r
+ * makes no representations about the suitability of this software for\r
+ * any purpose.\r
+ *\r
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY\r
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\r
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF\r
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,\r
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\r
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS\r
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO\r
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,\r
+ * OR MODIFICATIONS.\r
+ */\r
+\r
+#define TIMEOUT(f, a, t)    sys_untimeout((f), (a)), sys_timeout((t)*1000, (f), (a))\r
+#define UNTIMEOUT(f, a)     sys_untimeout((f), (a))\r
+\r
+\r
+# ifndef __u_char_defined\r
+\r
+/* Type definitions for BSD code. */\r
+typedef unsigned long u_long;\r
+typedef unsigned int u_int;\r
+typedef unsigned short u_short;\r
+typedef unsigned char u_char;\r
+\r
+#endif\r
+\r
+/*\r
+ * Constants and structures defined by the internet system,\r
+ * Per RFC 790, September 1981, and numerous additions.\r
+ */\r
+\r
+/*\r
+ * The basic PPP frame.\r
+ */\r
+#define PPP_HDRLEN  4       /* octets for standard ppp header */\r
+#define PPP_FCSLEN  2       /* octets for FCS */\r
+\r
+\r
+/*\r
+ * Significant octet values.\r
+ */\r
+#define PPP_ALLSTATIONS 0xff    /* All-Stations broadcast address */\r
+#define PPP_UI          0x03    /* Unnumbered Information */\r
+#define PPP_FLAG        0x7e    /* Flag Sequence */\r
+#define PPP_ESCAPE      0x7d    /* Asynchronous Control Escape */\r
+#define PPP_TRANS       0x20    /* Asynchronous transparency modifier */\r
+\r
+/*\r
+ * Protocol field values.\r
+ */\r
+#define PPP_IP          0x21    /* Internet Protocol */\r
+#define PPP_AT          0x29    /* AppleTalk Protocol */\r
+#define PPP_VJC_COMP    0x2d    /* VJ compressed TCP */\r
+#define PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */\r
+#define PPP_COMP        0xfd    /* compressed packet */\r
+#define PPP_IPCP        0x8021  /* IP Control Protocol */\r
+#define PPP_ATCP        0x8029  /* AppleTalk Control Protocol */\r
+#define PPP_CCP         0x80fd  /* Compression Control Protocol */\r
+#define PPP_LCP         0xc021  /* Link Control Protocol */\r
+#define PPP_PAP         0xc023  /* Password Authentication Protocol */\r
+#define PPP_LQR         0xc025  /* Link Quality Report protocol */\r
+#define PPP_CHAP        0xc223  /* Cryptographic Handshake Auth. Protocol */\r
+#define PPP_CBCP        0xc029  /* Callback Control Protocol */\r
+\r
+/*\r
+ * Values for FCS calculations.\r
+ */\r
+#define PPP_INITFCS 0xffff  /* Initial FCS value */\r
+#define PPP_GOODFCS 0xf0b8  /* Good final FCS value */\r
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])\r
+\r
+/*\r
+ * Extended asyncmap - allows any character to be escaped.\r
+ */\r
+typedef u_char  ext_accm[32];\r
+\r
+/*\r
+ * What to do with network protocol (NP) packets.\r
+ */\r
+enum NPmode {\r
+    NPMODE_PASS,        /* pass the packet through */\r
+    NPMODE_DROP,        /* silently drop the packet */\r
+    NPMODE_ERROR,       /* return an error */\r
+    NPMODE_QUEUE        /* save it up for later. */\r
+};\r
+\r
+/*\r
+ * Inline versions of get/put char/short/long.\r
+ * Pointer is advanced; we assume that both arguments\r
+ * are lvalues and will already be in registers.\r
+ * cp MUST be u_char *.\r
+ */\r
+#define GETCHAR(c, cp) { \\r
+    (c) = *(cp)++; \\r
+}\r
+#define PUTCHAR(c, cp) { \\r
+    *(cp)++ = (u_char) (c); \\r
+}\r
+\r
+\r
+#define GETSHORT(s, cp) { \\r
+    (s) = *(cp); (cp)++; (s) << 8; \\r
+    (s) |= *(cp); (cp)++; \\r
+}\r
+#define PUTSHORT(s, cp) { \\r
+    *(cp)++ = (u_char) ((s) >> 8); \\r
+    *(cp)++ = (u_char) (s); \\r
+}\r
+\r
+#define GETLONG(l, cp) { \\r
+    (l) = *(cp); (cp)++; (l) << 8; \\r
+    (l) |= *(cp); (cp)++; (l) <<= 8; \\r
+    (l) |= *(cp); (cp)++; (l) <<= 8; \\r
+    (l) |= *(cp); (cp)++; \\r
+}\r
+#define PUTLONG(l, cp) { \\r
+    *(cp)++ = (u_char) ((l) >> 24); \\r
+    *(cp)++ = (u_char) ((l) >> 16); \\r
+    *(cp)++ = (u_char) ((l) >> 8); \\r
+    *(cp)++ = (u_char) (l); \\r
+}\r
+\r
+\r
+#define INCPTR(n, cp)   ((cp) += (n))\r
+#define DECPTR(n, cp)   ((cp) -= (n))\r
+\r
+#define BCMP(s0, s1, l)     memcmp((u_char *)(s0), (u_char *)(s1), (l))\r
+#define BCOPY(s, d, l)      memcpy((d), (s), (l))\r
+#define BZERO(s, n)         memset(s, 0, n)\r
+#if PPP_DEBUG\r
+#define PRINTMSG(m, l)  { m[l] = '\0'; ppp_trace(LOG_INFO, "Remote message: %s\n", m); }\r
+#else\r
+#define PRINTMSG(m, l)\r
+#endif\r
+\r
+/*\r
+ * MAKEHEADER - Add PPP Header fields to a packet.\r
+ */\r
+#define MAKEHEADER(p, t) { \\r
+    PUTCHAR(PPP_ALLSTATIONS, p); \\r
+    PUTCHAR(PPP_UI, p); \\r
+    PUTSHORT(t, p); }\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+\r
+/* Error codes. */\r
+#define PPPERR_NONE 0                          /* No error. */\r
+#define PPPERR_PARAM -1                                /* Invalid parameter. */\r
+#define PPPERR_OPEN -2                         /* Unable to open PPP session. */\r
+#define PPPERR_DEVICE -3                       /* Invalid I/O device for PPP. */\r
+#define PPPERR_ALLOC -4                                /* Unable to allocate resources. */\r
+#define PPPERR_USER -5                         /* User interrupt. */\r
+#define PPPERR_CONNECT -6                      /* Connection lost. */\r
+#define PPPERR_AUTHFAIL -7                     /* Failed authentication challenge. */\r
+#define PPPERR_PROTOCOL -8                     /* Failed to meet protocol. */\r
+\r
+/*\r
+ * PPP IOCTL commands.\r
+ */\r
+/*\r
+ * Get the up status - 0 for down, non-zero for up.  The argument must\r
+ * point to an int.\r
+ */\r
+#define PPPCTLG_UPSTATUS 100   /* Get the up status - 0 down else up */\r
+#define PPPCTLS_ERRCODE 101            /* Set the error code */\r
+#define PPPCTLG_ERRCODE 102            /* Get the error code */\r
+#define        PPPCTLG_FD              103             /* Get the fd associated with the ppp */\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+/*\r
+ * The following struct gives the addresses of procedures to call\r
+ * for a particular protocol.\r
+ */\r
+struct protent {\r
+    u_short protocol;       /* PPP protocol number */\r
+    /* Initialization procedure */\r
+    void (*init) (int unit);\r
+    /* Process a received packet */\r
+    void (*input) (int unit, u_char *pkt, int len);\r
+    /* Process a received protocol-reject */\r
+    void (*protrej) (int unit);\r
+    /* Lower layer has come up */\r
+    void (*lowerup) (int unit);\r
+    /* Lower layer has gone down */\r
+    void (*lowerdown) (int unit);\r
+    /* Open the protocol */\r
+    void (*open) (int unit);\r
+    /* Close the protocol */\r
+    void (*close) (int unit, char *reason);\r
+#if 0\r
+    /* Print a packet in readable form */\r
+    int  (*printpkt) (u_char *pkt, int len,\r
+              void (*printer) (void *, char *, ...),\r
+              void *arg);\r
+    /* Process a received data packet */\r
+    void (*datainput) (int unit, u_char *pkt, int len);\r
+#endif\r
+    int  enabled_flag;      /* 0 iff protocol is disabled */\r
+    char *name;         /* Text name of protocol */\r
+#if 0\r
+    /* Check requested options, assign defaults */\r
+    void (*check_options) (u_long);\r
+    /* Configure interface for demand-dial */\r
+    int  (*demand_conf) (int unit);\r
+    /* Say whether to bring up link for this pkt */\r
+    int  (*active_pkt) (u_char *pkt, int len);\r
+#endif\r
+};\r
+\r
+/*\r
+ * The following structure records the time in seconds since\r
+ * the last NP packet was sent or received.\r
+ */\r
+struct ppp_idle {\r
+    u_short xmit_idle;      /* seconds since last NP packet sent */\r
+    u_short recv_idle;      /* seconds since last NP packet received */\r
+};\r
+\r
+struct ppp_settings {\r
+\r
+       u_int  disable_defaultip : 1;   /* Don't use hostname for default IP addrs */\r
+       u_int  auth_required : 1;      /* Peer is required to authenticate */\r
+       u_int  explicit_remote : 1;    /* remote_name specified with remotename opt */\r
+       u_int  refuse_pap : 1;         /* Don't wanna auth. ourselves with PAP */\r
+       u_int  refuse_chap : 1;        /* Don't wanna auth. ourselves with CHAP */\r
+       u_int  usehostname : 1;        /* Use hostname for our_name */\r
+       u_int  usepeerdns : 1;         /* Ask peer for DNS adds */\r
+\r
+       u_short idle_time_limit; /* Shut down link if idle for this long */\r
+       int  maxconnect;         /* Maximum connect time (seconds) */\r
+\r
+       char user[MAXNAMELEN + 1];/* Username for PAP */\r
+       char passwd[MAXSECRETLEN + 1];           /* Password for PAP, secret for CHAP */\r
+       char our_name[MAXNAMELEN + 1];         /* Our name for authentication purposes */\r
+       char remote_name[MAXNAMELEN + 1];      /* Peer's name for authentication */\r
+};\r
+\r
+struct ppp_addrs {\r
+    struct ip_addr our_ipaddr, his_ipaddr, netmask, dns1, dns2;\r
+};\r
+\r
+/*****************************\r
+*** PUBLIC DATA STRUCTURES ***\r
+*****************************/\r
+/* Buffers for outgoing packets. */\r
+extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];\r
+\r
+extern struct ppp_settings ppp_settings;\r
+\r
+extern struct protent *ppp_protocols[];/* Table of pointers to supported protocols */\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+/* Initialize the PPP subsystem. */\r
+void pppInit(void);\r
+\r
+/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.\r
+ * RFC 1994 says:\r
+ *\r
+ * In practice, within or associated with each PPP server, there is a\r
+ * database which associates "user" names with authentication\r
+ * information ("secrets").  It is not anticipated that a particular\r
+ * named user would be authenticated by multiple methods.  This would\r
+ * make the user vulnerable to attacks which negotiate the least secure\r
+ * method from among a set (such as PAP rather than CHAP).  If the same\r
+ * secret was used, PAP would reveal the secret to be used later with\r
+ * CHAP.\r
+ *\r
+ * Instead, for each user name there should be an indication of exactly\r
+ * one method used to authenticate that user name.  If a user needs to\r
+ * make use of different authentication methods under different\r
+ * circumstances, then distinct user names SHOULD be employed, each of\r
+ * which identifies exactly one authentication method.\r
+ *\r
+ */\r
+enum pppAuthType {\r
+    PPPAUTHTYPE_NONE,\r
+    PPPAUTHTYPE_ANY,\r
+    PPPAUTHTYPE_PAP,\r
+    PPPAUTHTYPE_CHAP\r
+};\r
+\r
+void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd);\r
+\r
+/*\r
+ * Open a new PPP connection using the given I/O device.\r
+ * This initializes the PPP control block but does not\r
+ * attempt to negotiate the LCP session.\r
+ * Return a new PPP connection descriptor on success or\r
+ * an error code (negative) on failure. \r
+ */\r
+int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);\r
+\r
+/*\r
+ * Close a PPP connection and release the descriptor. \r
+ * Any outstanding packets in the queues are dropped.\r
+ * Return 0 on success, an error code on failure. \r
+ */\r
+int pppClose(int pd);\r
+\r
+/*\r
+ * Indicate to the PPP process that the line has disconnected.\r
+ */\r
+void pppSigHUP(int pd);\r
+\r
+/*\r
+ * Get and set parameters for the given connection.\r
+ * Return 0 on success, an error code on failure. \r
+ */\r
+int  pppIOCtl(int pd, int cmd, void *arg);\r
+\r
+/*\r
+ * Return the Maximum Transmission Unit for the given PPP connection.\r
+ */\r
+u_int pppMTU(int pd);\r
+\r
+/*\r
+ * Write n characters to a ppp link.\r
+ *     RETURN: >= 0 Number of characters written\r
+ *                      -1 Failed to write to device\r
+ */\r
+int pppWrite(int pd, const u_char *s, int n);\r
+\r
+void pppMainWakeup(int pd);\r
+\r
+/* Configure i/f transmit parameters */\r
+void ppp_send_config (int, int, u32_t, int, int);\r
+/* Set extended transmit ACCM */\r
+void ppp_set_xaccm (int, ext_accm *);\r
+/* Configure i/f receive parameters */\r
+void ppp_recv_config (int, int, u32_t, int, int);\r
+/* Find out how long link has been idle */\r
+int  get_idle_time (int, struct ppp_idle *);\r
+\r
+/* Configure VJ TCP header compression */\r
+int  sifvjcomp (int, int, int, int);\r
+/* Configure i/f down (for IP) */\r
+int  sifup (int);              \r
+/* Set mode for handling packets for proto */\r
+int  sifnpmode (int u, int proto, enum NPmode mode);\r
+/* Configure i/f down (for IP) */\r
+int  sifdown (int);    \r
+/* Configure IP addresses for i/f */\r
+int  sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t);\r
+/* Reset i/f IP addresses */\r
+int  cifaddr (int, u32_t, u32_t);\r
+/* Create default route through i/f */\r
+int  sifdefaultroute (int, u32_t, u32_t);\r
+/* Delete default route through i/f */\r
+int  cifdefaultroute (int, u32_t, u32_t);\r
+\r
+/* Get appropriate netmask for address */\r
+u32_t GetMask (u32_t); \r
+\r
+#endif /* PPP_SUPPORT */\r
+\r
+#endif /* PPP_H */\r
index de1478cee832505541b76f2c49f7174209661f33..e4cf25a393c56306ebbb6863827b9e9a8f5fc897 100644 (file)
@@ -1,89 +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 */
+/*****************************************************************************\r
+* pppdebug.h - System debugging utilities.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1998 Global Election Systems Inc.\r
+* portions Copyright (c) 2001 by Cognizant Pty Ltd.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY (please don't use tabs!)\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 98-07-29 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*      Original.\r
+*\r
+*****************************************************************************\r
+*/\r
+#ifndef PPPDEBUG_H\r
+#define PPPDEBUG_H\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+/* Trace levels. */\r
+typedef enum {\r
+       LOG_CRITICAL = 0,\r
+       LOG_ERR = 1,\r
+       LOG_NOTICE = 2,\r
+       LOG_WARNING = 3,\r
+       LOG_INFO = 5,\r
+       LOG_DETAIL = 6,\r
+       LOG_DEBUG = 7\r
+} LogCodes;\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+/*\r
+ *     ppp_trace - a form of printf to send tracing information to stderr\r
+ */\r
+void ppp_trace(int level, const char *format,...);\r
+\r
+#if PPP_DEBUG > 0\r
+\r
+#define AUTHDEBUG(a) ppp_trace a\r
+#define IPCPDEBUG(a) ppp_trace a\r
+#define UPAPDEBUG(a) ppp_trace a\r
+#define LCPDEBUG(a) ppp_trace a\r
+#define FSMDEBUG(a) ppp_trace a\r
+#define CHAPDEBUG(a) ppp_trace a\r
+#define PPPDEBUG(a) ppp_trace a\r
+\r
+#define TRACELCP 1\r
+\r
+#else\r
+\r
+#define AUTHDEBUG(a)\r
+#define IPCPDEBUG(a)\r
+#define UPAPDEBUG(a)\r
+#define LCPDEBUG(a)\r
+#define FSMDEBUG(a)\r
+#define CHAPDEBUG(a)\r
+\r
+#define PPPDEBUG(a)\r
+\r
+#define TRACELCP 0\r
+\r
+#endif\r
+\r
+#endif /* PPPDEBUG_H */\r
index 05eeb4410d7ca60ca2be5dc6d5077e1d214f1c1e..d4431dd8ec104e1fba076ead68e71830aab33122 100644 (file)
-/*****************************************************************************
-* 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 */
-
+/*****************************************************************************\r
+* randm.c - Random number generator program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1998 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 98-06-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Extracted from avos.\r
+*****************************************************************************/\r
+\r
+#include "ppp.h"\r
+#if PPP_SUPPORT > 0\r
+#include "md5.h"\r
+#include "randm.h"\r
+\r
+#include "pppdebug.h"\r
+\r
+\r
+#if MD5_SUPPORT>0   /* this module depends on MD5 */\r
+#define RANDPOOLSZ 16   /* Bytes stored in the pool of randomness. */\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+static char randPool[RANDPOOLSZ];   /* Pool of randomness. */\r
+static long randCount = 0;      /* Pseudo-random incrementer */\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * Initialize the random number generator.\r
+ *\r
+ * Since this is to be called on power up, we don't have much\r
+ *  system randomess to work with.  Here all we use is the\r
+ *  real-time clock.  We'll accumulate more randomness as soon\r
+ *  as things start happening.\r
+ */\r
+void avRandomInit()\r
+{\r
+    avChurnRand(NULL, 0);\r
+}\r
+\r
+/*\r
+ * Churn the randomness pool on a random event.  Call this early and often\r
+ *  on random and semi-random system events to build randomness in time for\r
+ *  usage.  For randomly timed events, pass a null pointer and a zero length\r
+ *  and this will use the system timer and other sources to add randomness.\r
+ *  If new random data is available, pass a pointer to that and it will be\r
+ *  included.\r
+ *\r
+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427\r
+ */\r
+void avChurnRand(char *randData, u32_t randLen)\r
+{\r
+    MD5_CTX md5;\r
+\r
+/*  ppp_trace(LOG_INFO, "churnRand: %u@%P\n", randLen, randData); */\r
+    MD5Init(&md5);\r
+    MD5Update(&md5, (u_char *)randPool, sizeof(randPool));\r
+    if (randData)\r
+        MD5Update(&md5, (u_char *)randData, randLen);\r
+    else {\r
+        struct {\r
+            /* INCLUDE fields for any system sources of randomness */\r
+            char foobar;\r
+        } sysData;\r
+\r
+        /* Load sysData fields here. */\r
+        ;\r
+        MD5Update(&md5, (u_char *)&sysData, sizeof(sysData));\r
+    }\r
+    MD5Final((u_char *)randPool, &md5);\r
+/*  ppp_trace(LOG_INFO, "churnRand: -> 0\n"); */\r
+}\r
+\r
+/*\r
+ * Use the random pool to generate random data.  This degrades to pseudo\r
+ *  random when used faster than randomness is supplied using churnRand().\r
+ * Note: It's important that there be sufficient randomness in randPool\r
+ *  before this is called for otherwise the range of the result may be\r
+ *  narrow enough to make a search feasible.\r
+ *\r
+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427\r
+ *\r
+ * XXX Why does he not just call churnRand() for each block?  Probably\r
+ *  so that you don't ever publish the seed which could possibly help\r
+ *  predict future values.\r
+ * XXX Why don't we preserve md5 between blocks and just update it with\r
+ *  randCount each time?  Probably there is a weakness but I wish that\r
+ *  it was documented.\r
+ */\r
+void avGenRand(char *buf, u32_t bufLen)\r
+{\r
+    MD5_CTX md5;\r
+    u_char tmp[16];\r
+    u32_t n;\r
+\r
+    while (bufLen > 0) {\r
+        n = LWIP_MIN(bufLen, RANDPOOLSZ);\r
+        MD5Init(&md5);\r
+        MD5Update(&md5, (u_char *)randPool, sizeof(randPool));\r
+        MD5Update(&md5, (u_char *)&randCount, sizeof(randCount));\r
+        MD5Final(tmp, &md5);\r
+        randCount++;\r
+        memcpy(buf, tmp, n);\r
+        buf += n;\r
+        bufLen -= n;\r
+    }\r
+}\r
+\r
+/*\r
+ * Return a new random number.\r
+ */\r
+u32_t avRandom()\r
+{\r
+    u32_t newRand;\r
+\r
+    avGenRand((char *)&newRand, sizeof(newRand));\r
+\r
+    return newRand;\r
+}\r
+\r
+#else /* MD5_SUPPORT */\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+static int  avRandomized = 0;       /* Set when truely randomized. */\r
+static u32_t avRandomSeed = 0;      /* Seed used for random number generation. */\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * Initialize the random number generator.\r
+ *\r
+ * Here we attempt to compute a random number seed but even if\r
+ * it isn't random, we'll randomize it later.\r
+ *\r
+ * The current method uses the fields from the real time clock,\r
+ * the idle process counter, the millisecond counter, and the\r
+ * hardware timer tick counter.  When this is invoked\r
+ * in startup(), then the idle counter and timer values may\r
+ * repeat after each boot and the real time clock may not be\r
+ * operational.  Thus we call it again on the first random\r
+ * event.\r
+ */\r
+void avRandomInit()\r
+{\r
+#if 0\r
+    /* Get a pointer into the last 4 bytes of clockBuf. */\r
+    u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]);\r
+\r
+    /*\r
+     * Initialize our seed using the real-time clock, the idle\r
+     * counter, the millisecond timer, and the hardware timer\r
+     * tick counter.  The real-time clock and the hardware\r
+     * tick counter are the best sources of randomness but\r
+     * since the tick counter is only 16 bit (and truncated\r
+     * at that), the idle counter and millisecond timer\r
+     * (which may be small values) are added to help\r
+     * randomize the lower 16 bits of the seed.\r
+     */\r
+    readClk();\r
+    avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr\r
+             + ppp_mtime() + ((u32_t)TM1 << 16) + TM1;\r
+#else\r
+    avRandomSeed += sys_jiffies(); /* XXX */\r
+#endif\r
+        \r
+    /* Initialize the Borland random number generator. */\r
+    srand((unsigned)avRandomSeed);\r
+}\r
+\r
+/*\r
+ * Randomize our random seed value.  Here we use the fact that\r
+ * this function is called at *truely random* times by the polling\r
+ * and network functions.  Here we only get 16 bits of new random\r
+ * value but we use the previous value to randomize the other 16\r
+ * bits.\r
+ */\r
+void avRandomize(void)\r
+{\r
+    static u32_t last_jiffies;\r
+\r
+    if (!avRandomized) {\r
+        avRandomized = !0;\r
+        avRandomInit();\r
+        /* The initialization function also updates the seed. */\r
+    } else {\r
+/*        avRandomSeed += (avRandomSeed << 16) + TM1; */\r
+       avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */\r
+    }\r
+    last_jiffies = sys_jiffies();\r
+}\r
+\r
+/*\r
+ * Return a new random number.\r
+ * Here we use the Borland rand() function to supply a pseudo random\r
+ * number which we make truely random by combining it with our own\r
+ * seed which is randomized by truely random events. \r
+ * Thus the numbers will be truely random unless there have been no\r
+ * operator or network events in which case it will be pseudo random\r
+ * seeded by the real time clock.\r
+ */\r
+u32_t avRandom()\r
+{\r
+    return ((((u32_t)rand() << 16) + rand()) + avRandomSeed);\r
+}\r
+\r
+\r
+\r
+#endif /* MD5_SUPPORT */\r
+#endif /* PPP_SUPPORT */\r
+\r
index baa42f0c2cdfe3f82a0f3a7483f48b43b6419e84..2563d8976719a8332d38df26879cf6a38f395a37 100644 (file)
@@ -1,81 +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 */
+/*****************************************************************************\r
+* randm.h - Random number generator header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1998 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 98-05-29 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*      Extracted from avos.\r
+*****************************************************************************/\r
+\r
+#ifndef RANDM_H\r
+#define RANDM_H\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+/*\r
+ * Initialize the random number generator.\r
+ */\r
+void avRandomInit(void);\r
+\r
+/*\r
+ * Churn the randomness pool on a random event.  Call this early and often\r
+ *     on random and semi-random system events to build randomness in time for\r
+ *     usage.  For randomly timed events, pass a null pointer and a zero length\r
+ *     and this will use the system timer and other sources to add randomness.\r
+ *     If new random data is available, pass a pointer to that and it will be\r
+ *     included.\r
+ */\r
+void avChurnRand(char *randData, u32_t randLen);\r
+\r
+/*\r
+ * Randomize our random seed value.  To be called for truely random events\r
+ * such as user operations and network traffic.\r
+ */\r
+#if MD5_SUPPORT\r
+#define avRandomize()  avChurnRand(NULL, 0)\r
+#else\r
+void avRandomize(void);\r
+#endif\r
+\r
+/*\r
+ * Use the random pool to generate random data.  This degrades to pseudo\r
+ *     random when used faster than randomness is supplied using churnRand().\r
+ *     Thus it's important to make sure that the results of this are not\r
+ *     published directly because one could predict the next result to at\r
+ *     least some degree.  Also, it's important to get a good seed before\r
+ *     the first use.\r
+ */\r
+void avGenRand(char *buf, u32_t bufLen);\r
+\r
+/*\r
+ * Return a new random number.\r
+ */\r
+u32_t avRandom(void);\r
+\r
+\r
+#endif /* RANDM_H */\r
index 0636ee11bd89afc885a57dd467f2b0fc67800592..2c11affe35821fd4774a66d45c72c8841664589c 100644 (file)
-/*
- * 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
-
-
+/*\r
+ * Routines to compress and uncompess tcp packets (for transmission\r
+ * over low speed serial lines.\r
+ *\r
+ * Copyright (c) 1989 Regents of the University of California.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the University of California, Berkeley.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ *     Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:\r
+ *     - Initial distribution.\r
+ *\r
+ * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,\r
+ * so that the entire packet being decompressed doesn't have\r
+ * to be in contiguous memory (just the compressed header).\r
+ *\r
+ * Modified March 1998 by Guy Lancaster, glanca@gesn.com,\r
+ * for a 16 bit processor.\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include "ppp.h"\r
+#include "vj.h"\r
+#include "pppdebug.h"\r
+\r
+#if VJ_SUPPORT > 0\r
+\r
+#if LINK_STATS\r
+#define INCR(counter) ++comp->stats.counter\r
+#else\r
+#define INCR(counter)\r
+#endif\r
+\r
+#if defined(NO_CHAR_BITFIELDS)\r
+#define getip_hl(base) ((base).ip_hl_v&0xf)\r
+#define getth_off(base)        (((base).th_x2_off&0xf0)>>4)\r
+#else\r
+#define getip_hl(base) ((base).ip_hl)\r
+#define getth_off(base)        ((base).th_off)\r
+#endif\r
+\r
+void vj_compress_init(struct vjcompress *comp)\r
+{\r
+       register u_int i;\r
+       register struct cstate *tstate = comp->tstate;\r
+       \r
+#if MAX_SLOTS == 0\r
+       memset((char *)comp, 0, sizeof(*comp));\r
+#endif\r
+       comp->maxSlotIndex = MAX_SLOTS - 1;\r
+       comp->compressSlot = 0;         /* Disable slot ID compression by default. */\r
+       for (i = MAX_SLOTS - 1; i > 0; --i) {\r
+               tstate[i].cs_id = i;\r
+               tstate[i].cs_next = &tstate[i - 1];\r
+       }\r
+       tstate[0].cs_next = &tstate[MAX_SLOTS - 1];\r
+       tstate[0].cs_id = 0;\r
+       comp->last_cs = &tstate[0];\r
+       comp->last_recv = 255;\r
+       comp->last_xmit = 255;\r
+       comp->flags = VJF_TOSS;\r
+}\r
+\r
+\r
+/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ\r
+ * checks for zero (since zero has to be encoded in the long, 3 byte\r
+ * form).\r
+ */\r
+#define ENCODE(n) { \\r
+       if ((u_short)(n) >= 256) { \\r
+               *cp++ = 0; \\r
+               cp[1] = (n); \\r
+               cp[0] = (n) >> 8; \\r
+               cp += 2; \\r
+       } else { \\r
+               *cp++ = (n); \\r
+       } \\r
+}\r
+#define ENCODEZ(n) { \\r
+       if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \\r
+               *cp++ = 0; \\r
+               cp[1] = (n); \\r
+               cp[0] = (n) >> 8; \\r
+               cp += 2; \\r
+       } else { \\r
+               *cp++ = (n); \\r
+       } \\r
+}\r
+\r
+#define DECODEL(f) { \\r
+       if (*cp == 0) {\\r
+               u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \\r
+               (f) = htonl(tmp); \\r
+               cp += 3; \\r
+       } else { \\r
+               u32_t tmp = ntohl(f) + (u32_t)*cp++; \\r
+               (f) = htonl(tmp); \\r
+       } \\r
+}\r
+\r
+#define DECODES(f) { \\r
+       if (*cp == 0) {\\r
+               u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \\r
+               (f) = htons(tmp); \\r
+               cp += 3; \\r
+       } else { \\r
+               u_short tmp = ntohs(f) + (u_short)*cp++; \\r
+               (f) = htons(tmp); \\r
+       } \\r
+}\r
+\r
+#define DECODEU(f) { \\r
+       if (*cp == 0) {\\r
+               (f) = htons(((u_short)cp[1] << 8) | cp[2]); \\r
+               cp += 3; \\r
+       } else { \\r
+               (f) = htons((u_short)*cp++); \\r
+       } \\r
+}\r
+\r
+/*\r
+ * vj_compress_tcp - Attempt to do Van Jacobsen header compression on a\r
+ * packet.  This assumes that nb and comp are not null and that the first\r
+ * buffer of the chain contains a valid IP header.\r
+ * Return the VJ type code indicating whether or not the packet was\r
+ * compressed.\r
+ */\r
+u_int vj_compress_tcp(\r
+       struct vjcompress *comp,\r
+       struct pbuf *pb\r
+)\r
+{\r
+       register struct ip *ip = (struct ip *)pb->payload;\r
+       register struct cstate *cs = comp->last_cs->cs_next;\r
+       register u_short hlen = getip_hl(*ip);\r
+       register struct tcphdr *oth;\r
+       register struct tcphdr *th;\r
+       register u_short deltaS, deltaA;\r
+       register u_long deltaL;\r
+       register u_int changes = 0;\r
+       u_char new_seq[16];\r
+       register u_char *cp = new_seq;\r
+\r
+       /*      \r
+        * Check that the packet is IP proto TCP.\r
+        */\r
+       if (ip->ip_p != IPPROTO_TCP)\r
+               return (TYPE_IP);\r
+               \r
+       /*\r
+        * Bail if this is an IP fragment or if the TCP packet isn't\r
+        * `compressible' (i.e., ACK isn't set or some other control bit is\r
+        * set).  \r
+        */\r
+       if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40)\r
+               return (TYPE_IP);\r
+       th = (struct tcphdr *)&((long *)ip)[hlen];\r
+       if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK)\r
+               return (TYPE_IP);\r
+               \r
+       /*\r
+        * Packet is compressible -- we're going to send either a\r
+        * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need\r
+        * to locate (or create) the connection state.  Special case the\r
+        * most recently used connection since it's most likely to be used\r
+        * again & we don't have to do any reordering if it's used.\r
+        */\r
+       INCR(vjs_packets);\r
+       if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr \r
+                       || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr \r
+                       || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {\r
+               /*\r
+                * Wasn't the first -- search for it.\r
+                *\r
+                * States are kept in a circularly linked list with\r
+                * last_cs pointing to the end of the list.  The\r
+                * list is kept in lru order by moving a state to the\r
+                * head of the list whenever it is referenced.  Since\r
+                * the list is short and, empirically, the connection\r
+                * we want is almost always near the front, we locate\r
+                * states via linear search.  If we don't find a state\r
+                * for the datagram, the oldest state is (re-)used.\r
+                */\r
+               register struct cstate *lcs;\r
+               register struct cstate *lastcs = comp->last_cs;\r
+               \r
+               do {\r
+                       lcs = cs; cs = cs->cs_next;\r
+                       INCR(vjs_searches);\r
+                       if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr\r
+                                       && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr\r
+                                       && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)])\r
+                               goto found;\r
+               } while (cs != lastcs);\r
+               \r
+               /*\r
+                * Didn't find it -- re-use oldest cstate.  Send an\r
+                * uncompressed packet that tells the other side what\r
+                * connection number we're using for this conversation.\r
+                * Note that since the state list is circular, the oldest\r
+                * state points to the newest and we only need to set\r
+                * last_cs to update the lru linkage.\r
+                */\r
+               INCR(vjs_misses);\r
+               comp->last_cs = lcs;\r
+               hlen += getth_off(*th);\r
+               hlen <<= 2;\r
+               /* Check that the IP/TCP headers are contained in the first buffer. */\r
+               if (hlen > pb->len)\r
+                       return (TYPE_IP);\r
+               goto uncompressed;\r
+               \r
+               found:\r
+               /*\r
+                * Found it -- move to the front on the connection list.\r
+                */\r
+               if (cs == lastcs)\r
+                       comp->last_cs = lcs;\r
+               else {\r
+                       lcs->cs_next = cs->cs_next;\r
+                       cs->cs_next = lastcs->cs_next;\r
+                       lastcs->cs_next = cs;\r
+               }\r
+       }\r
+       \r
+       oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen];\r
+       deltaS = hlen;\r
+       hlen += getth_off(*th);\r
+       hlen <<= 2;\r
+       /* Check that the IP/TCP headers are contained in the first buffer. */\r
+       if (hlen > pb->len) {\r
+               PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", \r
+                                       hlen));\r
+               return (TYPE_IP);\r
+       }\r
+       \r
+       /*\r
+        * Make sure that only what we expect to change changed. The first\r
+        * line of the `if' checks the IP protocol version, header length &\r
+        * type of service.  The 2nd line checks the "Don't fragment" bit.\r
+        * The 3rd line checks the time-to-live and protocol (the protocol\r
+        * check is unnecessary but costless).  The 4th line checks the TCP\r
+        * header length.  The 5th line checks IP options, if any.  The 6th\r
+        * line checks TCP options, if any.  If any of these things are\r
+        * different between the previous & current datagram, we send the\r
+        * current datagram `uncompressed'.\r
+        */\r
+       if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] \r
+                       || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] \r
+                       || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] \r
+                       || getth_off(*th) != getth_off(*oth) \r
+                       || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) \r
+                       || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2)))\r
+               goto uncompressed;\r
+       \r
+       /*\r
+        * Figure out which of the changing fields changed.  The\r
+        * receiver expects changes in the order: urgent, window,\r
+        * ack, seq (the order minimizes the number of temporaries\r
+        * needed in this section of code).\r
+        */\r
+       if (th->th_flags & TCP_URG) {\r
+               deltaS = ntohs(th->th_urp);\r
+               ENCODEZ(deltaS);\r
+               changes |= NEW_U;\r
+       } else if (th->th_urp != oth->th_urp)\r
+               /* argh! URG not set but urp changed -- a sensible\r
+                * implementation should never do this but RFC793\r
+                * doesn't prohibit the change so we have to deal\r
+                * with it. */\r
+               goto uncompressed;\r
+       \r
+       if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) {\r
+               ENCODE(deltaS);\r
+               changes |= NEW_W;\r
+       }\r
+       \r
+       if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) {\r
+               if (deltaL > 0xffff)\r
+                       goto uncompressed;\r
+               deltaA = (u_short)deltaL;\r
+               ENCODE(deltaA);\r
+               changes |= NEW_A;\r
+       }\r
+       \r
+       if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) {\r
+               if (deltaL > 0xffff)\r
+                       goto uncompressed;\r
+               deltaS = (u_short)deltaL;\r
+               ENCODE(deltaS);\r
+               changes |= NEW_S;\r
+       }\r
+       \r
+       switch(changes) {\r
+       \r
+       case 0:\r
+               /*\r
+                * Nothing changed. If this packet contains data and the\r
+                * last one didn't, this is probably a data packet following\r
+                * an ack (normal on an interactive connection) and we send\r
+                * it compressed.  Otherwise it's probably a retransmit,\r
+                * retransmitted ack or window probe.  Send it uncompressed\r
+                * in case the other side missed the compressed version.\r
+                */\r
+               if (ip->ip_len != cs->cs_ip.ip_len &&\r
+                       ntohs(cs->cs_ip.ip_len) == hlen)\r
+               break;\r
+       \r
+       /* (fall through) */\r
+       \r
+       case SPECIAL_I:\r
+       case SPECIAL_D:\r
+               /*\r
+                * actual changes match one of our special case encodings --\r
+                * send packet uncompressed.\r
+                */\r
+               goto uncompressed;\r
+       \r
+       case NEW_S|NEW_A:\r
+               if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {\r
+                       /* special case for echoed terminal traffic */\r
+                       changes = SPECIAL_I;\r
+                       cp = new_seq;\r
+               }\r
+               break;\r
+       \r
+       case NEW_S:\r
+               if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {\r
+                       /* special case for data xfer */\r
+                       changes = SPECIAL_D;\r
+                       cp = new_seq;\r
+               }\r
+               break;\r
+       }\r
+       \r
+       deltaS = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id));\r
+       if (deltaS != 1) {\r
+               ENCODEZ(deltaS);\r
+               changes |= NEW_I;\r
+       }\r
+       if (th->th_flags & TCP_PSH)\r
+       changes |= TCP_PUSH_BIT;\r
+       /*\r
+        * Grab the cksum before we overwrite it below.  Then update our\r
+        * state with this packet's header.\r
+        */\r
+       deltaA = ntohs(th->th_sum);\r
+       BCOPY(ip, &cs->cs_ip, hlen);\r
+       \r
+       /*\r
+        * We want to use the original packet as our compressed packet.\r
+        * (cp - new_seq) is the number of bytes we need for compressed\r
+        * sequence numbers.  In addition we need one byte for the change\r
+        * mask, one for the connection id and two for the tcp checksum.\r
+        * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how\r
+        * many bytes of the original packet to toss so subtract the two to\r
+        * get the new packet size.\r
+        */\r
+       deltaS = (u_short)(cp - new_seq);\r
+       if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {\r
+               comp->last_xmit = cs->cs_id;\r
+               hlen -= deltaS + 4;\r
+               pbuf_header(pb, -hlen);\r
+               cp = (u_char *)pb->payload;\r
+               *cp++ = changes | NEW_C;\r
+               *cp++ = cs->cs_id;\r
+       } else {\r
+               hlen -= deltaS + 3;\r
+               pbuf_header(pb, -hlen);\r
+               cp = (u_char *)pb->payload;\r
+               *cp++ = changes;\r
+       }\r
+       *cp++ = deltaA >> 8;\r
+       *cp++ = deltaA;\r
+       BCOPY(new_seq, cp, deltaS);\r
+       INCR(vjs_compressed);\r
+       return (TYPE_COMPRESSED_TCP);\r
+\r
+       /*\r
+        * Update connection state cs & send uncompressed packet (that is,\r
+        * a regular ip/tcp packet but with the 'conversation id' we hope\r
+        * to use on future compressed packets in the protocol field).\r
+        */\r
+uncompressed:\r
+       BCOPY(ip, &cs->cs_ip, hlen);\r
+       ip->ip_p = cs->cs_id;\r
+       comp->last_xmit = cs->cs_id;\r
+       return (TYPE_UNCOMPRESSED_TCP);\r
+}\r
+\r
+/*\r
+ * Called when we may have missed a packet.\r
+ */\r
+void vj_uncompress_err(struct vjcompress *comp)\r
+{\r
+    comp->flags |= VJF_TOSS;\r
+       INCR(vjs_errorin);\r
+}\r
+\r
+/*\r
+ * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.\r
+ * Return 0 on success, -1 on failure.\r
+ */\r
+int vj_uncompress_uncomp(\r
+       struct pbuf *nb,\r
+       struct vjcompress *comp\r
+)\r
+{\r
+       register u_int hlen;\r
+       register struct cstate *cs;\r
+       register struct ip *ip;\r
+       \r
+       ip = (struct ip *)nb->payload;\r
+       hlen = getip_hl(*ip) << 2;\r
+       if (ip->ip_p >= MAX_SLOTS\r
+                       || hlen + sizeof(struct tcphdr) > nb->len\r
+                       || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2)\r
+                           > nb->len\r
+                       || hlen > MAX_HDR) {\r
+               PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", \r
+                                       ip->ip_p, hlen, nb->len));\r
+               comp->flags |= VJF_TOSS;\r
+               INCR(vjs_errorin);\r
+               return -1;\r
+       }\r
+       cs = &comp->rstate[comp->last_recv = ip->ip_p];\r
+       comp->flags &=~ VJF_TOSS;\r
+       ip->ip_p = IPPROTO_TCP;\r
+       BCOPY(ip, &cs->cs_ip, hlen);\r
+       cs->cs_hlen = hlen;\r
+       INCR(vjs_uncompressedin);\r
+       return 0;\r
+}\r
+\r
+/*\r
+ * Uncompress a packet of type TYPE_COMPRESSED_TCP.\r
+ * The packet is composed of a buffer chain and the first buffer\r
+ * must contain an accurate chain length.\r
+ * The first buffer must include the entire compressed TCP/IP header. \r
+ * This procedure replaces the compressed header with the uncompressed\r
+ * header and returns the length of the VJ header.\r
+ */\r
+int vj_uncompress_tcp(\r
+       struct pbuf **nb,\r
+       struct vjcompress *comp\r
+)\r
+{\r
+       u_char *cp;\r
+       struct tcphdr *th;\r
+       struct cstate *cs;\r
+       u_short *bp;\r
+       struct pbuf *n0 = *nb;\r
+       u32_t tmp;\r
+       u_int vjlen, hlen, changes;\r
+       \r
+       INCR(vjs_compressedin);\r
+       cp = (u_char *)n0->payload;\r
+       changes = *cp++;\r
+       if (changes & NEW_C) {\r
+               /* \r
+                * Make sure the state index is in range, then grab the state.\r
+                * If we have a good state index, clear the 'discard' flag. \r
+                */\r
+               if (*cp >= MAX_SLOTS) {\r
+                       PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: bad cid=%d\n", *cp));\r
+                       goto bad;\r
+               }\r
+               \r
+               comp->flags &=~ VJF_TOSS;\r
+               comp->last_recv = *cp++;\r
+       } else {\r
+               /* \r
+                * this packet has an implicit state index.  If we've\r
+                * had a line error since the last time we got an\r
+                * explicit state index, we have to toss the packet. \r
+                */\r
+               if (comp->flags & VJF_TOSS) {\r
+                       PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: tossing\n"));\r
+                       INCR(vjs_tossed);\r
+                       return (-1);\r
+               }\r
+       }\r
+       cs = &comp->rstate[comp->last_recv];\r
+       hlen = getip_hl(cs->cs_ip) << 2;\r
+       th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];\r
+       th->th_sum = htons((*cp << 8) | cp[1]);\r
+       cp += 2;\r
+       if (changes & TCP_PUSH_BIT)\r
+               th->th_flags |= TCP_PSH;\r
+       else\r
+               th->th_flags &=~ TCP_PSH;\r
+       \r
+       switch (changes & SPECIALS_MASK) {\r
+       case SPECIAL_I:\r
+               {\r
+                       register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;\r
+                       /* some compilers can't nest inline assembler.. */\r
+                       tmp = ntohl(th->th_ack) + i;\r
+                       th->th_ack = htonl(tmp);\r
+                       tmp = ntohl(th->th_seq) + i;\r
+                       th->th_seq = htonl(tmp);\r
+               }\r
+               break;\r
+       \r
+       case SPECIAL_D:\r
+               /* some compilers can't nest inline assembler.. */\r
+               tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;\r
+               th->th_seq = htonl(tmp);\r
+               break;\r
+       \r
+       default:\r
+               if (changes & NEW_U) {\r
+                       th->th_flags |= TCP_URG;\r
+                       DECODEU(th->th_urp);\r
+               } else\r
+                       th->th_flags &=~ TCP_URG;\r
+               if (changes & NEW_W)\r
+                       DECODES(th->th_win);\r
+               if (changes & NEW_A)\r
+                       DECODEL(th->th_ack);\r
+               if (changes & NEW_S)\r
+                       DECODEL(th->th_seq);\r
+               break;\r
+       }\r
+       if (changes & NEW_I) {\r
+               DECODES(cs->cs_ip.ip_id);\r
+       } else {\r
+               cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1;\r
+               cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id);\r
+       }\r
+       \r
+       /*\r
+        * At this point, cp points to the first byte of data in the\r
+        * packet.  Fill in the IP total length and update the IP\r
+        * header checksum.\r
+        */\r
+       vjlen = (u_short)(cp - (u_char*)n0->payload);\r
+       if (n0->len < vjlen) {\r
+               /* \r
+                * We must have dropped some characters (crc should detect\r
+                * this but the old slip framing won't) \r
+                */\r
+               PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: head buffer %d too short %d\n", \r
+                                 n0->len, vjlen));\r
+               goto bad;\r
+       }\r
+       \r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+       tmp = n0->tot_len - vjlen + cs->cs_hlen;\r
+       cs->cs_ip.ip_len = htons(tmp);\r
+#else\r
+       cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen);\r
+#endif\r
+       \r
+       /* recompute the ip header checksum */\r
+       bp = (u_short *) &cs->cs_ip;\r
+       cs->cs_ip.ip_sum = 0;\r
+       for (tmp = 0; hlen > 0; hlen -= 2)\r
+               tmp += *bp++;\r
+       tmp = (tmp & 0xffff) + (tmp >> 16);\r
+       tmp = (tmp & 0xffff) + (tmp >> 16);\r
+       cs->cs_ip.ip_sum = (u_short)(~tmp);\r
+       \r
+       /* Remove the compressed header and prepend the uncompressed header. */\r
+       pbuf_header(n0, -vjlen);\r
+\r
+       if(MEM_ALIGN(n0->payload) != n0->payload) {\r
+               struct pbuf *np, *q;\r
+               u8_t *bufptr;\r
+\r
+               np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);\r
+               if(!np) {\r
+                       PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: realign failed\n"));\r
+                       *nb = NULL;\r
+                       goto bad;\r
+               }\r
+\r
+               pbuf_header(np, -cs->cs_hlen);\r
+\r
+               bufptr = n0->payload;\r
+               for(q = np; q != NULL; q = q->next) {\r
+                       memcpy(q->payload, bufptr, q->len);\r
+                       bufptr += q->len;\r
+               }\r
+\r
+               if(n0->next) {\r
+                       pbuf_chain(np, n0->next);\r
+                       pbuf_dechain(n0);\r
+               }\r
+               pbuf_free(n0);\r
+               n0 = np;\r
+       }\r
+\r
+       if(pbuf_header(n0, cs->cs_hlen)) {\r
+               struct pbuf *np;\r
+\r
+               LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);\r
+               np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);\r
+               if(!np) {\r
+                       PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: prepend failed\n"));\r
+                       *nb = NULL;\r
+                       goto bad;\r
+               }\r
+               pbuf_cat(np, n0);\r
+               n0 = np;\r
+       }\r
+       LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);\r
+       memcpy(n0->payload, &cs->cs_ip, cs->cs_hlen);\r
+\r
+       *nb = n0;\r
+\r
+       return vjlen;\r
+       \r
+bad:\r
+       comp->flags |= VJF_TOSS;\r
+       INCR(vjs_errorin);\r
+       return (-1);\r
+}\r
+\r
+#endif\r
+\r
+\r
index 717208145731c10c507c906ebdc86f6b756ef86a..9da27148114bb7f5324497fc7118c1cf3b32fa14 100644 (file)
-/*
- * 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 */
+/*\r
+ * Definitions for tcp compression routines.\r
+ *\r
+ * $Id: vj.h,v 1.4 2004/02/07 00:30:03 likewise Exp $\r
+ *\r
+ * Copyright (c) 1989 Regents of the University of California.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the University of California, Berkeley.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ *     Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:\r
+ *     - Initial distribution.\r
+ */\r
+\r
+#ifndef VJ_H\r
+#define VJ_H\r
+\r
+#include "vjbsdhdr.h"\r
+\r
+#define MAX_SLOTS      16                      /* must be > 2 and < 256 */\r
+#define MAX_HDR                128\r
+\r
+/*\r
+ * Compressed packet format:\r
+ *\r
+ * The first octet contains the packet type (top 3 bits), TCP\r
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence\r
+ * numbers have changed (bottom 5 bits).  The next octet is a\r
+ * conversation number that associates a saved IP/TCP header with\r
+ * the compressed packet.  The next two octets are the TCP checksum\r
+ * from the original datagram.  The next 0 to 15 octets are\r
+ * sequence number changes, one change per bit set in the header\r
+ * (there may be no changes and there are two special cases where\r
+ * the receiver implicitly knows what changed -- see below).\r
+ * \r
+ * There are 5 numbers which can change (they are always inserted\r
+ * in the following order): TCP urgent pointer, window,\r
+ * acknowlegement, sequence number and IP ID.  (The urgent pointer\r
+ * is different from the others in that its value is sent, not the\r
+ * change in value.)  Since typical use of SLIP links is biased\r
+ * toward small packets (see comments on MTU/MSS below), changes\r
+ * use a variable length coding with one octet for numbers in the\r
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the\r
+ * range 256 - 65535 or 0.  (If the change in sequence number or\r
+ * ack is more than 65535, an uncompressed packet is sent.)\r
+ */\r
+\r
+/*\r
+ * Packet types (must not conflict with IP protocol version)\r
+ *\r
+ * The top nibble of the first octet is the packet type.  There are\r
+ * three possible types: IP (not proto TCP or tcp with one of the\r
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but\r
+ * with the 8-bit protocol field replaced by an 8-bit connection id --\r
+ * this type of packet syncs the sender & receiver); and compressed\r
+ * TCP (described above).\r
+ *\r
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and\r
+ * is logically part of the 4-bit "changes" field that follows.  Top\r
+ * three bits are actual packet type.  For backward compatibility\r
+ * and in the interest of conserving bits, numbers are chosen so the\r
+ * IP protocol version number (4) which normally appears in this nibble\r
+ * means "IP packet".\r
+ */\r
+\r
+/* packet types */\r
+#define TYPE_IP 0x40\r
+#define TYPE_UNCOMPRESSED_TCP 0x70\r
+#define TYPE_COMPRESSED_TCP 0x80\r
+#define TYPE_ERROR 0x00\r
+\r
+/* Bits in first octet of compressed packet */\r
+#define NEW_C  0x40    /* flag bits for what changed in a packet */\r
+#define NEW_I  0x20\r
+#define NEW_S  0x08\r
+#define NEW_A  0x04\r
+#define NEW_W  0x02\r
+#define NEW_U  0x01\r
+\r
+/* reserved, special-case values of above */\r
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U)          /* echoed interactive traffic */\r
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)    /* unidirectional data */\r
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)\r
+\r
+#define TCP_PUSH_BIT 0x10\r
+\r
+\r
+/*\r
+ * "state" data for each active tcp conversation on the wire.  This is\r
+ * basically a copy of the entire IP/TCP header from the last packet\r
+ * we saw from the conversation together with a small identifier\r
+ * the transmit & receive ends of the line use to locate saved header.\r
+ */\r
+struct cstate {\r
+    struct cstate *cs_next;    /* next most recently used state (xmit only) */\r
+    u_short cs_hlen;           /* size of hdr (receive only) */\r
+    u_char cs_id;                      /* connection # associated with this state */\r
+    u_char cs_filler;\r
+    union {\r
+               char csu_hdr[MAX_HDR];\r
+               struct ip csu_ip;       /* ip/tcp hdr from most recent packet */\r
+    } vjcs_u;\r
+};\r
+#define cs_ip vjcs_u.csu_ip\r
+#define cs_hdr vjcs_u.csu_hdr\r
+\r
+\r
+struct vjstat {\r
+    unsigned long vjs_packets;                 /* outbound packets */\r
+    unsigned long vjs_compressed;              /* outbound compressed packets */\r
+    unsigned long vjs_searches;                        /* searches for connection state */\r
+    unsigned long vjs_misses;                  /* times couldn't find conn. state */\r
+    unsigned long vjs_uncompressedin;  /* inbound uncompressed packets */\r
+    unsigned long vjs_compressedin;            /* inbound compressed packets */\r
+    unsigned long vjs_errorin;                 /* inbound unknown type packets */\r
+    unsigned long vjs_tossed;                  /* inbound packets tossed because of error */\r
+};\r
+\r
+/*\r
+ * all the state data for one serial line (we need one of these per line).\r
+ */\r
+struct vjcompress {\r
+    struct cstate *last_cs;    /* most recently used tstate */\r
+    u_char last_recv;          /* last rcvd conn. id */\r
+    u_char last_xmit;          /* last sent conn. id */\r
+    u_short flags;\r
+    u_char maxSlotIndex;\r
+    u_char compressSlot;       /* Flag indicating OK to compress slot ID. */\r
+#if LINK_STATS\r
+    struct vjstat stats;\r
+#endif\r
+    struct cstate tstate[MAX_SLOTS];   /* xmit connection states */\r
+    struct cstate rstate[MAX_SLOTS];   /* receive connection states */\r
+};\r
+\r
+/* flag values */\r
+#define VJF_TOSS 1U            /* tossing rcvd frames because of input err */\r
+\r
+extern void  vj_compress_init (struct vjcompress *comp);\r
+extern u_int vj_compress_tcp (struct vjcompress *comp, struct pbuf *pb);\r
+extern void  vj_uncompress_err (struct vjcompress *comp);\r
+extern int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp);\r
+extern int vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp);\r
+\r
+#endif /* VJ_H */\r
index a089352ade270e0f6b7d7f427696b7fd97193eb3..a7d180c16c80de16b992d13a8037ee210178557c 100644 (file)
@@ -1,76 +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 */
+#ifndef VJBSDHDR_H\r
+#define VJBSDHDR_H\r
+\r
+#include "lwip/tcp.h"\r
+\r
+\r
+/*\r
+ * Structure of an internet header, naked of options.\r
+ *\r
+ * We declare ip_len and ip_off to be short, rather than u_short\r
+ * pragmatically since otherwise unsigned comparisons can result\r
+ * against negative integers quite easily, and fail in subtle ways.\r
+ */\r
+PACK_STRUCT_BEGIN\r
+struct ip\r
+{\r
+#if defined(NO_CHAR_BITFIELDS)\r
+       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... */\r
+#else\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+       unsigned ip_hl:4,                               /* header length */\r
+               ip_v:4;                                         /* version */\r
+#elif BYTE_ORDER == BIG_ENDIAN \r
+       unsigned ip_v:4,                                        /* version */\r
+               ip_hl:4;                                        /* header length */\r
+#else\r
+       COMPLAIN - NO BYTE ORDER SELECTED!\r
+#endif\r
+#endif\r
+       u_char  ip_tos;                                 /* type of service */\r
+       u_short ip_len;                                 /* total length */\r
+       u_short ip_id;                                  /* identification */\r
+       u_short ip_off;                                 /* fragment offset field */\r
+#define        IP_DF 0x4000                            /* dont fragment flag */\r
+#define        IP_MF 0x2000                            /* more fragments flag */\r
+#define        IP_OFFMASK 0x1fff                       /* mask for fragmenting bits */\r
+       u_char  ip_ttl;                                 /* time to live */\r
+       u_char  ip_p;                                   /* protocol */\r
+       u_short ip_sum;                                 /* checksum */\r
+       struct  in_addr ip_src,ip_dst;  /* source and dest address */\r
+};\r
+PACK_STRUCT_END\r
+\r
+typedef u32_t tcp_seq;\r
+\r
+/*\r
+ * TCP header.\r
+ * Per RFC 793, September, 1981.\r
+ */\r
+PACK_STRUCT_BEGIN\r
+struct tcphdr  \r
+{\r
+       u_short th_sport;               /* source port */\r
+       u_short th_dport;               /* destination port */\r
+       tcp_seq th_seq;                 /* sequence number */\r
+       tcp_seq th_ack;                 /* acknowledgement number */\r
+#if defined(NO_CHAR_BITFIELDS)\r
+       u_char th_x2_off;\r
+#else\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+       unsigned        th_x2:4,                /* (unused) */\r
+                       th_off:4;               /* data offset */\r
+#endif\r
+#if BYTE_ORDER == BIG_ENDIAN \r
+       unsigned        th_off:4,               /* data offset */\r
+                       th_x2:4;                /* (unused) */\r
+#endif\r
+#endif\r
+       u_char  th_flags;\r
+       u_short th_win;                 /* window */\r
+       u_short th_sum;                 /* checksum */\r
+       u_short th_urp;                 /* urgent pointer */\r
+};\r
+PACK_STRUCT_END\r
+\r
+#endif /* VJBSDHDR_H */\r
index dd8db208cce04301151b1b7805b6dac6fe8be1b7..ba8510b0dbdcdcf8d92781ab7370d719627227e5 100644 (file)
-/*
- * 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;
-}
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ *\r
+ * Redistribution and use in source and binary forms, with or without \r
+ * modification, are permitted provided that the following conditions \r
+ * are met: \r
+ * 1. Redistributions of source code must retain the above copyright \r
+ *    notice, this list of conditions and the following disclaimer. \r
+ * 2. Redistributions in binary form must reproduce the above copyright \r
+ *    notice, this list of conditions and the following disclaimer in the \r
+ *    documentation and/or other materials provided with the distribution. \r
+ * 3. Neither the name of the Institute nor the names of its contributors \r
+ *    may be used to endorse or promote products derived from this software \r
+ *    without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND \r
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE \r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \r
+ * SUCH DAMAGE. \r
+ *\r
+ * This file is built upon the file: src/arch/rtxc/netif/sioslip.c\r
+ *\r
+ * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com> \r
+ */\r
+\r
+/* \r
+ * This is an arch independent SLIP netif. The specific serial hooks must be\r
+ * provided by another file. They are sio_open, sio_recv and sio_send\r
+ */\r
+\r
+#include "netif/slipif.h"\r
+#include "lwip/opt.h"\r
+#include "lwip/def.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/sio.h"\r
+\r
+#define SLIP_END     0300\r
+#define SLIP_ESC     0333\r
+#define SLIP_ESC_END 0334\r
+#define SLIP_ESC_ESC 0335\r
+\r
+#define MAX_SIZE     1500\r
+\r
+/**\r
+ * Send a pbuf doing the necessary SLIP encapsulation\r
+ *\r
+ * Uses the serial layer's sio_send() \r
+ */\r
+err_t\r
+slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)\r
+{\r
+  struct pbuf *q;\r
+  u16_t i;\r
+  u8_t c;\r
+\r
+  /* Send pbuf out on the serial I/O device. */\r
+  sio_send(SLIP_END, netif->state);\r
+\r
+  for (q = p; q != NULL; q = q->next) {\r
+    for (i = 0; i < q->len; i++) {\r
+      c = ((u8_t *)q->payload)[i];\r
+      switch (c) {\r
+      case SLIP_END:\r
+        sio_send(SLIP_ESC, netif->state);\r
+        sio_send(SLIP_ESC_END, netif->state);\r
+        break;\r
+      case SLIP_ESC:\r
+        sio_send(SLIP_ESC, netif->state);\r
+        sio_send(SLIP_ESC_ESC, netif->state);\r
+        break;\r
+      default:\r
+        sio_send(c, netif->state);\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  sio_send(SLIP_END, netif->state);\r
+  return 0;\r
+}\r
+\r
+/**\r
+ * Handle the incoming SLIP stream character by character\r
+ *\r
+ * Poll the serial layer by calling sio_recv()\r
+ * \r
+ * @return The IP packet when SLIP_END is received \r
+ */\r
+static struct pbuf *\r
+slipif_input(struct netif *netif)\r
+{\r
+  u8_t c;\r
+  struct pbuf *p, *q;\r
+  u16_t recved;\r
+  u16_t i;\r
+\r
+  q = p = NULL;\r
+  recved = i = 0;\r
+  c = 0;\r
+\r
+  while (1) {\r
+    c = sio_recv(netif->state);\r
+    switch (c) {\r
+    case SLIP_END:\r
+      if (recved > 0) {\r
+        /* Received whole packet. */\r
+        pbuf_realloc(q, recved);\r
+        \r
+        LINK_STATS_INC(link.recv);\r
+        \r
+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));\r
+        return q;\r
+      }\r
+      break;\r
+\r
+    case SLIP_ESC:\r
+      c = sio_recv(netif->state);\r
+      switch (c) {\r
+      case SLIP_ESC_END:\r
+        c = SLIP_END;\r
+        break;\r
+      case SLIP_ESC_ESC:\r
+        c = SLIP_ESC;\r
+        break;\r
+      }\r
+      /* FALLTHROUGH */\r
+\r
+    default:\r
+      if (p == NULL) {\r
+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));\r
+        p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL);\r
+\r
+        if (p == NULL) {\r
+          LINK_STATS_INC(link.drop);\r
+          LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));\r
+        }\r
+\r
+        if (q != NULL) {\r
+          pbuf_cat(q, p);\r
+        } else {\r
+          q = p;\r
+        }\r
+      }\r
+      if (p != NULL && recved < MAX_SIZE) {\r
+        ((u8_t *)p->payload)[i] = c;\r
+        recved++;\r
+        i++;\r
+        if (i >= p->len) {\r
+          i = 0;\r
+          if (p->next != NULL && p->next->len > 0)\r
+            p = p->next;\r
+          else\r
+            p = NULL;\r
+        }\r
+      }\r
+      break;\r
+    }\r
+\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * The SLIP input thread.\r
+ *\r
+ * Feed the IP layer with incoming packets\r
+ */\r
+static void\r
+slipif_loop(void *nf)\r
+{\r
+  struct pbuf *p;\r
+  struct netif *netif = (struct netif *)nf;\r
+\r
+  while (1) {\r
+    p = slipif_input(netif);\r
+    netif->input(p, netif);\r
+  }\r
+}\r
+\r
+/**\r
+ * SLIP netif initialization\r
+ *\r
+ * Call the arch specific sio_open and remember\r
+ * the opened device in the state field of the netif.\r
+ */\r
+err_t\r
+slipif_init(struct netif *netif)\r
+{\r
+\r
+  LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));\r
+\r
+  netif->name[0] = 's';\r
+  netif->name[1] = 'l';\r
+  netif->output = slipif_output;\r
+  netif->mtu = 1500;\r
+  netif->flags = NETIF_FLAG_POINTTOPOINT;\r
+\r
+  netif->state = sio_open(netif->num);\r
+  if (!netif->state)\r
+    return ERR_IF;\r
+\r
+  sys_thread_new(slipif_loop, netif, SLIPIF_THREAD_PRIO);\r
+  return ERR_OK;\r
+}\r
index 5b7f78ec9b75d337ec69d493be90239962232582..fd0b2ced132838e8a201f3ac31e53da84249e0d7 100644 (file)
@@ -135,8 +135,14 @@ struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
 #endif\r
 \r
 #ifndef UIP_CONF_EXTERNAL_BUFFER\r
-u8_t uip_buf[UIP_BUFSIZE + 2] ALIGN_STRUCT_END; /* The packet buffer that contains\r
-                                   incoming packets. */\r
+\r
+#ifdef __ICCARM__\r
+       #pragma data_alignment=4\r
+               u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains incoming packets. */\r
+#else\r
+       u8_t uip_buf[UIP_BUFSIZE + 2] ALIGN_STRUCT_END; /* The packet buffer that contains incoming packets. */\r
+#endif\r
+                               \r
 #endif /* UIP_CONF_EXTERNAL_BUFFER */\r
 \r
 void *uip_appdata;               /* The uip_appdata pointer points to\r
@@ -251,15 +257,15 @@ uip_add32(u8_t *op32, u16_t op16)
   uip_acc32[2] = op32[2] + (op16 >> 8);\r
   uip_acc32[1] = op32[1];\r
   uip_acc32[0] = op32[0];\r
-  \r
+\r
   if(uip_acc32[2] < (op16 >> 8)) {\r
     ++uip_acc32[1];\r
     if(uip_acc32[1] == 0) {\r
       ++uip_acc32[0];\r
     }\r
   }\r
-  \r
-  \r
+\r
+\r
   if(uip_acc32[3] < (op16 & 0xff)) {\r
     ++uip_acc32[2];\r
     if(uip_acc32[2] == 0) {\r
@@ -284,7 +290,7 @@ chksum(u16_t sum, const u8_t *data, u16_t len)
 \r
   dataptr = data;\r
   last_byte = data + len - 1;\r
-  \r
+\r
   while(dataptr < last_byte) { /* At least two more bytes */\r
     t = (dataptr[0] << 8) + dataptr[1];\r
     sum += t;\r
@@ -293,7 +299,7 @@ chksum(u16_t sum, const u8_t *data, u16_t len)
     }\r
     dataptr += 2;\r
   }\r
-  \r
+\r
   if(dataptr == last_byte) {\r
     t = (dataptr[0] << 8) + 0;\r
     sum += t;\r
@@ -329,15 +335,15 @@ upper_layer_chksum(u8_t proto)
 {\r
   u16_t upper_layer_len;\r
   u16_t sum;\r
-  \r
+\r
 #if UIP_CONF_IPV6\r
   upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]);\r
 #else /* UIP_CONF_IPV6 */\r
   upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN;\r
 #endif /* UIP_CONF_IPV6 */\r
-  \r
+\r
   /* First sum pseudoheader. */\r
-  \r
+\r
   /* IP protocol and length fields. This addition cannot carry. */\r
   sum = upper_layer_len + proto;\r
   /* Sum IP source and destination addresses. */\r
@@ -346,7 +352,7 @@ upper_layer_chksum(u8_t proto)
   /* Sum TCP header and data. */\r
   sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN],\r
               upper_layer_len);\r
-    \r
+\r
   return (sum == 0) ? 0xffff : htons(sum);\r
 }\r
 /*---------------------------------------------------------------------------*/\r
@@ -355,7 +361,7 @@ u16_t
 uip_icmp6chksum(void)\r
 {\r
   return upper_layer_chksum(UIP_PROTO_ICMP6);\r
-  \r
+\r
 }\r
 #endif /* UIP_CONF_IPV6 */\r
 /*---------------------------------------------------------------------------*/\r
@@ -392,7 +398,7 @@ uip_init(void)
     uip_udp_conns[c].lport = 0;\r
   }\r
 #endif /* UIP_UDP */\r
-  \r
+\r
 \r
   /* IPv4 initialization. */\r
 #if UIP_FIXEDADDR == 0\r
@@ -406,7 +412,7 @@ struct uip_conn *
 uip_connect(uip_ipaddr_t *ripaddr, u16_t rport)\r
 {\r
   register struct uip_conn *conn, *cconn;\r
-  \r
+\r
   /* Find an unused local port. */\r
  again:\r
   ++lastport;\r
@@ -443,7 +449,7 @@ uip_connect(uip_ipaddr_t *ripaddr, u16_t rport)
   if(conn == 0) {\r
     return 0;\r
   }\r
-  \r
+\r
   conn->tcpstateflags = UIP_SYN_SENT;\r
 \r
   conn->snd_nxt[0] = iss[0];\r
@@ -452,7 +458,7 @@ uip_connect(uip_ipaddr_t *ripaddr, u16_t rport)
   conn->snd_nxt[3] = iss[3];\r
 \r
   conn->initialmss = conn->mss = UIP_TCP_MSS;\r
-  \r
+\r
   conn->len = 1;   /* TCP length of the SYN is one. */\r
   conn->nrtx = 0;\r
   conn->timer = 1; /* Send the SYN next time around. */\r
@@ -462,7 +468,7 @@ uip_connect(uip_ipaddr_t *ripaddr, u16_t rport)
   conn->lport = htons(lastport);\r
   conn->rport = rport;\r
   uip_ipaddr_copy(&conn->ripaddr, ripaddr);\r
-  \r
+\r
   return conn;\r
 }\r
 #endif /* UIP_ACTIVE_OPEN */\r
@@ -472,7 +478,7 @@ struct uip_udp_conn *
 uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport)\r
 {\r
   register struct uip_udp_conn *conn;\r
-  \r
+\r
   /* Find an unused local port. */\r
  again:\r
   ++lastport;\r
@@ -480,7 +486,7 @@ uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport)
   if(lastport >= 32000) {\r
     lastport = 4096;\r
   }\r
-  \r
+\r
   for(c = 0; c < UIP_UDP_CONNS; ++c) {\r
     if(uip_udp_conns[c].lport == htons(lastport)) {\r
       goto again;\r
@@ -499,7 +505,7 @@ uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport)
   if(conn == 0) {\r
     return 0;\r
   }\r
-  \r
+\r
   conn->lport = HTONS(lastport);\r
   conn->rport = rport;\r
   if(ripaddr == NULL) {\r
@@ -508,7 +514,7 @@ uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport)
     uip_ipaddr_copy(&conn->ripaddr, ripaddr);\r
   }\r
   conn->ttl = UIP_TTL;\r
-  \r
+\r
   return conn;\r
 }\r
 #endif /* UIP_UDP */\r
@@ -593,12 +599,12 @@ uip_reass(void)
     memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],\r
           (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),\r
           len);\r
-      \r
+\r
     /* Update the bitmap. */\r
     if(offset / (8 * 8) == (offset + len) / (8 * 8)) {\r
       /* If the two endpoints are in the same byte, we only update\r
         that byte. */\r
-            \r
+       \r
       uip_reassbitmap[offset / (8 * 8)] |=\r
             bitmap_bits[(offset / 8 ) & 7] &\r
             ~bitmap_bits[((offset + len) / 8 ) & 7];\r
@@ -614,7 +620,7 @@ uip_reass(void)
       uip_reassbitmap[(offset + len) / (8 * 8)] |=\r
        ~bitmap_bits[((offset + len) / 8 ) & 7];\r
     }\r
-    \r
+\r
     /* If this fragment has the More Fragments flag set to zero, we\r
        know that this is the last fragment, so we can calculate the\r
        size of the entire packet. We also set the\r
@@ -625,7 +631,7 @@ uip_reass(void)
       uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;\r
       uip_reasslen = offset + len;\r
     }\r
-    \r
+\r
     /* Finally, we check if we have a full packet in the buffer. We do\r
        this by checking if we have the last fragment and if all bits\r
        in the bitmap are set. */\r
@@ -687,7 +693,7 @@ uip_process(u8_t flag)
     goto udp_send;\r
   }\r
 #endif /* UIP_UDP */\r
-  \r
+\r
   uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];\r
 \r
   /* Check if we were invoked because of a poll request for a\r
@@ -700,7 +706,7 @@ uip_process(u8_t flag)
        goto appsend;\r
     }\r
     goto drop;\r
-    \r
+\r
     /* Check if we were invoked because of the perodic timer fireing. */\r
   } else if(flag == UIP_TIMER) {\r
 #if UIP_REASSEMBLY\r
@@ -759,7 +765,7 @@ uip_process(u8_t flag)
                                         4:\r
                                         uip_connr->nrtx);\r
          ++(uip_connr->nrtx);\r
-         \r
+       \r
          /* Ok, so we need to retransmit. We do this differently\r
             depending on which state we are in. In ESTABLISHED, we\r
             call upon the application so that it may prepare the\r
@@ -772,14 +778,14 @@ uip_process(u8_t flag)
            /* In the SYN_RCVD state, we should retransmit our\r
                SYNACK. */\r
            goto tcp_send_synack;\r
-           \r
+       \r
 #if UIP_ACTIVE_OPEN\r
          case UIP_SYN_SENT:\r
            /* In the SYN_SENT state, we retransmit out SYN. */\r
            BUF->flags = 0;\r
            goto tcp_send_syn;\r
 #endif /* UIP_ACTIVE_OPEN */\r
-           \r
+       \r
          case UIP_ESTABLISHED:\r
            /* In the ESTABLISHED state, we call upon the application\r
                to do the actual retransmit after which we jump into\r
@@ -788,13 +794,13 @@ uip_process(u8_t flag)
            uip_flags = UIP_REXMIT;\r
            UIP_APPCALL();\r
            goto apprexmit;\r
-           \r
+       \r
          case UIP_FIN_WAIT_1:\r
          case UIP_CLOSING:\r
          case UIP_LAST_ACK:\r
            /* In all these states we should retransmit a FINACK. */\r
            goto tcp_send_finack;\r
-           \r
+       \r
          }\r
        }\r
       } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) {\r
@@ -826,7 +832,7 @@ uip_process(u8_t flag)
   UIP_STAT(++uip_stat.ip.recv);\r
 \r
   /* Start of IP input header processing code. */\r
-  \r
+\r
 #if UIP_CONF_IPV6\r
   /* Check validity of the IP header. */\r
   if((BUF->vtc & 0xf0) != 0x60)  { /* IP version and header length. */\r
@@ -844,7 +850,7 @@ uip_process(u8_t flag)
     goto drop;\r
   }\r
 #endif /* UIP_CONF_IPV6 */\r
-  \r
+\r
   /* Check the size of the packet. If the size reported to us in\r
      uip_len is smaller the size reported in the IP header, we assume\r
      that the packet has been corrupted in transit. If the size of\r
@@ -914,7 +920,7 @@ uip_process(u8_t flag)
       goto udp_input;\r
     }\r
 #endif /* UIP_BROADCAST */\r
-    \r
+\r
     /* Check if the packet is destined for our IP address. */\r
 #if !UIP_CONF_IPV6\r
     if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) {\r
@@ -1032,14 +1038,14 @@ uip_process(u8_t flag)
        /* Save the sender's address in our neighbor list. */\r
        uip_neighbor_add(ICMPBUF->srcipaddr, &(ICMPBUF->options[2]));\r
       }\r
-      \r
+\r
       /* We should now send a neighbor advertisement back to where the\r
         neighbor solicication came from. */\r
       ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT;\r
       ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */\r
-      \r
+\r
       ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;\r
-      \r
+\r
       uip_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr);\r
       uip_ipaddr_copy(ICMPBUF->srcipaddr, uip_hostaddr);\r
       ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;\r
@@ -1048,7 +1054,7 @@ uip_process(u8_t flag)
       ICMPBUF->icmpchksum = 0;\r
       ICMPBUF->icmpchksum = ~uip_icmp6chksum();\r
       goto send;\r
-      \r
+\r
     }\r
     goto drop;\r
   } else if(ICMPBUF->type == ICMP6_ECHO) {\r
@@ -1057,12 +1063,12 @@ uip_process(u8_t flag)
        ICMP checksum before we return the packet. */\r
 \r
     ICMPBUF->type = ICMP6_ECHO_REPLY;\r
-    \r
+\r
     uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);\r
     uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);\r
     ICMPBUF->icmpchksum = 0;\r
     ICMPBUF->icmpchksum = ~uip_icmp6chksum();\r
-    \r
+\r
     UIP_STAT(++uip_stat.icmp.sent);\r
     goto send;\r
   } else {\r
@@ -1074,7 +1080,7 @@ uip_process(u8_t flag)
   }\r
 \r
   /* End of IPv6 ICMP processing. */\r
-  \r
+\r
 #endif /* !UIP_CONF_IPV6 */\r
 \r
 #if UIP_UDP\r
@@ -1120,7 +1126,7 @@ uip_process(u8_t flag)
   }\r
   UIP_LOG("udp: no matching connection found");\r
   goto drop;\r
-  \r
+\r
  udp_found:\r
   uip_conn = NULL;\r
   uip_flags = UIP_NEWDATA;\r
@@ -1154,7 +1160,7 @@ uip_process(u8_t flag)
 \r
   uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);\r
   uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr);\r
-   \r
+\r
   uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];\r
 \r
 #if UIP_UDP_CHECKSUMS\r
@@ -1164,16 +1170,16 @@ uip_process(u8_t flag)
     UDPBUF->udpchksum = 0xffff;\r
   }\r
 #endif /* UIP_UDP_CHECKSUMS */\r
-  \r
+\r
   goto ip_send_nolen;\r
 #endif /* UIP_UDP */\r
-  \r
+\r
   /* TCP input processing. */\r
  tcp_input:\r
   UIP_STAT(++uip_stat.tcp.recv);\r
 \r
   /* Start of TCP input header processing code. */\r
-  \r
+\r
   if(uip_tcpchksum() != 0xffff) {   /* Compute and check the TCP\r
                                       checksum. */\r
     UIP_STAT(++uip_stat.tcp.drop);\r
@@ -1181,8 +1187,8 @@ uip_process(u8_t flag)
     UIP_LOG("tcp: bad checksum.");\r
     goto drop;\r
   }\r
-  \r
-  \r
+\r
+\r
   /* Demultiplex this segment. */\r
   /* First check any active connections. */\r
   for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1];\r
@@ -1202,14 +1208,14 @@ uip_process(u8_t flag)
   if((BUF->flags & TCP_CTL) != TCP_SYN) {\r
     goto reset;\r
   }\r
-  \r
+\r
   tmp16 = BUF->destport;\r
   /* Next, check listening connections. */\r
   for(c = 0; c < UIP_LISTENPORTS; ++c) {\r
     if(tmp16 == uip_listenports[c])\r
       goto found_listen;\r
   }\r
-  \r
+\r
   /* No matching connection found, so we send a RST packet. */\r
   UIP_STAT(++uip_stat.tcp.synrst);\r
  reset:\r
@@ -1220,7 +1226,7 @@ uip_process(u8_t flag)
   }\r
 \r
   UIP_STAT(++uip_stat.tcp.rst);\r
-  \r
+\r
   BUF->flags = TCP_RST | TCP_ACK;\r
   uip_len = UIP_IPTCPH_LEN;\r
   BUF->tcpoffset = 5 << 4;\r
@@ -1229,15 +1235,15 @@ uip_process(u8_t flag)
   c = BUF->seqno[3];\r
   BUF->seqno[3] = BUF->ackno[3];\r
   BUF->ackno[3] = c;\r
-  \r
+\r
   c = BUF->seqno[2];\r
   BUF->seqno[2] = BUF->ackno[2];\r
   BUF->ackno[2] = c;\r
-  \r
+\r
   c = BUF->seqno[1];\r
   BUF->seqno[1] = BUF->ackno[1];\r
   BUF->ackno[1] = c;\r
-  \r
+\r
   c = BUF->seqno[0];\r
   BUF->seqno[0] = BUF->ackno[0];\r
   BUF->ackno[0] = c;\r
@@ -1252,16 +1258,16 @@ uip_process(u8_t flag)
       }\r
     }\r
   }\r
\r
+\r
   /* Swap port numbers. */\r
   tmp16 = BUF->srcport;\r
   BUF->srcport = BUF->destport;\r
   BUF->destport = tmp16;\r
-  \r
+\r
   /* Swap IP addresses. */\r
   uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);\r
   uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);\r
-  \r
+\r
   /* And send out the RST packet! */\r
   goto tcp_send_noconn;\r
 \r
@@ -1298,7 +1304,7 @@ uip_process(u8_t flag)
     goto drop;\r
   }\r
   uip_conn = uip_connr;\r
-  \r
+\r
   /* Fill in the necessary fields for the new connection. */\r
   uip_connr->rto = uip_connr->timer = UIP_RTO;\r
   uip_connr->sa = 0;\r
@@ -1354,19 +1360,19 @@ uip_process(u8_t flag)
       }\r
     }\r
   }\r
-  \r
+\r
   /* Our response will be a SYNACK. */\r
 #if UIP_ACTIVE_OPEN\r
  tcp_send_synack:\r
   BUF->flags = TCP_ACK;\r
-  \r
+\r
  tcp_send_syn:\r
   BUF->flags |= TCP_SYN;\r
 #else /* UIP_ACTIVE_OPEN */\r
  tcp_send_synack:\r
   BUF->flags = TCP_SYN | TCP_ACK;\r
 #endif /* UIP_ACTIVE_OPEN */\r
-  \r
+\r
   /* We send out the TCP Maximum Segment Size option with our\r
      SYNACK. */\r
   BUF->optdata[0] = TCP_OPT_MSS;\r
@@ -1455,7 +1461,7 @@ uip_process(u8_t flag)
       /* Reset length of outstanding data. */\r
       uip_connr->len = 0;\r
     }\r
-    \r
+\r
   }\r
 \r
   /* Do different things depending on in what state the connection is. */\r
@@ -1543,7 +1549,7 @@ uip_process(u8_t flag)
     uip_conn->tcpstateflags = UIP_CLOSED;\r
     goto reset;\r
 #endif /* UIP_ACTIVE_OPEN */\r
-    \r
+\r
   case UIP_ESTABLISHED:\r
     /* In the ESTABLISHED state, we call upon the application to feed\r
     data into the uip_buf. If the UIP_ACKDATA flag is set, the\r
@@ -1645,7 +1651,7 @@ uip_process(u8_t flag)
       UIP_APPCALL();\r
 \r
     appsend:\r
-      \r
+\r
       if(uip_flags & UIP_ABORT) {\r
        uip_slen = 0;\r
        uip_connr->tcpstateflags = UIP_CLOSED;\r
@@ -1697,7 +1703,7 @@ uip_process(u8_t flag)
       uip_connr->nrtx = 0;\r
     apprexmit:\r
       uip_appdata = uip_sappdata;\r
-      \r
+\r
       /* If the application has data to be sent, or if the incoming\r
          packet had new data in it, we must send out a packet. */\r
       if(uip_slen > 0 && uip_connr->len > 0) {\r
@@ -1726,7 +1732,7 @@ uip_process(u8_t flag)
       UIP_APPCALL();\r
     }\r
     break;\r
-    \r
+\r
   case UIP_FIN_WAIT_1:\r
     /* The application has closed the connection, but the remote host\r
        hasn't closed its end yet. Thus we do nothing but wait for a\r
@@ -1755,7 +1761,7 @@ uip_process(u8_t flag)
       goto tcp_send_ack;\r
     }\r
     goto drop;\r
-      \r
+\r
   case UIP_FIN_WAIT_2:\r
     if(uip_len > 0) {\r
       uip_add_rcv_nxt(uip_len);\r
@@ -1775,7 +1781,7 @@ uip_process(u8_t flag)
 \r
   case UIP_TIME_WAIT:\r
     goto tcp_send_ack;\r
-    \r
+\r
   case UIP_CLOSING:\r
     if(uip_flags & UIP_ACKDATA) {\r
       uip_connr->tcpstateflags = UIP_TIME_WAIT;\r
@@ -1783,7 +1789,7 @@ uip_process(u8_t flag)
     }\r
   }\r
   goto drop;\r
-  \r
+\r
 \r
   /* We jump here when we are ready to send the packet, and just want\r
      to set the appropriate TCP sequence numbers in the TCP header. */\r
@@ -1802,14 +1808,14 @@ uip_process(u8_t flag)
   BUF->ackno[1] = uip_connr->rcv_nxt[1];\r
   BUF->ackno[2] = uip_connr->rcv_nxt[2];\r
   BUF->ackno[3] = uip_connr->rcv_nxt[3];\r
-  \r
+\r
   BUF->seqno[0] = uip_connr->snd_nxt[0];\r
   BUF->seqno[1] = uip_connr->snd_nxt[1];\r
   BUF->seqno[2] = uip_connr->snd_nxt[2];\r
   BUF->seqno[3] = uip_connr->snd_nxt[3];\r
 \r
   BUF->proto = UIP_PROTO_TCP;\r
-  \r
+\r
   BUF->srcport  = uip_connr->lport;\r
   BUF->destport = uip_connr->rport;\r
 \r
@@ -1838,11 +1844,11 @@ uip_process(u8_t flag)
 #endif /* UIP_CONF_IPV6 */\r
 \r
   BUF->urgp[0] = BUF->urgp[1] = 0;\r
-  \r
+\r
   /* Calculate TCP checksum. */\r
   BUF->tcpchksum = 0;\r
   BUF->tcpchksum = ~(uip_tcpchksum());\r
-  \r
+\r
  ip_send_nolen:\r
 \r
 #if UIP_CONF_IPV6\r
@@ -1861,12 +1867,12 @@ uip_process(u8_t flag)
   BUF->ipchksum = ~(uip_ipchksum());\r
   DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum());\r
 #endif /* UIP_CONF_IPV6 */\r
-   \r
+\r
   UIP_STAT(++uip_stat.tcp.sent);\r
  send:\r
   DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len,\r
               (BUF->len[0] << 8) | BUF->len[1]);\r
-  \r
+\r
   UIP_STAT(++uip_stat.ip.sent);\r
   /* Return and let the caller do the actual transmission. */\r
   uip_flags = 0;\r
index 8ff9a240c9cbbd01cee6cfd490c107d733f221dd..82da6fbd2ca77f0732f5314983b8d43858c0456a 100644 (file)
@@ -95,7 +95,7 @@ typedef uip_ip4addr_t uip_ipaddr_t;
 \r
  uip_ipaddr(&addr, 192,168,1,2);\r
  uip_sethostaddr(&addr);\r
\r
+\r
  \endcode\r
  * \param addr A pointer to an IP address of type uip_ipaddr_t;\r
  *\r
@@ -419,7 +419,11 @@ void uip_setipid(u16_t id);
  }\r
  \endcode\r
  */\r
-extern u8_t uip_buf[UIP_BUFSIZE+2];\r
+#ifndef UIP_CONF_EXTERNAL_BUFFER\r
+       extern u8_t uip_buf[UIP_BUFSIZE+2];\r
+#else\r
+       extern unsigned char *uip_buf;\r
+#endif\r
 \r
 /** @} */\r
 \r
@@ -749,7 +753,7 @@ void uip_send(const void *data, int len);
  \code\r
  uip_ipaddr_t addr;\r
  struct uip_udp_conn *c;\r
\r
+\r
  uip_ipaddr(&addr, 192,168,2,1);\r
  c = uip_udp_new(&addr, HTONS(12345));\r
  if(c != NULL) {\r
@@ -810,7 +814,7 @@ struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport);
  * These functions can be used for converting between different data\r
  * formats used by uIP.\r
  */\r
\r
+\r
 /**\r
  * Construct an IP address from four bytes.\r
  *\r
@@ -822,7 +826,7 @@ struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport);
  \code\r
  uip_ipaddr_t ipaddr;\r
  struct uip_conn *c;\r
\r
+\r
  uip_ipaddr(&ipaddr, 192,168,1,2);\r
  c = uip_connect(&ipaddr, HTONS(80));\r
  \endcode\r
@@ -1152,11 +1156,11 @@ extern u16_t uip_urglen, uip_surglen;
  */\r
 struct uip_conn {\r
   uip_ipaddr_t ripaddr;   /**< The IP address of the remote host. */\r
-  \r
+\r
   u16_t lport;        /**< The local TCP port, in network byte order. */\r
   u16_t rport;        /**< The local remote TCP port, in network byte\r
                         order. */\r
-  \r
+\r
   u8_t rcv_nxt[4];    /**< The sequence number that we expect to\r
                         receive next. */\r
   u8_t snd_nxt[4];    /**< The sequence number that was last sent by\r
@@ -1352,7 +1356,7 @@ void uip_process(u8_t flag);
    incoming data that should be processed, or because the periodic\r
    timer has fired. These values are never used directly, but only in\r
    the macrose defined in this file. */\r
\r
+\r
 #define UIP_DATA          1     /* Tells uIP that there is incoming\r
                                   data in the uip_buf buffer. The\r
                                   length of the data is stored in the\r
@@ -1379,10 +1383,15 @@ void uip_process(u8_t flag);
 #define UIP_TIME_WAIT   7\r
 #define UIP_LAST_ACK    8\r
 #define UIP_TS_MASK     15\r
-  \r
+\r
 #define UIP_STOPPED      16\r
 \r
 /* The TCP and IP headers. */\r
+\r
+#ifdef __ICCARM__\r
+       #pragma pack(1)\r
+#endif\r
+\r
 struct uip_tcpip_hdr {\r
 #if UIP_CONF_IPV6\r
   /* IPv6 header. */\r
@@ -1405,7 +1414,7 @@ struct uip_tcpip_hdr {
   u16_t srcipaddr[2],\r
     destipaddr[2];\r
 #endif /* UIP_CONF_IPV6 */\r
-  \r
+\r
   /* TCP header. */\r
   u16_t srcport,\r
     destport;\r
@@ -1419,7 +1428,15 @@ struct uip_tcpip_hdr {
   u8_t optdata[4];\r
 } PACK_STRUCT_END;\r
 \r
+#ifdef __ICCARM__\r
+       #pragma pack()\r
+#endif\r
+\r
 /* The ICMP and IP headers. */\r
+#ifdef __ICCARM__\r
+       #pragma pack(1)\r
+#endif\r
+\r
 struct uip_icmpip_hdr {\r
 #if UIP_CONF_IPV6\r
   /* IPv6 header. */\r
@@ -1442,7 +1459,7 @@ struct uip_icmpip_hdr {
   u16_t srcipaddr[2],\r
     destipaddr[2];\r
 #endif /* UIP_CONF_IPV6 */\r
-  \r
+\r
   /* ICMP (echo) header. */\r
   u8_t type, icode;\r
   u16_t icmpchksum;\r
@@ -1455,8 +1472,16 @@ struct uip_icmpip_hdr {
 #endif /* !UIP_CONF_IPV6 */\r
 } PACK_STRUCT_END;\r
 \r
+#ifdef __ICCARM__\r
+       #pragma pack()\r
+#endif\r
+\r
 \r
 /* The UDP and IP headers. */\r
+#ifdef __ICCARM__\r
+       #pragma pack(1)\r
+#endif\r
+\r
 struct uip_udpip_hdr {\r
 #if UIP_CONF_IPV6\r
   /* IPv6 header. */\r
@@ -1479,7 +1504,7 @@ struct uip_udpip_hdr {
   u16_t srcipaddr[2],\r
     destipaddr[2];\r
 #endif /* UIP_CONF_IPV6 */\r
-  \r
+\r
   /* UDP header. */\r
   u16_t srcport,\r
     destport;\r
@@ -1487,6 +1512,10 @@ struct uip_udpip_hdr {
   u16_t udpchksum;\r
 } PACK_STRUCT_END;\r
 \r
+#ifdef __ICCARM__\r
+       #pragma pack()\r
+#endif\r
+\r
 \r
 \r
 /**\r
@@ -1539,10 +1568,18 @@ extern uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr;
 /**\r
  * Representation of a 48-bit Ethernet address.\r
  */\r
+#ifdef __ICCARM__\r
+       #pragma pack(1)\r
+#endif\r
+\r
 struct uip_eth_addr {\r
   u8_t addr[6];\r
 } PACK_STRUCT_END;\r
 \r
+#ifdef __ICCARM__\r
+       #pragma pack()\r
+#endif\r
+\r
 /**\r
  * Calculate the Internet checksum over a buffer.\r
  *\r
index 577d515272a9f50dd4d9200974e5799047fddd5e..44c7975fceb65dc369147cd45ed23cd341c5ca0e 100644 (file)
@@ -16,7 +16,7 @@
  *\r
  * \note This ARP implementation only supports Ethernet.\r
  */\r
\r
+\r
 /**\r
  * \file\r
  * Implementation of the ARP Address Resolution Protocol.\r
 \r
 #include <string.h>\r
 \r
+#ifdef __ICCARM__\r
+       #pragma pack(1)\r
+#endif\r
+\r
 struct arp_hdr {\r
   struct uip_eth_hdr ethhdr;\r
   u16_t hwtype;\r
@@ -76,6 +80,14 @@ struct arp_hdr {
   u16_t dipaddr[2];\r
 } PACK_STRUCT_END;\r
 \r
+#ifdef __ICCARM__\r
+       #pragma pack()\r
+#endif\r
+\r
+#ifdef __ICCARM__\r
+       #pragma pack(1)\r
+#endif\r
+\r
 struct ethip_hdr {\r
   struct uip_eth_hdr ethhdr;\r
   /* IP header. */\r
@@ -91,6 +103,10 @@ struct ethip_hdr {
     destipaddr[2];\r
 } PACK_STRUCT_END;\r
 \r
+#ifdef __ICCARM__\r
+       #pragma pack()\r
+#endif\r
+\r
 #define ARP_REQUEST 1\r
 #define ARP_REPLY   2\r
 \r
@@ -142,7 +158,7 @@ void
 uip_arp_timer(void)\r
 {\r
   struct arp_entry *tabptr;\r
-  \r
+\r
   ++arptime;\r
   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {\r
     tabptr = &arp_table[i];\r
@@ -172,7 +188,7 @@ uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
          the IP address in this ARP table entry. */\r
       if(ipaddr[0] == tabptr->ipaddr[0] &&\r
         ipaddr[1] == tabptr->ipaddr[1]) {\r
-        \r
+       \r
        /* An old entry found, update this and return. */\r
        memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);\r
        tabptr->time = arptime;\r
@@ -247,7 +263,7 @@ uip_arp_ipin(void)
     return;\r
   }\r
   uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));\r
-  \r
+\r
   return;\r
 }\r
 #endif /* 0 */\r
@@ -277,13 +293,13 @@ uip_arp_ipin(void)
 void\r
 uip_arp_arpin(void)\r
 {\r
-  \r
+\r
   if(uip_len < sizeof(struct arp_hdr)) {\r
     uip_len = 0;\r
     return;\r
   }\r
   uip_len = 0;\r
-  \r
+\r
   switch(BUF->opcode) {\r
   case HTONS(ARP_REQUEST):\r
     /* ARP request. If it asked for our address, we send out a\r
@@ -293,7 +309,7 @@ uip_arp_arpin(void)
         table, since it is likely that we will do more communication\r
         with this host in the future. */\r
       uip_arp_update(BUF->sipaddr, &BUF->shwaddr);\r
-      \r
+\r
       /* The reply opcode is 2. */\r
       BUF->opcode = HTONS(2);\r
 \r
@@ -301,7 +317,7 @@ uip_arp_arpin(void)
       memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);\r
       memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);\r
       memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);\r
-      \r
+\r
       BUF->dipaddr[0] = BUF->sipaddr[0];\r
       BUF->dipaddr[1] = BUF->sipaddr[1];\r
       BUF->sipaddr[0] = uip_hostaddr[0];\r
@@ -354,7 +370,7 @@ void
 uip_arp_out(void)\r
 {\r
   struct arp_entry *tabptr;\r
-  \r
+\r
   /* Find the destination IP address in the ARP table and construct\r
      the Ethernet header. If the destination IP addres isn't on the\r
      local network, we use the default router's IP address instead.\r
@@ -376,7 +392,7 @@ uip_arp_out(void)
       /* Else, we use the destination IP address. */\r
       uip_ipaddr_copy(ipaddr, IPBUF->destipaddr);\r
     }\r
-      \r
+\r
     for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {\r
       tabptr = &arp_table[i];\r
       if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) {\r
@@ -392,7 +408,7 @@ uip_arp_out(void)
       memset(BUF->dhwaddr.addr, 0x00, 6);\r
       memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);\r
       memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);\r
-    \r
+\r
       uip_ipaddr_copy(BUF->dipaddr, ipaddr);\r
       uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);\r
       BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */\r
@@ -403,7 +419,7 @@ uip_arp_out(void)
       BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);\r
 \r
       uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];\r
-    \r
+\r
       uip_len = sizeof(struct arp_hdr);\r
       return;\r
     }\r
@@ -412,7 +428,7 @@ uip_arp_out(void)
     memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);\r
   }\r
   memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);\r
-  \r
+\r
   IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);\r
 \r
   uip_len += sizeof(struct uip_eth_hdr);\r
index d6bc1fb0e6b53ff0d4d985a297d1ff5053dff439..b6b2b66b4192c5b2b56ac380dc9f62df373fb476 100644 (file)
@@ -7,13 +7,13 @@
  * \addtogroup uiparp\r
  * @{\r
  */\r
\r
+\r
 /**\r
  * \file\r
  * Macros and definitions for the ARP module.\r
  * \author Adam Dunkels <adam@dunkels.com>\r
  */\r
-  \r
+\r
 \r
 /*\r
  * Copyright (c) 2001-2003, Adam Dunkels.\r
@@ -60,12 +60,20 @@ extern struct uip_eth_addr uip_ethaddr;
 /**\r
  * The Ethernet header.\r
  */\r
+#ifdef __ICCARM__\r
+       #pragma pack(1)\r
+#endif\r
+\r
 struct uip_eth_hdr {\r
   struct uip_eth_addr dest;\r
   struct uip_eth_addr src;\r
   u16_t type;\r
 }PACK_STRUCT_END;\r
 \r
+#ifdef __ICCARM__\r
+       #pragma pack()\r
+#endif\r
+\r
 #define UIP_ETHTYPE_ARP 0x0806\r
 #define UIP_ETHTYPE_IP  0x0800\r
 #define UIP_ETHTYPE_IP6 0x86dd\r
index a05aac08ea77cbc0404ab1f3d5ba893c43cc4a52..6325ac905eeae93253005e8e010554e79a48bb05 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index f97f2b71af780108a08f2a84682137bd72607093..a5892b8cd410d154c9707eff55774c7d519bc6c2 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index d0549dda3158931618d6f23217fddb756065e028..d36ab9d10c5888921f380f65b2b8dc64c4aae61a 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index bb5e8efe756c54dffb139da087e7c72934cce00c..6536ffe6269572430cba1df3959e989c9c513ebb 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 7ad1eebd23b1e46148c57de76a0e735a66a96249..02ddc279f7bc53c576d4c213feb6404dc5586ed3 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index ef3a718047e92544b8853b4a438a4ae123e781ff..53ba5020a723a400e344fd701b4efa1577149fea 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index c1a2f3a64444fecf4109ad93a4dc290052070fad..9a4c7840f8849bad968337e732221156a1b0a4ad 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index b0bebd7cb758ec8e22dcfbe5b45c956ed2ce21ec..2f54f3272f2f210013d9b2e197ab146bc50a9ab6 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index c5599f894c277a4d46fee74486d81b6fab997ef4..c30b00b9cf813b45f6672ea44c3a23eba542fab1 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 60808b16b1ca8e663940130e6b1711fe55eccc30..afcab72de04fd49e0b6889dd278ca5f67a6e5cae 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 1be2809c860a6b556a76b9520024780c077f5236..16708299d46de26ffee7fb5a10083cd9939dec9e 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index f53d3fa4d43acd27c301416339d0ca25840fe8bd..741f2f2ff8f30236ae408af4de7cb0b5759e8613 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index dbc76a3e41c3a12c0dd8192e2ea1519fe2fcaa57..9a7db7bbb924610c7ac40e8bc6f0bcba513e8c7b 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 75696b703256a6b6a747642b706c1a3b7ae9b687..75d8132968b47e9f45f15c9fccf9d8f5ef6770ed 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index dc4c0836edfdf384a5cb8227f622392cc4f649b8..f1f78ae7989235e5f73f13100867bc4d829ada3f 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index d370423ae20d242bf0b4314edca8037cc9c4b030..56dd19b1cb0f92733ab4e1224f2024df59b9f9a7 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 58cc77915671c1bf592e7f53935c80153ad349d1..f34ab5bdbad0cfb4d4c505940af793c1c9389b78 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
index 0cfc0c8092629a64426ebbfa62494679fc6baca5..9a7f97b2f4eeb2124a0245e39bd0a75174b4985b 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r