Browse Source

update lwip to 1.3.2

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@297 bbd45198-f89e-11dd-88c7-29a3b14d5316
bernard.xiong 15 years ago
parent
commit
a27f7c67bd
73 changed files with 2663 additions and 965 deletions
  1. 171 0
      net/lwip/CHANGELOG
  2. 1 1
      net/lwip/README
  3. 1 1
      net/lwip/SConscript
  4. 2 1
      net/lwip/src/api/api_lib.c
  5. 12 1
      net/lwip/src/api/api_msg.c
  6. 5 0
      net/lwip/src/api/netbuf.c
  7. 15 25
      net/lwip/src/api/netdb.c
  8. 36 0
      net/lwip/src/api/netifapi.c
  9. 43 42
      net/lwip/src/api/sockets.c
  10. 176 87
      net/lwip/src/core/dhcp.c
  11. 1 1
      net/lwip/src/core/dns.c
  12. 5 0
      net/lwip/src/core/init.c
  13. 75 31
      net/lwip/src/core/ipv4/autoip.c
  14. 38 64
      net/lwip/src/core/ipv4/ip.c
  15. 4 4
      net/lwip/src/core/mem.c
  16. 53 6
      net/lwip/src/core/memp.c
  17. 0 116
      net/lwip/src/core/memp_tiny.c
  18. 37 11
      net/lwip/src/core/netif.c
  19. 77 43
      net/lwip/src/core/pbuf.c
  20. 5 5
      net/lwip/src/core/raw.c
  21. 27 25
      net/lwip/src/core/snmp/mib2.c
  22. 1 1
      net/lwip/src/core/snmp/mib_structs.c
  23. 8 6
      net/lwip/src/core/sys.c
  24. 44 41
      net/lwip/src/core/tcp.c
  25. 211 124
      net/lwip/src/core/tcp_in.c
  26. 139 66
      net/lwip/src/core/tcp_out.c
  27. 13 12
      net/lwip/src/core/udp.c
  28. 11 0
      net/lwip/src/include/ipv4/lwip/autoip.h
  29. 9 10
      net/lwip/src/include/ipv4/lwip/icmp.h
  30. 13 2
      net/lwip/src/include/ipv4/lwip/ip.h
  31. 5 0
      net/lwip/src/include/ipv4/lwip/ip_addr.h
  32. 1 1
      net/lwip/src/include/lwip/api_msg.h
  33. 3 2
      net/lwip/src/include/lwip/debug.h
  34. 7 7
      net/lwip/src/include/lwip/dhcp.h
  35. 1 1
      net/lwip/src/include/lwip/init.h
  36. 1 4
      net/lwip/src/include/lwip/memp.h
  37. 9 0
      net/lwip/src/include/lwip/netbuf.h
  38. 1 1
      net/lwip/src/include/lwip/netdb.h
  39. 2 2
      net/lwip/src/include/lwip/netif.h
  40. 5 0
      net/lwip/src/include/lwip/netifapi.h
  41. 31 11
      net/lwip/src/include/lwip/opt.h
  42. 66 6
      net/lwip/src/include/lwip/sio.h
  43. 18 10
      net/lwip/src/include/lwip/tcp.h
  44. 3 0
      net/lwip/src/include/lwip/udp.h
  45. 25 13
      net/lwip/src/include/netif/etharp.h
  46. 1 0
      net/lwip/src/include/netif/slipif.h
  47. 7 1
      net/lwip/src/lwipopts.h
  48. 4 0
      net/lwip/src/netif/FILES
  49. 62 25
      net/lwip/src/netif/etharp.c
  50. 9 17
      net/lwip/src/netif/ethernetif.c
  51. 2 0
      net/lwip/src/netif/ppp/auth.c
  52. 1 0
      net/lwip/src/netif/ppp/chap.c
  53. 3 0
      net/lwip/src/netif/ppp/chpms.c
  54. 3 1
      net/lwip/src/netif/ppp/fsm.c
  55. 1 14
      net/lwip/src/netif/ppp/ipcp.c
  56. 2 0
      net/lwip/src/netif/ppp/md5.c
  57. 3 0
      net/lwip/src/netif/ppp/pap.c
  58. 28 38
      net/lwip/src/netif/ppp/ppp.c
  59. 2 2
      net/lwip/src/netif/ppp/ppp.h
  60. 3 3
      net/lwip/src/netif/ppp/ppp_oe.c
  61. 1 0
      net/lwip/src/netif/ppp/randm.c
  62. 1 1
      net/lwip/src/netif/ppp/vj.c
  63. 167 79
      net/lwip/src/netif/slipif.c
  64. 37 0
      net/lwip/test/unit/lwip_check.h
  65. 42 0
      net/lwip/test/unit/lwip_unittests.c
  66. 196 0
      net/lwip/test/unit/tcp/tcp_helper.c
  67. 36 0
      net/lwip/test/unit/tcp/tcp_helper.h
  68. 104 0
      net/lwip/test/unit/tcp/test_tcp.c
  69. 8 0
      net/lwip/test/unit/tcp/test_tcp.h
  70. 433 0
      net/lwip/test/unit/tcp/test_tcp_oos.c
  71. 8 0
      net/lwip/test/unit/tcp/test_tcp_oos.h
  72. 80 0
      net/lwip/test/unit/udp/test_udp.c
  73. 8 0
      net/lwip/test/unit/udp/test_udp.h

+ 171 - 0
net/lwip/CHANGELOG

@@ -19,8 +19,179 @@ HISTORY
 
   ++ New features:
 
+
+  ++ Bugfixes:
+
+
+(STABLE-1.3.2)
+
+  ++ New features:
+
+  2009-10-27 Simon Goldschmidt/Stephan Lesage
+  * netifapi.c/.h: Added netifapi_netif_set_addr()
+
+  2009-10-07 Simon Goldschmidt/Fabian Koch
+  * api_msg.c, netbuf.c/.h, opt.h: patch #6888: Patch for UDP Netbufs to
+    support dest-addr and dest-port (optional: LWIP_NETBUF_RECVINFO)
+
+  2009-08-26 Simon Goldschmidt/Simon Kallweit
+  * slipif.c/.h: bug #26397: SLIP polling support
+
+  2009-08-25 Simon Goldschmidt
+  * opt.h, etharp.h/.c: task #9033: Support IEEE 802.1q tagged frame (VLAN),
+    New configuration options ETHARP_SUPPORT_VLAN and ETHARP_VLAN_CHECK.
+
+  2009-08-25 Simon Goldschmidt
+  * ip_addr.h, netdb.c: patch #6900: added define ip_ntoa(struct ip_addr*)
+
+  2009-08-24 Jakob Stoklund Olesen
+  * autoip.c, dhcp.c, netif.c: patch #6725: Teach AutoIP and DHCP to respond
+    to netif_set_link_up().
+
+  2009-08-23 Simon Goldschmidt
+  * tcp.h/.c: Added function tcp_debug_state_str() to convert a tcp state
+    to a human-readable string.
+
   ++ Bugfixes:
 
+  2009-12-24: Kieran Mansley
+  * tcp_in.c Apply patches from Oleg Tyshev to improve OOS processing
+    (BUG#28241)
+
+  2009-12-06: Simon Goldschmidt
+  * ppp.h/.c: Fixed bug #27079 (Yet another leak in PPP): outpacket_buf can
+    be statically allocated (like in ucip)
+
+  2009-12-04: Simon Goldschmidt (patch by Ioardan Neshev)
+  * pap.c: patch #6969: PPP: missing PAP authentication UNTIMEOUT
+
+  2009-12-03: Simon Goldschmidt
+  * tcp.h, tcp_in.c, tcp_out.c: Fixed bug #28106: dup ack for fast retransmit
+    could have non-zero length
+
+  2009-12-02: Simon Goldschmidt
+  * tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting
+    tcp_input_pcb until after calling the pcb's callbacks
+
+  2009-11-29: Simon Goldschmidt
+  * tcp_in.c: Fixed bug #28054: Two segments with FIN flag on the out-of-
+    sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code
+
+  2009-11-29: Simon Goldschmidt
+  * pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by
+    queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty
+
+  2009-11-26: Simon Goldschmidt
+  * tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending
+    segment
+
+  2009-11-26: Simon Goldschmidt
+  * tcp.h, sockets.c: Fixed bug #28099: API required to disable Nagle
+    algorithm at PCB level
+
+  2009-11-22: Simon Goldschmidt
+  * tcp_out.c: Fixed bug #27905: FIN isn't combined with data on unsent
+
+  2009-11-22: Simon Goldschmidt (suggested by Bill Auerbach)
+  * tcp.c: tcp_alloc: prevent increasing stats.err for MEMP_TCP_PCB when
+    reusing time-wait pcb
+
+  2009-11-20: Simon Goldschmidt (patch by Albert Bartel)
+  * sockets.c: Fixed bug #28062: Data received directly after accepting
+    does not wake up select
+
+  2009-11-11: Simon Goldschmidt
+  * netdb.h: Fixed bug #27994: incorrect define for freeaddrinfo(addrinfo)
+
+  2009-10-30: Simon Goldschmidt
+  * opt.h: Increased default value for TCP_MSS to 536, updated default
+    value for TCP_WND to 4*TCP_MSS to keep delayed ACK working.
+
+  2009-10-28: Kieran Mansley
+  * tcp_in.c, tcp_out.c, tcp.h: re-work the fast retransmission code
+    to follow algorithm from TCP/IP Illustrated
+
+  2009-10-27: Kieran Mansley
+  * tcp_in.c: fix BUG#27445: grow cwnd with every duplicate ACK
+
+  2009-10-25: Simon Goldschmidt
+  * tcp.h: bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if
+    pcb->recv is NULL to keep rcv_wnd correct)
+
+  2009-10-25: Simon Goldschmidt
+  * tcp_in.c: Fixed bug #26251: RST process in TIME_WAIT TCP state
+
+  2009-10-23: Simon Goldschmidt (David Empson)
+  * tcp.c: Fixed bug #27783: Silly window avoidance for small window sizes
+
+  2009-10-21: Simon Goldschmidt
+  * tcp_in.c: Fixed bug #27215: TCP sent() callback gives leading and
+    trailing 1 byte len (SYN/FIN)
+
+  2009-10-21: Simon Goldschmidt
+  * tcp_out.c: Fixed bug #27315: zero window probe and FIN
+
+  2009-10-19: Simon Goldschmidt
+  * dhcp.c/.h: Minor code simplification (don't store received pbuf, change
+    conditional code to assert where applicable), check pbuf length before
+    testing for valid reply
+
+  2009-10-19: Simon Goldschmidt
+  * dhcp.c: Removed most calls to udp_connect since they aren't necessary
+    when using udp_sendto_if() - always stay connected to IP_ADDR_ANY.
+
+  2009-10-16: Simon Goldschmidt
+  * ip.c: Fixed bug #27390: Source IP check in ip_input() causes it to drop
+    valid DHCP packets -> allow 0.0.0.0 as source address when LWIP_DHCP is
+    enabled
+
+  2009-10-15: Simon Goldschmidt (Oleg Tyshev)
+  * tcp_in.c: Fixed bug #27329: dupacks by unidirectional data transmit
+
+  2009-10-15: Simon Goldschmidt
+  * api_lib.c: Fixed bug #27709: conn->err race condition on netconn_recv()
+    timeout
+
+  2009-10-15: Simon Goldschmidt
+  * autoip.c: Fixed bug #27704: autoip starts with wrong address
+    LWIP_AUTOIP_CREATE_SEED_ADDR() returned address in host byte order instead
+    of network byte order
+
+  2009-10-11 Simon Goldschmidt (Jörg Kesten)
+  * tcp_out.c: Fixed bug #27504: tcp_enqueue wrongly concatenates segments
+    which are not consecutive when retransmitting unacked segments
+
+  2009-10-09 Simon Goldschmidt
+  * opt.h: Fixed default values of some stats to only be enabled if used
+    Fixes bug #27338: sys_stats is defined when NO_SYS = 1
+
+  2009-08-30 Simon Goldschmidt
+  * ip.c: Fixed bug bug #27345: "ip_frag() does not use the LWIP_NETIF_LOOPBACK
+    function" by checking for loopback before calling ip_frag
+
+  2009-08-25 Simon Goldschmidt
+  * dhcp.c: fixed invalid dependency to etharp_query if DHCP_DOES_ARP_CHECK==0
+
+  2009-08-23 Simon Goldschmidt
+  * ppp.c: bug #27078: Possible memory leak in pppInit()
+
+  2009-08-23 Simon Goldschmidt
+  * netdb.c, dns.c: bug #26657: DNS, if host name is "localhost", result
+    is error.
+
+  2009-08-23 Simon Goldschmidt
+  * opt.h, init.c: bug #26649: TCP fails when TCP_MSS > TCP_SND_BUF
+    Fixed wrong parenthesis, added check in init.c
+
+  2009-08-23 Simon Goldschmidt
+  * ppp.c: bug #27266: wait-state debug message in pppMain occurs every ms
+
+  2009-08-23 Simon Goldschmidt
+  * many ppp files: bug #27267: Added include to string.h where needed
+
+  2009-08-23 Simon Goldschmidt
+  * tcp.h: patch #6843: tcp.h macro optimization patch (for little endian)
+
 
 (STABLE-1.3.1)
 

+ 1 - 1
net/lwip/README

@@ -72,7 +72,7 @@ current CVS sources and is available from this web page:
   http://www.nongnu.org/lwip/
 
 There is now a constantly growin wiki about lwIP at
-  http://lwip.scribblewiki.com/
+  http://lwip.wikia.com/wiki/LwIP_Wiki
 
 Also, there are mailing lists you can subscribe at
   http://savannah.nongnu.org/mail/?group=lwip

+ 1 - 1
net/lwip/SConscript

@@ -16,7 +16,7 @@ src/arch/sys_arch_init.c
 src/core/dhcp.c
 src/core/dns.c
 src/core/init.c
-src/core/memp_tiny.c
+src/core/memp.c
 src/core/netif.c
 src/core/pbuf.c
 src/core/raw.c

+ 2 - 1
net/lwip/src/api/api_lib.c

@@ -327,8 +327,9 @@ netconn_recv(struct netconn *conn)
 
 #if LWIP_SO_RCVTIMEO
     if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
+      memp_free(MEMP_NETBUF, buf);
       conn->err = ERR_TIMEOUT;
-      p = NULL;
+      return NULL;
     }
 #else
     sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);

+ 12 - 1
net/lwip/src/api/api_msg.c

@@ -168,6 +168,15 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
     buf->ptr = p;
     buf->addr = addr;
     buf->port = port;
+#if LWIP_NETBUF_RECVINFO
+    {
+      const struct ip_hdr* iphdr = ip_current_header();
+      /* get the UDP header - always in the first pbuf, ensured by udp_input */
+      const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
+      buf->toaddr = (struct ip_addr*)&iphdr->dest;
+      buf->toport = udphdr->dest;
+    }
+#endif /* LWIP_NETBUF_RECVINFO */
   }
 
   if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
@@ -807,6 +816,8 @@ do_connect(struct api_msg_msg *msg)
     break;
 #endif /* LWIP_TCP */
   default:
+    LWIP_ERROR("Invalid netconn type", 0, do{ msg->conn->err = ERR_VAL;
+      sys_sem_signal(msg->conn->op_completed); }while(0));
     break;
   }
 }
@@ -1149,7 +1160,7 @@ do_close(struct api_msg_msg *msg)
 #endif /* LWIP_TCP */
   {
     msg->conn->err = ERR_VAL;
-    TCPIP_APIMSG_ACK(msg);
+    sys_sem_signal(msg->conn->op_completed);
   }
 }
 

+ 5 - 0
net/lwip/src/api/netbuf.c

@@ -62,6 +62,11 @@ netbuf *netbuf_new(void)
     buf->p = NULL;
     buf->ptr = NULL;
     buf->addr = NULL;
+    buf->port = 0;
+#if LWIP_NETBUF_RECVINFO
+    buf->toaddr = NULL;
+    buf->toport = 0;
+#endif /* LWIP_NETBUF_RECVINFO */
     return buf;
   } else {
     return NULL;

+ 15 - 25
net/lwip/src/api/netdb.c

@@ -116,7 +116,7 @@ lwip_gethostbyname(const char *name)
     u8_t idx;
     for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %p\n", idx, s_hostent.h_aliases[idx]));
-      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n",      idx, s_hostent.h_aliases[idx]));
+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n", idx, s_hostent.h_aliases[idx]));
     }
   }
   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %d\n", s_hostent.h_addrtype));
@@ -126,7 +126,7 @@ lwip_gethostbyname(const char *name)
     u8_t idx;
     for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]   == %p\n", idx, s_hostent.h_addr_list[idx]));
-      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));
+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa(s_hostent.h_addr_list[idx])));
     }
   }
 #endif /* DNS_DEBUG */
@@ -234,12 +234,6 @@ lwip_freeaddrinfo(struct addrinfo *ai)
   struct addrinfo *next;
 
   while (ai != NULL) {
-    if (ai->ai_addr != NULL) {
-      mem_free(ai->ai_addr);
-    }
-    if (ai->ai_canonname != NULL) {
-      mem_free(ai->ai_canonname);
-    }
     next = ai->ai_next;
     mem_free(ai);
     ai = next;
@@ -274,6 +268,8 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
   struct addrinfo *ai;
   struct sockaddr_in *sa = NULL;
   int port_nr = 0;
+  size_t total_size;
+  size_t namelen = 0;
 
   if (res == NULL) {
     return EAI_FAIL;
@@ -300,19 +296,21 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
     }
   } else {
     /* service location specified, use loopback address */
-    addr.addr = INADDR_LOOPBACK;
+    addr.addr = htonl(INADDR_LOOPBACK);
   }
 
-  ai = mem_malloc(sizeof(struct addrinfo));
-  if (ai == NULL) {
-    goto memerr;
+  total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
+  if (nodename != NULL) {
+    namelen = strlen(nodename);
+    LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
+    total_size += namelen + 1;
   }
-  memset(ai, 0, sizeof(struct addrinfo));
-  sa = mem_malloc(sizeof(struct sockaddr_in));
-  if (sa == NULL) {
+  ai = mem_malloc(total_size);
+  if (ai == NULL) {
     goto memerr;
   }
-  memset(sa, 0, sizeof(struct sockaddr_in));
+  memset(ai, 0, total_size);
+  sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
   /* set up sockaddr */
   sa->sin_addr.s_addr = addr.addr;
   sa->sin_family = AF_INET;
@@ -328,12 +326,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
   }
   if (nodename != NULL) {
     /* copy nodename to canonname if specified */
-    size_t namelen = strlen(nodename);
-    LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
-    ai->ai_canonname = mem_malloc((mem_size_t)(namelen + 1));
-    if (ai->ai_canonname == NULL) {
-      goto memerr;
-    }
+    ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
     MEMCPY(ai->ai_canonname, nodename, namelen);
     ai->ai_canonname[namelen] = 0;
   }
@@ -347,9 +340,6 @@ memerr:
   if (ai != NULL) {
     mem_free(ai);
   }
-  if (sa != NULL) {
-    mem_free(sa);
-  }
   return EAI_MEMORY;
 }
 

+ 36 - 0
net/lwip/src/api/netifapi.c

@@ -58,6 +58,20 @@ do_netifapi_netif_add( struct netifapi_msg_msg *msg)
   TCPIP_NETIFAPI_ACK(msg);
 }
 
+/**
+ * Call netif_set_addr() inside the tcpip_thread context.
+ */
+void
+do_netifapi_netif_set_addr( struct netifapi_msg_msg *msg)
+{
+  netif_set_addr( msg->netif,
+                  msg->msg.add.ipaddr,
+                  msg->msg.add.netmask,
+                  msg->msg.add.gw);
+  msg->err = ERR_OK;
+  TCPIP_NETIFAPI_ACK(msg);
+}
+
 /**
  * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
  * tcpip_thread context.
@@ -103,6 +117,28 @@ netifapi_netif_add(struct netif *netif,
   return msg.msg.err;
 }
 
+/**
+ * Call netif_set_addr() in a thread-safe way by running that function inside the
+ * tcpip_thread context.
+ *
+ * @note for params @see netif_set_addr()
+ */
+err_t
+netifapi_netif_set_addr(struct netif *netif,
+                        struct ip_addr *ipaddr,
+                        struct ip_addr *netmask,
+                        struct ip_addr *gw)
+{
+  struct netifapi_msg msg;
+  msg.function = do_netifapi_netif_set_addr;
+  msg.msg.netif = netif;
+  msg.msg.msg.add.ipaddr  = ipaddr;
+  msg.msg.msg.add.netmask = netmask;
+  msg.msg.msg.add.gw      = gw;
+  TCPIP_NETIFAPI(&msg);
+  return msg.msg.err;
+}
+
 /**
  * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
  * way by running that function inside the tcpip_thread context.

+ 43 - 42
net/lwip/src/api/sockets.c

@@ -494,7 +494,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
       buf = sock->lastdata;
     } else {
       /* If this is non-blocking call, then check first */
-      if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) &&
+      if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && 
           (sock->rcvevent <= 0)) {
         if (off > 0) {
           /* already received data, return that */
@@ -546,9 +546,9 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
     if (netconn_type(sock->conn) == NETCONN_TCP) {
       LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
       len -= copylen;
-      if ( (len <= 0) ||
-           (buf->p->flags & PBUF_FLAG_PUSH) ||
-           (sock->rcvevent <= 0) ||
+      if ( (len <= 0) || 
+           (buf->p->flags & PBUF_FLAG_PUSH) || 
+           (sock->rcvevent <= 0) || 
            ((flags & MSG_PEEK)!=0)) {
         done = 1;
       }
@@ -702,16 +702,16 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
 #if LWIP_TCPIP_CORE_LOCKING
   /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
   { struct pbuf* p;
-
+  
     p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
     if (p == NULL) {
       err = ERR_MEM;
     } else {
       p->payload = (void*)data;
       p->len = p->tot_len = short_size;
-
+      
       remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr;
-
+      
       LOCK_TCPIP_CORE();
       if (sock->conn->type==NETCONN_RAW) {
         err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);
@@ -719,7 +719,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
         err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((const struct sockaddr_in *)to)->sin_port));
       }
       UNLOCK_TCPIP_CORE();
-
+      
       pbuf_free(p);
     }
   }
@@ -845,11 +845,11 @@ 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++) {
@@ -875,7 +875,7 @@ lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
   *readset = lreadset;
   *writeset = lwriteset;
   FD_ZERO(exceptset);
-
+  
   return nready;
 }
 
@@ -935,27 +935,27 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
         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 */
@@ -965,7 +965,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
       if(msectimeout == 0)
         msectimeout = 1;
     }
-
+    
 	if (sys_arch_timeouts() == NULL){
 	  /* it's not a lwip thread, use os semaphore with timeout to handle it */
 	  i = sys_arch_sem_wait(select_cb.sem, msectimeout);
@@ -976,7 +976,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
 	  /* it's a lwip thread, use os semaphore with timeout to handle it */
       i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
     }
-
+    
     /* Take us off the list */
     sys_sem_wait(selectsem);
     if (select_cb_list == &select_cb)
@@ -988,9 +988,9 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
           break;
         }
       }
-
+    
     sys_sem_signal(selectsem);
-
+    
     sys_sem_free(select_cb.sem);
     if (i == 0)  {
       /* Timeout */
@@ -1000,13 +1000,13 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
         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
@@ -1019,22 +1019,22 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *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;
 }
 
@@ -1068,6 +1068,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
         sys_sem_signal(socksem);
         return;
       }
+      s = conn->socket;
       sys_sem_signal(socksem);
     }
 
@@ -1205,11 +1206,11 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
 
   /* 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: */
@@ -1258,7 +1259,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
       err = ENOPROTOOPT;
     }  /* switch (optname) */
     break;
-
+                     
 /* Level: IPPROTO_IP */
   case IPPROTO_IP:
     switch (optname) {
@@ -1290,7 +1291,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
       err = ENOPROTOOPT;
     }  /* switch (optname) */
     break;
-
+         
 #if LWIP_TCP
 /* Level: IPPROTO_TCP */
   case IPPROTO_TCP:
@@ -1298,7 +1299,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
       err = EINVAL;
       break;
     }
-
+    
     /* If this is no TCP socket, ignore any options. */
     if (sock->conn->type != NETCONN_TCP)
       return 0;
@@ -1312,7 +1313,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
     case TCP_KEEPCNT:
 #endif /* LWIP_TCP_KEEPALIVE */
       break;
-
+       
     default:
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
                                   s, optname));
@@ -1327,7 +1328,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
       err = EINVAL;
       break;
     }
-
+    
     /* If this is no UDP lite socket, ignore any options. */
     if (sock->conn->type != NETCONN_UDPLITE)
       return 0;
@@ -1336,7 +1337,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
     case UDPLITE_SEND_CSCOV:
     case UDPLITE_RECV_CSCOV:
       break;
-
+       
     default:
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
                                   s, optname));
@@ -1351,7 +1352,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
       err = ENOPROTOOPT;
   }  /* switch */
 
-
+   
   if (err != ERR_OK) {
     sock_set_errno(sock, err);
     return -1;
@@ -1396,7 +1397,7 @@ lwip_getsockopt_internal(void *arg)
   optval = data->optval;
 
   switch (level) {
-
+   
 /* Level: SOL_SOCKET */
   case SOL_SOCKET:
     switch (optname) {
@@ -1442,7 +1443,7 @@ lwip_getsockopt_internal(void *arg)
     case SO_ERROR:
       if (sock->err == 0) {
         sock_set_errno(sock, err_to_errno(sock->conn->err));
-      }
+      } 
       *(int *)optval = sock->err;
       sock->err = 0;
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
@@ -1500,7 +1501,7 @@ lwip_getsockopt_internal(void *arg)
   case IPPROTO_TCP:
     switch (optname) {
     case TCP_NODELAY:
-      *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);
+      *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
                   s, (*(int*)optval)?"on":"off") );
       break;
@@ -1861,9 +1862,9 @@ lwip_setsockopt_internal(void *arg)
     switch (optname) {
     case TCP_NODELAY:
       if (*(int*)optval) {
-        sock->conn->pcb.tcp->flags |= TF_NODELAY;
+        tcp_nagle_disable(sock->conn->pcb.tcp);
       } else {
-        sock->conn->pcb.tcp->flags &= ~TF_NODELAY;
+        tcp_nagle_enable(sock->conn->pcb.tcp);
       }
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
                   s, (*(int *)optval)?"on":"off") );

+ 176 - 87
net/lwip/src/core/dhcp.c

@@ -99,6 +99,10 @@
  * MTU is checked to be big enough in dhcp_start */
 #define DHCP_MAX_MSG_LEN(netif)        (netif->mtu)
 #define DHCP_MAX_MSG_LEN_MIN_REQUIRED  576
+/** Minimum length for reply before packet is parsed */
+#define DHCP_MIN_REPLY_LEN             44
+
+#define REBOOT_TRIES 2
 
 /* DHCP client state machine functions */
 static void dhcp_handle_ack(struct netif *netif);
@@ -107,17 +111,18 @@ 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);
 #if DHCP_DOES_ARP_CHECK
+static void dhcp_check(struct netif *netif);
 static err_t dhcp_decline(struct netif *netif);
 #endif /* DHCP_DOES_ARP_CHECK */
 static err_t dhcp_rebind(struct netif *netif);
+static err_t dhcp_reboot(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 err_t dhcp_unfold_reply(struct dhcp *dhcp, struct pbuf *p);
 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
@@ -161,7 +166,7 @@ static void
 dhcp_handle_nak(struct netif *netif)
 {
   struct dhcp *dhcp = netif->dhcp;
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", 
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", 
     (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
   /* Set the interface down since the address must no longer be used, as per RFC2131 */
   netif_set_down(netif);
@@ -175,6 +180,7 @@ dhcp_handle_nak(struct netif *netif)
   dhcp_discover(netif);
 }
 
+#if DHCP_DOES_ARP_CHECK
 /**
  * Checks if the offered IP address is already in use.
  *
@@ -190,20 +196,21 @@ dhcp_check(struct netif *netif)
   struct dhcp *dhcp = netif->dhcp;
   err_t result;
   u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
     (s16_t)netif->name[1]));
   dhcp_set_state(dhcp, DHCP_CHECKING);
   /* 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 | LWIP_DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("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 | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
 }
+#endif /* DHCP_DOES_ARP_CHECK */
 
 /**
  * Remember the configuration offered by a DHCP server.
@@ -216,7 +223,7 @@ 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 | LWIP_DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("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]));
@@ -247,7 +254,7 @@ dhcp_select(struct netif *netif)
   const char *p;
 #endif /* LWIP_NETIF_HOSTNAME */
 
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
   dhcp_set_state(dhcp, DHCP_REQUESTING);
 
   /* create and initialize the DHCP message header */
@@ -286,16 +293,12 @@ dhcp_select(struct netif *netif)
     /* 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 */
     /* send broadcast to any DHCP server */
     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
-    /* 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 | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
   } else {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n"));
   }
   dhcp->tries++;
   msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
@@ -378,7 +381,7 @@ static void
 dhcp_timeout(struct netif *netif)
 {
   struct dhcp *dhcp = netif->dhcp;
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_timeout()\n"));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("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 | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
@@ -393,6 +396,7 @@ dhcp_timeout(struct netif *netif)
       dhcp_release(netif);
       dhcp_discover(netif);
     }
+#if DHCP_DOES_ARP_CHECK
   /* received no ARP reply for the offered address (which is good) */
   } else if (dhcp->state == DHCP_CHECKING) {
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
@@ -404,6 +408,7 @@ dhcp_timeout(struct netif *netif)
       /* bind the interface to the offered address */
       dhcp_bind(netif);
     }
+#endif /* DHCP_DOES_ARP_CHECK */
   }
   /* did not get response to renew request? */
   else if (dhcp->state == DHCP_RENEWING) {
@@ -421,6 +426,12 @@ dhcp_timeout(struct netif *netif)
       dhcp_release(netif);
       dhcp_discover(netif);
     }
+  } else if (dhcp->state == DHCP_REBOOTING) {
+    if (dhcp->tries < REBOOT_TRIES) {
+      dhcp_reboot(netif);
+    } else {
+      dhcp_discover(netif);
+    }
   }
 }
 
@@ -600,13 +611,13 @@ dhcp_start(struct netif *netif)
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
   /* already has DHCP client attached */
   } else {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
     if (dhcp->pcb != NULL) {
       udp_remove(dhcp->pcb);
     }
-    if (dhcp->p != NULL) {
-      pbuf_free(dhcp->p);
-    }
+    LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL);
+    LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
+      dhcp->options_in == NULL && dhcp->options_in_len == 0);
   }
     
   /* clear data structure */
@@ -652,23 +663,23 @@ dhcp_start(struct netif *netif)
 void
 dhcp_inform(struct netif *netif)
 {
-  struct dhcp *dhcp, *old_dhcp = netif->dhcp;
+  struct dhcp *dhcp, *old_dhcp;
   err_t result = ERR_OK;
   dhcp = mem_malloc(sizeof(struct dhcp));
   if (dhcp == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not allocate dhcp\n"));
     return;
   }
-  netif->dhcp = dhcp;
   memset(dhcp, 0, sizeof(struct dhcp));
 
   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));
   dhcp->pcb = udp_new();
   if (dhcp->pcb == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));
-    mem_free((void *)dhcp);
-    return;
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb"));
+    goto free_dhcp_and_return;
   }
+  old_dhcp = netif->dhcp;
+  netif->dhcp = dhcp;
   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
   /* create and initialize the DHCP message header */
   result = dhcp_create_request(netif);
@@ -688,21 +699,48 @@ dhcp_inform(struct netif *netif)
     dhcp->pcb->so_options|=SOF_BROADCAST;
 #endif /* IP_SOF_BROADCAST */
     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
-    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
     dhcp_delete_request(netif);
   } else {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n"));
   }
 
-  if (dhcp->pcb != NULL) {
-    udp_remove(dhcp->pcb);
-  }
+  udp_remove(dhcp->pcb);
   dhcp->pcb = NULL;
-  mem_free((void *)dhcp);
   netif->dhcp = old_dhcp;
+free_dhcp_and_return:
+  mem_free((void *)dhcp);
+}
+
+/** Handle a possible change in the network configuration.
+ *
+ * This enters the REBOOTING state to verify that the currently bound
+ * address is still valid.
+ */
+void
+dhcp_network_changed(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  if (!dhcp)
+    return;
+  switch (dhcp->state) {
+  case DHCP_REBINDING:
+  case DHCP_RENEWING:
+  case DHCP_BOUND:
+  case DHCP_REBOOTING:
+    netif_set_down(netif);
+    dhcp->tries = 0;
+    dhcp_reboot(netif);
+    break;
+  case DHCP_OFF:
+    /* stay off */
+    break;
+  default:
+    dhcp->tries = 0;
+    dhcp_discover(netif);
+    break;
+  }
 }
 
 #if DHCP_DOES_ARP_CHECK
@@ -715,7 +753,7 @@ dhcp_inform(struct netif *netif)
 void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
 {
   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_arp_reply()\n"));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("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 | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));
@@ -723,7 +761,8 @@ void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
        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 | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
+        ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
       dhcp_decline(netif);
     }
   }
@@ -744,7 +783,7 @@ dhcp_decline(struct netif *netif)
   struct dhcp *dhcp = netif->dhcp;
   err_t result = ERR_OK;
   u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_decline()\n"));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n"));
   dhcp_set_state(dhcp, DHCP_BACKING_OFF);
   /* create and initialize the DHCP message header */
   result = dhcp_create_request(netif);
@@ -759,14 +798,13 @@ dhcp_decline(struct netif *netif)
     /* resize pbuf to reflect true size of options */
     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
 
-    /* @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_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
     dhcp_delete_request(netif);
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
   } else {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("dhcp_decline: could not allocate DHCP request\n"));
   }
   dhcp->tries++;
   msecs = 10*1000;
@@ -788,7 +826,7 @@ dhcp_discover(struct netif *netif)
   struct dhcp *dhcp = netif->dhcp;
   err_t result = ERR_OK;
   u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n"));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n"));
   ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
   dhcp_set_state(dhcp, DHCP_SELECTING);
   /* create and initialize the DHCP message header */
@@ -812,14 +850,13 @@ dhcp_discover(struct netif *netif)
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
 
-    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
     dhcp_delete_request(netif);
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
   } else {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n"));
   }
   dhcp->tries++;
 #if LWIP_DHCP_AUTOIP_COOP
@@ -849,7 +886,7 @@ dhcp_bind(struct netif *netif)
   LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
   dhcp = netif->dhcp;
   LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("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) {
@@ -937,7 +974,7 @@ dhcp_renew(struct netif *netif)
 #if LWIP_NETIF_HOSTNAME
   const char *p;
 #endif /* LWIP_NETIF_HOSTNAME */
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n"));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n"));
   dhcp_set_state(dhcp, DHCP_RENEWING);
 
   /* create and initialize the DHCP message header */
@@ -974,13 +1011,12 @@ dhcp_renew(struct netif *netif)
 
     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
 
-    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
     udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
     dhcp_delete_request(netif);
 
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));
   } else {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n"));
   }
   dhcp->tries++;
   /* back-off on retries, but to a maximum of 20 seconds */
@@ -1040,12 +1076,11 @@ dhcp_rebind(struct netif *netif)
     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
 
     /* broadcast to server */
-    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
     dhcp_delete_request(netif);
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));
   } else {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n"));
   }
   dhcp->tries++;
   msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
@@ -1054,6 +1089,52 @@ dhcp_rebind(struct netif *netif)
   return result;
 }
 
+/**
+ * Enter REBOOTING state to verify an existing lease
+ *
+ * @param netif network interface which must reboot
+ */
+static err_t
+dhcp_reboot(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result;
+  u16_t msecs;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n"));
+  dhcp_set_state(dhcp, DHCP_REBOOTING);
+
+  /* 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);
+
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
+
+    dhcp_option_trailer(dhcp);
+
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+    /* broadcast to server */
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+    dhcp_delete_request(netif);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n"));
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: 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 | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs));
+  return result;
+}
+
+
 /**
  * Release a DHCP lease.
  *
@@ -1065,7 +1146,7 @@ dhcp_release(struct netif *netif)
   struct dhcp *dhcp = netif->dhcp;
   err_t result;
   u16_t msecs;
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_release()\n"));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n"));
 
   /* idle DHCP client */
   dhcp_set_state(dhcp, DHCP_OFF);
@@ -1086,12 +1167,11 @@ dhcp_release(struct netif *netif)
 
     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
 
-    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
     udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
     dhcp_delete_request(netif);
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
   } else {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n"));
   }
   dhcp->tries++;
   msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
@@ -1121,7 +1201,7 @@ dhcp_stop(struct netif *netif)
   /* Remove the flag that says this netif is handled by DHCP. */
   netif->flags &= ~NETIF_FLAG_DHCP;
 
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_stop()\n"));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n"));
   /* netif is DHCP configured? */
   if (dhcp != NULL) {
 #if LWIP_DHCP_AUTOIP_COOP
@@ -1135,12 +1215,8 @@ dhcp_stop(struct netif *netif)
       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);
+    LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
+      dhcp->options_in == NULL && dhcp->options_in_len == 0);
     mem_free((void *)dhcp);
     netif->dhcp = NULL;
   }
@@ -1214,39 +1290,44 @@ dhcp_option_long(struct dhcp *dhcp, u32_t value)
  *
  */
 static err_t
-dhcp_unfold_reply(struct dhcp *dhcp)
+dhcp_unfold_reply(struct dhcp *dhcp, struct pbuf *p)
 {
   u16_t ret;
   LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;);
-  LWIP_ERROR("dhcp->p != NULL", (dhcp->p != NULL), return ERR_VAL;);
   /* 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);
+  if (p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) {
+    dhcp->options_in_len = 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 | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+        ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
+      dhcp->options_in_len = 0;
       return ERR_MEM;
     }
   }
   dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
   if (dhcp->msg_in == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));
-    mem_free((void *)dhcp->options_in);
-    dhcp->options_in = NULL;
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));
+    if (dhcp->options_in != NULL) {
+      mem_free(dhcp->options_in);
+      dhcp->options_in = NULL;
+      dhcp->options_in_len = 0;
+    }
     return ERR_MEM;
   }
 
   /** copy the DHCP message without options */
-  ret = pbuf_copy_partial(dhcp->p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0);
+  ret = pbuf_copy_partial(p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0);
   LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n",
      sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN));
 
   if (dhcp->options_in != NULL) {
     /** copy the DHCP options */
-    ret = pbuf_copy_partial(dhcp->p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
+    ret = pbuf_copy_partial(p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
     LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len);
     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n",
       dhcp->options_in_len));
@@ -1258,7 +1339,6 @@ dhcp_unfold_reply(struct dhcp *dhcp)
 /**
  * Free the incoming DHCP message including contiguous copy of
  * its DHCP options.
- *
  */
 static void dhcp_free_reply(struct dhcp *dhcp)
 {
@@ -1267,14 +1347,13 @@ static void dhcp_free_reply(struct dhcp *dhcp)
     dhcp->msg_in = NULL;
   }
   if (dhcp->options_in) {
-    mem_free((void *)dhcp->options_in);
+    mem_free(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
  */
@@ -1286,7 +1365,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
   u8_t *options_ptr;
   u8_t msg_type;
   u8_t i;
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("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 | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
@@ -1295,28 +1374,38 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
   LWIP_UNUSED_ARG(pcb);
   LWIP_UNUSED_ARG(addr);
   LWIP_UNUSED_ARG(port);
-  dhcp->p = p;
-  /* TODO: check packet length before reading them */
+
+  LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
+    dhcp->options_in == NULL && dhcp->options_in_len == 0);
+
+  if (p->len < DHCP_MIN_REPLY_LEN) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message too short\n"));
+    goto free_pbuf_and_return;
+  }
+
   if (reply_msg->op != DHCP_BOOTREPLY) {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
     goto free_pbuf_and_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 | LWIP_DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+        ("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]));
       goto free_pbuf_and_return;
     }
   }
   /* match transaction ID against what we expected */
   if (ntohl(reply_msg->xid) != dhcp->xid) {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+      ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
     goto free_pbuf_and_return;
   }
   /* option fields could be unfold? */
-  if (dhcp_unfold_reply(dhcp) != ERR_OK) {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));
+  if (dhcp_unfold_reply(dhcp, p) != ERR_OK) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("problem unfolding DHCP message - too short on memory?\n"));
     goto free_pbuf_and_return;
   }
 
@@ -1324,7 +1413,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
   /* 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 | LWIP_DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
     goto free_pbuf_and_return;
   }
 
@@ -1332,7 +1421,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
   msg_type = dhcp_get_option_byte(options_ptr + 2);
   /* message type is DHCP ACK? */
   if (msg_type == DHCP_ACK) {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_ACK received\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n"));
     /* in requesting state? */
     if (dhcp->state == DHCP_REQUESTING) {
       dhcp_handle_ack(netif);
@@ -1355,13 +1444,13 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
   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 | LWIP_DBG_TRACE | 1, ("DHCP_NAK received\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("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 | LWIP_DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
     dhcp->request_timeout = 0;
     /* remember offered lease */
     dhcp_handle_offer(netif);
@@ -1369,7 +1458,6 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
 free_pbuf_and_return:
   dhcp_free_reply(dhcp);
   pbuf_free(p);
-  dhcp->p = NULL;
 }
 
 /**
@@ -1403,7 +1491,8 @@ dhcp_create_request(struct netif *netif)
   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 | LWIP_DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("dhcp_create_request(): could not allocate pbuf\n"));
     return ERR_MEM;
   }
   LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg",
@@ -1413,7 +1502,7 @@ dhcp_create_request(struct netif *netif)
   if (dhcp->tries==0)
       xid++;
   dhcp->xid = xid;
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2,
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
               ("transaction id xid(%"X32_F")\n", xid));
 
   dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
@@ -1521,7 +1610,7 @@ static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
       /* 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 | LWIP_DBG_TRACE | 2, ("overloaded message detected\n"));
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded message detected\n"));
         /* skip option type and length */
         offset += 2;
         overload = options[offset++];
@@ -1543,16 +1632,16 @@ static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
     if (overload != DHCP_OVERLOAD_NONE) {
       u16_t field_len;
       if (overload == DHCP_OVERLOAD_FILE) {
-        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded file field\n"));
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("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 | LWIP_DBG_TRACE | 1, ("overloaded sname field\n"));
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("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 | LWIP_DBG_TRACE | 1, ("overloaded sname and file field\n"));
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
         options = (u8_t *)&dhcp->msg_in->sname;
         field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;
       }

+ 1 - 1
net/lwip/src/core/dns.c

@@ -961,7 +961,7 @@ dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback
 
 #if LWIP_HAVE_LOOPIF
   if (strcmp(hostname,"localhost")==0) {
-    addr->addr = INADDR_LOOPBACK;
+    addr->addr = htonl(INADDR_LOOPBACK);
     return ERR_OK;
   }
 #endif /* LWIP_HAVE_LOOPIF */

+ 5 - 0
net/lwip/src/core/init.c

@@ -168,6 +168,9 @@
 #if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
   #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
 #endif
+#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
+  #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
+#endif
 
 
 /* Compile-time checks for deprecated options.
@@ -208,6 +211,8 @@ lwip_sanity_check(void)
 #if LWIP_TCP
   if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
     LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
+  if (TCP_SND_BUF < 2 * TCP_MSS)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
   if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
     LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
   if (TCP_SNDLOWAT > TCP_SND_BUF)

+ 75 - 31
net/lwip/src/core/ipv4/autoip.c

@@ -100,7 +100,7 @@
  */
 #ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
 #define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
-  (AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
+  htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
                  ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
 #endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
 
@@ -108,7 +108,10 @@
 static void autoip_handle_arp_conflict(struct netif *netif);
 
 /* creates a pseudo random LL IP-Address for a network interface */
-static void autoip_create_addr(struct netif *netif, struct ip_addr *IPAddr);
+static void autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr);
+
+/* sends an ARP probe */
+static err_t autoip_arp_probe(struct netif *netif);
 
 /* sends an ARP announce */
 static err_t autoip_arp_announce(struct netif *netif);
@@ -116,13 +119,16 @@ static err_t autoip_arp_announce(struct netif *netif);
 /* configure interface for use with current LL IP-Address */
 static err_t autoip_bind(struct netif *netif);
 
+/* start sending probes for llipaddr */
+static void autoip_start_probing(struct netif *netif);
+
 /**
  * Initialize this module
  */
 void
 autoip_init(void)
 {
-  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n"));
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
 }
 
 /**
@@ -139,19 +145,19 @@ autoip_handle_arp_conflict(struct netif *netif)
       /* retreat, there was a conflicting ARP in the last
        * DEFEND_INTERVAL seconds
        */
-      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
         ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
 
       /* TODO: close all TCP sessions */
       autoip_start(netif);
     } else {
-      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
         ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
       autoip_arp_announce(netif);
       netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
     }
   } else {
-    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
       ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
     /* TODO: close all TCP sessions */
     autoip_start(netif);
@@ -162,10 +168,10 @@ autoip_handle_arp_conflict(struct netif *netif)
  * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
  *
  * @param netif network interface on which create the IP-Address
- * @param IPAddr ip address to initialize
+ * @param ipaddr ip address to initialize
  */
 static void
-autoip_create_addr(struct netif *netif, struct ip_addr *IPAddr)
+autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr)
 {
   /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
    * compliant to RFC 3927 Section 2.1
@@ -183,12 +189,25 @@ autoip_create_addr(struct netif *netif, struct ip_addr *IPAddr)
     addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
   }
   LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
-	(addr <= AUTOIP_RANGE_END));
-  IPAddr->addr = htonl(addr);
+    (addr <= AUTOIP_RANGE_END));
+  ipaddr->addr = htonl(addr);
   
-  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
     ("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
-    (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(IPAddr->addr)));
+    (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(ipaddr->addr)));
+}
+
+/**
+ * Sends an ARP probe from a network interface
+ *
+ * @param netif network interface used to send the probe
+ */
+static err_t
+autoip_arp_probe(struct netif *netif)
+{
+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
+    (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,
+    &netif->autoip->llipaddr, ARP_REQUEST);
 }
 
 /**
@@ -215,7 +234,7 @@ autoip_bind(struct netif *netif)
   struct autoip *autoip = netif->autoip;
   struct ip_addr sn_mask, gw_addr;
 
-  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
     ("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n",
     (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr));
 
@@ -281,6 +300,16 @@ autoip_start(struct netif *netif)
 
   autoip_create_addr(netif, &(autoip->llipaddr));
   autoip->tried_llipaddr++;
+  autoip_start_probing(netif);
+
+  return result;
+}
+
+static void
+autoip_start_probing(struct netif *netif)
+{
+  struct autoip *autoip = netif->autoip;
+
   autoip->state = AUTOIP_STATE_PROBING;
   autoip->sent_num = 0;
 
@@ -295,12 +324,24 @@ autoip_start(struct netif *netif)
    * accquiring and probing address
    * compliant to RFC 3927 Section 2.2.1
    */
-
   if(autoip->tried_llipaddr > MAX_CONFLICTS) {
     autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
   }
+}
 
-  return result;
+/**
+ * Handle a possible change in the network configuration.
+ *
+ * If there is an AutoIP address configured, take the interface down
+ * and begin probing with the same address.
+ */
+void
+autoip_network_changed(struct netif *netif)
+{
+  if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
+    netif_set_down(netif);
+    autoip_start_probing(netif);
+  }
 }
 
 /**
@@ -340,13 +381,13 @@ autoip_tmr()
           if(netif->autoip->ttw > 0) {
             netif->autoip->ttw--;
           } else {
-            if(netif->autoip->sent_num == PROBE_NUM) {
+            if(netif->autoip->sent_num >= PROBE_NUM) {
               netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
               netif->autoip->sent_num = 0;
               netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
             } else {
-              etharp_request(netif, &(netif->autoip->llipaddr));
-              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
+              autoip_arp_probe(netif);
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
                 ("autoip_tmr() PROBING Sent Probe\n"));
               netif->autoip->sent_num++;
               /* calculate time to wait to next probe */
@@ -363,21 +404,24 @@ autoip_tmr()
           } else {
             if(netif->autoip->sent_num == 0) {
              /* We are here the first time, so we waited ANNOUNCE_WAIT seconds
-              * Now we can bind to an IP address and use it
+              * Now we can bind to an IP address and use it.
+              *
+              * autoip_bind calls netif_set_up. This triggers a gratuitous ARP
+              * which counts as an announcement.
               */
               autoip_bind(netif);
-            }
-
-            if(netif->autoip->sent_num == ANNOUNCE_NUM) {
-              netif->autoip->state = AUTOIP_STATE_BOUND;
-              netif->autoip->sent_num = 0;
-              netif->autoip->ttw = 0;
             } else {
               autoip_arp_announce(netif);
-              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
                 ("autoip_tmr() ANNOUNCING Sent Announce\n"));
-              netif->autoip->sent_num++;
-              netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+            }
+            netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+            netif->autoip->sent_num++;
+
+            if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
+                netif->autoip->state = AUTOIP_STATE_BOUND;
+                netif->autoip->sent_num = 0;
+                netif->autoip->ttw = 0;
             }
           }
           break;
@@ -397,7 +441,7 @@ autoip_tmr()
 void
 autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
 {
-  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n"));
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
   if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
    /* when ip.src == llipaddr && hw.src != netif->hwaddr
     *
@@ -431,7 +475,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
       if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
           (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
            !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
-        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
+        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
           ("autoip_arp_reply(): Probe Conflict detected\n"));
         autoip_start(netif);
       }
@@ -442,7 +486,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
       */
       if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
           !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
-        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
+        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
           ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
         autoip_handle_arp_conflict(netif);
       }

+ 38 - 64
net/lwip/src/core/ipv4/ip.c

@@ -62,40 +62,12 @@
  * The interface that provided the packet for the current callback
  * invocation.
  */
-static struct netif *current_netif;
+struct netif *current_netif;
 
 /**
  * Header of the input packet currently being processed.
  */
-static const struct ip_hdr *current_header;
-
-/**
- * Get the interface that received the current packet.
- *
- * This function must only be called from a receive callback (udp_recv,
- * raw_recv, tcp_accept). It will return NULL otherwise.
- *
- * @param pcb Pointer to the pcb receiving a packet.
- */
-struct netif *
-ip_current_netif(void)
-{
-  return current_netif;
-}
-
-/**
- * Get the IP header of the current packet.
- *
- * This function must only be called from a receive callback (udp_recv,
- * raw_recv, tcp_accept). It will return NULL otherwise.
- *
- * @param pcb Pointer to the pcb receiving a packet.
- */
-const struct ip_hdr *
-ip_current_header(void)
-{
-  return current_header;
-}
+const struct ip_hdr *current_header;
 
 /**
  * Finds the appropriate network interface for a given IP address. It
@@ -122,7 +94,7 @@ ip_route(struct ip_addr *dest)
     }
   }
   if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
-    LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
     IP_STATS_INC(ip.rterr);
     snmp_inc_ipoutnoroutes();
     return NULL;
@@ -230,7 +202,7 @@ ip_input(struct pbuf *p, struct netif *inp)
   /* identify the IP header */
   iphdr = p->payload;
   if (IPH_V(iphdr) != 4) {
-    LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
     ip_debug_print(p);
     pbuf_free(p);
     IP_STATS_INC(ip.err);
@@ -248,13 +220,16 @@ ip_input(struct pbuf *p, struct netif *inp)
 
   /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
   if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
-    if (iphdr_hlen > p->len)
-    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
-                               iphdr_hlen, p->len));
-    if (iphdr_len > p->tot_len)
-    LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "
-                               "IP packet dropped.\n",
-                               iphdr_len, p->tot_len));
+    if (iphdr_hlen > p->len) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
+        iphdr_hlen, p->len));
+    }
+    if (iphdr_len > p->tot_len) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
+        iphdr_len, p->tot_len));
+    }
     /* free (drop) packet pbufs */
     pbuf_free(p);
     IP_STATS_INC(ip.lenerr);
@@ -267,7 +242,8 @@ ip_input(struct pbuf *p, struct netif *inp)
 #if CHECKSUM_CHECK_IP
   if (inet_chksum(iphdr, iphdr_hlen) != 0) {
 
-    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+      ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
     ip_debug_print(p);
     pbuf_free(p);
     IP_STATS_INC(ip.chkerr);
@@ -336,10 +312,10 @@ ip_input(struct pbuf *p, struct netif *inp)
   if (netif == NULL) {
     /* remote port is DHCP server? */
     if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
-      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
         ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
       if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
-        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
         netif = inp;
         check_ip_src = 0;
       }
@@ -349,12 +325,13 @@ ip_input(struct pbuf *p, struct netif *inp)
 
   /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
 #if LWIP_DHCP
-  if (check_ip_src)
+  /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
+  if (check_ip_src && (iphdr->src.addr != 0))
 #endif /* LWIP_DHCP */
   {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
          (ip_addr_ismulticast(&(iphdr->src)))) {
       /* packet source is not valid */
-      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
       /* free (drop) packet pbufs */
       pbuf_free(p);
       IP_STATS_INC(ip.drop);
@@ -367,7 +344,7 @@ ip_input(struct pbuf *p, struct netif *inp)
   /* packet not for us? */
   if (netif == NULL) {
     /* packet not for us, route or discard */
-    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
 #if IP_FORWARD
     /* non-broadcast packet? */
     if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
@@ -396,7 +373,7 @@ ip_input(struct pbuf *p, struct netif *inp)
     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",
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
       ntohs(IPH_OFFSET(iphdr))));
     IP_STATS_INC(ip.opterr);
     IP_STATS_INC(ip.drop);
@@ -414,7 +391,7 @@ ip_input(struct pbuf *p, struct netif *inp)
 #else
   if (iphdr_hlen > IP_HLEN) {
 #endif /* LWIP_IGMP */
-    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
     pbuf_free(p);
     IP_STATS_INC(ip.opterr);
     IP_STATS_INC(ip.drop);
@@ -476,7 +453,7 @@ ip_input(struct pbuf *p, struct netif *inp)
 #endif /* LWIP_ICMP */
       pbuf_free(p);
 
-      LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
 
       IP_STATS_INC(ip.proterr);
       IP_STATS_INC(ip.drop);
@@ -551,7 +528,7 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
       ip_hlen += optlen_aligned;
       /* First write in the IP options */
       if (pbuf_header(p, optlen_aligned)) {
-        LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
         IP_STATS_INC(ip.err);
         snmp_inc_ipoutdiscards();
         return ERR_BUF;
@@ -565,7 +542,7 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
 #endif /* IP_OPTIONS_SEND */
     /* generate IP header */
     if (pbuf_header(p, IP_HLEN)) {
-      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
 
       IP_STATS_INC(ip.err);
       snmp_inc_ipoutdiscards();
@@ -603,30 +580,27 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
     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);
 
-#if (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
+#if ENABLE_LOOPBACK
   if (ip_addr_cmp(dest, &netif->ip_addr)) {
     /* Packet to self, enqueue it for loopback */
     LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
-
     return netif_loop_output(netif, p, dest);
-  } else
-#endif /* (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) */
-  {
-    LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
-
-    return netif->output(netif, p, dest);
   }
+#endif /* ENABLE_LOOPBACK */
+#if IP_FRAG
+  /* don't fragment if interface has mtu set to 0 [loopif] */
+  if (netif->mtu && (p->tot_len > netif->mtu)) {
+    return ip_frag(p,netif,dest);
+  }
+#endif
+
+  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
+  return netif->output(netif, p, dest);
 }
 
 /**

+ 4 - 4
net/lwip/src/core/mem.c

@@ -300,7 +300,7 @@ mem_free(void *rmem)
   LWIP_MEM_FREE_DECL_PROTECT();
 
   if (rmem == NULL) {
-    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
+    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
     return;
   }
   LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
@@ -310,7 +310,7 @@ mem_free(void *rmem)
 
   if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
     SYS_ARCH_DECL_PROTECT(lev);
-    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
+    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
     /* protect mem stats from concurrent access */
     SYS_ARCH_PROTECT(lev);
     MEM_STATS_INC(illegal);
@@ -380,7 +380,7 @@ mem_realloc(void *rmem, mem_size_t newsize)
 
   if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
     SYS_ARCH_DECL_PROTECT(lev);
-    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
+    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_realloc: illegal memory\n"));
     /* protect mem stats from concurrent access */
     SYS_ARCH_PROTECT(lev);
     MEM_STATS_INC(illegal);
@@ -599,7 +599,7 @@ mem_malloc(mem_size_t size)
     /* if we got interrupted by a mem_free, try again */
   } while(local_mem_free_count != 0);
 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
-  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
+  LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
   MEM_STATS_INC(err);
   LWIP_MEM_ALLOC_UNPROTECT();
   sys_sem_signal(mem_sem);

+ 53 - 6
net/lwip/src/core/memp.c

@@ -289,7 +289,11 @@ memp_init(void)
   /* check everything a first time to see if it worked */
   memp_overflow_check_all();
 #endif /* MEMP_OVERFLOW_CHECK */
-}
+}
+#else
+/* fix time-wait tcp pcb issue */
+static rt_uint16_t tcp_pcbs = 0;
+#endif /* MEMP_MEM_MALLOC */
 
 /**
  * Get an element from a specific pool.
@@ -308,7 +312,8 @@ memp_malloc(memp_t type)
 #else
 memp_malloc_fn(memp_t type, const char* file, const int line)
 #endif
-{
+{
+#if !MEMP_MEM_MALLOC
   struct memp *memp;
   SYS_ARCH_DECL_PROTECT(old_level);
  
@@ -333,13 +338,41 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
                 ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
     memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);
   } else {
-    LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
+    LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
     MEMP_STATS_INC(err, type);
   }
-
   SYS_ARCH_UNPROTECT(old_level);
 
   return memp;
+#else
+  void* ptr;
+  rt_uint32_t size;
+  SYS_ARCH_DECL_PROTECT(old_level);
+
+  size = memp_sizes[type];
+  LWIP_DEBUGF(MEMP_DEBUG, ("memp malloc %s, size %d, ", memp_desc[type], memp_sizes[type]));
+
+  SYS_ARCH_PROTECT(old_level);
+  if (type == MEMP_TCP_PCB)
+  {
+    if (tcp_pcbs >= MEMP_NUM_TCP_PCB)
+    {
+      SYS_ARCH_UNPROTECT(old_level);
+      return NULL;
+    }
+    else
+    {
+      /* increased tcp pcb allocated number */
+      tcp_pcbs ++;
+    }
+  }
+  SYS_ARCH_UNPROTECT(old_level);
+
+  ptr = mem_malloc(size);
+  LWIP_DEBUGF(MEMP_DEBUG, ("mem 0x%x\n", ptr));
+
+  return ptr;
+#endif /* MEMP_MEM_MALLOC */
 }
 
 /**
@@ -351,6 +384,7 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
 void
 memp_free(memp_t type, void *mem)
 {
+#if !MEMP_MEM_MALLOC
   struct memp *memp;
   SYS_ARCH_DECL_PROTECT(old_level);
 
@@ -381,6 +415,19 @@ memp_free(memp_t type, void *mem)
 #endif /* MEMP_SANITY_CHECK */
 
   SYS_ARCH_UNPROTECT(old_level);
-}
-
+#else
+  SYS_ARCH_DECL_PROTECT(old_level);
+
+  SYS_ARCH_PROTECT(old_level);
+  if (type == MEMP_TCP_PCB && mem)
+  {
+    tcp_pcbs --;
+  }
+  SYS_ARCH_UNPROTECT(old_level);
+
+  LWIP_DEBUGF(MEMP_DEBUG, ("memp free %s, mem 0x%x\n", memp_desc[type], mem));
+  /* release this memory */
+  mem_free(mem);
 #endif /* MEMP_MEM_MALLOC */
+}
+

+ 0 - 116
net/lwip/src/core/memp_tiny.c

@@ -1,116 +0,0 @@
-#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/igmp.h"
-#include "lwip/api.h"
-#include "lwip/api_msg.h"
-#include "lwip/tcpip.h"
-#include "lwip/sys.h"
-#include "lwip/stats.h"
-#include "netif/etharp.h"
-#include "lwip/ip_frag.h"
-
-#include <string.h>
-
-#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
-
-/** This array holds the element sizes of each pool. */
-static const u16_t memp_sizes[MEMP_MAX] = {
-#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_ALIGN_SIZE(size),
-#include "lwip/memp_std.h"
-};
-
-/** This array holds a textual description of each pool. */
-#ifdef LWIP_DEBUG
-static const char *memp_desc[MEMP_MAX] = {
-#define LWIP_MEMPOOL(name,num,size,desc)  (desc),
-#include "lwip/memp_std.h"
-};
-#endif /* LWIP_DEBUG */
-
-/* fix time-wait tcp pcb issue */
-static rt_uint32_t tcp_pcbs = 0;
-
-/**
- * Initialize this module.
- *
- * Carves out memp_memory into linked lists for each pool-type.
- */
-void
-memp_init(void)
-{
-	/* nothing */
-}
-
-/**
- * Get an element from a specific pool.
- *
- * @param type the pool to get an element from
- *
- * the debug version has two more parameters:
- * @param file file name calling this function
- * @param line number of line where this function is called
- *
- * @return a pointer to the allocated memory or a NULL pointer on error
- */
-void *
-#if !MEMP_OVERFLOW_CHECK
-memp_malloc(memp_t type)
-#else
-memp_malloc_fn(memp_t type, const char* file, const int line)
-#endif
-{
-    void* ptr;
-    rt_uint32_t size, level;
-
-    size = memp_sizes[type];
-    LWIP_DEBUGF(MEMP_DEBUG, ("memp malloc %s, size %d, ", memp_desc[type], memp_sizes[type]));
-
-	level = rt_hw_interrupt_disable();
-	if (type == MEMP_TCP_PCB)
-	{
-		if (tcp_pcbs >= MEMP_NUM_TCP_PCB)
-		{
-			rt_hw_interrupt_enable(level);
-			return RT_NULL;
-		}
-		else
-		{
-			/* increased tcp pcb allocated number */
-			tcp_pcbs ++;
-		}
-	}
-	rt_hw_interrupt_enable(level);
-
-    ptr = rt_malloc(size);
-	LWIP_DEBUGF(MEMP_DEBUG, ("mem 0x%x\n", ptr));
-
-    return ptr;
-}
-
-/**
- * Put an element back into its pool.
- *
- * @param type the pool where to put mem
- * @param mem the memp element to free
- */
-void
-memp_free(memp_t type, void *mem)
-{
-	rt_uint32_t level;
-
-	level = rt_hw_interrupt_disable();
-	if (type == MEMP_TCP_PCB && mem)
-	{
-		tcp_pcbs --;
-	}
-	rt_hw_interrupt_enable(level);
-
-    LWIP_DEBUGF(MEMP_DEBUG, ("memp free %s, mem 0x%x\n", memp_desc[type], mem));
-    /* release this memory */
-    rt_free(mem);
-}

+ 37 - 11
net/lwip/src/core/netif.c

@@ -52,6 +52,13 @@
 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
 #endif /* ENABLE_LOOPBACK */
 
+#if LWIP_AUTOIP
+#include "lwip/autoip.h"
+#endif /* LWIP_AUTOIP */
+#if LWIP_DHCP
+#include "lwip/dhcp.h"
+#endif /* LWIP_DHCP */
+
 #if LWIP_NETIF_STATUS_CALLBACK
 #define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }
 #else
@@ -271,14 +278,14 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
   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"));
+    LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("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));
+        LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
         tcp_abort(pcb);
         pcb = next;
       } else {
@@ -303,7 +310,7 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
   snmp_insert_ipaddridx_tree(netif);
   snmp_insert_iprteidx_tree(0,netif);
 
-  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("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),
@@ -323,7 +330,7 @@ void
 netif_set_gw(struct netif *netif, struct ip_addr *gw)
 {
   ip_addr_set(&(netif->gw), gw);
-  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("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),
@@ -347,7 +354,7 @@ netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
   /* set new netmask to netif */
   ip_addr_set(&(netif->netmask), netmask);
   snmp_insert_iprteidx_tree(0, netif);
-  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("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),
@@ -406,7 +413,13 @@ void netif_set_up(struct netif *netif)
       etharp_gratuitous(netif);
     }
 #endif /* LWIP_ARP */
-    
+
+#if LWIP_IGMP
+    /* resend IGMP memberships */
+    if (netif->flags & NETIF_FLAG_IGMP) {
+      igmp_report_groups( netif);
+    }
+#endif /* LWIP_IGMP */
   }
 }
 
@@ -459,6 +472,19 @@ void netif_set_link_up(struct netif *netif )
 {
   netif->flags |= NETIF_FLAG_LINK_UP;
 
+#if LWIP_DHCP
+  if (netif->dhcp) {
+    dhcp_network_changed(netif);
+  }
+#endif /* LWIP_DHCP */
+
+#if LWIP_AUTOIP
+  if (netif->autoip) {
+    autoip_network_changed(netif);
+  }
+#endif /* LWIP_AUTOIP */
+
+  if (netif->flags & NETIF_FLAG_UP) {
 #if LWIP_ARP
   /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 
   if (netif->flags & NETIF_FLAG_ETHARP) {
@@ -467,12 +493,12 @@ void netif_set_link_up(struct netif *netif )
 #endif /* LWIP_ARP */
 
 #if LWIP_IGMP
-  /* resend IGMP memberships */
-  if (netif->flags & NETIF_FLAG_IGMP) {
-    igmp_report_groups( netif);
-  }
+    /* resend IGMP memberships */
+    if (netif->flags & NETIF_FLAG_IGMP) {
+      igmp_report_groups( netif);
+    }
 #endif /* LWIP_IGMP */
-
+  }
   NETIF_LINK_CALLBACK(netif);
 }
 

+ 77 - 43
net/lwip/src/core/pbuf.c

@@ -81,41 +81,71 @@
    aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
 
-#if TCP_QUEUE_OOSEQ
-#define ALLOC_POOL_PBUF(p) do { (p) = alloc_pool_pbuf(); } while (0)
-#else
-#define ALLOC_POOL_PBUF(p) do { (p) = memp_malloc(MEMP_PBUF_POOL); } while (0)
-#endif
-
-
-#if TCP_QUEUE_OOSEQ
+#if !TCP_QUEUE_OOSEQ || NO_SYS
+#define PBUF_POOL_IS_EMPTY()
+#else /* !TCP_QUEUE_OOSEQ || NO_SYS */
+/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
+#ifndef PBUF_POOL_FREE_OOSEQ
+#define PBUF_POOL_FREE_OOSEQ 1
+#endif /* PBUF_POOL_FREE_OOSEQ */
+
+#if PBUF_POOL_FREE_OOSEQ
+#include "lwip/tcpip.h"
+#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
+static u8_t pbuf_free_ooseq_queued;
 /**
  * Attempt to reclaim some memory from queued out-of-sequence TCP segments
  * if we run out of pool pbufs. It's better to give priority to new packets
  * if we're running out.
  *
- * @return the allocated pbuf.
+ * This must be done in the correct thread context therefore this function
+ * can only be used with NO_SYS=0 and through tcpip_callback.
  */
-static struct pbuf *
-alloc_pool_pbuf(void)
+static void
+pbuf_free_ooseq(void* arg)
 {
-  struct tcp_pcb *pcb;
-  struct pbuf *p;
+  struct tcp_pcb* pcb;
+  SYS_ARCH_DECL_PROTECT(old_level);
+  LWIP_UNUSED_ARG(arg);
+
+  SYS_ARCH_PROTECT(old_level);
+  pbuf_free_ooseq_queued = 0;
+  SYS_ARCH_UNPROTECT(old_level);
+
+  for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
+    if (NULL != pcb->ooseq) {
+      /** Free the ooseq pbufs of one PCB only */
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
+      tcp_segs_free(pcb->ooseq);
+      pcb->ooseq = NULL;
+      return;
+    }
+  }
+}
 
-retry:
-  p = memp_malloc(MEMP_PBUF_POOL);
-  if (NULL == p) {
-    for (pcb=tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
-      if (NULL != pcb->ooseq) {
-        tcp_segs_free(pcb->ooseq);
-        pcb->ooseq = NULL;
-        goto retry;
-      }
+/** Queue a call to pbuf_free_ooseq if not already queued. */
+static void
+pbuf_pool_is_empty(void)
+{
+  u8_t queued;
+  SYS_ARCH_DECL_PROTECT(old_level);
+
+  SYS_ARCH_PROTECT(old_level);
+  queued = pbuf_free_ooseq_queued;
+  pbuf_free_ooseq_queued = 1;
+  SYS_ARCH_UNPROTECT(old_level);
+
+  if(!queued) {
+    /* queue a call to pbuf_free_ooseq if not already queued */
+    if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
+      SYS_ARCH_PROTECT(old_level);
+      pbuf_free_ooseq_queued = 0;
+      SYS_ARCH_UNPROTECT(old_level);
     }
   }
-  return p;
 }
-#endif /* TCP_QUEUE_OOSEQ */
+#endif /* PBUF_POOL_FREE_OOSEQ */
+#endif /* !TCP_QUEUE_OOSEQ || NO_SYS */
 
 /**
  * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
@@ -154,7 +184,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
   struct pbuf *p, *q, *r;
   u16_t offset;
   s32_t rem_len; /* remaining length */
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
 
   /* determine header offset */
   offset = 0;
@@ -181,9 +211,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
   switch (type) {
   case PBUF_POOL:
     /* allocate head of pbuf chain into p */
-    ALLOC_POOL_PBUF(p);
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
+    p = memp_malloc(MEMP_PBUF_POOL);
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
     if (p == NULL) {
+      PBUF_POOL_IS_EMPTY();
       return NULL;
     }
     p->type = type;
@@ -213,8 +244,9 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
     rem_len = length - p->len;
     /* any remaining pbufs to be allocated? */
     while (rem_len > 0) {
-      ALLOC_POOL_PBUF(q);
+      q = memp_malloc(MEMP_PBUF_POOL);
       if (q == NULL) {
+        PBUF_POOL_IS_EMPTY();
         /* free chain so far allocated */
         pbuf_free(p);
         /* bail out unsuccesfully */
@@ -268,7 +300,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
     /* only allocate memory for the pbuf structure */
     p = memp_malloc(MEMP_PBUF);
     if (p == NULL) {
-      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+                  ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
                   (type == PBUF_ROM) ? "ROM" : "REF"));
       return NULL;
     }
@@ -286,7 +319,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
   p->ref = 1;
   /* set flags */
   p->flags = 0;
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
   return p;
 }
 
@@ -426,9 +459,9 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
     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)));\
+      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("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 */
@@ -455,7 +488,7 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
   p->len += header_size_increment;
   p->tot_len += header_size_increment;
 
-  LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
     (void *)payload, (void *)p->payload, header_size_increment));
 
   return 0;
@@ -504,10 +537,11 @@ pbuf_free(struct pbuf *p)
   if (p == NULL) {
     LWIP_ASSERT("p != NULL", p != NULL);
     /* if assertions are disabled, proceed with debug output */
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+      ("pbuf_free(p == NULL) was called.\n"));
     return 0;
   }
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
 
   PERF_START;
 
@@ -534,7 +568,7 @@ pbuf_free(struct pbuf *p)
     if (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));
+      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
       type = p->type;
       /* is this a pbuf from the pool? */
       if (type == PBUF_POOL) {
@@ -552,7 +586,7 @@ pbuf_free(struct pbuf *p)
     /* 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, ref));
+      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
       /* stop walking through the chain */
       p = NULL;
     }
@@ -657,7 +691,7 @@ 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 | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
 }
 
 /**
@@ -686,10 +720,10 @@ pbuf_dechain(struct pbuf *p)
     /* 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 | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
     tail_gone = pbuf_free(q);
     if (tail_gone > 0) {
-      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
                   ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
     }
     /* return remaining tail or NULL if deallocated */
@@ -722,7 +756,7 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
 {
   u16_t offset_to=0, offset_from=0, len;
 
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n",
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
     (void*)p_to, (void*)p_from));
 
   /* is the target big enough to hold the source? */
@@ -768,7 +802,7 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
                   (p_to->next == NULL), return ERR_VAL;);
     }
   } while (p_from);
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n"));
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
   return ERR_OK;
 }
 

+ 5 - 5
net/lwip/src/core/raw.c

@@ -210,7 +210,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
   struct ip_addr *src_ip;
   struct pbuf *q; /* q will be sent down the stack */
   
-  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_sendto\n"));
+  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
   
   /* not enough space to add an IP header to first pbuf in given p chain? */
   if (pbuf_header(p, IP_HLEN)) {
@@ -218,7 +218,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
     q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
     /* new header pbuf could not be allocated? */
     if (q == NULL) {
-      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));
+      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
       return ERR_MEM;
     }
     /* chain header q in front of given pbuf p */
@@ -235,7 +235,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
   }
 
   if ((netif = ip_route(ipaddr)) == NULL) {
-    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
+    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
     /* free any temporary header pbuf allocated by pbuf_header() */
     if (q != p) {
       pbuf_free(q);
@@ -246,7 +246,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
 #if IP_SOF_BROADCAST
   /* broadcast filter? */
   if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif) ) {
-    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
+    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
     /* free any temporary header pbuf allocated by pbuf_header() */
     if (q != p) {
       pbuf_free(q);
@@ -335,7 +335,7 @@ struct raw_pcb *
 raw_new(u8_t proto) {
   struct raw_pcb *pcb;
 
-  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_new\n"));
+  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
 
   pcb = memp_malloc(MEMP_RAW_PCB);
   /* could allocate RAW PCB? */

+ 27 - 25
net/lwip/src/core/snmp/mib2.c

@@ -2077,25 +2077,25 @@ void snmp_get_snmpenableauthentraps(u8_t *value)
 void
 noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
 {
-  if (ident_len){}
-  if (ident){}
+  LWIP_UNUSED_ARG(ident_len);
+  LWIP_UNUSED_ARG(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){}
+  LWIP_UNUSED_ARG(od);
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);
 }
 
 u8_t
 noleafs_set_test(struct obj_def *od, u16_t len, void *value)
 {
-  if (od){}
-  if (len){}
-  if (value){}
+  LWIP_UNUSED_ARG(od);
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);
   /* can't set */
   return 0;
 }
@@ -2103,9 +2103,9 @@ 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)
 {
-  if (od){}
-  if (len){}
-  if (value){}
+  LWIP_UNUSED_ARG(od);
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);
 }
 
 
@@ -2238,7 +2238,7 @@ system_set_test(struct obj_def *od, u16_t len, void *value)
 {
   u8_t id, set_ok;
 
-  if (value) {}
+  LWIP_UNUSED_ARG(value);
   set_ok = 0;
   id = od->id_inst_ptr[0];
   switch (id)
@@ -2332,7 +2332,7 @@ 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)
 {
-  if (len){}
+  LWIP_UNUSED_ARG(len);
   if (od->id_inst_ptr[0] == 1)
   {
     s32_t *sint_ptr = value;
@@ -2724,7 +2724,8 @@ atentry_get_value(struct obj_def *od, u16_t len, void *value)
   struct ip_addr ip;
   struct netif *netif;
 
-  if (len) {}
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */
 
   snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
   snmp_oidtoip(&od->id_inst_ptr[2], &ip);
@@ -2831,7 +2832,7 @@ ip_get_value(struct obj_def *od, u16_t len, void *value)
 {
   u8_t id;
 
-  if (len) {}
+  LWIP_UNUSED_ARG(len);
   id = od->id_inst_ptr[0];
   switch (id)
   {
@@ -2985,7 +2986,7 @@ ip_set_test(struct obj_def *od, u16_t len, void *value)
   u8_t id, set_ok;
   s32_t *sint_ptr = value;
 
-  if (len) {}
+  LWIP_UNUSED_ARG(len);
   set_ok = 0;
   id = od->id_inst_ptr[0];
   switch (id)
@@ -3065,7 +3066,7 @@ ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)
   struct ip_addr ip;
   struct netif *netif = netif_list;
 
-  if (len) {}
+  LWIP_UNUSED_ARG(len);
   snmp_oidtoip(&od->id_inst_ptr[1], &ip);
   ip.addr = htonl(ip.addr);
   ifidx = 0;
@@ -3408,7 +3409,8 @@ ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)
   struct ip_addr ip;
   struct netif *netif;
 
-  if (len) {}
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */
 
   snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
   snmp_oidtoip(&od->id_inst_ptr[2], &ip);
@@ -3482,7 +3484,7 @@ icmp_get_value(struct obj_def *od, u16_t len, void *value)
   u32_t *uint_ptr = value;
   u8_t id;
 
-  if (len){}
+  LWIP_UNUSED_ARG(len);
   id = od->id_inst_ptr[0];
   switch (id)
   {
@@ -3636,7 +3638,7 @@ tcp_get_value(struct obj_def *od, u16_t len, void *value)
   s32_t *sint_ptr = value;
   u8_t id;
 
-  if (len){}
+  LWIP_UNUSED_ARG(len);
   id = od->id_inst_ptr[0];
   switch (id)
   {
@@ -3804,7 +3806,7 @@ udp_get_value(struct obj_def *od, u16_t len, void *value)
   u32_t *uint_ptr = value;
   u8_t id;
 
-  if (len){}
+  LWIP_UNUSED_ARG(len);
   id = od->id_inst_ptr[0];
   switch (id)
   {
@@ -3870,7 +3872,7 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value)
   struct ip_addr ip;
   u16_t port;
 
-  if (len){}
+  LWIP_UNUSED_ARG(len);
   snmp_oidtoip(&od->id_inst_ptr[1], &ip);
   ip.addr = htonl(ip.addr);
   port = od->id_inst_ptr[5];
@@ -3977,7 +3979,7 @@ snmp_get_value(struct obj_def *od, u16_t len, void *value)
   u32_t *uint_ptr = value;
   u8_t id;
 
-  if (len){}
+  LWIP_UNUSED_ARG(len);
   id = od->id_inst_ptr[0];
   switch (id)
   {
@@ -4080,7 +4082,7 @@ snmp_set_test(struct obj_def *od, u16_t len, void *value)
 {
   u8_t id, set_ok;
 
-  if (len) {}
+  LWIP_UNUSED_ARG(len);
   set_ok = 0;
   id = od->id_inst_ptr[0];
   if (id == 30)
@@ -4113,7 +4115,7 @@ snmp_set_value(struct obj_def *od, u16_t len, void *value)
 {
   u8_t id;
 
-  if (len) {}
+  LWIP_UNUSED_ARG(len);
   id = od->id_inst_ptr[0];
   if (id == 30)
   {

+ 1 - 1
net/lwip/src/core/snmp/mib_structs.c

@@ -118,7 +118,7 @@ snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
   u16_t i;
 
   i = 0;
-  while (nif != netif)
+  while ((nif != NULL) && (nif != netif))
   {
     nif = nif->next;
     i++;

+ 8 - 6
net/lwip/src/core/sys.c

@@ -97,7 +97,7 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg)
       arg = tmptimeout->arg;
       memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
       if (h != NULL) {
-        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg));
+        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", *(void**)&h, arg));
         h(arg);
       }
 
@@ -154,7 +154,7 @@ sys_sem_wait(sys_sem_t sem)
       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));
+        LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", *(void**)&h, (void *)arg));
         h(arg);
       }
 
@@ -203,7 +203,7 @@ sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
   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));
+    (void *)timeout, msecs, *(void**)&h, (void *)arg));
 
   if (timeouts == NULL) {
     LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
@@ -264,13 +264,15 @@ sys_untimeout(sys_timeout_handler h, void *arg)
     if ((t->h == h) && (t->arg == arg)) {
       /* We have a match */
       /* Unlink from previous in list */
-      if (prev_t == NULL)
+      if (prev_t == NULL) {
         timeouts->next = t->next;
-      else
+      } else {
         prev_t->next = t->next;
+      }
       /* If not the last one, add time of this one back to next */
-      if (t->next != NULL)
+      if (t->next != NULL) {
         t->next->time += t->time;
+      }
       memp_free(MEMP_SYS_TIMEOUT, t);
       return;
     }

+ 44 - 41
net/lwip/src/core/tcp.c

@@ -50,9 +50,24 @@
 #include "lwip/snmp.h"
 #include "lwip/tcp.h"
 #include "lwip/debug.h"
+#include "lwip/stats.h"
 
 #include <string.h>
 
+const char *tcp_state_str[] = {
+  "CLOSED",      
+  "LISTEN",      
+  "SYN_SENT",    
+  "SYN_RCVD",    
+  "ESTABLISHED", 
+  "FIN_WAIT_1",  
+  "FIN_WAIT_2",  
+  "CLOSE_WAIT",  
+  "CLOSING",     
+  "LAST_ACK",    
+  "TIME_WAIT"   
+};
+
 /* Incremented every coarse grained timer shot (typically every 500 ms). */
 u32_t tcp_ticks;
 const u8_t tcp_backoff[13] =
@@ -394,7 +409,7 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
 {
   u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;
 
-  if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + pcb->mss)) {
+  if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) {
     /* we can advertise more window */
     pcb->rcv_ann_wnd = pcb->rcv_wnd;
     return new_right_edge - pcb->rcv_ann_right_edge;
@@ -564,6 +579,7 @@ tcp_slowtmr(void)
   struct tcp_pcb *pcb, *pcb2, *prev;
   u16_t eff_wnd;
   u8_t pcb_remove;      /* flag if a PCB should be removed */
+  u8_t pcb_reset;       /* flag if a RST should be sent when removing */
   err_t err;
 
   err = ERR_OK;
@@ -583,6 +599,7 @@ tcp_slowtmr(void)
     LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
 
     pcb_remove = 0;
+    pcb_reset = 0;
 
     if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
       ++pcb_remove;
@@ -666,7 +683,8 @@ tcp_slowtmr(void)
                                 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
                                 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
         
-        tcp_abort(pcb);
+        ++pcb_remove;
+        ++pcb_reset;
       }
 #if LWIP_TCP_KEEPALIVE
       else if((u32_t)(tcp_ticks - pcb->tmr) > 
@@ -726,6 +744,10 @@ tcp_slowtmr(void)
       }
 
       TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
+      if (pcb_reset) {
+        tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
+          pcb->local_port, pcb->remote_port);
+      }
 
       pcb2 = pcb->next;
       memp_free(MEMP_TCP_PCB, pcb);
@@ -899,11 +921,12 @@ tcp_seg_copy(struct tcp_seg *seg)
  * Default receive callback that is called if the user didn't register
  * a recv callback for the pcb.
  */
-static err_t
+err_t
 tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
 {
-  arg = arg;
+  LWIP_UNUSED_ARG(arg);
   if (p != NULL) {
+    tcp_recved(pcb, p->tot_len);
     pbuf_free(p);
   } else if (err == ERR_OK) {
     return tcp_close(pcb);
@@ -993,9 +1016,18 @@ tcp_alloc(u8_t prio)
     pcb = memp_malloc(MEMP_TCP_PCB);
     if (pcb == NULL) {
       /* Try killing active connections with lower priority than the new one. */
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio));
       tcp_kill_prio(prio);
       /* Try to allocate a tcp_pcb again. */
       pcb = memp_malloc(MEMP_TCP_PCB);
+      if (pcb != NULL) {
+        /* adjust err stats: memp_malloc failed twice before */
+        MEMP_STATS_DEC(err, MEMP_TCP_PCB);
+      }
+    }
+    if (pcb != NULL) {
+      /* adjust err stats: timewait PCB was freed above */
+      MEMP_STATS_DEC(err, MEMP_TCP_PCB);
     }
   }
   if (pcb != NULL) {
@@ -1218,7 +1250,7 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
  * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
  *
  * @param pcblist PCB list to purge.
- * @param pcb tcp_pcb to purge. The pcb itself is also deallocated!
+ * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated!
  */
 void
 tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
@@ -1288,6 +1320,12 @@ tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr)
 }
 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
 
+const char*
+tcp_debug_state_str(enum tcp_state s)
+{
+  return tcp_state_str[s];
+}
+
 #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
 /**
  * Print a tcp header for debugging purposes.
@@ -1333,42 +1371,7 @@ tcp_debug_print(struct tcp_hdr *tcphdr)
 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;
-  }
+  LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s]));
 }
 
 /**

+ 211 - 124
net/lwip/src/core/tcp_in.c

@@ -74,7 +74,7 @@ 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_receive(struct tcp_pcb *pcb);
 static void tcp_parseopt(struct tcp_pcb *pcb);
 
 static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
@@ -288,10 +288,8 @@ tcp_input(struct pbuf *p, struct netif *inp)
         return;
       }
     }
-
     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) {
@@ -338,12 +336,17 @@ tcp_input(struct pbuf *p, struct netif *inp)
           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);
-        }
+        tcp_input_pcb = NULL;
+        /* Try to send something out. */
+        tcp_output(pcb);
+#if TCP_INPUT_DEBUG
+#if TCP_DEBUG
+        tcp_debug_print_state(pcb->state);
+#endif /* TCP_DEBUG */
+#endif /* TCP_INPUT_DEBUG */
       }
     }
+    tcp_input_pcb = NULL;
 
 
     /* give up our reference to inseg.p */
@@ -352,12 +355,6 @@ tcp_input(struct pbuf *p, struct netif *inp)
       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
@@ -481,13 +478,36 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
 static err_t
 tcp_timewait_input(struct tcp_pcb *pcb)
 {
-  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {
-    pcb->rcv_nxt = seqno + tcplen;
+  /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
+  /* RFC 793 3.9 Event Processing - Segment Arrives:
+   * - first check sequence number - we skip that one in TIME_WAIT (always
+   *   acceptable since we only send ACKs)
+   * - second check the RST bit (... return) */
+  if (flags & TCP_RST)  {
+    return ERR_OK;
   }
-  if (tcplen > 0) {
-    tcp_ack_now(pcb);
+  /* - fourth, check the SYN bit, */
+  if (flags & TCP_SYN) {
+    /* If an incoming segment is not acceptable, an acknowledgment
+       should be sent in reply */
+    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
+      /* If the SYN is in the window it is an error, send a reset */
+      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
+        tcphdr->dest, tcphdr->src);
+      return ERR_OK;
+    }
+  } else if (flags & TCP_FIN) {
+    /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
+         Restart the 2 MSL time-wait timeout.*/
+    pcb->tmr = tcp_ticks;
+  }
+
+  if ((tcplen > 0))  {
+    /* Acknowledge data, FIN or out-of-window SYN */
+    pcb->flags |= TF_ACK_NOW;
+    return tcp_output(pcb);
   }
-  return tcp_output(pcb);
+  return ERR_OK;
 }
 
 /**
@@ -628,6 +648,11 @@ tcp_process(struct tcp_pcb *pcb)
          * we'd better pass it on to the application as well. */
         tcp_receive(pcb);
 
+        /* Prevent ACK for SYN to generate a sent event */
+        if (pcb->acked != 0) {
+          pcb->acked--;
+        }
+
         pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
 
         if (recv_flags & TF_GOT_FIN) {
@@ -660,7 +685,7 @@ tcp_process(struct tcp_pcb *pcb)
     if (recv_flags & TF_GOT_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 connection closed: FIN_WAIT_1 %"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);
@@ -677,7 +702,7 @@ tcp_process(struct tcp_pcb *pcb)
   case FIN_WAIT_2:
     tcp_receive(pcb);
     if (recv_flags & TF_GOT_FIN) {
-      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"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);
@@ -688,7 +713,7 @@ tcp_process(struct tcp_pcb *pcb)
   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));
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
       tcp_pcb_purge(pcb);
       TCP_RMV(&tcp_active_pcbs, pcb);
       pcb->state = TIME_WAIT;
@@ -698,7 +723,7 @@ tcp_process(struct tcp_pcb *pcb)
   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));
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
       /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
       recv_flags |= TF_CLOSED;
     }
@@ -709,6 +734,47 @@ tcp_process(struct tcp_pcb *pcb)
   return ERR_OK;
 }
 
+#if TCP_QUEUE_OOSEQ
+/**
+ * Insert segment into the list (segments covered with new one will be deleted)
+ *
+ * Called from tcp_receive()
+ */
+static void
+tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
+{
+  struct tcp_seg *old_seg;
+
+  if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
+    /* received segment overlaps all following segments */
+    tcp_segs_free(next);
+    next = NULL;
+  }
+  else {
+    /* delete some following segments
+       oos queue may have segments with FIN flag */
+    while (next &&
+           TCP_SEQ_GEQ((seqno + cseg->len),
+                      (next->tcphdr->seqno + next->len))) {
+      /* cseg with FIN already processed */
+      if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
+        TCPH_FLAGS_SET(cseg->tcphdr, TCPH_FLAGS(cseg->tcphdr) | TCP_FIN);
+      }
+      old_seg = next;
+      next = next->next;
+      tcp_seg_free(old_seg);
+    }
+    if (next &&
+        TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
+      /* We need to trim the incoming segment. */
+      cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
+      pbuf_realloc(cseg->p, cseg->len);
+    }
+  }
+  cseg->next = next;
+}
+#endif
+
 /**
  * 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
@@ -720,10 +786,8 @@ tcp_process(struct tcp_pcb *pcb)
  * estimation, the RTT is estimated here as well.
  *
  * Called from tcp_process().
- *
- * @return 1 if the incoming segment is the next in sequence, 0 if not
  */
-static u8_t
+static void
 tcp_receive(struct tcp_pcb *pcb)
 {
   struct tcp_seg *next;
@@ -735,7 +799,7 @@ tcp_receive(struct tcp_pcb *pcb)
   s16_t m;
   u32_t right_wnd_edge;
   u16_t new_tot_len;
-  u8_t accepted_inseq = 0;
+  int found_dupack = 0;
 
   if (flags & TCP_ACK) {
     right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
@@ -762,51 +826,62 @@ tcp_receive(struct tcp_pcb *pcb)
 #endif /* TCP_WND_DEBUG */
     }
 
-    if (pcb->lastack == ackno) {
+    /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
+     * duplicate ack if:
+     * 1) It doesn't ACK new data 
+     * 2) length of received packet is zero (i.e. no payload) 
+     * 3) the advertised window hasn't changed 
+     * 4) There is outstanding unacknowledged data (retransmission timer running)
+     * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
+     * 
+     * If it passes all five, should process as a dupack: 
+     * a) dupacks < 3: do nothing 
+     * b) dupacks == 3: fast retransmit 
+     * c) dupacks > 3: increase cwnd 
+     * 
+     * If it only passes 1-3, should reset dupack counter (and add to
+     * stats, which we don't do in lwIP)
+     *
+     * If it only passes 1, should reset dupack counter
+     *
+     */
+
+    /* Clause 1 */
+    if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
       pcb->acked = 0;
-
-      if (pcb->snd_wl2 + 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 current cwnd and the advertised window */
-            if (pcb->cwnd > pcb->snd_wnd)
-              pcb->ssthresh = pcb->snd_wnd / 2;
-            else
-              pcb->ssthresh = pcb->cwnd / 2;
-
-            /* The minimum value for ssthresh should be 2 MSS */
-            if (pcb->ssthresh < 2*pcb->mss) {
-              LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: The minimum value for ssthresh %"U16_F" should be min 2 mss %"U16_F"...\n", pcb->ssthresh, 2*pcb->mss));
-              pcb->ssthresh = 2*pcb->mss;
-            }
-
-            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;
+      /* Clause 2 */
+      if (tcplen == 0) {
+        /* Clause 3 */
+        if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
+          /* Clause 4 */
+          if (pcb->rtime >= 0) {
+            /* Clause 5 */
+            if (pcb->lastack == ackno) {
+              found_dupack = 1;
+              if (pcb->dupacks + 1 > pcb->dupacks)
+                ++pcb->dupacks;
+              if (pcb->dupacks > 3) {
+                /* 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 if (pcb->dupacks == 3) {
+                /* Do fast retransmit */
+                tcp_rexmit_fast(pcb);
+              }
             }
           }
         }
-      } else {
-        LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",
-                                   pcb->snd_wl2 + pcb->snd_wnd, right_wnd_edge));
+      }
+      /* If Clause (1) or more is true, but not a duplicate ack, reset
+       * count of consecutive duplicate acks */
+      if (!found_dupack) {
+        pcb->dupacks = 0;
       }
     } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
       /* 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. */
@@ -868,6 +943,11 @@ tcp_receive(struct tcp_pcb *pcb)
 
         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
         LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
+        /* Prevent ACK for FIN to generate a sent event */
+        if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
+          pcb->acked--;
+        }
+
         pcb->snd_queuelen -= pbuf_clen(next->p);
         tcp_seg_free(next);
 
@@ -908,6 +988,10 @@ tcp_receive(struct tcp_pcb *pcb)
       pcb->unsent = pcb->unsent->next;
       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
       LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
+      /* Prevent ACK for FIN to generate a sent event */
+      if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
+        pcb->acked--;
+      }
       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));
@@ -1051,7 +1135,6 @@ tcp_receive(struct tcp_pcb *pcb)
     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. */
@@ -1084,17 +1167,45 @@ tcp_receive(struct tcp_pcb *pcb)
                         ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
             /* Received in-order FIN means anything that was received
              * out of order must now have been received in-order, so
-             * bin the ooseq queue */
+             * bin the ooseq queue
+             * rcv_nxt
+             * .    |--ooseq--|
+             * .==seg============|FIN
+             */
             while (pcb->ooseq != NULL) {
               struct tcp_seg *old_ooseq = pcb->ooseq;
               pcb->ooseq = pcb->ooseq->next;
-              memp_free(MEMP_TCP_SEG, old_ooseq);
+              tcp_seg_free(old_ooseq);
             }               
-          } else if (TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + tcplen)) {
-            if (pcb->ooseq->len > 0) {
-              /* We have to trim the second edge of the incoming segment. */
-              LWIP_ASSERT("tcp_receive: trimmed segment would have zero length\n",
-                          TCP_SEQ_GT(pcb->ooseq->tcphdr->seqno, seqno));
+          } 
+          else {
+            struct tcp_seg* next = pcb->ooseq;
+            struct tcp_seg *old_seg;
+            /* rcv_nxt
+             * .    |--ooseq--|
+             * .==seg============|
+             */
+            while (next &&
+                   TCP_SEQ_GEQ(seqno + tcplen,
+                               next->tcphdr->seqno + next->len)) {
+              /* inseg doesn't have FIN (already processed) */
+              if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
+                  (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
+                TCPH_FLAGS_SET(inseg.tcphdr, 
+                               TCPH_FLAGS(inseg.tcphdr) | TCP_FIN);
+                tcplen = TCP_TCPLEN(&inseg);
+              }
+              old_seg = next;
+              next = next->next;
+              tcp_seg_free(old_seg);
+            }
+            /* rcv_nxt
+             * .             |--ooseq--|
+             * .==seg============|
+             */
+            if (next &&
+                TCP_SEQ_GT(seqno + tcplen,
+                           next->tcphdr->seqno)) {
               /* FIN in inseg already handled by dropping whole ooseq queue */
               inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);
               if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
@@ -1104,15 +1215,8 @@ tcp_receive(struct tcp_pcb *pcb)
               tcplen = TCP_TCPLEN(&inseg);
               LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
                           (seqno + tcplen) == pcb->ooseq->tcphdr->seqno);
-            } else {
-              /* does the ooseq segment contain only flags that are in inseg also? */
-              if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) ==
-                  (TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {
-                struct tcp_seg *old_ooseq = pcb->ooseq;
-                pcb->ooseq = pcb->ooseq->next;
-                memp_free(MEMP_TCP_SEG, old_ooseq);
-              }
             }
+            pcb->ooseq = next;
           }
         }
 #endif /* TCP_QUEUE_OOSEQ */
@@ -1180,7 +1284,6 @@ tcp_receive(struct tcp_pcb *pcb)
             } 
           }
 
-
           pcb->ooseq = cseg->next;
           tcp_seg_free(cseg);
         }
@@ -1192,7 +1295,7 @@ tcp_receive(struct tcp_pcb *pcb)
 
       } else {
         /* We get here if the incoming segment is out-of-sequence. */
-        tcp_ack_now(pcb);
+        tcp_send_empty_ack(pcb);
 #if TCP_QUEUE_OOSEQ
         /* We queue the segment on the ->ooseq queue. */
         if (pcb->ooseq == NULL) {
@@ -1219,25 +1322,16 @@ tcp_receive(struct tcp_pcb *pcb)
                  discard. */
               if (inseg.len > next->len) {
                 /* The incoming segment is larger than the old
-                   segment. We replace the old segment with the new
+                   segment. We replace some segments 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;
                   }
-                  tcp_seg_free(next);
-                  if (cseg->next != NULL) {
-                    next = cseg->next;
-                    if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
-                      /* We need to trim the incoming segment. */
-                      cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
-                      pbuf_realloc(cseg->p, cseg->len);
-                    }
-                  }
+                  tcp_oos_insert_segment(cseg, next);
                 }
                 break;
               } else {
@@ -1253,51 +1347,44 @@ tcp_receive(struct tcp_pcb *pcb)
                      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 = (u16_t)(next->tcphdr->seqno - seqno);
-                    pbuf_realloc(inseg.p, inseg.len);
-                  }
                   cseg = tcp_seg_copy(&inseg);
                   if (cseg != NULL) {
-                    cseg->next = next;
                     pcb->ooseq = cseg;
+                    tcp_oos_insert_segment(cseg, next);
                   }
                   break;
                 }
-              } else 
+              } 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 = (u16_t)(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 = (u16_t)(seqno - prev->tcphdr->seqno);
-                    pbuf_realloc(prev->p, prev->len);
+                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 trim the previous
+                     segment, delete next segments that included in received segment
+                     and trim received, if needed. */
+                  cseg = tcp_seg_copy(&inseg);
+                  if (cseg != NULL) {
+                    if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
+                      /* We need to trim the prev segment. */
+                      prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
+                      pbuf_realloc(prev->p, prev->len);
+                    }
+                    prev->next = cseg;
+                    tcp_oos_insert_segment(cseg, next);
                   }
+                  break;
                 }
-                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)) {
+                if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
+                  /* segment "next" already contains all data */
+                  break;
+                }
                 next->next = tcp_seg_copy(&inseg);
                 if (next->next != NULL) {
                   if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
@@ -1316,7 +1403,8 @@ tcp_receive(struct tcp_pcb *pcb)
 
       }
     } else {
-      tcp_ack_now(pcb);
+      /* The incoming segment is not withing the window. */
+      tcp_send_empty_ack(pcb);
     }
   } else {
     /* Segments with length 0 is taken care of here. Segments that
@@ -1327,7 +1415,6 @@ tcp_receive(struct tcp_pcb *pcb)
       tcp_ack_now(pcb);
     }
   }
-  return accepted_inseq;
 }
 
 /**

+ 139 - 66
net/lwip/src/core/tcp_out.c

@@ -132,7 +132,7 @@ tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags)
     }
     return ERR_OK;
   } else {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | 3, ("tcp_write() called in invalid state\n"));
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n"));
     return ERR_CONN;
   }
 }
@@ -174,7 +174,8 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
 
   /* fail on too much data */
   if (len > pcb->snd_buf) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_WARNING,
+      ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));
     pcb->flags |= TF_NAGLEMEMERR;
     return ERR_MEM;
   }
@@ -194,7 +195,8 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
   queuelen = pcb->snd_queuelen;
   /* check for configured max queuelen and possible overflow */
   if ((queuelen >= TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_WARNING,
+      ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
     TCP_STATS_INC(tcp.memerr);
     pcb->flags |= TF_NAGLEMEMERR;
     return ERR_MEM;
@@ -218,7 +220,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
     /* Allocate memory for tcp_seg, and fill in fields. */
     seg = memp_malloc(MEMP_TCP_SEG);
     if (seg == NULL) {
-      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, 
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 
                   ("tcp_enqueue: could not allocate memory for tcp_seg\n"));
       goto memerr;
     }
@@ -243,7 +245,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
      * ROM or other static memory, and need not be copied.  */
     if (apiflags & TCP_WRITE_FLAG_COPY) {
       if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen + optlen, PBUF_RAM)) == NULL) {
-        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, 
+        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 
                     ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
         goto memerr;
       }
@@ -259,7 +261,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
     else {
       /* First, allocate a pbuf for the headers. */
       if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
-        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, 
+        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 
                     ("tcp_enqueue: could not allocate memory for header pbuf\n"));
         goto memerr;
       }
@@ -275,7 +277,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
           /* If allocation fails, we have to deallocate the header pbuf as well. */
           pbuf_free(seg->p);
           seg->p = NULL;
-          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, 
+          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 
                       ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));
           goto memerr;
         }
@@ -293,7 +295,8 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
     /* Now that there are more segments queued, we check again if the
     length of the queue exceeds the configured maximum or overflows. */
     if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
-      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
       goto memerr;
     }
 
@@ -301,7 +304,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
 
     /* build TCP header */
     if (pbuf_header(seg->p, TCP_HLEN)) {
-      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
       TCP_STATS_INC(tcp.err);
       goto memerr;
     }
@@ -343,11 +346,13 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
   if (useg != NULL &&
     TCP_TCPLEN(useg) != 0 &&
     !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
-    !(flags & (TCP_SYN | TCP_FIN)) &&
+    (!(flags & (TCP_SYN | TCP_FIN)) || (flags == TCP_FIN)) &&
     /* fit within max seg size */
     (useg->len + queue->len <= pcb->mss) &&
     /* only concatenate segments with the same options */
-    (useg->flags == queue->flags)) {
+    (useg->flags == queue->flags) &&
+    /* segments are consecutive */
+    (ntohl(useg->tcphdr->seqno) + useg->len == ntohl(queue->tcphdr->seqno)) ) {
     /* Remove TCP header from first segment of our to-be-queued list */
     if(pbuf_header(queue->p, -(TCP_HLEN + optlen))) {
       /* Can we cope with this failing?  Just assert for now */
@@ -363,10 +368,16 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
       queuelen--;
       pbuf_free(old_q);
     }
-    LWIP_ASSERT("zero-length pbuf", (queue->p != NULL) && (queue->p->len > 0));
-    pbuf_cat(useg->p, queue->p);
-    useg->len += queue->len;
-    useg->next = queue->next;
+    if (flags & TCP_FIN) {
+      /* the new segment contains only FIN, no data -> put the FIN into the last segment */
+      LWIP_ASSERT("FIN enqueued together with data", queue->p == NULL && queue->len == 0);
+      TCPH_SET_FLAG(useg->tcphdr, TCP_FIN);
+    } else {
+      LWIP_ASSERT("zero-length pbuf", (queue->p != NULL) && (queue->p->len > 0));
+      pbuf_cat(useg->p, queue->p);
+      useg->len += queue->len;
+      useg->next = queue->next;
+    }
 
     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len));
     if (seg == queue) {
@@ -443,6 +454,58 @@ tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
 }
 #endif
 
+/** Send an ACK without data.
+ *
+ * @param pcb Protocol control block for the TCP connection to send the ACK
+ */
+err_t
+tcp_send_empty_ack(struct tcp_pcb *pcb)
+{
+  struct pbuf *p;
+  struct tcp_hdr *tcphdr;
+  u8_t optlen = 0;
+
+#if LWIP_TCP_TIMESTAMPS
+  if (pcb->flags & TF_TIMESTAMP) {
+    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
+  }
+#endif
+  p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, 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 = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt));
+
+  /* NB. MSS option is only sent on SYNs, so ignore it here */
+#if LWIP_TCP_TIMESTAMPS
+  pcb->ts_lastacksent = pcb->rcv_nxt;
+
+  if (pcb->flags & TF_TIMESTAMP) {
+    tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
+  }
+#endif 
+
+#if CHECKSUM_GEN_TCP
+  tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
+        IP_PROTO_TCP, p->tot_len);
+#endif
+#if LWIP_NETIF_HWADDRHINT
+  ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
+      IP_PROTO_TCP, &(pcb->addr_hint));
+#else /* LWIP_NETIF_HWADDRHINT*/
+  ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
+      IP_PROTO_TCP);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+  pbuf_free(p);
+
+  return ERR_OK;
+}
 
 /**
  * Find out what we can send and send it
@@ -454,14 +517,11 @@ tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
 err_t
 tcp_output(struct tcp_pcb *pcb)
 {
-  struct pbuf *p;
-  struct tcp_hdr *tcphdr;
   struct tcp_seg *seg, *useg;
   u32_t wnd, snd_nxt;
 #if TCP_CWND_DEBUG
   s16_t i = 0;
 #endif /* TCP_CWND_DEBUG */
-  u8_t optlen = 0;
 
   /* First, check if we are invoked by the TCP input processing
      code. If so, we do not output anything. Instead, we rely on the
@@ -475,12 +535,6 @@ tcp_output(struct tcp_pcb *pcb)
 
   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.
@@ -490,44 +544,13 @@ tcp_output(struct tcp_pcb *pcb)
   if (pcb->flags & TF_ACK_NOW &&
      (seg == NULL ||
       ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
-#if LWIP_TCP_TIMESTAMPS
-    if (pcb->flags & TF_TIMESTAMP)
-      optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
-#endif
-    p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, 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 = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt));
-
-    /* NB. MSS option is only sent on SYNs, so ignore it here */
-#if LWIP_TCP_TIMESTAMPS
-    pcb->ts_lastacksent = pcb->rcv_nxt;
-
-    if (pcb->flags & TF_TIMESTAMP)
-      tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
-#endif 
-
-#if CHECKSUM_GEN_TCP
-    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
-          IP_PROTO_TCP, p->tot_len);
-#endif
-#if LWIP_NETIF_HWADDRHINT
-    ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-        IP_PROTO_TCP, &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
-    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-        IP_PROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-    pbuf_free(p);
+     return tcp_send_empty_ack(pcb);
+  }
 
-    return ERR_OK;
+  /* useg should point to last segment on unacked queue */
+  useg = pcb->unacked;
+  if (useg != NULL) {
+    for (; useg->next != NULL; useg = useg->next);
   }
 
 #if TCP_OUTPUT_DEBUG
@@ -853,9 +876,50 @@ tcp_rexmit(struct tcp_pcb *pcb)
 
   /* Do the actual retransmission. */
   snmp_inc_tcpretranssegs();
-  tcp_output(pcb);
+  /* No need to call tcp_output: we are always called from tcp_input()
+     and thus tcp_output directly returns. */
+}
+
+
+/**
+ * Handle retransmission after three dupacks received
+ *
+ * @param pcb the tcp_pcb for which to retransmit the first unacked segment
+ */
+void 
+tcp_rexmit_fast(struct tcp_pcb *pcb)
+{
+  if (pcb->unacked != NULL && !(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 half of the minimum of the current
+     * cwnd and the advertised window */
+    if (pcb->cwnd > pcb->snd_wnd)
+      pcb->ssthresh = pcb->snd_wnd / 2;
+    else
+      pcb->ssthresh = pcb->cwnd / 2;
+    
+    /* The minimum value for ssthresh should be 2 MSS */
+    if (pcb->ssthresh < 2*pcb->mss) {
+      LWIP_DEBUGF(TCP_FR_DEBUG, 
+                  ("tcp_receive: The minimum value for ssthresh %"U16_F
+                   " should be min 2 mss %"U16_F"...\n",
+                   pcb->ssthresh, 2*pcb->mss));
+      pcb->ssthresh = 2*pcb->mss;
+    }
+    
+    pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
+    pcb->flags |= TF_INFR;
+  } 
 }
 
+
 /**
  * Send keepalive packets to keep a connection active although
  * no data is sent over it.
@@ -924,6 +988,8 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
   struct pbuf *p;
   struct tcp_hdr *tcphdr;
   struct tcp_seg *seg;
+  u16_t len;
+  u8_t is_fin;
 
   LWIP_DEBUGF(TCP_DEBUG, 
               ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
@@ -944,8 +1010,10 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
   if(seg == NULL)
     return;
 
-  p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM);
-   
+  is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
+  len = is_fin ? TCP_HLEN : TCP_HLEN + 1;
+
+  p = pbuf_alloc(PBUF_IP, len, PBUF_RAM);
   if(p == NULL) {
     LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
     return;
@@ -955,8 +1023,13 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
 
   tcphdr = tcp_output_set_header(pcb, p, 0, seg->tcphdr->seqno);
 
-  /* Copy in one byte from the head of the unacked queue */
-  *((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;
+  if (is_fin) {
+    /* FIN segment, no data */
+    TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
+  } else {
+    /* Data segment, copy in one byte from the head of the unacked queue */
+    *((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;
+  }
 
 #if CHECKSUM_GEN_TCP
   tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,

+ 13 - 12
net/lwip/src/core/udp.c

@@ -241,8 +241,8 @@ udp_input(struct pbuf *p, struct netif *inp)
       if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),
                              (struct ip_addr *)&(iphdr->dest),
                              IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
-        LWIP_DEBUGF(UDP_DEBUG | 2,
-                    ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
+       LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+                   ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
         UDP_STATS_INC(udp.chkerr);
         UDP_STATS_INC(udp.drop);
         snmp_inc_udpinerrors();
@@ -258,7 +258,7 @@ udp_input(struct pbuf *p, struct netif *inp)
         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,
+          LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                       ("udp_input: UDP datagram discarded due to failing checksum\n"));
           UDP_STATS_INC(udp.chkerr);
           UDP_STATS_INC(udp.drop);
@@ -282,7 +282,7 @@ udp_input(struct pbuf *p, struct netif *inp)
       /* callback */
       if (pcb->recv != NULL) {
         /* now the recv function is responsible for freeing p */
-        pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
+        pcb->recv(pcb->recv_arg, pcb, p, &iphdr->src, src);
       } else {
         /* no recv function registered? then we have to free the pbuf! */
         pbuf_free(p);
@@ -362,7 +362,7 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
 {
   struct netif *netif;
 
-  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n"));
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
 
   /* find the outgoing network interface for this packet */
 #if LWIP_IGMP
@@ -373,7 +373,7 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
 
   /* no outgoing network interface could be found? */
   if (netif == NULL) {
-    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
+    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
     UDP_STATS_INC(udp.rterr);
     return ERR_RTE;
   }
@@ -411,17 +411,18 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
 #if IP_SOF_BROADCAST
   /* broadcast filter? */
   if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
-    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
+    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+      ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
     return ERR_VAL;
   }
 #endif /* IP_SOF_BROADCAST */
 
   /* if the PCB is not yet bound to a port, bind it here */
   if (pcb->local_port == 0) {
-    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
+    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("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 | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
+      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
       return err;
     }
   }
@@ -432,7 +433,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
     q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
     /* new header pbuf could not be allocated? */
     if (q == NULL) {
-      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
+      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
       return ERR_MEM;
     }
     /* chain header q in front of given pbuf p */
@@ -580,9 +581,9 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
   struct udp_pcb *ipcb;
   u8_t rebind;
 
-  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = "));
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
   ip_addr_debug_print(UDP_DEBUG, ipaddr);
-  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", port = %"U16_F")\n", port));
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
 
   rebind = 0;
   /* Check for double bind and rebind of the same pcb */

+ 11 - 0
net/lwip/src/include/ipv4/lwip/autoip.h

@@ -52,6 +52,10 @@
 #include "lwip/udp.h"
 #include "netif/etharp.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* AutoIP Timing */
 #define AUTOIP_TMR_INTERVAL      100
 #define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)
@@ -100,6 +104,13 @@ void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);
 /** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */
 void autoip_tmr(void);
 
+/** Handle a possible change in the network configuration */
+void autoip_network_changed(struct netif *netif);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* LWIP_AUTOIP */
 
 #endif /* __LWIP_AUTOIP_H__ */

+ 9 - 10
net/lwip/src/include/ipv4/lwip/icmp.h

@@ -33,9 +33,6 @@
 #define __LWIP_ICMP_H__
 
 #include "lwip/opt.h"
-
-#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
-
 #include "lwip/pbuf.h"
 #include "lwip/ip_addr.h"
 #include "lwip/netif.h"
@@ -70,11 +67,6 @@ enum icmp_te_type {
   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
@@ -103,10 +95,17 @@ PACK_STRUCT_END
 #define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
 #define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
 
+
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
+
+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);
+
+#endif /* LWIP_ICMP */
+
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* LWIP_ICMP */
-
 #endif /* __LWIP_ICMP_H__ */

+ 13 - 2
net/lwip/src/include/ipv4/lwip/ip.h

@@ -153,6 +153,11 @@ PACK_STRUCT_END
 #define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
 #define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
 
+/** The interface that provided the packet for the current callback invocation. */
+extern struct netif *current_netif;
+/** Header of the input packet currently being processed. */
+extern const struct ip_hdr *current_header;
+
 #define ip_init() /* Compatibility define, not init needed. */
 struct netif *ip_route(struct ip_addr *dest);
 err_t ip_input(struct pbuf *p, struct netif *inp);
@@ -170,8 +175,14 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
        u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
        u16_t optlen);
 #endif /* IP_OPTIONS_SEND */
-struct netif *ip_current_netif(void);
-const struct ip_hdr *ip_current_header(void);
+/** Get the interface that received the current packet.
+ * This function must only be called from a receive callback (udp_recv,
+ * raw_recv, tcp_accept). It will return NULL otherwise. */
+#define ip_current_netif()  (current_netif)
+/** Get the IP header of the current packet.
+ * This function must only be called from a receive callback (udp_recv,
+ * raw_recv, tcp_accept). It will return NULL otherwise. */
+#define ip_current_header() (current_header)
 #if IP_DEBUG
 void ip_debug_print(struct pbuf *p);
 #else

+ 5 - 0
net/lwip/src/include/ipv4/lwip/ip_addr.h

@@ -161,6 +161,11 @@ u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
 #define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)
 #define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)
 
+/**
+ * Same as inet_ntoa() but takes a struct ip_addr*
+ */
+#define ip_ntoa(addr)  ((addr != NULL) ? inet_ntoa(*((struct in_addr*)(addr))) : "NULL")
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
net/lwip/src/include/lwip/api_msg.h

@@ -83,7 +83,7 @@ struct api_msg_msg {
       size_t len;
       u8_t apiflags;
     } w;
-    /** used ofr do_recv */
+    /** used for do_recv */
     struct {
       u16_t len;
     } r;

+ 3 - 2
net/lwip/src/include/lwip/debug.h

@@ -35,12 +35,13 @@
 #include "lwip/arch.h"
 
 /** lower two bits indicate debug level
- * - 0 off
+ * - 0 all
  * - 1 warning
  * - 2 serious
  * - 3 severe
  */
-#define LWIP_DBG_LEVEL_OFF     0x00
+#define LWIP_DBG_LEVEL_ALL     0x00
+#define LWIP_DBG_LEVEL_OFF     LWIP_DBG_LEVEL_ALL /* compatibility define only */
 #define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
 #define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
 #define LWIP_DBG_LEVEL_SEVERE  0x03

+ 7 - 7
net/lwip/src/include/lwip/dhcp.h

@@ -24,22 +24,20 @@ extern "C" {
 
 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; 
+  void *options_in; 
   /** ingoing msg options length */
   u16_t options_in_len;
+  /** current DHCP state machine state */
+  u8_t state;
+  /** retries of current request */
+  u8_t tries;
 
   struct pbuf *p_out; /* pbuf of outcoming msg */
   struct dhcp_msg *msg_out; /* outgoing msg */
@@ -124,6 +122,8 @@ err_t dhcp_release(struct netif *netif);
 void dhcp_stop(struct netif *netif);
 /** inform server of our manual IP address */
 void dhcp_inform(struct netif *netif);
+/** Handle a possible change in the network configuration */
+void dhcp_network_changed(struct netif *netif);
 
 /** if enabled, check whether the offered IP address is not in use, using ARP */
 #if DHCP_DOES_ARP_CHECK

+ 1 - 1
net/lwip/src/include/lwip/init.h

@@ -43,7 +43,7 @@ extern "C" {
 /** x.X.x: Minor version of the stack */
 #define LWIP_VERSION_MINOR      3U
 /** x.x.X: Revision of the stack */
-#define LWIP_VERSION_REVISION   1U
+#define LWIP_VERSION_REVISION   2U
 /** For release candidates, this is set to 1..254
   * For official releases, this is set to 255 (LWIP_RC_RELEASE)
   * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */

+ 1 - 4
net/lwip/src/include/lwip/memp.h

@@ -84,8 +84,6 @@ extern const u16_t memp_sizes[MEMP_MAX];
 #include "mem.h"
 
 #define memp_init()
-#define memp_malloc(type)     mem_malloc(memp_sizes[type])
-#define memp_free(type, mem)  mem_free(mem)
 
 #else /* MEMP_MEM_MALLOC */
 
@@ -98,6 +96,7 @@ struct memp_malloc_helper
 #endif /* MEM_USE_POOLS */
 
 void  memp_init(void);
+#endif /* MEMP_MEM_MALLOC */
 
 #if MEMP_OVERFLOW_CHECK
 void *memp_malloc_fn(memp_t type, const char* file, const int line);
@@ -107,8 +106,6 @@ void *memp_malloc(memp_t type);
 #endif
 void  memp_free(memp_t type, void *mem);
 
-#endif /* MEMP_MEM_MALLOC */
-
 #ifdef __cplusplus
 }
 #endif

+ 9 - 0
net/lwip/src/include/lwip/netbuf.h

@@ -34,6 +34,7 @@
 
 #include "lwip/opt.h"
 #include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -43,6 +44,10 @@ struct netbuf {
   struct pbuf *p, *ptr;
   struct ip_addr *addr;
   u16_t port;
+#if LWIP_NETBUF_RECVINFO
+  struct ip_addr *toaddr;
+  u16_t toport;
+#endif /* LWIP_NETBUF_RECVINFO */
 };
 
 /* Network buffer functions: */
@@ -69,6 +74,10 @@ void              netbuf_first    (struct netbuf *buf);
 #define netbuf_len(buf)              ((buf)->p->tot_len)
 #define netbuf_fromaddr(buf)         ((buf)->addr)
 #define netbuf_fromport(buf)         ((buf)->port)
+#if LWIP_NETBUF_RECVINFO
+#define netbuf_destaddr(buf)         ((buf)->toaddr)
+#define netbuf_destport(buf)         ((buf)->toport)
+#endif /* LWIP_NETBUF_RECVINFO */
 
 #ifdef __cplusplus
 }

+ 1 - 1
net/lwip/src/include/lwip/netdb.h

@@ -103,7 +103,7 @@ int lwip_getaddrinfo(const char *nodename,
 #define gethostbyname(name) lwip_gethostbyname(name)
 #define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
        lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
-#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a)
+#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
 #define getaddrinfo(nodname, servname, hints, res) \
        lwip_getaddrinfo(nodname, servname, hints, res)
 #endif /* LWIP_COMPAT_SOCKETS */

+ 2 - 2
net/lwip/src/include/lwip/netif.h

@@ -131,12 +131,12 @@ struct netif {
   /* the hostname for this netif, NULL is a valid value */
   char*  hostname;
 #endif /* LWIP_NETIF_HOSTNAME */
+  /** maximum transfer unit (in bytes) */
+  u16_t mtu;
   /** 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 */

+ 5 - 0
net/lwip/src/include/lwip/netifapi.h

@@ -78,6 +78,11 @@ err_t netifapi_netif_add       ( struct netif *netif,
                                  err_t (* init)(struct netif *netif),
                                  err_t (* input)(struct pbuf *p, struct netif *netif) );
 
+err_t netifapi_netif_set_addr  ( struct netif *netif,
+                                 struct ip_addr *ipaddr,
+                                 struct ip_addr *netmask,
+                                 struct ip_addr *gw );
+
 err_t netifapi_netif_common    ( struct netif *netif,
                                  void  (* voidfunc)(struct netif *netif),
                                  err_t (* errtfunc)(struct netif *netif) );

+ 31 - 11
net/lwip/src/include/lwip/opt.h

@@ -366,6 +366,16 @@
 #define ETHARP_TRUST_IP_MAC             1
 #endif
 
+/**
+ * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header.
+ * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check.
+ * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted.
+ * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted.
+ */
+#ifndef ETHARP_SUPPORT_VLAN
+#define ETHARP_SUPPORT_VLAN             0
+#endif
+
 /*
    --------------------------------
    ---------- IP options ----------
@@ -718,6 +728,13 @@
 #define UDP_TTL                         (IP_DEFAULT_TTL)
 #endif
 
+/**
+ * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf.
+ */
+#ifndef LWIP_NETBUF_RECVINFO
+#define LWIP_NETBUF_RECVINFO            0
+#endif
+
 /*
    ---------------------------------
    ---------- TCP options ----------
@@ -742,7 +759,7 @@
  * (2 * TCP_MSS) for things to work well
  */
 #ifndef TCP_WND
-#define TCP_WND                         2048
+#define TCP_WND                         (4 * TCP_MSS)
 #endif 
 
 /**
@@ -768,14 +785,14 @@
 #endif
 
 /**
- * TCP_MSS: TCP Maximum segment size. (default is 128, a *very*
- * conservative default.)
+ * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,
+ * you might want to increase this.)
  * For the receive side, this MSS is advertised to the remote side
  * when opening a connection. For the transmit size, this MSS sets
  * an upper limit on the MSS advertised by the remote host.
  */
 #ifndef TCP_MSS
-#define TCP_MSS                         128
+#define TCP_MSS                         536
 #endif
 
 /**
@@ -803,7 +820,7 @@
  * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.
  */
 #ifndef TCP_SND_QUEUELEN
-#define TCP_SND_QUEUELEN                (4 * (TCP_SND_BUF/TCP_MSS))
+#define TCP_SND_QUEUELEN                (4 * (TCP_SND_BUF)/(TCP_MSS))
 #endif
 
 /**
@@ -812,7 +829,7 @@
  * TCP snd_buf for select to return writable.
  */
 #ifndef TCP_SNDLOWAT
-#define TCP_SNDLOWAT                    (TCP_SND_BUF/2)
+#define TCP_SNDLOWAT                    ((TCP_SND_BUF)/2)
 #endif
 
 /**
@@ -1322,21 +1339,21 @@
  * MEM_STATS==1: Enable mem.c stats.
  */
 #ifndef MEM_STATS
-#define MEM_STATS                       1
+#define MEM_STATS                       ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0))
 #endif
 
 /**
  * MEMP_STATS==1: Enable memp.c pool stats.
  */
 #ifndef MEMP_STATS
-#define MEMP_STATS                      1
+#define MEMP_STATS                      (MEMP_MEM_MALLOC == 0)
 #endif
 
 /**
  * SYS_STATS==1: Enable system stats (sem and mbox counts, etc).
  */
 #ifndef SYS_STATS
-#define SYS_STATS                       1
+#define SYS_STATS                       (NO_SYS == 0)
 #endif
 
 #else
@@ -1510,9 +1527,12 @@
 #endif
 #define PPP_MINMRU                      128             /* No MRUs below this */
 
-
+#ifndef MAXNAMELEN
 #define MAXNAMELEN                      256     /* max length of hostname or name for auth */
+#endif
+#ifndef MAXSECRETLEN
 #define MAXSECRETLEN                    256     /* max length of password or secret */
+#endif
 
 #endif /* PPP_SUPPORT */
 
@@ -1574,7 +1594,7 @@
  * messages are written.
  */
 #ifndef LWIP_DBG_MIN_LEVEL
-#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_OFF
+#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
 #endif
 
 /**

+ 66 - 6
net/lwip/src/include/lwip/sio.h

@@ -51,27 +51,87 @@ typedef void * sio_fd_t;
    or be implemented in your custom sio.c file. */
 
 #ifndef sio_open
-sio_fd_t sio_open(u8_t);
+/**
+ * Opens a serial device for communication.
+ * 
+ * @param devnum device number
+ * @return handle to serial device if successful, NULL otherwise
+ */
+sio_fd_t sio_open(u8_t devnum);
 #endif
 
 #ifndef sio_send
-void sio_send(u8_t, sio_fd_t);
+/**
+ * Sends a single character to the serial device.
+ * 
+ * @param c character to send
+ * @param fd serial device handle
+ * 
+ * @note This function will block until the character can be sent.
+ */
+void sio_send(u8_t c, sio_fd_t fd);
 #endif
 
 #ifndef sio_recv
-u8_t sio_recv(sio_fd_t);
+/**
+ * Receives a single character from the serial device.
+ * 
+ * @param fd serial device handle
+ * 
+ * @note This function will block until a character is received.
+ */
+u8_t sio_recv(sio_fd_t fd);
 #endif
 
 #ifndef sio_read
-u32_t sio_read(sio_fd_t, u8_t *, u32_t);
+/**
+ * Reads from the serial device.
+ * 
+ * @param fd serial device handle
+ * @param data pointer to data buffer for receiving
+ * @param len maximum length (in bytes) of data to receive
+ * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
+ * 
+ * @note This function will block until data can be received. The blocking
+ * can be cancelled by calling sio_read_abort().
+ */
+u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
+#endif
+
+#ifndef sio_tryread
+/**
+ * Tries to read from the serial device. Same as sio_read but returns
+ * immediately if no data is available and never blocks.
+ * 
+ * @param fd serial device handle
+ * @param data pointer to data buffer for receiving
+ * @param len maximum length (in bytes) of data to receive
+ * @return number of bytes actually received
+ */
+u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len);
 #endif
 
 #ifndef sio_write
-u32_t sio_write(sio_fd_t, u8_t *, u32_t);
+/**
+ * Writes to the serial device.
+ * 
+ * @param fd serial device handle
+ * @param data pointer to data to send
+ * @param len length (in bytes) of data to send
+ * @return number of bytes actually sent
+ * 
+ * @note This function will block until all data can be sent.
+ */
+u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
 #endif
 
 #ifndef sio_read_abort
-void sio_read_abort(sio_fd_t);
+/**
+ * Aborts a blocking sio_read() call.
+ * 
+ * @param fd serial device handle
+ */
+void sio_read_abort(sio_fd_t fd);
 #endif
 
 #ifdef __cplusplus

+ 18 - 10
net/lwip/src/include/lwip/tcp.h

@@ -78,6 +78,9 @@ void             tcp_err     (struct tcp_pcb *pcb,
 
 #define          tcp_mss(pcb)      ((pcb)->mss)
 #define          tcp_sndbuf(pcb)   ((pcb)->snd_buf)
+#define          tcp_nagle_disable(pcb)  ((pcb)->flags |= TF_NODELAY)
+#define          tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY)
+#define          tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0)
 
 #if TCP_LISTEN_BACKLOG
 #define          tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--)
@@ -122,9 +125,11 @@ 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_send_empty_ack(struct tcp_pcb *pcb);
 err_t            tcp_output  (struct tcp_pcb *pcb);
 void             tcp_rexmit  (struct tcp_pcb *pcb);
 void             tcp_rexmit_rto  (struct tcp_pcb *pcb);
+void             tcp_rexmit_fast (struct tcp_pcb *pcb);
 u32_t            tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
 
 /**
@@ -134,9 +139,10 @@ u32_t            tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
  * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or
  * - the only unsent segment is at least pcb->mss bytes long (or there is more
  *   than one unsent segment - with lwIP, this can happen although unsent->len < mss)
+ * - or if we are in fast-retransmit (TF_INFR)
  */
 #define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
-                            ((tpcb)->flags & TF_NODELAY) || \
+                            ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \
                             (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
                               ((tpcb)->unsent->len >= (tpcb)->mss))) \
                             ) ? 1 : 0)
@@ -230,12 +236,11 @@ PACK_STRUCT_END
 
 #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_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & htons((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags))
+#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(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))
+#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0))
 
 enum tcp_state {
   CLOSED      = 0,
@@ -489,9 +494,7 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
     if((pcb)->recv != NULL) {                                   \
       (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \
     } else {                                                    \
-      (ret) = ERR_OK;                                           \
-      if (p != NULL)                                            \
-        pbuf_free(p);                                           \
+      (ret) = tcp_recv_null(NULL, (pcb), (p), (err));           \
     }                                                           \
   } while (0)
 
@@ -585,9 +588,14 @@ void tcp_zero_window_probe(struct tcp_pcb *pcb);
 u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr);
 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
 
+#if LWIP_CALLBACK_API
+err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
+#endif /* LWIP_CALLBACK_API */
+
 extern struct tcp_pcb *tcp_input_pcb;
 extern u32_t tcp_ticks;
 
+const char* tcp_debug_state_str(enum tcp_state s);
 #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);
@@ -651,7 +659,7 @@ extern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */
                             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) { \
+                               if(tcp_tmp_pcb->next == npcb) { \
                                   tcp_tmp_pcb->next = npcb->next; \
                                   break; \
                                } \
@@ -679,7 +687,7 @@ extern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */
       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) {   \
+        if(tcp_tmp_pcb->next == npcb) {   \
           tcp_tmp_pcb->next = npcb->next;          \
           break;                                   \
         }                                          \

+ 3 - 0
net/lwip/src/include/lwip/udp.h

@@ -94,6 +94,9 @@ struct udp_pcb {
    * The callback is responsible for freeing the pbuf
    * if it's not used any more.
    *
+   * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf
+   *            makes 'addr' invalid, too.
+   *
    * @param arg user supplied argument (udp_pcb.recv_arg)
    * @param pcb the udp_pcb which received data
    * @param p the packet buffer that was received

+ 25 - 13
net/lwip/src/include/netif/etharp.h

@@ -85,13 +85,34 @@ PACK_STRUCT_END
 #  include "arch/epstruct.h"
 #endif
 
+#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
+
+#if ETHARP_SUPPORT_VLAN
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct eth_vlan_hdr {
+  PACK_STRUCT_FIELD(u16_t tpid);
+  PACK_STRUCT_FIELD(u16_t prio_vid);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define SIZEOF_VLAN_HDR 4
+#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF)
+
+#endif /* ETHARP_SUPPORT_VLAN */
+
 #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);
@@ -106,24 +127,15 @@ PACK_STRUCT_END
 #  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
+#define SIZEOF_ETHARP_HDR 28
+#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR)
 
 /** 5 seconds period */
 #define ARP_TMR_INTERVAL 5000
 
 #define ETHTYPE_ARP       0x0806
 #define ETHTYPE_IP        0x0800
+#define ETHTYPE_VLAN      0x8100
 #define ETHTYPE_PPPOEDISC 0x8863  /* PPP Over Ethernet Discovery Stage */
 #define ETHTYPE_PPPOE     0x8864  /* PPP Over Ethernet Session Stage */
 

+ 1 - 0
net/lwip/src/include/netif/slipif.h

@@ -41,6 +41,7 @@ extern "C" {
 #endif
 
 err_t slipif_init(struct netif * netif);
+void slipif_poll(struct netif *netif);
 
 #ifdef __cplusplus
 }

+ 7 - 1
net/lwip/src/lwipopts.h

@@ -89,7 +89,13 @@
 #define MEM_LIBC_MALLOC             1
 #define mem_malloc                  rt_malloc
 #define mem_free                    rt_free
-#define mem_calloc                  rt_calloc
+#define mem_calloc                  rt_calloc
+
+#ifdef RT_LWIP_USING_RT_MEM
+#define MEMP_MEM_MALLOC				1
+#else
+#define MEMP_MEM_MALLOC				0
+#endif
 
 /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
    sends a lot of data out of ROM (or other static memory), this

+ 4 - 0
net/lwip/src/netif/FILES

@@ -23,3 +23,7 @@ slipif.c
           protocol. It requires a sio (serial I/O) module to work.
 
 ppp/      Point-to-Point Protocol stack
+          The PPP stack has been ported from ucip (http://ucip.sourceforge.net).
+          It matches quite well to pppd 2.3.1 (http://ppp.samba.org), although
+          compared to that, it has some modifications for embedded systems and
+          the source code has been reordered a bit.

+ 62 - 25
net/lwip/src/netif/etharp.c

@@ -468,7 +468,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
 {
   s8_t i;
   u8_t k;
-  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 3, ("update_arp_entry()\n"));
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry()\n"));
   LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
   LWIP_DEBUGF(ETHARP_DEBUG | LWIP_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), 
@@ -579,13 +579,21 @@ etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,
 void
 etharp_ip_input(struct netif *netif, struct pbuf *p)
 {
-  struct ethip_hdr *hdr;
+  struct eth_hdr *ethhdr;
+  struct ip_hdr *iphdr;
   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
   /* 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;
+  ethhdr = p->payload;
+  iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
+#if ETHARP_SUPPORT_VLAN
+  if (ethhdr->type == ETHTYPE_VLAN) {
+    iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
+  }
+#endif /* ETHARP_SUPPORT_VLAN */
+
   /* source is not on the local network? */
-  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
+  if (!ip_addr_netcmp(&(iphdr->src), &(netif->ip_addr), &(netif->netmask))) {
     /* do nothing */
     return;
   }
@@ -594,7 +602,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
   /* 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);
+  update_arp_entry(netif, &(iphdr->src), &(ethhdr->src), 0);
 }
 
 
@@ -617,6 +625,7 @@ void
 etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
 {
   struct etharp_hdr *hdr;
+  struct eth_hdr *ethhdr;
   /* these are aligned properly, whereas the ARP header fields might not be */
   struct ip_addr sipaddr, dipaddr;
   u8_t i;
@@ -629,24 +638,32 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
   
   /* drop short ARP packets: we have to check for p->len instead of p->tot_len here
      since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
-  if (p->len < sizeof(struct etharp_hdr)) {
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)sizeof(struct etharp_hdr)));
+  if (p->len < SIZEOF_ETHARP_PACKET) {
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+      ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len,
+      (s16_t)SIZEOF_ETHARP_PACKET));
     ETHARP_STATS_INC(etharp.lenerr);
     ETHARP_STATS_INC(etharp.drop);
     pbuf_free(p);
     return;
   }
 
-  hdr = p->payload;
+  ethhdr = p->payload;
+  hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
+#if ETHARP_SUPPORT_VLAN
+  if (ethhdr->type == ETHTYPE_VLAN) {
+    hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
+  }
+#endif /* ETHARP_SUPPORT_VLAN */
 
   /* RFC 826 "Packet Reception": */
   if ((hdr->hwtype != htons(HWTYPE_ETHERNET)) ||
       (hdr->_hwlen_protolen != htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr))) ||
       (hdr->proto != htons(ETHTYPE_IP)) ||
-      (hdr->ethhdr.type != htons(ETHTYPE_ARP)))  {
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1,
+      (ethhdr->type != htons(ETHTYPE_ARP)))  {
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
       ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
-      hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), hdr->ethhdr.type));
+      hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), ethhdr->type));
     ETHARP_STATS_INC(etharp.proterr);
     ETHARP_STATS_INC(etharp.drop);
     pbuf_free(p);
@@ -719,12 +736,12 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
         i--;
         hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
 #if LWIP_AUTOIP
-        hdr->ethhdr.dest.addr[i] = ethdst_hwaddr[i];
+        ethhdr->dest.addr[i] = ethdst_hwaddr[i];
 #else  /* LWIP_AUTOIP */
-        hdr->ethhdr.dest.addr[i] = hdr->shwaddr.addr[i];
+        ethhdr->dest.addr[i] = hdr->shwaddr.addr[i];
 #endif /* LWIP_AUTOIP */
         hdr->shwaddr.addr[i] = ethaddr->addr[i];
-        hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
+        ethhdr->src.addr[i] = ethaddr->addr[i];
       }
 
       /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header
@@ -788,7 +805,8 @@ etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr)
   /* make room for Ethernet header - should not fail */
   if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
     /* bail out */
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("etharp_output: could not allocate room for header.\n"));
     LINK_STATS_INC(link.lenerr);
     return ERR_BUF;
   }
@@ -1034,23 +1052,26 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
   struct pbuf *p;
   err_t result = ERR_OK;
   u8_t k; /* ARP entry index */
+  struct eth_hdr *ethhdr;
   struct etharp_hdr *hdr;
 #if LWIP_AUTOIP
   const u8_t * ethdst_hwaddr;
 #endif /* LWIP_AUTOIP */
 
   /* allocate a pbuf for the outgoing ARP request packet */
-  p = pbuf_alloc(PBUF_RAW, sizeof(struct etharp_hdr), PBUF_RAM);
+  p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);
   /* could allocate a pbuf for an ARP request? */
   if (p == NULL) {
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n"));
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("etharp_raw: could not allocate pbuf for ARP request.\n"));
     ETHARP_STATS_INC(etharp.memerr);
     return ERR_MEM;
   }
   LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",
-              (p->len >= sizeof(struct etharp_hdr)));
+              (p->len >= SIZEOF_ETHARP_PACKET));
 
-  hdr = p->payload;
+  ethhdr = p->payload;
+  hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
   LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));
   hdr->opcode = htons(opcode);
 
@@ -1070,11 +1091,11 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
     hdr->dhwaddr.addr[k] = hwdst_addr->addr[k];
     /* Write the Ethernet MAC-Addresses */
 #if LWIP_AUTOIP
-    hdr->ethhdr.dest.addr[k] = ethdst_hwaddr[k];
+    ethhdr->dest.addr[k] = ethdst_hwaddr[k];
 #else  /* LWIP_AUTOIP */
-    hdr->ethhdr.dest.addr[k] = ethdst_addr->addr[k];
+    ethhdr->dest.addr[k] = ethdst_addr->addr[k];
 #endif /* LWIP_AUTOIP */
-    hdr->ethhdr.src.addr[k]  = ethsrc_addr->addr[k];
+    ethhdr->src.addr[k]  = ethsrc_addr->addr[k];
   }
   hdr->sipaddr = *(struct ip_addr2 *)ipsrc_addr;
   hdr->dipaddr = *(struct ip_addr2 *)ipdst_addr;
@@ -1084,7 +1105,7 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
   /* set hwlen and protolen together */
   hdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr));
 
-  hdr->ethhdr.type = htons(ETHTYPE_ARP);
+  ethhdr->type = htons(ETHTYPE_ARP);
   /* send ARP query */
   result = netif->linkoutput(netif, p);
   ETHARP_STATS_INC(etharp.xmit);
@@ -1126,6 +1147,7 @@ err_t
 ethernet_input(struct pbuf *p, struct netif *netif)
 {
   struct eth_hdr* ethhdr;
+  u16_t type;
 
   /* points to packet payload, which starts with an Ethernet header */
   ethhdr = p->payload;
@@ -1137,7 +1159,22 @@ ethernet_input(struct pbuf *p, struct netif *netif)
      (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5],
      (unsigned)htons(ethhdr->type)));
 
-  switch (htons(ethhdr->type)) {
+  type = htons(ethhdr->type);
+#if ETHARP_SUPPORT_VLAN
+  if (type == ETHTYPE_VLAN) {
+    struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
+#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */
+    if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
+      /* silently ignore this packet: not for our VLAN */
+      pbuf_free(p);
+      return ERR_OK;
+    }
+#endif /* ETHARP_VLAN_CHECK */
+    type = htons(vlan->tpid);
+  }
+#endif /* ETHARP_SUPPORT_VLAN */
+
+  switch (type) {
     /* IP packet? */
     case ETHTYPE_IP:
 #if ETHARP_TRUST_IP_MAC
@@ -1145,7 +1182,7 @@ ethernet_input(struct pbuf *p, struct netif *netif)
       etharp_ip_input(netif, p);
 #endif /* ETHARP_TRUST_IP_MAC */
       /* skip Ethernet header */
-      if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) {
+      if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) {
         LWIP_ASSERT("Can't move over header in packet", 0);
         pbuf_free(p);
         p = NULL;

+ 9 - 17
net/lwip/src/netif/ethernetif.c

@@ -301,26 +301,18 @@ FINSH_FUNCTION_EXPORT(set_dns, set DNS server address);
 
 void list_if()
 {
-	struct ip_addr ip_addr;
-	struct _ip_addr
-	{
-		rt_uint8_t addr0, addr1, addr2, addr3;
-	} *addr;
-
 	rt_kprintf("Default network interface: %c%c\n", netif_default->name[0], netif_default->name[1]);
-	addr = (struct _ip_addr*)&netif_default->ip_addr.addr;
-	rt_kprintf("ip address: %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
-
-	addr = (struct _ip_addr*)&netif_default->gw.addr;
-	rt_kprintf("gw address: %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
-
-	addr = (struct _ip_addr*)&netif_default->netmask.addr;
-	rt_kprintf("net mask  : %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+	rt_kprintf("ip address: %s\n", ip_ntoa(&(netif_default->ip_addr.addr)));
+	rt_kprintf("gw address: %s\n", ip_ntoa(&(netif_default->ip_addr.addr)));
+	rt_kprintf("net mask  : %s\n", ip_ntoa(&(netif_default->ip_addr.addr)));
 
 #if LWIP_DNS
-	ip_addr = dns_getserver(0);
-	addr = (struct _ip_addr*)&ip_addr;
-	rt_kprintf("dns server: %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+	{
+		struct ip_addr ip_addr;
+
+		ip_addr = dns_getserver(0);
+		rt_kprintf("dns server: %d.%d.%d.%d\n", ip_ntoa(&ip_addr));
+	}
 #endif
 }
 FINSH_FUNCTION_EXPORT(list_if, list network interface information);

+ 2 - 0
net/lwip/src/netif/ppp/auth.c

@@ -82,6 +82,8 @@
 #include "cbcp.h"
 #endif /* CBCP_SUPPORT */
 
+#include <string.h>
+
 /*************************/
 /*** LOCAL DEFINITIONS ***/
 /*************************/

+ 1 - 0
net/lwip/src/netif/ppp/chap.c

@@ -82,6 +82,7 @@
 #include "chap.h"
 #include "chpms.h"
 
+#include <string.h>
 
 /*************************/
 /*** LOCAL DEFINITIONS ***/

+ 3 - 0
net/lwip/src/netif/ppp/chpms.c

@@ -1,4 +1,7 @@
 /*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
+/*** The original PPPD code is written in a way to require either the UNIX DES
+     encryption functions encrypt(3) and setkey(3) or the DES library libdes.
+     Since both is not included in lwIP, MSCHAP currently does not work! */
 /*****************************************************************************
 * chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
 *

+ 3 - 1
net/lwip/src/netif/ppp/fsm.c

@@ -64,6 +64,8 @@
 
 #include "fsm.h"
 
+#include <string.h>
+
 
 /*************************/
 /*** LOCAL DEFINITIONS ***/
@@ -551,7 +553,7 @@ fsm_timeout(void *arg)
       break;
 
     default:
-      FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d (%s)!\n",
+      FSMDEBUG((LOG_INFO, "%s: UNHANDLED timeout event in state %d (%s)!\n",
           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
   }
 }

+ 1 - 14
net/lwip/src/netif/ppp/ipcp.c

@@ -183,20 +183,7 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
 /*** 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
+#define inet_ntoa(addr) ip_ntoa(((struct ip_addr*)&(addr)))
 
 /*
  * ipcp_init - Initialize IPCP.

+ 2 - 0
net/lwip/src/netif/ppp/md5.c

@@ -42,6 +42,8 @@
 
 #include "md5.h"
 
+#include <string.h>
+
 /*
  ***********************************************************************
  **  Message-digest routines:                                         **

+ 3 - 0
net/lwip/src/netif/ppp/pap.c

@@ -61,6 +61,8 @@
 #include "auth.h"
 #include "pap.h"
 
+#include <string.h>
+
 /***********************************/
 /*** LOCAL FUNCTION DECLARATIONS ***/
 /***********************************/
@@ -490,6 +492,7 @@ upap_rauthack(upap_state *u, u_char *inp, int id, int len)
   msg = (char *) inp;
   PRINTMSG(msg, msglen);
 
+  UNTIMEOUT(upap_timeout, u);    /* Cancel timeout */
   u->us_clientstate = UPAPCS_OPEN;
 
   auth_withpeer_success(u->us_unit, PPP_PAP);

+ 28 - 38
net/lwip/src/netif/ppp/ppp.c

@@ -166,7 +166,7 @@ typedef struct PPPControl_s {
   ext_accm outACCM;             /* Async-Ctl-Char-Map for output. */
 #if PPPOS_SUPPORT && VJ_SUPPORT
   int  vjEnabled;               /* Flag indicating VJ compression enabled. */
-  struct vjcompress vjComp;     /* Van Jabobsen compression header. */
+  struct vjcompress vjComp;     /* Van Jacobson compression header. */
 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
 
   struct netif netif;
@@ -235,7 +235,7 @@ struct protent *ppp_protocols[] = {
  * 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];  
+u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
 
 
 /*****************************/
@@ -306,13 +306,11 @@ pppMainWakeup(int pd)
 void
 pppLinkTerminated(int pd)
 {
-  PPPControl *pc = &pppControl[pd];
-
   PPPDEBUG((LOG_DEBUG, "pppLinkTerminated: unit %d\n", pd));
 
 #if PPPOE_SUPPORT
-  if(pc->ethif) {
-    pppoe_disconnect(pc->pppoe_sc);
+  if(pppControl[pd].ethif) {
+    pppoe_disconnect(pppControl[pd].pppoe_sc);
   } else
 #endif /* PPPOE_SUPPORT */
   {
@@ -325,13 +323,11 @@ pppLinkTerminated(int pd)
 void
 pppLinkDown(int pd)
 {
-  PPPControl *pc = &pppControl[pd];
-
   PPPDEBUG((LOG_DEBUG, "pppLinkDown: unit %d\n", pd));
 
 #if PPPOE_SUPPORT
-  if(pc->ethif) {
-    pppoe_disconnect(pc->pppoe_sc);
+  if(pppControl[pd].ethif) {
+    pppoe_disconnect(pppControl[pd].pppoe_sc);
   } else
 #endif /* PPPOE_SUPPORT */
   {
@@ -383,7 +379,7 @@ pppHupCB(void *arg)
 
 struct ppp_settings ppp_settings;
 
-err_t
+void
 pppInit(void)
 {
   struct protent *protp;
@@ -395,16 +391,11 @@ pppInit(void)
 
   magicInit();
 
+  subnetMask = htonl(0xffffff00);
+
   for (i = 0; i < NUM_PPP; i++) {
     pppControl[i].openFlag = 0;
 
-    subnetMask = htonl(0xffffff00);
-
-    outpacket_buf[i] = (u_char *)mem_malloc(PPP_MRU+PPP_HDRLEN);
-    if(!outpacket_buf[i]) {
-      return ERR_MEM;
-    }
-
     /*
      * Initialize to the standard option set.
      */
@@ -413,17 +404,9 @@ pppInit(void)
     }
   }
 
-#if LINK_STATS
-  /** @todo already done in stats_init (in fact, zeroed at boot). So, remove it? */
-  /* Clear the statistics. */
-  memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));
-#endif /* LINK_STATS */
-
 #if PPPOE_SUPPORT
   pppoe_init();
 #endif /* PPPOE_SUPPORT */
-
-  return ERR_OK;
 }
 
 void
@@ -601,7 +584,7 @@ int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const cha
     pppControl[pd].openFlag = !0;
   }
 
-  /* Launch a deamon thread. */
+  /* PPP session descriptor found, start PPPoE */
   if (pd >= 0) {
 
     pppControl[pd].openFlag = 1;
@@ -824,9 +807,9 @@ 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];
 #if PPPOS_SUPPORT
+  u_short protocol = PPP_IP;
   u_int fcsOut = PPP_INITFCS;
   struct pbuf *headMB = NULL, *tailMB = NULL, *p;
   u_char c;
@@ -839,7 +822,7 @@ pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
    * 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));
+              pd, PPP_IP, pb));
     LINK_STATS_INC(link.opterr);
     LINK_STATS_INC(link.drop);
     return ERR_ARG;
@@ -1294,7 +1277,7 @@ GetMask(u32_t addr)
  * sifvjcomp - config tcp header compression
  */
 int
-sifvjcomp( int pd, int vjcomp, int cidcomp, int maxcid)
+sifvjcomp(int pd, int vjcomp, int cidcomp, int maxcid)
 {
 #if PPPOS_SUPPORT && VJ_SUPPORT
   PPPControl *pc = &pppControl[pd];
@@ -1304,6 +1287,11 @@ sifvjcomp( int pd, int vjcomp, int cidcomp, int maxcid)
   pc->vjComp.maxSlotIndex = maxcid;
   PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
             vjcomp, cidcomp, maxcid));
+#else /* PPPOS_SUPPORT && VJ_SUPPORT */
+  LWIP_UNUSED_ARG(pd);
+  LWIP_UNUSED_ARG(vjcomp);
+  LWIP_UNUSED_ARG(cidcomp);
+  LWIP_UNUSED_ARG(maxcid);
 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
 
   return 0;
@@ -1381,6 +1369,8 @@ sifdown(int pd)
     PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));
   } else {
     pc->if_up = 0;
+    /* make sure the netif status callback is called */
+    netif_set_down(&pc->netif);
     netif_remove(&pc->netif);
     PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
     if(pc->linkStatusCB) {
@@ -1537,8 +1527,8 @@ pppMain(void *arg)
       if(c > 0) {
         pppInProc(pd, p->payload, c);
       } else {
-        PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
-        sys_msleep(1); /* give other tasks a chance to run */
+        /* nothing received, give other tasks a chance to run */
+        sys_msleep(1);
       }
     }
   }
@@ -1658,7 +1648,7 @@ pppInput(void *arg)
 
   switch(protocol) {
     case PPP_VJC_COMP:      /* VJ compressed TCP */
-#if VJ_SUPPORT
+#if PPPOS_SUPPORT && VJ_SUPPORT
       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
@@ -1670,14 +1660,14 @@ pppInput(void *arg)
       }
       /* Something's wrong so drop it. */
       PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));
-#else  /* VJ_SUPPORT */
+#else  /* PPPOS_SUPPORT && VJ_SUPPORT */
       /* 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 */
+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
       break;
 
     case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */
-#if VJ_SUPPORT
+#if PPPOS_SUPPORT && VJ_SUPPORT
       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
@@ -1689,12 +1679,12 @@ pppInput(void *arg)
       }
       /* Something's wrong so drop it. */
       PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));
-#else  /* VJ_SUPPORT */
+#else  /* PPPOS_SUPPORT && VJ_SUPPORT */
       /* 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 */
+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
       break;
 
     case PPP_IP:            /* Internet Protocol */

+ 2 - 2
net/lwip/src/netif/ppp/ppp.h

@@ -333,7 +333,7 @@ struct ppp_addrs {
 *****************************/
 
 /* Buffers for outgoing packets. */
-extern u_char *outpacket_buf[NUM_PPP];
+extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
 
 extern struct ppp_settings ppp_settings;
 
@@ -345,7 +345,7 @@ extern struct protent *ppp_protocols[]; /* Table of pointers to supported protoc
 ***********************/
 
 /* Initialize the PPP subsystem. */
-err_t pppInit(void);
+void pppInit(void);
 
 /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
  * RFC 1994 says:

+ 3 - 3
net/lwip/src/netif/ppp/ppp_oe.c

@@ -398,7 +398,7 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)
 #endif
   struct pppoehdr *ph;
   struct pppoetag pt;
-  int off = 0, err, errortag;
+  int off, err, errortag;
   struct eth_hdr *ethhdr;
 
   pb = pppSingleBuf(pb);
@@ -410,7 +410,7 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)
     goto done;
   }
   ethhdr = (struct eth_hdr *)pb->payload;
-  off += sizeof(*ethhdr);
+  off = sizeof(*ethhdr);
 
   ac_cookie = NULL;
   ac_cookie_len = 0;
@@ -419,7 +419,7 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)
   hunique_len = 0;
 #endif
   session = 0;
-  if (pb->len - off <= PPPOE_HEADERLEN) {
+  if (pb->len - off < PPPOE_HEADERLEN) {
     printf("pppoe: packet too short: %d\n", pb->len);
     goto done;
   }

+ 1 - 0
net/lwip/src/netif/ppp/randm.c

@@ -41,6 +41,7 @@
 #include "ppp.h"
 #include "pppdebug.h"
 
+#include <string.h>
 
 #if MD5_SUPPORT /* this module depends on MD5 */
 #define RANDPOOLSZ 16   /* Bytes stored in the pool of randomness. */

+ 1 - 1
net/lwip/src/netif/ppp/vj.c

@@ -136,7 +136,7 @@ vj_compress_init(struct vjcompress *comp)
 }
 
 /*
- * vj_compress_tcp - Attempt to do Van Jacobsen header compression on a
+ * vj_compress_tcp - Attempt to do Van Jacobson 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

+ 167 - 79
net/lwip/src/netif/slipif.c

@@ -39,7 +39,7 @@
 
 /* 
  * 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
+ * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send
  */
 
 #include "netif/slipif.h"
@@ -54,12 +54,28 @@
 #include "lwip/snmp.h"
 #include "lwip/sio.h"
 
+#define SLIP_BLOCK     1
+#define SLIP_DONTBLOCK 0
+
 #define SLIP_END     0300 /* 0xC0 */
 #define SLIP_ESC     0333 /* 0xDB */
 #define SLIP_ESC_END 0334 /* 0xDC */
 #define SLIP_ESC_ESC 0335 /* 0xDD */
 
-#define MAX_SIZE     1500
+#define SLIP_MAX_SIZE 1500
+
+enum slipif_recv_state {
+    SLIP_RECV_NORMAL,
+    SLIP_RECV_ESCAPE,
+};
+
+struct slipif_priv {
+  sio_fd_t sd;
+  /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
+  struct pbuf *p, *q;
+  enum slipif_recv_state state;
+  u16_t i, recved;
+};
 
 /**
  * Send a pbuf doing the necessary SLIP encapsulation
@@ -74,6 +90,7 @@
 err_t
 slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
 {
+  struct slipif_priv *priv;
   struct pbuf *q;
   u16_t i;
   u8_t c;
@@ -84,73 +101,101 @@ slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
 
   LWIP_UNUSED_ARG(ipaddr);
 
+  priv = netif->state;
+
   /* Send pbuf out on the serial I/O device. */
-  sio_send(SLIP_END, netif->state);
+  sio_send(SLIP_END, priv->sd);
 
   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);
+        sio_send(SLIP_ESC, priv->sd);
+        sio_send(SLIP_ESC_END, priv->sd);
         break;
       case SLIP_ESC:
-        sio_send(SLIP_ESC, netif->state);
-        sio_send(SLIP_ESC_ESC, netif->state);
+        sio_send(SLIP_ESC, priv->sd);
+        sio_send(SLIP_ESC_ESC, priv->sd);
         break;
       default:
-        sio_send(c, netif->state);
+        sio_send(c, priv->sd);
         break;
       }
     }
   }
-  sio_send(SLIP_END, netif->state);
+  sio_send(SLIP_END, priv->sd);
   return ERR_OK;
 }
 
+/**
+ * Static function for easy use of blockig or non-blocking
+ * sio_read
+ *
+ * @param fd serial device handle
+ * @param data pointer to data buffer for receiving
+ * @param len maximum length (in bytes) of data to receive
+ * @param block if 1, call sio_read; if 0, call sio_tryread
+ * @return return value of sio_read of sio_tryread
+ */
+static u32_t
+slip_sio_read(sio_fd_t fd, u8_t* data, u32_t len, u8_t block)
+{
+  if (block) {
+    return sio_read(fd, data, len);
+  } else {
+    return sio_tryread(fd, data, len);
+  }
+}
+
 /**
  * Handle the incoming SLIP stream character by character
  *
- * Poll the serial layer by calling sio_recv()
+ * Poll the serial layer by calling sio_read() or sio_tryread().
  *
  * @param netif the lwip network interface structure for this slipif
- * @return The IP packet when SLIP_END is received 
+ * @param block if 1, block until data is received; if 0, return when all data
+ *        from the buffer is received (multiple calls to this function will
+ *        return a complete packet, NULL is returned before - used for polling)
+ * @return The IP packet when SLIP_END is received
  */
 static struct pbuf *
-slipif_input(struct netif *netif)
+slipif_input(struct netif *netif, u8_t block)
 {
+  struct slipif_priv *priv;
   u8_t c;
-  /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
-  struct pbuf *p, *q;
-  u16_t recved;
-  u16_t i;
+  struct pbuf *t;
 
   LWIP_ASSERT("netif != NULL", (netif != NULL));
   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
 
-  q = p = NULL;
-  recved = i = 0;
-  c = 0;
+  priv = netif->state;
 
-  while (1) {
-    c = sio_recv(netif->state);
-    switch (c) {
-    case SLIP_END:
-      if (recved > 0) {
-        /* Received whole packet. */
-        /* Trim the pbuf to the size of the received packet. */
-        pbuf_realloc(q, recved);
-        
-        LINK_STATS_INC(link.recv);
-        
-        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
-        return q;
+  while (slip_sio_read(priv->sd, &c, 1, block) > 0) {
+    switch (priv->state) {
+    case SLIP_RECV_NORMAL:
+      switch (c) {
+      case SLIP_END:
+        if (priv->recved > 0) {
+          /* Received whole packet. */
+          /* Trim the pbuf to the size of the received packet. */
+          pbuf_realloc(priv->q, priv->recved);
+
+          LINK_STATS_INC(link.recv);
+
+          LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
+          t = priv->q;
+          priv->p = priv->q = NULL;
+          priv->i = priv->recved = 0;
+          return t;
+        }
+        continue;
+      case SLIP_ESC:
+        priv->state = SLIP_RECV_ESCAPE;
+        continue;
       }
       break;
-
-    case SLIP_ESC:
-      c = sio_recv(netif->state);
+    case SLIP_RECV_ESCAPE:
       switch (c) {
       case SLIP_ESC_END:
         c = SLIP_END;
@@ -159,52 +204,52 @@ slipif_input(struct netif *netif)
         c = SLIP_ESC;
         break;
       }
+      priv->state = SLIP_RECV_NORMAL;
       /* FALLTHROUGH */
+    }
 
-    default:
-      /* byte received, packet not yet completely received */
-      if (p == NULL) {
-        /* allocate a new pbuf */
-        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"));
-          /* don't process any further since we got no pbuf to receive to */
-          break;
-        }
+    /* byte received, packet not yet completely received */
+    if (priv->p == NULL) {
+      /* allocate a new pbuf */
+      LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
+      priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL);
 
-        if (q != NULL) {
-          /* 'chain' the pbuf to the existing chain */
-          pbuf_cat(q, p);
-        } else {
-          /* p is the first pbuf in the chain */
-          q = p;
-        }
+      if (priv->p == NULL) {
+        LINK_STATS_INC(link.drop);
+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
+        /* don't process any further since we got no pbuf to receive to */
+        break;
       }
 
-      /* this automatically drops bytes if > MAX_SIZE */
-      if ((p != NULL) && (recved <= MAX_SIZE)) {
-        ((u8_t *)p->payload)[i] = c;
-        recved++;
-        i++;
-        if (i >= p->len) {
-          /* on to the next pbuf */
-          i = 0;
-          if (p->next != NULL && p->next->len > 0) {
-            /* p is a chain, on to the next in the chain */
-            p = p->next;
-          } else {
-            /* p is a single pbuf, set it to NULL so next time a new
-             * pbuf is allocated */
-            p = NULL;
-          }
+      if (priv->q != NULL) {
+        /* 'chain' the pbuf to the existing chain */
+        pbuf_cat(priv->q, priv->p);
+      } else {
+        /* p is the first pbuf in the chain */
+        priv->q = priv->p;
+      }
+    }
+
+    /* this automatically drops bytes if > SLIP_MAX_SIZE */
+    if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
+      ((u8_t *)priv->p->payload)[priv->i] = c;
+      priv->recved++;
+      priv->i++;
+      if (priv->i >= priv->p->len) {
+        /* on to the next pbuf */
+        priv->i = 0;
+        if (priv->p->next != NULL && priv->p->next->len > 0) {
+          /* p is a chain, on to the next in the chain */
+            priv->p = priv->p->next;
+        } else {
+          /* p is a single pbuf, set it to NULL so next time a new
+           * pbuf is allocated */
+            priv->p = NULL;
         }
       }
-      break;
     }
   }
+
   return NULL;
 }
 
@@ -217,13 +262,13 @@ slipif_input(struct netif *netif)
  * @param nf the lwip network interface structure for this slipif
  */
 static void
-slipif_loop(void *nf)
+slipif_loop_thread(void *nf)
 {
   struct pbuf *p;
   struct netif *netif = (struct netif *)nf;
 
   while (1) {
-    p = slipif_input(netif);
+    p = slipif_input(netif, SLIP_BLOCK);
     if (p != NULL) {
       if (netif->input(p, netif) != ERR_OK) {
         pbuf_free(p);
@@ -242,6 +287,7 @@ slipif_loop(void *nf)
  *
  * @param netif the lwip network interface structure for this slipif
  * @return ERR_OK if serial line could be opened,
+ *         ERR_MEM if no memory could be allocated,
  *         ERR_IF is serial line couldn't be opened
  *
  * @note netif->num must contain the number of the serial port to open
@@ -250,22 +296,39 @@ slipif_loop(void *nf)
 err_t
 slipif_init(struct netif *netif)
 {
+  struct slipif_priv *priv;
 
   LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));
 
+  /* Allocate private data */
+  priv = mem_malloc(sizeof(struct slipif_priv));
+  if (!priv) {
+    return ERR_MEM;
+  }
+
   netif->name[0] = 's';
   netif->name[1] = 'l';
   netif->output = slipif_output;
-  netif->mtu = MAX_SIZE;
-  netif->flags = NETIF_FLAG_POINTTOPOINT;
+  netif->mtu = SLIP_MAX_SIZE;
+  netif->flags |= NETIF_FLAG_POINTTOPOINT;
 
   /* Try to open the serial port (netif->num contains the port number). */
-  netif->state = sio_open(netif->num);
-  if (!netif->state) {
+  priv->sd = sio_open(netif->num);
+  if (!priv->sd) {
     /* Opening the serial port failed. */
+    mem_free(priv);
     return ERR_IF;
   }
 
+  /* Initialize private data */
+  priv->p = NULL;
+  priv->q = NULL;
+  priv->state = SLIP_RECV_NORMAL;
+  priv->i = 0;
+  priv->recved = 0;
+
+  netif->state = priv;
+
   /* initialize the snmp variables and counters inside the struct netif
    * ifSpeed: no assumption can be made without knowing more about the
    * serial line!
@@ -273,7 +336,32 @@ slipif_init(struct netif *netif)
   NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0);
 
   /* Create a thread to poll the serial line. */
-  sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
+  sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
+    SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
   return ERR_OK;
 }
+
+/**
+ * Polls the serial device and feeds the IP layer with incoming packets.
+ *
+ * @param netif The lwip network interface structure for this slipif
+ */
+void
+slipif_poll(struct netif *netif)
+{
+  struct pbuf *p;
+  struct slipif_priv *priv;
+
+  LWIP_ASSERT("netif != NULL", (netif != NULL));
+  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
+
+  priv = netif->state;
+
+  while ((p = slipif_input(netif, SLIP_DONTBLOCK)) != NULL) {
+    if (netif->input(p, netif) != ERR_OK) {
+      pbuf_free(p);
+    }
+  }
+}
+
 #endif /* LWIP_HAVE_SLIPIF */

+ 37 - 0
net/lwip/test/unit/lwip_check.h

@@ -0,0 +1,37 @@
+#ifndef __LWIP_CHECK_H__
+#define __LWIP_CHECK_H__
+
+/* Common header file for lwIP unit tests using the check framework */
+
+#include <config.h>
+#include <check.h>
+#include <stdlib.h>
+
+#define FAIL_RET() do { fail(); return; } while(0)
+#define EXPECT(x) fail_unless(x)
+#define EXPECT_RET(x) do { fail_unless(x); if(!(x)) { return; }} while(0)
+#define EXPECT_RETX(x, y) do { fail_unless(x); if(!(x)) { return y; }} while(0)
+#define EXPECT_RETNULL(x) EXPECT_RETX(x, NULL)
+
+/** typedef for a function returning a test suite */
+typedef Suite* (suite_getter_fn)(void);
+
+/** Create a test suite */
+static Suite* create_suite(const char* name, TFun *tests, size_t num_tests, SFun setup, SFun teardown)
+{
+  size_t i;
+  Suite *s = suite_create(name);
+
+  for(i = 0; i < num_tests; i++) {
+    // Core test case
+    TCase *tc_core = tcase_create("Core");
+    if ((setup != NULL) || (teardown != NULL)) {
+      tcase_add_checked_fixture(tc_core, setup, teardown);
+    }
+    tcase_add_test(tc_core, tests[i]);
+    suite_add_tcase(s, tc_core);
+  }
+  return s;
+}
+
+#endif /* __LWIP_CHECK_H__ */

+ 42 - 0
net/lwip/test/unit/lwip_unittests.c

@@ -0,0 +1,42 @@
+#include "lwip_check.h"
+
+#include "udp/test_udp.h"
+#include "tcp/test_tcp.h"
+#include "tcp/test_tcp_oos.h"
+
+#include "lwip/init.h"
+
+
+int main()
+{
+  int number_failed;
+  SRunner *sr;
+  size_t i;
+  suite_getter_fn* suites[] = {
+    udp_suite,
+    tcp_suite,
+    tcp_oos_suite,
+  };
+  size_t num = sizeof(suites)/sizeof(void*);
+  LWIP_ASSERT("No suites defined", num > 0);
+
+  lwip_init();
+
+  sr = srunner_create((suites[0])());
+  for(i = 1; i < num; i++) {
+    srunner_add_suite(sr, ((suite_getter_fn*)suites[i])());
+  }
+
+#ifdef LWIP_UNITTESTS_NOFORK
+  srunner_set_fork_status(sr, CK_NOFORK);
+#endif
+#ifdef LWIP_UNITTESTS_FORK
+  srunner_set_fork_status(sr, CK_FORK);
+#endif
+
+  srunner_run_all(sr, CK_NORMAL);
+  number_failed = srunner_ntests_failed(sr);
+  srunner_free(sr);
+  return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+

+ 196 - 0
net/lwip/test/unit/tcp/tcp_helper.c

@@ -0,0 +1,196 @@
+#include "tcp_helper.h"
+
+#include "lwip/tcp.h"
+#include "lwip/stats.h"
+#include "lwip/pbuf.h"
+#include "lwip/inet_chksum.h"
+
+#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
+#error "This tests needs TCP- and MEMP-statistics enabled"
+#endif
+
+/** Remove all pcbs on the given list. */
+static void
+tcp_remove(struct tcp_pcb* pcb_list)
+{
+  struct tcp_pcb *pcb = pcb_list;
+  struct tcp_pcb *pcb2;
+
+  while(pcb != NULL) {
+    pcb2 = pcb;
+    pcb = pcb->next;
+    tcp_abort(pcb2);
+  }
+}
+
+/** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */
+void
+tcp_remove_all(void)
+{
+  //tcp_remove(tcp_bound_pcbs);
+  tcp_remove(tcp_listen_pcbs.pcbs);
+  tcp_remove(tcp_active_pcbs);
+  tcp_remove(tcp_tw_pcbs);
+  fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+  fail_unless(lwip_stats.memp[MEMP_TCP_PCB_LISTEN].used == 0);
+  fail_unless(lwip_stats.memp[MEMP_TCP_SEG].used == 0);
+  fail_unless(lwip_stats.memp[MEMP_PBUF_POOL].used == 0);
+}
+
+/** Create a TCP segment usable for passing to tcp_input
+ * - IP-addresses, ports, seqno and ackno are taken from pcb
+ * - seqno and ackno can be altered with an offset
+ */
+struct pbuf*
+tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset,
+                      u32_t ackno_offset, u8_t headerflags)
+{
+  return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
+    data, data_len, pcb->rcv_nxt + seqno_offset, pcb->snd_nxt + ackno_offset, headerflags);
+}
+
+/** Create a TCP segment usable for passing to tcp_input */
+struct pbuf*
+tcp_create_segment(struct ip_addr* src_ip, struct ip_addr* dst_ip,
+                   u16_t src_port, u16_t dst_port, void* data, size_t data_len,
+                   u32_t seqno, u32_t ackno, u8_t headerflags)
+{
+  struct pbuf* p;
+  struct ip_hdr* iphdr;
+  struct tcp_hdr* tcphdr;
+  u16_t pbuf_len = sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len;
+
+  p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
+  EXPECT_RETNULL(p != NULL);
+  EXPECT_RETNULL(p->next == NULL);
+
+  memset(p->payload, 0, p->len);
+
+  iphdr = p->payload;
+  /* fill IP header */
+  iphdr->dest.addr = dst_ip->addr;
+  iphdr->src.addr = src_ip->addr;
+  IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0);
+  IPH_LEN_SET(iphdr, htons(p->tot_len));
+  IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
+
+  pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
+
+  tcphdr = p->payload;
+  tcphdr->src   = htons(src_port);
+  tcphdr->dest  = htons(dst_port);
+  tcphdr->seqno = htonl(seqno);
+  tcphdr->ackno = htonl(ackno);
+  TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
+  TCPH_FLAGS_SET(tcphdr, headerflags);
+  tcphdr->wnd   = htonl(TCP_WND);
+
+  /* copy data */
+  memcpy((char*)tcphdr + sizeof(struct tcp_hdr), data, data_len);
+
+  /* calculate checksum */
+  tcphdr->chksum = inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest),
+          IP_PROTO_TCP, p->tot_len);
+
+  pbuf_header(p, sizeof(struct ip_hdr));
+
+  return p;
+}
+
+/** Safely bring a tcp_pcb into the requested state */
+void
+tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, struct ip_addr* local_ip,
+                   struct ip_addr* remote_ip, u16_t local_port, u16_t remote_port)
+{
+  /* @todo: are these all states? */
+  /* @todo: remove from previous list */
+  pcb->state = state;
+  if (state == ESTABLISHED) {
+    TCP_REG(&tcp_active_pcbs, pcb);
+    pcb->local_ip.addr = local_ip->addr;
+    pcb->local_port = local_port;
+    pcb->remote_ip.addr = remote_ip->addr;
+    pcb->remote_port = remote_port;
+  } else if(state == LISTEN) {
+    TCP_REG(&tcp_listen_pcbs.pcbs, pcb);
+    pcb->local_ip.addr = local_ip->addr;
+    pcb->local_port = local_port;
+  } else if(state == TIME_WAIT) {
+    TCP_REG(&tcp_tw_pcbs, pcb);
+    pcb->local_ip.addr = local_ip->addr;
+    pcb->local_port = local_port;
+    pcb->remote_ip.addr = remote_ip->addr;
+    pcb->remote_port = remote_port;
+  } else {
+    fail();
+  }
+}
+
+void
+test_tcp_counters_err(void* arg, err_t err)
+{
+  struct test_tcp_counters* counters = arg;
+  EXPECT_RET(arg != NULL);
+  counters->err_calls++;
+  counters->last_err = err;
+}
+
+static void
+test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p)
+{
+  struct pbuf* q;
+  u32_t i, received;
+  if(counters->expected_data == NULL) {
+    /* no data to compare */
+    return;
+  }
+  EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len);
+  received = counters->recved_bytes;
+  for(q = p; q != NULL; q = q->next) {
+    char *data = q->payload;
+    for(i = 0; i < q->len; i++) {
+      EXPECT_RET(data[i] == counters->expected_data[received]);
+      received++;
+    }
+  }
+  EXPECT(received == counters->recved_bytes + p->tot_len);
+}
+
+err_t
+test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err)
+{
+  struct test_tcp_counters* counters = arg;
+  EXPECT_RETX(arg != NULL, ERR_OK);
+  EXPECT_RETX(pcb != NULL, ERR_OK);
+  EXPECT_RETX(err == ERR_OK, ERR_OK);
+
+  if (p != NULL) {
+    if (counters->close_calls == 0) {
+      counters->recv_calls++;
+      test_tcp_counters_check_rxdata(counters, p);
+      counters->recved_bytes += p->tot_len;
+    } else {
+      counters->recv_calls_after_close++;
+      counters->recved_bytes_after_close += p->tot_len;
+    }
+    pbuf_free(p);
+  } else {
+    counters->close_calls++;
+  }
+  EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0);
+  return ERR_OK;
+}
+
+/** Allocate a pcb and set up the test_tcp_counters_* callbacks */
+struct tcp_pcb*
+test_tcp_new_counters_pcb(struct test_tcp_counters* counters)
+{
+  struct tcp_pcb* pcb = tcp_new();
+  if (pcb != NULL) {
+    /* set up args and callbacks */
+    tcp_arg(pcb, counters);
+    tcp_recv(pcb, test_tcp_counters_recv);
+    tcp_err(pcb, test_tcp_counters_err);
+  }
+  return pcb;
+}

+ 36 - 0
net/lwip/test/unit/tcp/tcp_helper.h

@@ -0,0 +1,36 @@
+#ifndef __TCP_HELPER_H__
+#define __TCP_HELPER_H__
+
+#include "../lwip_check.h"
+#include "lwip/arch.h"
+#include "lwip/tcp.h"
+
+/* counters used for test_tcp_counters_* callback functions */
+struct test_tcp_counters {
+  u32_t recv_calls;
+  u32_t recved_bytes;
+  u32_t recv_calls_after_close;
+  u32_t recved_bytes_after_close;
+  u32_t close_calls;
+  u32_t err_calls;
+  err_t last_err;
+  char* expected_data;
+  u32_t expected_data_len;
+};
+
+/* Helper functions */
+void tcp_remove_all(void);
+
+struct pbuf* tcp_create_segment(struct ip_addr* src_ip, struct ip_addr* dst_ip,
+                   u16_t src_port, u16_t dst_port, void* data, size_t data_len,
+                   u32_t seqno, u32_t ackno, u8_t headerflags);
+struct pbuf* tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len,
+                   u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags);
+void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, struct ip_addr* local_ip,
+                   struct ip_addr* remote_ip, u16_t local_port, u16_t remote_port);
+void test_tcp_counters_err(void* arg, err_t err);
+err_t test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err);
+
+struct tcp_pcb* test_tcp_new_counters_pcb(struct test_tcp_counters* counters);
+
+#endif

+ 104 - 0
net/lwip/test/unit/tcp/test_tcp.c

@@ -0,0 +1,104 @@
+#include "test_tcp.h"
+
+#include "lwip/tcp.h"
+#include "lwip/stats.h"
+#include "tcp_helper.h"
+
+#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
+#error "This tests needs TCP- and MEMP-statistics enabled"
+#endif
+
+/* Setups/teardown functions */
+
+static void
+tcp_setup(void)
+{
+  tcp_remove_all();
+}
+
+static void
+tcp_teardown(void)
+{
+  tcp_remove_all();
+}
+
+
+/* Test functions */
+
+/** Call tcp_new() and tcp_abort() and test memp stats */
+START_TEST(test_tcp_new_abort)
+{
+  struct tcp_pcb* pcb;
+  LWIP_UNUSED_ARG(_i);
+
+  fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+
+  pcb = tcp_new();
+  fail_unless(pcb != NULL);
+  if (pcb != NULL) {
+    fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
+    tcp_abort(pcb);
+    fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+  }
+}
+END_TEST
+
+/** Create an ESTABLISHED pcb and check if receive callback is called */
+START_TEST(test_tcp_recv_inseq)
+{
+  struct test_tcp_counters counters;
+  struct tcp_pcb* pcb;
+  struct pbuf* p;
+  char data[] = {1, 2, 3, 4};
+  struct ip_addr remote_ip, local_ip;
+  u16_t data_len;
+  u16_t remote_port = 0x100, local_port = 0x101;
+  struct netif netif;
+  LWIP_UNUSED_ARG(_i);
+
+  /* initialize local vars */
+  memset(&netif, 0, sizeof(netif));
+  IP4_ADDR(&local_ip, 192, 168, 1, 1);
+  IP4_ADDR(&remote_ip, 192, 168, 1, 2);
+  data_len = sizeof(data);
+  /* initialize counter struct */
+  memset(&counters, 0, sizeof(counters));
+  counters.expected_data_len = data_len;
+  counters.expected_data = data;
+
+  /* create and initialize the pcb */
+  pcb = test_tcp_new_counters_pcb(&counters);
+  EXPECT_RET(pcb != NULL);
+  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
+
+  /* create a segment */
+  p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);
+  EXPECT(p != NULL);
+  if (p != NULL) {
+    /* pass the segment to tcp_input */
+    tcp_input(p, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 1);
+    EXPECT(counters.recved_bytes == data_len);
+    EXPECT(counters.err_calls == 0);
+  }
+
+  /* make sure the pcb is freed */
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
+  tcp_abort(pcb);
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+}
+END_TEST
+
+
+/** Create the suite including all tests for this module */
+Suite *
+tcp_suite(void)
+{
+  TFun tests[] = {
+    test_tcp_new_abort,
+    test_tcp_recv_inseq,
+  };
+  return create_suite("TCP", tests, sizeof(tests)/sizeof(TFun), tcp_setup, tcp_teardown);
+}

+ 8 - 0
net/lwip/test/unit/tcp/test_tcp.h

@@ -0,0 +1,8 @@
+#ifndef __TEST_TCP_H__
+#define __TEST_TCP_H__
+
+#include "../lwip_check.h"
+
+Suite *tcp_suite(void);
+
+#endif

+ 433 - 0
net/lwip/test/unit/tcp/test_tcp_oos.c

@@ -0,0 +1,433 @@
+#include "test_tcp_oos.h"
+
+#include "lwip/tcp.h"
+#include "lwip/stats.h"
+#include "tcp_helper.h"
+
+#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
+#error "This tests needs TCP- and MEMP-statistics enabled"
+#endif
+#if !TCP_QUEUE_OOSEQ
+#error "This tests needs TCP_QUEUE_OOSEQ enabled"
+#endif
+
+/** CHECK_SEGMENTS_ON_OOSEQ:
+ * 1: check count, seqno and len of segments on pcb->ooseq (strict)
+ * 0: only check that bytes are received in correct order (less strict) */
+#define CHECK_SEGMENTS_ON_OOSEQ 1
+
+#if CHECK_SEGMENTS_ON_OOSEQ
+#define EXPECT_OOSEQ(x) EXPECT(x)
+#else
+#define EXPECT_OOSEQ(x)
+#endif
+
+/* helper functions */
+
+/** Get the numbers of segments on the ooseq list */
+static int tcp_oos_count(struct tcp_pcb* pcb)
+{
+  int num = 0;
+  struct tcp_seg* seg = pcb->ooseq;
+  while(seg != NULL) {
+    num++;
+    seg = seg->next;
+  }
+  return num;
+}
+
+/** Get the seqno of a segment (by index) on the ooseq list
+ *
+ * @param pcb the pcb to check for ooseq segments
+ * @param seg_index index of the segment on the ooseq list
+ * @return seqno of the segment
+ */
+static u32_t
+tcp_oos_seg_seqno(struct tcp_pcb* pcb, int seg_index)
+{
+  int num = 0;
+  struct tcp_seg* seg = pcb->ooseq;
+
+  /* then check the actual segment */
+  while(seg != NULL) {
+    if(num == seg_index) {
+      return seg->tcphdr->seqno;
+    }
+    num++;
+    seg = seg->next;
+  }
+  fail();
+  return 0;
+}
+
+/** Get the tcplen of a segment (by index) on the ooseq list
+ *
+ * @param pcb the pcb to check for ooseq segments
+ * @param seg_index index of the segment on the ooseq list
+ * @return tcplen of the segment
+ */
+static int
+tcp_oos_seg_tcplen(struct tcp_pcb* pcb, int seg_index)
+{
+  int num = 0;
+  struct tcp_seg* seg = pcb->ooseq;
+
+  /* then check the actual segment */
+  while(seg != NULL) {
+    if(num == seg_index) {
+      return TCP_TCPLEN(seg);
+    }
+    num++;
+    seg = seg->next;
+  }
+  fail();
+  return -1;
+}
+
+/* Setup/teardown functions */
+
+static void
+tcp_oos_setup(void)
+{
+  tcp_remove_all();
+}
+
+static void
+tcp_oos_teardown(void)
+{
+  tcp_remove_all();
+}
+
+
+
+/* Test functions */
+
+/** create multiple segments and pass them to tcp_input in a wrong
+ * order to see if ooseq-caching works correctly
+ * FIN is received in out-of-sequence segments only */
+START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ)
+{
+  struct test_tcp_counters counters;
+  struct tcp_pcb* pcb;
+  struct pbuf *p_8_9, *p_4_8, *p_4_10, *p_2_14, *p_fin, *pinseq;
+  char data[] = {
+     1,  2,  3,  4,
+     5,  6,  7,  8,
+     9, 10, 11, 12,
+    13, 14, 15, 16};
+  struct ip_addr remote_ip, local_ip;
+  u16_t data_len;
+  u16_t remote_port = 0x100, local_port = 0x101;
+  struct netif netif;
+  LWIP_UNUSED_ARG(_i);
+
+  /* initialize local vars */
+  memset(&netif, 0, sizeof(netif));
+  IP4_ADDR(&local_ip, 192, 168, 1, 1);
+  IP4_ADDR(&remote_ip, 192, 168, 1, 2);
+  data_len = sizeof(data);
+  /* initialize counter struct */
+  memset(&counters, 0, sizeof(counters));
+  counters.expected_data_len = data_len;
+  counters.expected_data = data;
+
+  /* create and initialize the pcb */
+  pcb = test_tcp_new_counters_pcb(&counters);
+  EXPECT_RET(pcb != NULL);
+  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
+
+  /* create segments */
+  /* pinseq is sent as last segment! */
+  pinseq = tcp_create_rx_segment(pcb, &data[0],  4, 0, 0, TCP_ACK);
+  /* p1: 8 bytes before FIN */
+  /*     seqno: 8..16 */
+  p_8_9  = tcp_create_rx_segment(pcb, &data[8],  8, 8, 0, TCP_ACK|TCP_FIN);
+  /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */
+  /*     seqno: 4..11 */
+  p_4_8  = tcp_create_rx_segment(pcb, &data[4],  8, 4, 0, TCP_ACK);
+  /* p3: same as p2 but 2 bytes longer */
+  /*     seqno: 4..13 */
+  p_4_10 = tcp_create_rx_segment(pcb, &data[4], 10, 4, 0, TCP_ACK);
+  /* p4: 14 bytes before FIN, includes data from p1 and p2, plus partly from pinseq */
+  /*     seqno: 2..15 */
+  p_2_14 = tcp_create_rx_segment(pcb, &data[2], 14, 2, 0, TCP_ACK);
+  /* FIN, seqno 16 */
+  p_fin  = tcp_create_rx_segment(pcb,     NULL,  0,16, 0, TCP_ACK|TCP_FIN);
+  EXPECT(pinseq != NULL);
+  EXPECT(p_8_9 != NULL);
+  EXPECT(p_4_8 != NULL);
+  EXPECT(p_4_10 != NULL);
+  EXPECT(p_2_14 != NULL);
+  EXPECT(p_fin != NULL);
+  if ((pinseq != NULL) && (p_8_9 != NULL) && (p_4_8 != NULL) && (p_4_10 != NULL) && (p_2_14 != NULL) && (p_fin != NULL)) {
+    /* pass the segment to tcp_input */
+    tcp_input(p_8_9, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 8);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 9); /* includes FIN */
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_4_8, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_4_10, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* ooseq queue: unchanged */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_2_14, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 6);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_fin, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* ooseq queue: unchanged */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 6);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
+
+    /* pass the segment to tcp_input */
+    tcp_input(pinseq, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 1);
+    EXPECT(counters.recv_calls == 1);
+    EXPECT(counters.recved_bytes == data_len);
+    EXPECT(counters.err_calls == 0);
+    EXPECT(pcb->ooseq == NULL);
+  }
+
+  /* make sure the pcb is freed */
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
+  tcp_abort(pcb);
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+}
+END_TEST
+
+
+/** create multiple segments and pass them to tcp_input in a wrong
+ * order to see if ooseq-caching works correctly
+ * FIN is received IN-SEQUENCE at the end */
+START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
+{
+  struct test_tcp_counters counters;
+  struct tcp_pcb* pcb;
+  struct pbuf *p_1_2, *p_4_8, *p_3_11, *p_2_12, *p_15_1, *p_15_1a, *pinseq, *pinseqFIN;
+  char data[] = {
+     1,  2,  3,  4,
+     5,  6,  7,  8,
+     9, 10, 11, 12,
+    13, 14, 15, 16};
+  struct ip_addr remote_ip, local_ip;
+  u16_t data_len;
+  u16_t remote_port = 0x100, local_port = 0x101;
+  struct netif netif;
+  LWIP_UNUSED_ARG(_i);
+
+  /* initialize local vars */
+  memset(&netif, 0, sizeof(netif));
+  IP4_ADDR(&local_ip, 192, 168, 1, 1);
+  IP4_ADDR(&remote_ip, 192, 168, 1, 2);
+  data_len = sizeof(data);
+  /* initialize counter struct */
+  memset(&counters, 0, sizeof(counters));
+  counters.expected_data_len = data_len;
+  counters.expected_data = data;
+
+  /* create and initialize the pcb */
+  pcb = test_tcp_new_counters_pcb(&counters);
+  EXPECT_RET(pcb != NULL);
+  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
+
+  /* create segments */
+  /* p1: 7 bytes - 2 before FIN */
+  /*     seqno: 1..2 */
+  p_1_2  = tcp_create_rx_segment(pcb, &data[1],  2, 1, 0, TCP_ACK);
+  /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */
+  /*     seqno: 4..11 */
+  p_4_8  = tcp_create_rx_segment(pcb, &data[4],  8, 4, 0, TCP_ACK);
+  /* p3: same as p2 but 2 bytes longer and one byte more at the front */
+  /*     seqno: 3..13 */
+  p_3_11 = tcp_create_rx_segment(pcb, &data[3], 11, 3, 0, TCP_ACK);
+  /* p4: 13 bytes - 2 before FIN - should be ignored as contained in p1 and p3 */
+  /*     seqno: 2..13 */
+  p_2_12 = tcp_create_rx_segment(pcb, &data[2], 12, 2, 0, TCP_ACK);
+  /* pinseq is the first segment that is held back to create ooseq! */
+  /*     seqno: 0..3 */
+  pinseq = tcp_create_rx_segment(pcb, &data[0],  4, 0, 0, TCP_ACK);
+  /* p5: last byte before FIN */
+  /*     seqno: 15 */
+  p_15_1 = tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK);
+  /* p6: same as p5, should be ignored */
+  p_15_1a= tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK);
+  /* pinseqFIN: last 2 bytes plus FIN */
+  /*     only segment containing seqno 14 and FIN */
+  pinseqFIN = tcp_create_rx_segment(pcb,  &data[14], 2, 14, 0, TCP_ACK|TCP_FIN);
+  EXPECT(pinseq != NULL);
+  EXPECT(p_1_2 != NULL);
+  EXPECT(p_4_8 != NULL);
+  EXPECT(p_3_11 != NULL);
+  EXPECT(p_2_12 != NULL);
+  EXPECT(p_15_1 != NULL);
+  EXPECT(p_15_1a != NULL);
+  EXPECT(pinseqFIN != NULL);
+  if ((pinseq != NULL) && (p_1_2 != NULL) && (p_4_8 != NULL) && (p_3_11 != NULL) && (p_2_12 != NULL)
+    && (p_15_1 != NULL) && (p_15_1a != NULL) && (pinseqFIN != NULL)) {
+    /* pass the segment to tcp_input */
+    tcp_input(p_1_2, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_4_8, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 4);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 8);
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_3_11, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
+    /* p_3_11 has removed p_4_8 from ooseq */
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 3);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 11);
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_2_12, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 3);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 2);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 2) == 3);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 2) == 11);
+
+    /* pass the segment to tcp_input */
+    tcp_input(pinseq, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 1);
+    EXPECT(counters.recved_bytes == 14);
+    EXPECT(counters.err_calls == 0);
+    EXPECT(pcb->ooseq == NULL);
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_15_1, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 1);
+    EXPECT(counters.recved_bytes == 14);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
+
+    /* pass the segment to tcp_input */
+    tcp_input(p_15_1a, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 1);
+    EXPECT(counters.recved_bytes == 14);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue: unchanged */
+    EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
+    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15);
+    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
+
+    /* pass the segment to tcp_input */
+    tcp_input(pinseqFIN, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 1);
+    EXPECT(counters.recv_calls == 2);
+    EXPECT(counters.recved_bytes == data_len);
+    EXPECT(counters.err_calls == 0);
+    EXPECT(pcb->ooseq == NULL);
+  }
+
+  /* make sure the pcb is freed */
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
+  tcp_abort(pcb);
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+}
+END_TEST
+
+/** Create the suite including all tests for this module */
+Suite *
+tcp_oos_suite(void)
+{
+  TFun tests[] = {
+    test_tcp_recv_ooseq_FIN_OOSEQ,
+    test_tcp_recv_ooseq_FIN_INSEQ,
+  };
+  return create_suite("TCP_OOS", tests, sizeof(tests)/sizeof(TFun), tcp_oos_setup, tcp_oos_teardown);
+}

+ 8 - 0
net/lwip/test/unit/tcp/test_tcp_oos.h

@@ -0,0 +1,8 @@
+#ifndef __TEST_TCP_OOS_H__
+#define __TEST_TCP_OOS_H__
+
+#include "../lwip_check.h"
+
+Suite *tcp_oos_suite(void);
+
+#endif

+ 80 - 0
net/lwip/test/unit/udp/test_udp.c

@@ -0,0 +1,80 @@
+#include "test_udp.h"
+
+#include "lwip/udp.h"
+#include "lwip/stats.h"
+
+#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS
+#error "This tests needs UDP- and MEMP-statistics enabled"
+#endif
+
+/* Helper functions */
+static void
+udp_remove_all(void)
+{
+  struct udp_pcb *pcb = udp_pcbs;
+  struct udp_pcb *pcb2;
+
+  while(pcb != NULL) {
+    pcb2 = pcb;
+    pcb = pcb->next;
+    udp_remove(pcb2);
+  }
+  fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0);
+}
+
+/* Setups/teardown functions */
+
+static void
+udp_setup(void)
+{
+  udp_remove_all();
+}
+
+static void
+udp_teardown(void)
+{
+  udp_remove_all();
+}
+
+
+/* Test functions */
+
+START_TEST(test_udp_new_remove)
+{
+  struct udp_pcb* pcb;
+  LWIP_UNUSED_ARG(_i);
+
+  fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0);
+
+  pcb = udp_new();
+  fail_unless(pcb != NULL);
+  if (pcb != NULL) {
+    fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 1);
+    udp_remove(pcb);
+    fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0);
+  }
+}
+END_TEST
+
+START_TEST(test_udp_remove)
+{
+  struct udp_pcb* pcb;
+  LWIP_UNUSED_ARG(_i);
+
+  pcb = NULL;
+  //pcb = udp_new();
+  //fail_unless(pcb != NULL);
+}
+END_TEST
+
+
+/** Create the suite including all tests for this module */
+Suite *
+udp_suite(void)
+{
+  TFun tests[] = {
+    test_udp_new_remove,
+    test_udp_remove
+  };
+  return create_suite("UDP", tests, sizeof(tests)/sizeof(TFun), udp_setup, udp_teardown);
+}

+ 8 - 0
net/lwip/test/unit/udp/test_udp.h

@@ -0,0 +1,8 @@
+#ifndef __TEST_UDP_H__
+#define __TEST_UDP_H__
+
+#include "../lwip_check.h"
+
+Suite* udp_suite(void);
+
+#endif