diff --git a/ext/lwip/CHANGELOG b/ext/lwip/CHANGELOG index 9f5cda9..3b47ec2 100755 --- a/ext/lwip/CHANGELOG +++ b/ext/lwip/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/ext/lwip/UPGRADING b/ext/lwip/UPGRADING index e32150a..89267ae 100755 --- a/ext/lwip/UPGRADING +++ b/ext/lwip/UPGRADING @@ -1,235 +1,243 @@ -This file lists major changes between release versions that require -ports or applications to be changed. Use it to update a port or an -application written for an older version of lwIP to correctly work -with newer versions. - - -(git master) - - * [Enter new changes just after this line - do not remove this line] - +This file lists major changes between release versions that require +ports or applications to be changed. Use it to update a port or an +application written for an older version of lwIP to correctly work +with newer versions. + + +(git master) + + * [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: - - * UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific - netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare - ip_current_netif() to the desired netif for every packet. - See bug #49662 for an explanation. - -(2.0.0) - - ++ Application changes: - - * Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of - "ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif - has to be set "up" before starting the DHCP client - * Added IPv6 support (dual-stack or IPv4/IPv6 only) - * Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only). - * Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs); - supports SNMPv2c (experimental v3 support) - * Moved some core applications from contrib repository to src/apps (and include/lwip/apps) - - +++ Raw API: - * Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/ - tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb - - +++ Socket API: - * Added an implementation for posix sendmsg() - * Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram - - ++ Port changes - - +++ new files: - * MANY new and moved files! - * Added src/Filelists.mk for use in Makefile projects - * Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv" - to let abc.h only contain the actual application programmer's API - - +++ sys layer: - * Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than - the traditional message passing (although with LWIP_COMPAT_MUTEX you are still - open to priority inversion, so this is not recommended any more) - * Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread - instead of using one per netconn (these semaphores are used even with core locking - enabled as some longer lasting functions like big writes still need to delay) - * Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr() - in def.h (to be overridden in cc.h) instead of config - options for netbiosns, httpd, dns, etc. ... - * New abstraction for hton* and ntoh* functions in def.h. - To override them, use the following in cc.h: - #define lwip_htons(x) - #define lwip_htonl(x) - - +++ new options: - * TODO - - +++ new pools: - * Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools - that share memp.c code but do not have to be made global via lwippools.h - * Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc. - * added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item - is now available - - * Signature of LWIP_HOOK_VLAN_SET macro was changed - - * LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp) - or to move buffers to dedicated memory using compiler attributes - - * Standard C headers are used to define sized types and printf formatters - (disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler - does not support these) - - - ++ Major bugfixes/improvements - - * Added IPv6 support (dual-stack or IPv4/IPv6 only) - * Major rewrite of PPP (incl. keep-up with apache pppd) - see doc/ppp.txt for an upgrading how-to - * Major rewrite of SNMP (incl. MIB parser) - * Fixed timing issues that might have lead to losing a DHCP lease - * Made rx processing path more robust against crafted errors - * TCP window scaling support - * modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads) - * made DNS client more robust - * support PBUF_REF for RX packets - * LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate - threads each (needs LWIP_NETCONN_SEM_PER_THREAD) - * Moved and reordered stats (mainly memp/mib2) - -(1.4.0) - - ++ Application changes: - - * Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for - compatibility to old applications, but will be removed in the future). - - * Renamed mem_realloc() to mem_trim() to prevent confusion with realloc() - - +++ Raw API: - * Changed the semantics of tcp_close() (since it was rather a - shutdown before): Now the application does *NOT* get any calls to the recv - callback (aside from NULL/closed) after calling tcp_close() - - * When calling tcp_abort() from a raw API TCP callback function, - make sure you return ERR_ABRT to prevent accessing unallocated memory. - (ERR_ABRT now means the applicaiton has called tcp_abort!) - - +++ Netconn API: - * Changed netconn_receive() and netconn_accept() to return - err_t, not a pointer to new data/netconn. - - +++ Socket API: - * LWIP_SO_RCVTIMEO: when accept() or recv() time out, they - now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT. - - * Added a minimal version of posix fctl() to have a - standardised way to set O_NONBLOCK for nonblocking sockets. - - +++ all APIs: - * correctly implemented SO(F)_REUSEADDR - - ++ Port changes - - +++ new files: - - * Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h: - - * Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains - the actual application programmer's API - - * Separated timer implementation from sys.h/.c, moved to timers.h/.c; - Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you - still want to use your own timer implementation for NO_SYS==0 (as before). - - +++ sys layer: - - * Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/ - sys_sem_t; - - * Converted sys_mbox_new/sys_sem_new to take pointers and return err_t; - - * Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use - binary semaphores instead of mutexes - as before) - - +++ new options: - - * Don't waste memory when chaining segments, added option TCP_OVERSIZE to - prevent creating many small pbufs when calling tcp_write with many small - blocks of data. Instead, pbufs are allocated larger than needed and the - space is used for later calls to tcp_write. - - * Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs - in tcp_write/udp_send. - - * Added an additional option LWIP_ETHERNET to support ethernet without ARP - (necessary for pure PPPoE) - - * Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may - be used to place these pools into user-defined memory by using external - declaration. - - * Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT - - +++ new pools: - - * Netdb uses a memp pool for allocating memory when getaddrinfo() is called, - so MEMP_NUM_NETDB has to be set accordingly. - - * DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so - MEMP_NUM_LOCALHOSTLIST has to be set accordingly. - - * Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have - to be set accordingly. - - * PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES - has to be set accordingly - - * Integrated loopif into netif.c - loopif does not have to be created by the - port any more, just define LWIP_HAVE_LOOPIF to 1. - - * Added define LWIP_RAND() for lwip-wide randomization (needs to be defined - in cc.h, e.g. used by igmp) - - * Added printf-formatter X8_F to printf u8_t as hex - - * The heap now may be moved to user-defined memory by defining - LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address - - * added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work - with user-allocated structs instead of calling mem_malloc - - * Added const char* name to mem- and memp-stats for easier debugging. - - * Calculate the TCP/UDP checksum while copying to only fetch data once: - Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum - - * Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to - more than one pcb. - - * Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned - off any more, if this is set to 0, only one packet (the most recent one) is - queued (like demanded by RFC 1122). - - - ++ Major bugfixes/improvements - - * Implemented tcp_shutdown() to only shut down one end of a connection - * Implemented shutdown() at socket- and netconn-level - * Added errorset support to select() + improved select speed overhead - * Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x) - * Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1 - * Use macros defined in ip_addr.h to work with IP addresses - * Implemented many nonblocking socket/netconn functions - * Fixed ARP input processing: only add a new entry if a request was directed as us - * mem_realloc() to mem_trim() to prevent confusion with realloc() - * Some improvements for AutoIP (don't route/forward link-local addresses, don't break - existing connections when assigning a routable address) - * Correctly handle remote side overrunning our rcv_wnd in ooseq case - * Removed packing from ip_addr_t, the packed version is now only used in protocol headers - * Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0 - * Added support for static ARP table entries - -(STABLE-1.3.2) - - * initial version of this file + ++ Application changes: + + * UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific + netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare + ip_current_netif() to the desired netif for every packet. + See bug #49662 for an explanation. + +(2.0.0) + + ++ Application changes: + + * Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of + "ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif + has to be set "up" before starting the DHCP client + * Added IPv6 support (dual-stack or IPv4/IPv6 only) + * Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only). + * Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs); + supports SNMPv2c (experimental v3 support) + * Moved some core applications from contrib repository to src/apps (and include/lwip/apps) + + +++ Raw API: + * Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/ + tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb + + +++ Socket API: + * Added an implementation for posix sendmsg() + * Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram + + ++ Port changes + + +++ new files: + * MANY new and moved files! + * Added src/Filelists.mk for use in Makefile projects + * Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv" + to let abc.h only contain the actual application programmer's API + + +++ sys layer: + * Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than + the traditional message passing (although with LWIP_COMPAT_MUTEX you are still + open to priority inversion, so this is not recommended any more) + * Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread + instead of using one per netconn (these semaphores are used even with core locking + enabled as some longer lasting functions like big writes still need to delay) + * Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr() + in def.h (to be overridden in cc.h) instead of config + options for netbiosns, httpd, dns, etc. ... + * New abstraction for hton* and ntoh* functions in def.h. + To override them, use the following in cc.h: + #define lwip_htons(x) + #define lwip_htonl(x) + + +++ new options: + * TODO + + +++ new pools: + * Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools + that share memp.c code but do not have to be made global via lwippools.h + * Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc. + * added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item + is now available + + * Signature of LWIP_HOOK_VLAN_SET macro was changed + + * LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp) + or to move buffers to dedicated memory using compiler attributes + + * Standard C headers are used to define sized types and printf formatters + (disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler + does not support these) + + + ++ Major bugfixes/improvements + + * Added IPv6 support (dual-stack or IPv4/IPv6 only) + * Major rewrite of PPP (incl. keep-up with apache pppd) + see doc/ppp.txt for an upgrading how-to + * Major rewrite of SNMP (incl. MIB parser) + * Fixed timing issues that might have lead to losing a DHCP lease + * Made rx processing path more robust against crafted errors + * TCP window scaling support + * modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads) + * made DNS client more robust + * support PBUF_REF for RX packets + * LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate + threads each (needs LWIP_NETCONN_SEM_PER_THREAD) + * Moved and reordered stats (mainly memp/mib2) + +(1.4.0) + + ++ Application changes: + + * Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for + compatibility to old applications, but will be removed in the future). + + * Renamed mem_realloc() to mem_trim() to prevent confusion with realloc() + + +++ Raw API: + * Changed the semantics of tcp_close() (since it was rather a + shutdown before): Now the application does *NOT* get any calls to the recv + callback (aside from NULL/closed) after calling tcp_close() + + * When calling tcp_abort() from a raw API TCP callback function, + make sure you return ERR_ABRT to prevent accessing unallocated memory. + (ERR_ABRT now means the applicaiton has called tcp_abort!) + + +++ Netconn API: + * Changed netconn_receive() and netconn_accept() to return + err_t, not a pointer to new data/netconn. + + +++ Socket API: + * LWIP_SO_RCVTIMEO: when accept() or recv() time out, they + now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT. + + * Added a minimal version of posix fctl() to have a + standardised way to set O_NONBLOCK for nonblocking sockets. + + +++ all APIs: + * correctly implemented SO(F)_REUSEADDR + + ++ Port changes + + +++ new files: + + * Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h: + + * Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains + the actual application programmer's API + + * Separated timer implementation from sys.h/.c, moved to timers.h/.c; + Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you + still want to use your own timer implementation for NO_SYS==0 (as before). + + +++ sys layer: + + * Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/ + sys_sem_t; + + * Converted sys_mbox_new/sys_sem_new to take pointers and return err_t; + + * Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use + binary semaphores instead of mutexes - as before) + + +++ new options: + + * Don't waste memory when chaining segments, added option TCP_OVERSIZE to + prevent creating many small pbufs when calling tcp_write with many small + blocks of data. Instead, pbufs are allocated larger than needed and the + space is used for later calls to tcp_write. + + * Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs + in tcp_write/udp_send. + + * Added an additional option LWIP_ETHERNET to support ethernet without ARP + (necessary for pure PPPoE) + + * Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may + be used to place these pools into user-defined memory by using external + declaration. + + * Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT + + +++ new pools: + + * Netdb uses a memp pool for allocating memory when getaddrinfo() is called, + so MEMP_NUM_NETDB has to be set accordingly. + + * DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so + MEMP_NUM_LOCALHOSTLIST has to be set accordingly. + + * Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have + to be set accordingly. + + * PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES + has to be set accordingly + + * Integrated loopif into netif.c - loopif does not have to be created by the + port any more, just define LWIP_HAVE_LOOPIF to 1. + + * Added define LWIP_RAND() for lwip-wide randomization (needs to be defined + in cc.h, e.g. used by igmp) + + * Added printf-formatter X8_F to printf u8_t as hex + + * The heap now may be moved to user-defined memory by defining + LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address + + * added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work + with user-allocated structs instead of calling mem_malloc + + * Added const char* name to mem- and memp-stats for easier debugging. + + * Calculate the TCP/UDP checksum while copying to only fetch data once: + Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum + + * Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to + more than one pcb. + + * Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned + off any more, if this is set to 0, only one packet (the most recent one) is + queued (like demanded by RFC 1122). + + + ++ Major bugfixes/improvements + + * Implemented tcp_shutdown() to only shut down one end of a connection + * Implemented shutdown() at socket- and netconn-level + * Added errorset support to select() + improved select speed overhead + * Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x) + * Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1 + * Use macros defined in ip_addr.h to work with IP addresses + * Implemented many nonblocking socket/netconn functions + * Fixed ARP input processing: only add a new entry if a request was directed as us + * mem_realloc() to mem_trim() to prevent confusion with realloc() + * Some improvements for AutoIP (don't route/forward link-local addresses, don't break + existing connections when assigning a routable address) + * Correctly handle remote side overrunning our rcv_wnd in ooseq case + * Removed packing from ip_addr_t, the packed version is now only used in protocol headers + * Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0 + * Added support for static ARP table entries + +(STABLE-1.3.2) + + * initial version of this file diff --git a/ext/lwip/doc/NO_SYS_SampleCode.c b/ext/lwip/doc/NO_SYS_SampleCode.c index e86d63e..fcc22c5 100755 --- a/ext/lwip/doc/NO_SYS_SampleCode.c +++ b/ext/lwip/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/ext/lwip/src/api/api_msg.c b/ext/lwip/src/api/api_msg.c index 971c8b1..a609017 100755 --- a/ext/lwip/src/api/api_msg.c +++ b/ext/lwip/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/ext/lwip/src/api/err.c b/ext/lwip/src/api/err.c index 997eb6c..cc3dabb 100755 --- a/ext/lwip/src/api/err.c +++ b/ext/lwip/src/api/err.c @@ -41,6 +41,7 @@ #include "lwip/sys.h" #include +//#include "lwip/errno.h" #if !NO_SYS /** Table to quickly map an lwIP error (err_t) to a socket error diff --git a/ext/lwip/src/apps/mqtt/mqtt.c b/ext/lwip/src/apps/mqtt/mqtt.c index 29a975e..565c34a 100755 --- a/ext/lwip/src/apps/mqtt/mqtt.c +++ b/ext/lwip/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/ext/lwip/src/core/init.c b/ext/lwip/src/core/init.c index 7d2cd38..5e50858 100755 --- a/ext/lwip/src/core/init.c +++ b/ext/lwip/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/ext/lwip/src/core/ipv4/dhcp.c b/ext/lwip/src/core/ipv4/dhcp.c index 8f2d573..74f6b58 100755 --- a/ext/lwip/src/core/ipv4/dhcp.c +++ b/ext/lwip/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 @@ again: 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 @@ decode_next: 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/ext/lwip/src/core/ipv4/ip4_frag.c b/ext/lwip/src/core/ipv4/ip4_frag.c index 61a24da..996c8be 100755 --- a/ext/lwip/src/core/ipv4/ip4_frag.c +++ b/ext/lwip/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/ext/lwip/src/core/netif.c b/ext/lwip/src/core/netif.c index f3ff808..f16a0ff 100755 --- a/ext/lwip/src/core/netif.c +++ b/ext/lwip/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/ext/lwip/src/core/tcp.c b/ext/lwip/src/core/tcp.c index 697bc2d..fb95374 100755 --- a/ext/lwip/src/core/tcp.c +++ b/ext/lwip/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/ext/lwip/src/core/tcp_in.c b/ext/lwip/src/core/tcp_in.c index 1c5ab6b..17ceaff 100755 --- a/ext/lwip/src/core/tcp_in.c +++ b/ext/lwip/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 @@ dropped: 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/ext/lwip/src/core/timeouts.c b/ext/lwip/src/core/timeouts.c index 40749f9..5c9b29d 100755 --- a/ext/lwip/src/core/timeouts.c +++ b/ext/lwip/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/ext/lwip/src/include/lwip/arch.h b/ext/lwip/src/include/lwip/arch.h index 58b9d6e..f366ab5 100755 --- a/ext/lwip/src/include/lwip/arch.h +++ b/ext/lwip/src/include/lwip/arch.h @@ -76,8 +76,7 @@ * systems, this should be defined to something less resource-consuming. */ #ifndef LWIP_PLATFORM_DIAG -#include "Debug.hpp" -#define LWIP_PLATFORM_DIAG(x) printf(x); +#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) #include #include #endif diff --git a/ext/lwip/src/include/lwip/def.h b/ext/lwip/src/include/lwip/def.h index 12b143c..2db7522 100755 --- a/ext/lwip/src/include/lwip/def.h +++ b/ext/lwip/src/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/ext/lwip/src/include/lwip/dhcp.h b/ext/lwip/src/include/lwip/dhcp.h index d090afb..9750491 100755 --- a/ext/lwip/src/include/lwip/dhcp.h +++ b/ext/lwip/src/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/ext/lwip/src/include/lwip/fuck_off.h b/ext/lwip/src/include/lwip/fuck_off.h index 5619491..2d326cb 100755 --- a/ext/lwip/src/include/lwip/fuck_off.h +++ b/ext/lwip/src/include/lwip/fuck_off.h @@ -43,8 +43,6 @@ extern "C" { #endif -#define LWIP_PROVIDE_ERRNO 0 - #ifdef LWIP_PROVIDE_ERRNO #define EPERM 1 /* Operation not permitted */ @@ -176,13 +174,12 @@ extern "C" { #define EMEDIUMTYPE 124 /* Wrong medium type */ #ifndef errno -//extern int errno; +extern int errno; #endif #else /* LWIP_PROVIDE_ERRNO */ /* Define LWIP_ERRNO_INCLUDE to to include the error defines here */ -#define LWIP_ERRNO_INCLUDE #ifdef LWIP_ERRNO_INCLUDE #include LWIP_ERRNO_INCLUDE #endif /* LWIP_ERRNO_INCLUDE */ diff --git a/ext/lwip/src/include/lwip/init.h b/ext/lwip/src/include/lwip/init.h index a38845a..721bb57 100755 --- a/ext/lwip/src/include/lwip/init.h +++ b/ext/lwip/src/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 2 +#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/ext/lwip/src/include/lwip/memp.h b/ext/lwip/src/include/lwip/memp.h index 34134cb..c45aca8 100755 --- a/ext/lwip/src/include/lwip/memp.h +++ b/ext/lwip/src/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/ext/lwip/src/include/lwip/stats.h b/ext/lwip/src/include/lwip/stats.h index 685f57b..a0c818b 100755 --- a/ext/lwip/src/include/lwip/stats.h +++ b/ext/lwip/src/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/ext/lwip/test/unit/ip4/test_ip4.c b/ext/lwip/test/unit/ip4/test_ip4.c new file mode 100755 index 0000000..383acf3 --- /dev/null +++ b/ext/lwip/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/ext/lwip/test/unit/ip4/test_ip4.h b/ext/lwip/test/unit/ip4/test_ip4.h new file mode 100755 index 0000000..71922b3 --- /dev/null +++ b/ext/lwip/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/ext/lwip/test/unit/lwip_unittests.c b/ext/lwip/test/unit/lwip_unittests.c index 84b895d..5563015 100755 --- a/ext/lwip/test/unit/lwip_unittests.c +++ b/ext/lwip/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/ext/lwip/test/unit/lwipopts.h b/ext/lwip/test/unit/lwipopts.h index a94c3fe..9bd672b 100755 --- a/ext/lwip/test/unit/lwipopts.h +++ b/ext/lwip/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 */