ccollins476ad closed pull request #939: Upgrade lwIP to 2.0.3
URL: https://github.com/apache/mynewt-core/pull/939
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/net/ip/lwip_base/CHANGELOG b/net/ip/lwip_base/CHANGELOG
index 3a277195c..306217fe5 100644
--- a/net/ip/lwip_base/CHANGELOG
+++ b/net/ip/lwip_base/CHANGELOG
@@ -4,6 +4,22 @@ HISTORY
 
   * [Enter new changes just after this line - do not remove this line]
 
+(STABLE-2.0.3)
+
+  ++ Bugfixes:
+
+  2017-09-11: Simon Goldschmidt
+  * tcp_in.c: fix bug #51937 (leaking tcp_pcbs on passive close with unacked 
data)
+
+  2017-08-02: Abroz Bizjak/Simon Goldschmidt
+  * multiple fixes in IPv4 reassembly (leading to corrupted datagrams received)
+  
+  2017-03-30: Simon Goldschmidt
+  * dhcp.c: return ERR_VAL instead of asserting on offset-out-of-pbuf
+
+  2017-03-23: Dirk Ziegelmeier
+  * dhcp.h: fix bug #50618 (dhcp_remove_struct() macro does not work)
+
 (STABLE-2.0.2)
 
   ++ New features:
@@ -13,6 +29,9 @@ HISTORY
     We now have a #define for a header file name that is #included in every .c
     file that provides hooks.
 
+  2017-02-10: Simon Goldschmidt
+  * tcp_close does not fail on memory error (instead, FIN is sent from tcp_tmr)
+
   ++ Bugfixes:
 
   2017-03-08
diff --git a/net/ip/lwip_base/MYNEWT b/net/ip/lwip_base/MYNEWT
new file mode 100644
index 000000000..d2f798ec3
--- /dev/null
+++ b/net/ip/lwip_base/MYNEWT
@@ -0,0 +1,23 @@
+To upgrade lwIP within the apache-mynewt-core repo:
+
+1. Delete the old version of lwIP.  Remove everything in the `net/ip/lwip_base`
+directory, *except* `MYNEWT` (this file) and `pkg.yml`:
+
+    rm -r * && git checkout MYNEWT pkg.yml
+
+2. Copy the lwIP repo contents into this directory (adjust source directory as
+needed).
+
+    cp -r ~/repos/lwip/* .
+
+3. Move the `src/include` directory to the top-level:
+
+    mv src/include .
+
+4. Delete the Windows-only makefsdata app:
+
+    rm -r src/apps/httpd/makefsdata
+
+5. Delete the pppoe files (not Apache-license-compatible):
+
+    rm include/netif/ppp/pppoe.h src/netif/ppp/pppoe.c 
diff --git a/net/ip/lwip_base/UPGRADING b/net/ip/lwip_base/UPGRADING
index f48f59113..89267aec5 100644
--- a/net/ip/lwip_base/UPGRADING
+++ b/net/ip/lwip_base/UPGRADING
@@ -8,6 +8,14 @@ with newer versions.
 
   * [Enter new changes just after this line - do not remove this line]
 
+(2.0.2)
+
+  ++ Application changes:
+
+  * slipif: The way to pass serial port number has changed. netif->num is not
+    supported any more, netif->state is interpreted as an u8_t port number now
+    (it's not a POINTER to an u8_t any more!)
+
 (2.0.1)
 
   ++ Application changes:
diff --git a/net/ip/lwip_base/doc/NO_SYS_SampleCode.c 
b/net/ip/lwip_base/doc/NO_SYS_SampleCode.c
index f5c6c10b6..f0af6600b 100644
--- a/net/ip/lwip_base/doc/NO_SYS_SampleCode.c
+++ b/net/ip/lwip_base/doc/NO_SYS_SampleCode.c
@@ -1,4 +1,5 @@
-void eth_mac_irq()
+void
+eth_mac_irq()
 {
   /* Service MAC IRQ here */
 
@@ -17,7 +18,8 @@ void eth_mac_irq()
   }
 }
 
-static err_t netif_output(struct netif *netif, struct pbuf *p)
+static err_t 
+netif_output(struct netif *netif, struct pbuf *p)
 {
   LINK_STATS_INC(link.xmit);
 
@@ -38,12 +40,14 @@ static err_t netif_output(struct netif *netif, struct pbuf 
*p)
   return ERR_OK;
 }
 
-static void netif_status_callback(struct netif *netif)
+static void 
+netif_status_callback(struct netif *netif)
 {
   printf("netif status changed %s\n", ip4addr_ntoa(netif_ip4_addr(netif)));
 }
 
-static err_t netif_init(struct netif *netif)
+static err_t 
+netif_init(struct netif *netif)
 {
   netif->linkoutput = netif_output;
   netif->output     = etharp_output;
@@ -58,7 +62,8 @@ static err_t netif_init(struct netif *netif)
   return ERR_OK;
 }
 
-void main(void)
+void 
+main(void)
 {
   struct netif netif;
 
@@ -74,7 +79,7 @@ void main(void)
   netif_set_up(&netif);
   
   /* Start DHCP and HTTPD */
-  dhcp_init();
+  dhcp_start(&netif );
   httpd_init();
 
   while(1) {
diff --git a/net/ip/lwip_base/doc/doxygen/lwip.Doxyfile 
b/net/ip/lwip_base/doc/doxygen/lwip.Doxyfile
index 0e3349a79..95fa363b4 100644
--- a/net/ip/lwip_base/doc/doxygen/lwip.Doxyfile
+++ b/net/ip/lwip_base/doc/doxygen/lwip.Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME           = "lwIP"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = "2.0.2"
+PROJECT_NUMBER         = "2.0.3"
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/net/ip/lwip_base/include/lwip/def.h 
b/net/ip/lwip_base/include/lwip/def.h
index aaa64c77a..82a9d896f 100644
--- a/net/ip/lwip_base/include/lwip/def.h
+++ b/net/ip/lwip_base/include/lwip/def.h
@@ -91,14 +91,6 @@ u32_t lwip_htonl(u32_t x);
 #endif
 #define lwip_ntohl(x) lwip_htonl(x)
 
-/* Provide usual function names as macros for users, but this can be turned 
off */
-#ifndef LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS
-#define htons(x) lwip_htons(x)
-#define ntohs(x) lwip_ntohs(x)
-#define htonl(x) lwip_htonl(x)
-#define ntohl(x) lwip_ntohl(x)
-#endif
-
 /* These macros should be calculated by the preprocessor and are used
    with compile-time constants only (so that there is no little-endian
    overhead at runtime). */
@@ -109,9 +101,16 @@ u32_t lwip_htonl(u32_t x);
                      (((x) & 0x00ff0000UL) >>  8) | \
                      (((x) & 0xff000000UL) >> 24))
 #define PP_NTOHL(x) PP_HTONL(x)
-
 #endif /* BYTE_ORDER == BIG_ENDIAN */
 
+/* Provide usual function names as macros for users, but this can be turned 
off */
+#ifndef LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS
+#define htons(x) lwip_htons(x)
+#define ntohs(x) lwip_ntohs(x)
+#define htonl(x) lwip_htonl(x)
+#define ntohl(x) lwip_ntohl(x)
+#endif
+
 /* Functions that are not available as standard implementations.
  * In cc.h, you can #define these to implementations available on
  * your platform to save some code bytes if you use these functions
diff --git a/net/ip/lwip_base/include/lwip/dhcp.h 
b/net/ip/lwip_base/include/lwip/dhcp.h
index ac1b18e9f..df932afb5 100644
--- a/net/ip/lwip_base/include/lwip/dhcp.h
+++ b/net/ip/lwip_base/include/lwip/dhcp.h
@@ -108,7 +108,7 @@ struct dhcp
 
 void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
 /** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
-#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
+#define dhcp_remove_struct(netif) netif_set_client_data(netif, 
LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL)
 void dhcp_cleanup(struct netif *netif);
 err_t dhcp_start(struct netif *netif);
 err_t dhcp_renew(struct netif *netif);
diff --git a/net/ip/lwip_base/include/lwip/init.h 
b/net/ip/lwip_base/include/lwip/init.h
index 1dd443799..3c234cb58 100644
--- a/net/ip/lwip_base/include/lwip/init.h
+++ b/net/ip/lwip_base/include/lwip/init.h
@@ -54,7 +54,7 @@ extern "C" {
 /** x.X.x: Minor version of the stack */
 #define LWIP_VERSION_MINOR      0
 /** x.x.X: Revision of the stack */
-#define LWIP_VERSION_REVISION   1
+#define LWIP_VERSION_REVISION   3
 /** For release candidates, this is set to 1..254
   * For official releases, this is set to 255 (LWIP_RC_RELEASE)
   * For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */
diff --git a/net/ip/lwip_base/include/lwip/memp.h 
b/net/ip/lwip_base/include/lwip/memp.h
index 68fcd9914..562cd05bf 100644
--- a/net/ip/lwip_base/include/lwip/memp.h
+++ b/net/ip/lwip_base/include/lwip/memp.h
@@ -38,6 +38,8 @@
 #ifndef LWIP_HDR_MEMP_H
 #define LWIP_HDR_MEMP_H
 
+#include "lwip/opt.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/net/ip/lwip_base/include/lwip/stats.h 
b/net/ip/lwip_base/include/lwip/stats.h
index bcda2ace6..5cde4a094 100644
--- a/net/ip/lwip_base/include/lwip/stats.h
+++ b/net/ip/lwip_base/include/lwip/stats.h
@@ -387,9 +387,9 @@ void stats_init(void);
 
 #if MEM_STATS
 #define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y
-#define MEM_STATS_INC(x) STATS_INC(mem.x)
-#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y)
-#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y
+#define MEM_STATS_INC(x) SYS_ARCH_INC(lwip_stats.mem.x, 1)
+#define MEM_STATS_INC_USED(x, y) SYS_ARCH_INC(lwip_stats.mem.x, y)
+#define MEM_STATS_DEC_USED(x, y) SYS_ARCH_DEC(lwip_stats.mem.x, y)
 #define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP")
 #else
 #define MEM_STATS_AVAIL(x, y)
diff --git a/net/ip/lwip_base/src/api/api_msg.c 
b/net/ip/lwip_base/src/api/api_msg.c
index dd99c1e01..5a8dad9bc 100644
--- a/net/ip/lwip_base/src/api/api_msg.c
+++ b/net/ip/lwip_base/src/api/api_msg.c
@@ -177,14 +177,20 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
   conn = (struct netconn *)arg;
+
+  if (conn == NULL) {
+    pbuf_free(p);
+    return;
+  }
+
   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
 
 #if LWIP_SO_RCVBUF
   SYS_ARCH_GET(conn->recv_avail, recv_avail);
-  if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
+  if (!sys_mbox_valid(&conn->recvmbox) ||
       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
 #else  /* LWIP_SO_RCVBUF */
-  if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
+  if (!sys_mbox_valid(&conn->recvmbox)) {
 #endif /* LWIP_SO_RCVBUF */
     pbuf_free(p);
     return;
@@ -471,8 +477,6 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t 
err)
   struct netconn *newconn;
   struct netconn *conn = (struct netconn *)arg;
 
-  LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", 
tcp_debug_state_str(newpcb->state)));
-
   if (conn == NULL) {
     return ERR_VAL;
   }
@@ -490,6 +494,8 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t 
err)
     return ERR_VAL;
   }
 
+  LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", 
tcp_debug_state_str(newpcb->state)));
+
   /* We have to set the callback here even though
    * the new socket is unknown. newconn->socket is marked as -1. */
   newconn = netconn_alloc(conn->type, conn->callback);
diff --git a/net/ip/lwip_base/src/apps/httpd/fsdata.c 
b/net/ip/lwip_base/src/apps/httpd/fsdata.c
index e8583b03b..6170ce632 100644
--- a/net/ip/lwip_base/src/apps/httpd/fsdata.c
+++ b/net/ip/lwip_base/src/apps/httpd/fsdata.c
@@ -6,6 +6,7 @@
 #define file_NULL (struct fsdata_file *) NULL
 
 
+static const unsigned int dummy_align__img_sics_gif = 0;
 static const unsigned char data__img_sics_gif[] = {
 /* /img/sics.gif (14 chars) */
 
0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00,
@@ -74,6 +75,7 @@ static const unsigned char data__img_sics_gif[] = {
 
0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10,
 0x41,0x00,0x00,0x3b,};
 
+static const unsigned int dummy_align__404_html = 1;
 static const unsigned char data__404_html[] = {
 /* /404.html (10 chars) */
 0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00,
@@ -132,6 +134,7 @@ static const unsigned char data__404_html[] = {
 
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
 0x6d,0x6c,0x3e,0x0d,0x0a,};
 
+static const unsigned int dummy_align__index_html = 2;
 static const unsigned char data__index_html[] = {
 /* /index.html (12 chars) */
 0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00,
diff --git a/net/ip/lwip_base/src/apps/mqtt/mqtt.c 
b/net/ip/lwip_base/src/apps/mqtt/mqtt.c
index a0e77b971..899e2cbff 100644
--- a/net/ip/lwip_base/src/apps/mqtt/mqtt.c
+++ b/net/ip/lwip_base/src/apps/mqtt/mqtt.c
@@ -360,8 +360,9 @@ mqtt_take_request(struct mqtt_request_t **tail, u16_t 
pkt_id)
 static void
 mqtt_request_time_elapsed(struct mqtt_request_t **tail, u8_t t)
 {
-  struct mqtt_request_t *r = *tail;
+  struct mqtt_request_t *r;
   LWIP_ASSERT("mqtt_request_time_elapsed: tail != NULL", tail != NULL);
+  r = *tail;
   while (t > 0 && r != NULL) {
     if (t >= r->timeout_diff) {
       t -= (u8_t)r->timeout_diff;
diff --git a/net/ip/lwip_base/src/core/init.c b/net/ip/lwip_base/src/core/init.c
index 313146133..ea3b5ebeb 100644
--- a/net/ip/lwip_base/src/core/init.c
+++ b/net/ip/lwip_base/src/core/init.c
@@ -337,7 +337,7 @@ void
 lwip_init(void)
 {
 #ifndef LWIP_SKIP_CONST_CHECK
-  int a;
+  int a = 0;
   LWIP_UNUSED_ARG(a);
   LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP 
port.", LWIP_CONST_CAST(void*, &a) == &a);
 #endif
diff --git a/net/ip/lwip_base/src/core/ipv4/dhcp.c 
b/net/ip/lwip_base/src/core/ipv4/dhcp.c
index dd3547102..0cf97b034 100644
--- a/net/ip/lwip_base/src/core/ipv4/dhcp.c
+++ b/net/ip/lwip_base/src/core/ipv4/dhcp.c
@@ -736,7 +736,7 @@ dhcp_start(struct netif *netif)
 
   /* no DHCP client attached yet? */
   if (dhcp == NULL) {
-    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP 
client\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): mallocing new 
DHCP client\n"));
     dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
     if (dhcp == NULL) {
       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not 
allocate dhcp\n"));
@@ -1500,7 +1500,7 @@ dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p)
   offset_max = options_idx_max;
   options = (u8_t*)q->payload;
   /* at least 1 byte to read and no end marker, then at least 3 bytes to read? 
*/
-  while ((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < 
offset_max)) {
+  while ((q != NULL) && (offset < offset_max) && (options[offset] != 
DHCP_OPTION_END)) {
     u8_t op = options[offset];
     u8_t len;
     u8_t decode_len = 0;
@@ -1617,7 +1617,7 @@ dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p)
       offset_max -= q->len;
       if ((offset < offset_max) && offset_max) {
         q = q->next;
-        LWIP_ASSERT("next pbuf was null", q);
+        LWIP_ERROR("next pbuf was null", q != NULL, return ERR_VAL;);
         options = (u8_t*)q->payload;
       } else {
         /* We've run out of bytes, probably no end marker. Don't proceed. */
@@ -1832,7 +1832,7 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, 
u8_t message_type)
            (dhcp->p_out->len >= sizeof(struct dhcp_msg)));
 
   /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */
-  if (message_type != DHCP_REQUEST) {
+  if ((message_type != DHCP_REQUEST) || (dhcp->state == DHCP_STATE_REBOOTING)) 
{
     /* reuse transaction identifier in retransmissions */
     if (dhcp->tries == 0) {
 #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
@@ -1942,7 +1942,8 @@ dhcp_supplied_address(const struct netif *netif)
 {
   if ((netif != NULL) && (netif_dhcp_data(netif) != NULL)) {
     struct dhcp* dhcp = netif_dhcp_data(netif);
-    return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == 
DHCP_STATE_RENEWING);
+    return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == 
DHCP_STATE_RENEWING) ||
+           (dhcp->state == DHCP_STATE_REBINDING);
   }
   return 0;
 }
diff --git a/net/ip/lwip_base/src/core/ipv4/ip4_frag.c 
b/net/ip/lwip_base/src/core/ipv4/ip4_frag.c
index 57fb44cbb..fdb20886c 100644
--- a/net/ip/lwip_base/src/core/ipv4/ip4_frag.c
+++ b/net/ip/lwip_base/src/core/ipv4/ip4_frag.c
@@ -79,6 +79,10 @@
 
 #define IP_REASS_FLAG_LASTFRAG 0x01
 
+#define IP_REASS_VALIDATE_TELEGRAM_FINISHED  1
+#define IP_REASS_VALIDATE_PBUF_QUEUED        0
+#define IP_REASS_VALIDATE_PBUF_DROPPED       -1
+
 /** This is a helper struct which holds the starting
  * offset and the ending offset of this fragment to
  * easily chain the fragments.
@@ -333,10 +337,11 @@ ip_reass_dequeue_datagram(struct ip_reassdata *ipr, 
struct ip_reassdata *prev)
  * fragment was received at least once).
  * @param ipr points to the reassembly state
  * @param new_p points to the pbuf for the current fragment
- * @return 0 if invalid, >0 otherwise
+ * @param is_last is 1 if this pbuf has MF==0 (ipr->flags not updated yet)
+ * @return see IP_REASS_VALIDATE_* defines
  */
 static int
-ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, 
struct pbuf *new_p)
+ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, 
struct pbuf *new_p, int is_last)
 {
   struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
   struct pbuf *q;
@@ -375,7 +380,18 @@ ip_reass_chain_frag_into_datagram_and_validate(struct 
ip_reassdata *ipr, struct
         }
 #endif /* IP_REASS_CHECK_OVERLAP */
         iprh_prev->next_pbuf = new_p;
+        if (iprh_prev->end != iprh->start) {
+          /* There is a fragment missing between the current
+           * and the previous fragment */
+          valid = 0;
+        }
       } else {
+#if IP_REASS_CHECK_OVERLAP
+        if (iprh->end > iprh_tmp->start) {
+          /* fragment overlaps with following, throw away */
+          goto freepbuf;
+        }
+#endif /* IP_REASS_CHECK_OVERLAP */
         /* fragment with the lowest offset */
         ipr->p = new_p;
       }
@@ -426,7 +442,7 @@ ip_reass_chain_frag_into_datagram_and_validate(struct 
ip_reassdata *ipr, struct
 
   /* At this point, the validation part begins: */
   /* If we already received the last fragment */
-  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
+  if (is_last || ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0)) {
     /* and had no holes so far */
     if (valid) {
       /* then check if the rest of the fragments is here */
@@ -454,23 +470,21 @@ ip_reass_chain_frag_into_datagram_and_validate(struct 
ip_reassdata *ipr, struct
             ((struct ip_reass_helper*)ipr->p->payload) != iprh);
           LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
             iprh->next_pbuf == NULL);
-          LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
-            iprh->end == ipr->datagram_len);
         }
       }
     }
     /* If valid is 0 here, there are some fragments missing in the middle
      * (since MF == 0 has already arrived). Such datagrams simply time out if
      * no more fragments are received... */
-    return valid;
+    return valid ? IP_REASS_VALIDATE_TELEGRAM_FINISHED : 
IP_REASS_VALIDATE_PBUF_QUEUED;
   }
   /* If we come here, not all fragments were received, yet! */
-  return 0; /* not yet valid! */
+  return IP_REASS_VALIDATE_PBUF_QUEUED; /* not yet valid! */
 #if IP_REASS_CHECK_OVERLAP
 freepbuf:
   ip_reass_pbufcount -= pbuf_clen(new_p);
   pbuf_free(new_p);
-  return 0;
+  return IP_REASS_VALIDATE_PBUF_DROPPED;
 #endif /* IP_REASS_CHECK_OVERLAP */
 }
 
@@ -488,6 +502,8 @@ ip4_reass(struct pbuf *p)
   struct ip_reassdata *ipr;
   struct ip_reass_helper *iprh;
   u16_t offset, len, clen;
+  int valid;
+  int is_last;
 
   IPFRAG_STATS_INC(ip_frag.recv);
   MIB2_STATS_INC(mib2.ipreasmreqds);
@@ -552,24 +568,41 @@ ip4_reass(struct pbuf *p)
       SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
     }
   }
-  /* Track the current number of pbufs current 'in-flight', in order to limit
-  the number of fragments that may be enqueued at any one time */
-  ip_reass_pbufcount += clen;
 
   /* At this point, we have either created a new entry or pointing
    * to an existing one */
 
   /* check for 'no more fragments', and update queue entry*/
-  if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
+  is_last = (IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0;
+  if (is_last) {
+    u16_t datagram_len = (u16_t)(offset + len);
+    if ((datagram_len < offset) || (datagram_len > (0xFFFF - IP_HLEN))) {
+      /* u16_t overflow, cannot handle this */
+      goto nullreturn;
+    }
+  }
+  /* find the right place to insert this pbuf */
+  /* @todo: trim pbufs if fragments are overlapping */
+  valid = ip_reass_chain_frag_into_datagram_and_validate(ipr, p, is_last);
+  if (valid == IP_REASS_VALIDATE_PBUF_DROPPED) {
+    goto nullreturn;
+  }
+  /* if we come here, the pbuf has been enqueued */
+
+  /* Track the current number of pbufs current 'in-flight', in order to limit
+     the number of fragments that may be enqueued at any one time
+     (overflow checked by testing against IP_REASS_MAX_PBUFS) */
+  ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount + clen);
+  if (is_last) {
+    u16_t datagram_len = (u16_t)(offset + len);
+    ipr->datagram_len = datagram_len;
     ipr->flags |= IP_REASS_FLAG_LASTFRAG;
-    ipr->datagram_len = offset + len;
     LWIP_DEBUGF(IP_REASS_DEBUG,
      ("ip4_reass: last fragment seen, total len %"S16_F"\n",
       ipr->datagram_len));
   }
-  /* find the right place to insert this pbuf */
-  /* @todo: trim pbufs if fragments are overlapping */
-  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
+
+  if (valid == IP_REASS_VALIDATE_TELEGRAM_FINISHED) {
     struct ip_reassdata *ipr_prev;
     /* the totally last fragment (flag more fragments = 0) was received at 
least
      * once AND all fragments are received */
diff --git a/net/ip/lwip_base/src/core/netif.c 
b/net/ip/lwip_base/src/core/netif.c
index 428b14842..644465467 100644
--- a/net/ip/lwip_base/src/core/netif.c
+++ b/net/ip/lwip_base/src/core/netif.c
@@ -849,7 +849,9 @@ netif_loop_output(struct netif *netif, struct pbuf *p)
      netif_poll(). */
 
   /* let last point to the last pbuf in chain r */
-  for (last = r; last->next != NULL; last = last->next);
+  for (last = r; last->next != NULL; last = last->next) {
+    /* nothing to do here, just get to the last pbuf */
+  }
 
   SYS_ARCH_PROTECT(lev);
   if (netif->loop_first != NULL) {
diff --git a/net/ip/lwip_base/src/core/tcp.c b/net/ip/lwip_base/src/core/tcp.c
index ec2e1f92c..b5144d2f1 100644
--- a/net/ip/lwip_base/src/core/tcp.c
+++ b/net/ip/lwip_base/src/core/tcp.c
@@ -358,7 +358,6 @@ tcp_close_shutdown_fin(struct tcp_pcb *pcb)
   default:
     /* Has already been closed, do nothing. */
     return ERR_OK;
-    break;
   }
 
   if (err == ERR_OK) {
@@ -371,6 +370,12 @@ tcp_close_shutdown_fin(struct tcp_pcb *pcb)
   } else if (err == ERR_MEM) {
     /* Mark this pcb for closing. Closing is retried from tcp_tmr. */
     pcb->flags |= TF_CLOSEPEND;
+    /* We have to return ERR_OK from here to indicate to the callers that this
+       pcb should not be used any more as it will be freed soon via tcp_tmr.
+       This is OK here since sending FIN does not guarantee a time frime for
+       actually freeing the pcb, either (it is left in closure states for
+       remote ACK or timeout) */
+    return ERR_OK;
   }
   return err;
 }
@@ -408,8 +413,8 @@ tcp_close(struct tcp_pcb *pcb)
  * @ingroup tcp_raw
  * Causes all or part of a full-duplex connection of this PCB to be shut down.
  * This doesn't deallocate the PCB unless shutting down both sides!
- * Shutting down both sides is the same as calling tcp_close, so if it succeds,
- * the PCB should not be referenced any more.
+ * Shutting down both sides is the same as calling tcp_close, so if it succeds
+ * (i.e. returns ER_OK), the PCB must not be referenced any more!
  *
  * @param pcb PCB to shutdown
  * @param shut_rx shut down receive side if this is != 0
diff --git a/net/ip/lwip_base/src/core/tcp_in.c 
b/net/ip/lwip_base/src/core/tcp_in.c
index ba879284f..5e839ff62 100644
--- a/net/ip/lwip_base/src/core/tcp_in.c
+++ b/net/ip/lwip_base/src/core/tcp_in.c
@@ -89,6 +89,8 @@ static void tcp_parseopt(struct tcp_pcb *pcb);
 static void tcp_listen_input(struct tcp_pcb_listen *pcb);
 static void tcp_timewait_input(struct tcp_pcb *pcb);
 
+static int tcp_input_delayed_close(struct tcp_pcb *pcb);
+
 /**
  * The initial input processing of TCP. It verifies the TCP header, 
demultiplexes
  * the segment between the PCBs and passes it on to tcp_process(), which 
implements
@@ -404,17 +406,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
           }
           recv_acked = 0;
         }
-        if (recv_flags & TF_CLOSED) {
-          /* The connection has been closed and we will deallocate the
-             PCB. */
-          if (!(pcb->flags & TF_RXCLOSED)) {
-            /* Connection closed although the application has only shut down 
the
-               tx side: call the PCB's err callback and indicate the closure to
-               ensure the application doesn't continue using the PCB. */
-            TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_CLSD);
-          }
-          tcp_pcb_remove(&tcp_active_pcbs, pcb);
-          memp_free(MEMP_TCP_PCB, pcb);
+        if (tcp_input_delayed_close(pcb)) {
           goto aborted;
         }
 #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
@@ -488,6 +480,9 @@ tcp_input(struct pbuf *p, struct netif *inp)
         }
 
         tcp_input_pcb = NULL;
+        if (tcp_input_delayed_close(pcb)) {
+          goto aborted;
+        }
         /* Try to send something out. */
         tcp_output(pcb);
 #if TCP_INPUT_DEBUG
@@ -532,6 +527,30 @@ tcp_input(struct pbuf *p, struct netif *inp)
   pbuf_free(p);
 }
 
+/** Called from tcp_input to check for TF_CLOSED flag. This results in closing
+ * and deallocating a pcb at the correct place to ensure noone references it
+ * any more.
+ * @returns 1 if the pcb has been closed and deallocated, 0 otherwise
+ */
+static int
+tcp_input_delayed_close(struct tcp_pcb *pcb)
+{
+  if (recv_flags & TF_CLOSED) {
+    /* The connection has been closed and we will deallocate the
+        PCB. */
+    if (!(pcb->flags & TF_RXCLOSED)) {
+      /* Connection closed although the application has only shut down the
+          tx side: call the PCB's err callback and indicate the closure to
+          ensure the application doesn't continue using the PCB. */
+      TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_CLSD);
+    }
+    tcp_pcb_remove(&tcp_active_pcbs, pcb);
+    memp_free(MEMP_TCP_PCB, pcb);
+    return 1;
+  }
+  return 0;
+}
+
 /**
  * Called by tcp_input() when a segment arrives for a listening
  * connection (from tcp_input()).
@@ -1749,11 +1768,11 @@ tcp_parseopt(struct tcp_pcb *pcb)
           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
           return;
         }
+        /* An WND_SCALE option with the right option length. */
+        data = tcp_getoptbyte();
         /* If syn was received with wnd scale option,
            activate wnd scale opt, but only if this is not a retransmission */
         if ((flags & TCP_SYN) && !(pcb->flags & TF_WND_SCALE)) {
-          /* An WND_SCALE option with the right option length. */
-          data = tcp_getoptbyte();
           pcb->snd_scale = data;
           if (pcb->snd_scale > 14U) {
             pcb->snd_scale = 14U;
diff --git a/net/ip/lwip_base/src/core/timeouts.c 
b/net/ip/lwip_base/src/core/timeouts.c
index 227d71fc9..8bf209a50 100644
--- a/net/ip/lwip_base/src/core/timeouts.c
+++ b/net/ip/lwip_base/src/core/timeouts.c
@@ -176,7 +176,7 @@ void sys_timeouts_init(void)
 {
   size_t i;
   /* tcp_tmr() at index 0 is started on demand */
-  for (i = 1; i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) {
+  for (i = (LWIP_TCP ? 1 : 0); i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) {
     /* we have to cast via size_t to get rid of const warning
       (this is OK as cyclic_timer() casts back to const* */
     sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, 
LWIP_CONST_CAST(void*, &lwip_cyclic_timers[i]));
diff --git a/net/ip/lwip_base/test/unit/ip4/test_ip4.c 
b/net/ip/lwip_base/test/unit/ip4/test_ip4.c
new file mode 100644
index 000000000..e0e82d8d5
--- /dev/null
+++ b/net/ip/lwip_base/test/unit/ip4/test_ip4.c
@@ -0,0 +1,154 @@
+#include "test_ip4.h"
+
+#include "lwip/ip4.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/stats.h"
+#include "lwip/prot/ip.h"
+#include "lwip/prot/ip4.h"
+
+#if !LWIP_IPV4 || !IP_REASSEMBLY || !MIB2_STATS || !IPFRAG_STATS
+#error "This tests needs LWIP_IPV4, IP_REASSEMBLY; MIB2- and IPFRAG-statistics 
enabled"
+#endif
+
+/* Helper functions */
+static void
+create_ip4_input_fragment(u16_t ip_id, u16_t start, u16_t len, int last)
+{
+  struct pbuf *p;
+  struct netif *input_netif = netif_list; /* just use any netif */
+  fail_unless((start & 7) == 0);
+  fail_unless(((len & 7) == 0) || last);
+  fail_unless(input_netif != NULL);
+
+  p = pbuf_alloc(PBUF_RAW, len + sizeof(struct ip_hdr), PBUF_RAM);
+  fail_unless(p != NULL);
+  if (p != NULL) {
+    err_t err;
+    struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
+    IPH_VHL_SET(iphdr, 4, sizeof(struct ip_hdr) / 4);
+    IPH_TOS_SET(iphdr, 0);
+    IPH_LEN_SET(iphdr, lwip_htons(p->tot_len));
+    IPH_ID_SET(iphdr, lwip_htons(ip_id));
+    if (last) {
+      IPH_OFFSET_SET(iphdr, lwip_htons(start / 8));
+    } else {
+      IPH_OFFSET_SET(iphdr, lwip_htons((start / 8) | IP_MF));
+    }
+    IPH_TTL_SET(iphdr, 5);
+    IPH_PROTO_SET(iphdr, IP_PROTO_UDP);
+    IPH_CHKSUM_SET(iphdr, 0);
+    ip4_addr_copy(iphdr->src, *netif_ip4_addr(input_netif));
+    iphdr->src.addr = lwip_htonl(lwip_htonl(iphdr->src.addr) + 1);
+    ip4_addr_copy(iphdr->dest, *netif_ip4_addr(input_netif));
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, sizeof(struct ip_hdr)));
+
+    err = ip4_input(p, input_netif);
+    if (err != ERR_OK) {
+      pbuf_free(p);
+    }
+    fail_unless(err == ERR_OK);
+  }
+}
+
+/* Setups/teardown functions */
+
+static void
+ip4_setup(void)
+{
+}
+
+static void
+ip4_teardown(void)
+{
+  if (netif_list->loop_first != NULL) {
+    pbuf_free(netif_list->loop_first);
+    netif_list->loop_first = NULL;
+  }
+  netif_list->loop_last = NULL;
+}
+
+
+/* Test functions */
+
+START_TEST(test_ip4_reass)
+{
+  const u16_t ip_id = 128;
+  LWIP_UNUSED_ARG(_i);
+
+  memset(&lwip_stats.mib2, 0, sizeof(lwip_stats.mib2));
+
+  create_ip4_input_fragment(ip_id, 8*200, 200, 1);
+  fail_unless(lwip_stats.ip_frag.recv == 1);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 0);
+
+  create_ip4_input_fragment(ip_id, 0*200, 200, 0);
+  fail_unless(lwip_stats.ip_frag.recv == 2);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 0);
+
+  create_ip4_input_fragment(ip_id, 1*200, 200, 0);
+  fail_unless(lwip_stats.ip_frag.recv == 3);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 0);
+
+  create_ip4_input_fragment(ip_id, 2*200, 200, 0);
+  fail_unless(lwip_stats.ip_frag.recv == 4);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 0);
+
+  create_ip4_input_fragment(ip_id, 3*200, 200, 0);
+  fail_unless(lwip_stats.ip_frag.recv == 5);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 0);
+
+  create_ip4_input_fragment(ip_id, 4*200, 200, 0);
+  fail_unless(lwip_stats.ip_frag.recv == 6);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 0);
+
+  create_ip4_input_fragment(ip_id, 7*200, 200, 0);
+  fail_unless(lwip_stats.ip_frag.recv == 7);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 0);
+
+  create_ip4_input_fragment(ip_id, 6*200, 200, 0);
+  fail_unless(lwip_stats.ip_frag.recv == 8);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 0);
+
+  create_ip4_input_fragment(ip_id, 5*200, 200, 0);
+  fail_unless(lwip_stats.ip_frag.recv == 9);
+  fail_unless(lwip_stats.ip_frag.err == 0);
+  fail_unless(lwip_stats.ip_frag.memerr == 0);
+  fail_unless(lwip_stats.ip_frag.drop == 0);
+  fail_unless(lwip_stats.mib2.ipreasmoks == 1);
+}
+END_TEST
+
+
+/** Create the suite including all tests for this module */
+Suite *
+ip4_suite(void)
+{
+  testfunc tests[] = {
+    TESTFUNC(test_ip4_reass),
+  };
+  return create_suite("IPv4", tests, sizeof(tests)/sizeof(testfunc), 
ip4_setup, ip4_teardown);
+}
diff --git a/net/ip/lwip_base/test/unit/ip4/test_ip4.h 
b/net/ip/lwip_base/test/unit/ip4/test_ip4.h
new file mode 100644
index 000000000..df84a69f1
--- /dev/null
+++ b/net/ip/lwip_base/test/unit/ip4/test_ip4.h
@@ -0,0 +1,8 @@
+#ifndef LWIP_HDR_TEST_IP4_H
+#define LWIP_HDR_TEST_IP4_H
+
+#include "../lwip_check.h"
+
+Suite* ip4_suite(void);
+
+#endif
diff --git a/net/ip/lwip_base/test/unit/lwip_unittests.c 
b/net/ip/lwip_base/test/unit/lwip_unittests.c
index 46fd4308e..76be87067 100644
--- a/net/ip/lwip_base/test/unit/lwip_unittests.c
+++ b/net/ip/lwip_base/test/unit/lwip_unittests.c
@@ -1,5 +1,6 @@
 #include "lwip_check.h"
 
+#include "ip4/test_ip4.h"
 #include "udp/test_udp.h"
 #include "tcp/test_tcp.h"
 #include "tcp/test_tcp_oos.h"
@@ -37,6 +38,7 @@ int main(void)
   SRunner *sr;
   size_t i;
   suite_getter_fn* suites[] = {
+    ip4_suite,
     udp_suite,
     tcp_suite,
     tcp_oos_suite,
diff --git a/net/ip/lwip_base/test/unit/lwipopts.h 
b/net/ip/lwip_base/test/unit/lwipopts.h
index 25252b426..fc2ca5dec 100644
--- a/net/ip/lwip_base/test/unit/lwipopts.h
+++ b/net/ip/lwip_base/test/unit/lwipopts.h
@@ -59,4 +59,7 @@
 /* Minimal changes to opt.h required for etharp unit tests: */
 #define ETHARP_SUPPORT_STATIC_ENTRIES   1
 
+/* MIB2 stats are required to check IPv4 reassembly results */
+#define MIB2_STATS                      1
+
 #endif /* LWIP_HDR_LWIPOPTS_H */


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to