From b9290bcef45a9ebc088e1f20596b7e02c7ca47f6 Mon Sep 17 00:00:00 2001 From: "bernard.xiong" Date: Sun, 6 Sep 2009 11:04:38 +0000 Subject: [PATCH] update lwip to 1.3.1 git-svn-id: https://rt-thread.googlecode.com/svn/trunk@37 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- net/lwip/CHANGELOG | 367 +++++++++++++++++++ net/lwip/doc/FILES | 1 + net/lwip/doc/rawapi.txt | 47 ++- net/lwip/doc/sys_arch.txt | 2 + net/lwip/src/api/api_lib.c | 17 +- net/lwip/src/api/api_msg.c | 70 +++- net/lwip/src/api/err.c | 22 +- net/lwip/src/api/netbuf.c | 4 +- net/lwip/src/api/netdb.c | 22 +- net/lwip/src/api/sockets.c | 315 +++++++++------- net/lwip/src/api/tcpip.c | 85 ++++- net/lwip/src/arch/include/arch/cc.h | 5 +- net/lwip/src/arch/sys.c | 137 ------- net/lwip/src/arch/sys_arch.c | 31 +- net/lwip/src/core/dhcp.c | 169 ++++++--- net/lwip/src/core/dns.c | 224 +++++++++-- net/lwip/src/core/init.c | 16 + net/lwip/src/core/ipv4/autoip.c | 61 ++- net/lwip/src/core/ipv4/icmp.c | 116 +++--- net/lwip/src/core/ipv4/igmp.c | 87 +---- net/lwip/src/core/ipv4/inet.c | 8 +- net/lwip/src/core/ipv4/inet_chksum.c | 111 +++--- net/lwip/src/core/ipv4/ip.c | 143 +++++++- net/lwip/src/core/ipv4/ip_frag.c | 19 +- net/lwip/src/core/ipv6/ip6.c | 22 ++ net/lwip/src/core/mem.c | 276 ++++++++------ net/lwip/src/core/memp.c | 58 +-- net/lwip/src/core/netif.c | 184 +++++++++- net/lwip/src/core/pbuf.c | 132 ++++++- net/lwip/src/core/raw.c | 49 ++- net/lwip/src/core/snmp/mib2.c | 8 +- net/lwip/src/core/snmp/msg_in.c | 7 +- net/lwip/src/core/stats.c | 81 ++-- net/lwip/src/core/sys.c | 26 +- net/lwip/src/core/tcp.c | 138 ++++--- net/lwip/src/core/tcp_in.c | 283 ++++++++------ net/lwip/src/core/tcp_out.c | 354 ++++++++++-------- net/lwip/src/core/udp.c | 42 ++- net/lwip/src/include/ipv4/lwip/icmp.h | 33 +- net/lwip/src/include/ipv4/lwip/inet.h | 12 +- net/lwip/src/include/ipv4/lwip/inet_chksum.h | 2 + net/lwip/src/include/ipv4/lwip/ip.h | 32 +- net/lwip/src/include/ipv4/lwip/ip_addr.h | 24 +- net/lwip/src/include/ipv6/lwip/ip.h | 3 + net/lwip/src/include/lwip/api.h | 13 +- net/lwip/src/include/lwip/api_msg.h | 4 +- net/lwip/src/include/lwip/arch.h | 17 +- net/lwip/src/include/lwip/debug.h | 16 +- net/lwip/src/include/lwip/dhcp.h | 2 +- net/lwip/src/include/lwip/dns.h | 5 + net/lwip/src/include/lwip/err.h | 32 +- net/lwip/src/include/lwip/init.h | 24 ++ net/lwip/src/include/lwip/mem.h | 12 +- net/lwip/src/include/lwip/memp.h | 22 ++ net/lwip/src/include/lwip/memp_std.h | 5 +- net/lwip/src/include/lwip/netbuf.h | 1 + net/lwip/src/include/lwip/netdb.h | 2 + net/lwip/src/include/lwip/netif.h | 18 + net/lwip/src/include/lwip/opt.h | 198 +++++++++- net/lwip/src/include/lwip/pbuf.h | 2 + net/lwip/src/include/lwip/sio.h | 10 + net/lwip/src/include/lwip/snmp_asn1.h | 4 + net/lwip/src/include/lwip/snmp_msg.h | 4 + net/lwip/src/include/lwip/sockets.h | 55 +-- net/lwip/src/include/lwip/stats.h | 78 +++- net/lwip/src/include/lwip/sys.h | 9 +- net/lwip/src/include/lwip/tcp.h | 244 +++++++----- net/lwip/src/include/lwip/tcpip.h | 12 +- net/lwip/src/include/netif/etharp.h | 5 + net/lwip/src/include/netif/loopif.h | 7 +- net/lwip/src/netif/etharp.c | 20 +- net/lwip/src/netif/loopif.c | 153 +------- net/lwip/src/netif/ppp/pap.c | 20 +- net/lwip/src/netif/ppp/ppp.c | 6 +- net/lwip/src/netif/slipif.c | 4 + 75 files changed, 3270 insertions(+), 1579 deletions(-) delete mode 100644 net/lwip/src/arch/sys.c diff --git a/net/lwip/CHANGELOG b/net/lwip/CHANGELOG index 5567d5c78..a45765010 100644 --- a/net/lwip/CHANGELOG +++ b/net/lwip/CHANGELOG @@ -19,8 +19,375 @@ HISTORY ++ New features: + ++ Bugfixes: + + +(STABLE-1.3.1) + + ++ New features: + + 2009-05-10 Simon Goldschmidt + * opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option + LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only + one pbuf to help MACs that don't support scatter-gather DMA. + + 2009-05-09 Simon Goldschmidt + * icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming + ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN + + 2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen + * ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive + extended info about the currently received packet. + + 2009-04-27 Simon Goldschmidt + * sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1 + + 2009-04-25 Simon Goldschmidt + * mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next + bigger malloc pool if one is empty (only usable with MEM_USE_POOLS). + + 2009-04-21 Simon Goldschmidt + * dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static + hosts table. New configuration options DNS_LOCAL_HOSTLIST and + DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined + as an external function for lookup. + + 2009-04-15 Simon Goldschmidt + * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique + + 2009-03-31 Kieran Mansley + * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for + TCP timestamp options, off by default. Rework tcp_enqueue() to + take option flags rather than specified option data + + 2009-02-18 Simon Goldschmidt + * cc.h: Added printf formatter for size_t: SZT_F + + 2009-02-16 Simon Goldschmidt (patch by Rishi Khan) + * icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast + pings + + 2009-02-12 Simon Goldschmidt + * init.h: Added LWIP_VERSION to get the current version of the stack + + 2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler) + * opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead + of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc + is otherwise used) + + 2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach) + * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial() + is only used by UDPLITE at present, so conditionalise it. + + 2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli) + * autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP + "seed" address. This should reduce AUTOIP conflicts if + LWIP_AUTOIP_CREATE_SEED_ADDR is overridden. + + 2008-10-02 Jonathan Larmour and Rishi Khan + * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking + socket. + + 2008-06-30 Simon Goldschmidt + * mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from + interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows + mem_free to run between mem_malloc iterations. Added illegal counter for + mem stats. + + 2008-06-27 Simon Goldschmidt + * stats.h/.c, some other files: patch #6483: stats module improvement: + Added defines to display each module's statistic individually, added stats + defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter. + + 2008-06-17 Simon Goldschmidt + * err.h: patch #6459: Made err_t overridable to use a more efficient type + (define LWIP_ERR_T in cc.h) + + 2008-06-17 Simon Goldschmidt + * slipif.c: patch #6480: Added a configuration option for slipif for symmetry + to loopif + + 2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli) + * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly + modified version of patch # 6370: Moved loopif code to netif.c so that + loopback traffic is supported on all netifs (all local IPs). + Added option to limit loopback packets for each netifs. + ++ Bugfixes: + 2009-08-12 Kieran Mansley + * tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when + out of window or out of order properly + + 2009-08-12 Kieran Mansley + * tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1 + + 2009-07-28 Simon Goldschmidt + * mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s + + 2009-07-27 Kieran Mansley + * api.h api_msg.h netdb.h sockets.h: add missing #include directives + + 2009-07-09 Kieran Mansley + * api_msg.c, sockets.c, api.h: BUG23240 use signed counters for + recv_avail and don't increment counters until message successfully + sent to mbox + + 2009-06-25 Kieran Mansley + * api_msg.c api.h: BUG26722: initialise netconn write variables + in netconn_alloc + + 2009-06-25 Kieran Mansley + * tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set + + 2009-06-25 Kieran Mansley + * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct + simultaneous close behaviour, and make snd_nxt have the same meaning + as in the RFCs. + + 2009-05-12 Simon Goldschmidt + * etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on + arp_table / uses etharp_query" by adding etharp_gratuitous() + + 2009-05-12 Simon Goldschmidt + * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options + to the IP header (used by igmp_ip_output_if) + + 2009-05-06 Simon Goldschmidt + * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if + defined) for SWAP_BYTES_IN_WORD to speed up checksumming. + + 2009-05-05 Simon Goldschmidt + * sockets.c: bug #26405: Prematurely released semaphore causes lwip_select() + to crash + + 2009-05-04 Simon Goldschmidt + * init.c: snmp was not initialized in lwip_init() + + 2009-05-04 Frédéric Bernon + * dhcp.c, netbios.c: Changes if IP_SOF_BROADCAST is enabled. + + 2009-05-03 Simon Goldschmidt + * tcp.h: bug #26349: Nagle algorithm doesn't send although segment is full + (and unsent->next == NULL) + + 2009-05-02 Simon Goldschmidt + * tcpip.h, tcpip.c: fixed tcpip_untimeout (does not need the time, broken after + 1.3.0 in CVS only) - fixes compilation of ppp_oe.c + + 2009-05-02 Simon Goldschmidt + * msg_in.c: fixed bug #25636: SNMPSET value is ignored for integer fields + + 2009-05-01 Simon Goldschmidt + * pap.c: bug #21680: PPP upap_rauthnak() drops legal NAK packets + + 2009-05-01 Simon Goldschmidt + * ppp.c: bug #24228: Memory corruption with PPP and DHCP + + 2009-04-29 Frédéric Bernon + * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the + SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception + of broadcast packets even when this option wasn't set. Port maintainers + which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. + If you want this option also filter broadcast on recv operations, you also + have to set IP_SOF_BROADCAST_RECV=1 in opt.h. + + 2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen + * dhcp.c: patch #6721, bugs #25575, #25576: Some small fixes to DHCP and + DHCP/AUTOIP cooperation + + 2009-04-25 Simon Goldschmidt, Oleg Tyshev + * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd + Fixed by sorting the unsent and unacked queues (segments are inserted at the + right place in tcp_output and tcp_rexmit). + + 2009-04-25 Simon Goldschmidt + * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation + when debugging": memp_sizes contained the wrong sizes (including sanity + regions); memp pools for MEM_USE_POOLS were too small + + 2009-04-24 Simon Goldschmidt, Frédéric Bernon + * inet.c: patch #6765: Fix a small problem with the last changes (incorrect + behavior, with with ip address string not ended by a '\0', a space or a + end of line) + + 2009-04-19 Simon Goldschmidt + * rawapi.txt: Fixed bug #26069: Corrected documentation: if tcp_connect fails, + pcb->err is called, not pcb->connected (with an error code). + + 2009-04-19 Simon Goldschmidt + * tcp_out.c: Fixed bug #26236: "TCP options (timestamp) don't work with + no-copy-tcpwrite": deallocate option data, only concat segments with same flags + + 2009-04-19 Simon Goldschmidt + * tcp_out.c: Fixed bug #25094: "Zero-length pbuf" (options are now allocated + in the header pbuf, not the data pbuf) + + 2009-04-18 Simon Goldschmidt + * api_msg.c: fixed bug #25695: Segmentation fault in do_writemore() + + 2009-04-15 Simon Goldschmidt + * sockets.c: tried to fix bug #23559: lwip_recvfrom problem with tcp + + 2009-04-15 Simon Goldschmidt + * dhcp.c: task #9192: mem_free of dhcp->options_in and dhcp->msg_in + + 2009-04-15 Simon Goldschmidt + * ip.c, ip6.c, tcp_out.c, ip.h: patch #6808: Add a utility function + ip_hinted_output() (for smaller code mainly) + + 2009-04-15 Simon Goldschmidt + * inet.c: patch #6765: Supporting new line characters in inet_aton() + + 2009-04-15 Simon Goldschmidt + * dhcp.c: patch #6764: DHCP rebind and renew did not send hostnam option; + Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu + is big enough in dhcp_start + + 2009-04-15 Simon Goldschmidt + * netbuf.c: bug #26027: netbuf_chain resulted in pbuf memory leak + + 2009-04-15 Simon Goldschmidt + * sockets.c, ppp.c: bug #25763: corrected 4 occurrences of SMEMCPY to MEMCPY + + 2009-04-15 Simon Goldschmidt + * sockets.c: bug #26121: set_errno can be overridden + + 2009-04-09 Kieran Mansley (patch from Luca Ceresoli ) + * init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when + LWIP_TCP==0 + + 2009-04-09 Kieran Mansley (patch from Roy Lee ) + * tcp.h: Patch#6802 Add do-while-clauses to those function like + macros in tcp.h + + 2009-03-31 Kieran Mansley + * tcp.c, tcp_in.c, tcp_out.c, tcp.h, opt.h: Rework the way window + updates are calculated and sent (BUG20515) + + * tcp_in.c: cope with SYN packets received during established states, + and retransmission of initial SYN. + + * tcp_out.c: set push bit correctly when tcp segments are merged + + 2009-03-27 Kieran Mansley + * tcp_out.c set window correctly on probes (correcting change made + yesterday) + + 2009-03-26 Kieran Mansley + * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping + connections where no reset required (bug #25622) + + * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes + (bug #20779) + + 2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach) + * ip_frag.c: patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be + too small depending on MEM_ALIGNMENT + + 2009-02-16 Simon Goldschmidt + * sockets.h/.c, api_*.h/.c: fixed arguments of socket functions to match the standard; + converted size argument of netconn_write to 'size_t' + + 2009-02-16 Simon Goldschmidt + * tcp.h, tcp.c: fixed bug #24440: TCP connection close problem on 64-bit host + by moving accept callback function pointer to TCP_PCB_COMMON + + 2009-02-12 Simon Goldschmidt + * dhcp.c: fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size" + option) + + 2009-02-11 Simon Goldschmidt + * dhcp.c: fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start) + + 2009-02-11 Simon Goldschmidt + * opt.h, api_msg.c: added configurable default valud for netconn->recv_bufsize: + RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv()) + + 2009-02-10 Simon Goldschmidt + * tcp.c: fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD: + Accepts_pending is decrease on a corresponding listen pcb when a connection + in state SYN_RCVD is close. + + 2009-01-28 Jonathan Larmour + * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run + out of pool pbufs. + + 2008-12-19 Simon Goldschmidt + * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2 + + 2008-12-10 Tamas Somogyi, Frédéric Bernon + * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and + port uses deleted netbuf. + + 2008-10-18 Simon Goldschmidt + * tcp_in.c: fixed bug ##24596: Vulnerability on faulty TCP options length + in tcp_parseopt + + 2008-10-15 Simon Goldschmidt + * ip_frag.c: fixed bug #24517: IP reassembly crashes on unaligned IP headers + by packing the struct ip_reass_helper. + + 2008-10-03 David Woodhouse, Jonathan Larmour + * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address. + + 2008-10-02 Jonathan Larmour + * dns.c: Hard-code structure sizes, to avoid issues on some compilers where + padding is included. + + 2008-09-30 Jonathan Larmour + * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an + assertion check that addrlen isn't NULL. + + 2008-09-30 Jonathan Larmour + * tcp.c: Fix bug #24227, wrong error message in tcp_bind. + + 2008-08-26 Simon Goldschmidt + * inet.h, ip_addr.h: fixed bug #24132: Cross-dependency between ip_addr.h and + inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h + + 2008-08-14 Simon Goldschmidt + * api_msg.c: fixed bug #23847: do_close_internal references freed memory (when + tcp_close returns != ERR_OK) + + 2008-07-08 Frédéric Bernon + * stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters + in macros, mainly if MEM_STATS=0 and MEMP_STATS=0). + + 2008-06-24 Jonathan Larmour + * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused + if tcp_seg_copy fails. + + 2008-06-17 Simon Goldschmidt + * inet_chksum.c: Checked in some ideas of patch #6460 (loop optimizations) + and created defines for swapping bytes and folding u32 to u16. + + 2008-05-30 Kieran Mansley + * tcp_in.c Remove redundant "if" statement, and use real rcv_wnd + rather than rcv_ann_wnd when deciding if packets are in-window. + Contributed by + + 2008-05-30 Kieran Mansley + * mem.h: Fix BUG#23254. Change macro definition of mem_* to allow + passing as function pointers when MEM_LIBC_MALLOC is defined. + + 2008-05-09 Jonathan Larmour + * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to + stop it being treated as a fatal error. + + 2008-04-15 Simon Goldschmidt + * dhcp.c: fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP + (flag now cleared) + + 2008-03-27 Simon Goldschmidt + * mem.c, tcpip.c, tcpip.h, opt.h: fixed bug #21433 (Calling mem_free/pbuf_free + from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1 + in lwipopts.h or use pbuf_free_callback(p)/mem_free_callback(m) to free pbufs + or heap memory from interrupt context + + 2008-03-26 Simon Goldschmidt + * tcp_in.c, tcp.c: fixed bug #22249: division by zero could occur if a remote + host sent a zero mss as TCP option. (STABLE-1.3.0) diff --git a/net/lwip/doc/FILES b/net/lwip/doc/FILES index 49806d7b4..05d356f4f 100644 --- a/net/lwip/doc/FILES +++ b/net/lwip/doc/FILES @@ -1,5 +1,6 @@ savannah.txt - How to obtain the current development source code. contrib.txt - How to contribute to lwIP as a developer. rawapi.txt - The documentation for the core API of lwIP. + Also provides an overview about the other APIs and multithreading. snmp_agent.txt - The documentation for the lwIP SNMP agent. sys_arch.txt - The documentation for a system abstraction layer of lwIP. diff --git a/net/lwip/doc/rawapi.txt b/net/lwip/doc/rawapi.txt index 3543bde1a..8eec6e786 100644 --- a/net/lwip/doc/rawapi.txt +++ b/net/lwip/doc/rawapi.txt @@ -2,10 +2,11 @@ Raw TCP/IP interface for lwIP Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons -lwIP provides two Application Program's Interfaces (APIs) for programs +lwIP provides three Application Program's Interfaces (APIs) for programs to use for communication with the TCP/IP code: * low-level "core" / "callback" or "raw" API. * higher-level "sequential" API. +* BSD-style socket API. The sequential API provides a way for ordinary, sequential, programs to use the lwIP stack. It is quite similar to the BSD socket API. The @@ -14,6 +15,45 @@ paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP code and the application program must reside in different execution contexts (threads). +The socket API is a compatibility API for existing applications, +currently it is built on top of the sequential API. It is meant to +provide all functions needed to run socket API applications running +on other platforms (e.g. unix / windows etc.). However, due to limitations +in the specification of this API, there might be incompatibilities +that require small modifications of existing programs. + +** Threading + +lwIP started targeting single-threaded environments. When adding multi- +threading support, instead of making the core thread-safe, another +approach was chosen: there is one main thread running the lwIP core +(also known as the "tcpip_thread"). The raw API may only be used from +this thread! Application threads using the sequential- or socket API +communicate with this main thread through message passing. + + As such, the list of functions that may be called from + other threads or an ISR is very limited! Only functions + from these API header files are thread-safe: + - api.h + - netbuf.h + - netdb.h + - netifapi.h + - sockets.h + - sys.h + + Additionaly, memory (de-)allocation functions may be + called from multiple threads (not ISR!) with NO_SYS=0 + since they are protected by SYS_LIGHTWEIGHT_PROT and/or + semaphores. + + Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1 + and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1, + pbuf_free() may also be called from another thread or + an ISR (since only then, mem_free - for PBUF_RAM - may + be called from an ISR: otherwise, the HEAP is only + protected by semaphores). + + ** The remainder of this document discusses the "raw" API. ** The raw TCP/IP interface allows the application program to integrate @@ -128,8 +168,9 @@ incoming connections or be explicitly connected to another host. function specified as the fourth argument (the "connected" argument) when the connection is established. If the connection could not be properly established, either because the other host refused the - connection or because the other host didn't answer, the "connected" - function will be called with an the "err" argument set accordingly. + connection or because the other host didn't answer, the "err" + callback function of this pcb (registered with tcp_err, see below) + will be called. The tcp_connect() function can return ERR_MEM if no memory is available for enqueueing the SYN segment. If the SYN indeed was diff --git a/net/lwip/doc/sys_arch.txt b/net/lwip/doc/sys_arch.txt index 0430b6ff3..66310a91e 100644 --- a/net/lwip/doc/sys_arch.txt +++ b/net/lwip/doc/sys_arch.txt @@ -195,6 +195,8 @@ cc.h - Architecture environment, some compiler specific, some Platform specific diagnostic output - LWIP_PLATFORM_DIAG(x) - non-fatal, print a message. LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution. + Portability defines for printf formatters: + U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F "lightweight" synchronization mechanisms - SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable. diff --git a/net/lwip/src/api/api_lib.c b/net/lwip/src/api/api_lib.c index 22b65a315..86df911ea 100644 --- a/net/lwip/src/api/api_lib.c +++ b/net/lwip/src/api/api_lib.c @@ -119,19 +119,6 @@ netconn_delete(struct netconn *conn) return ERR_OK; } -/** - * Get the type of a netconn (as enum netconn_type). - * - * @param conn the netconn of which to get the type - * @return the netconn_type of conn - */ -enum netconn_type -netconn_type(struct netconn *conn) -{ - LWIP_ERROR("netconn_type: invalid conn", (conn != NULL), return NETCONN_INVALID;); - return conn->type; -} - /** * Get the local or remote IP address and port of a netconn. * For RAW netconns, this returns the protocol instead of a port! @@ -439,7 +426,7 @@ netconn_send(struct netconn *conn, struct netbuf *buf) LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len)); + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); msg.function = do_send; msg.msg.conn = conn; msg.msg.msg.b = buf; @@ -459,7 +446,7 @@ netconn_send(struct netconn *conn, struct netbuf *buf) * @return ERR_OK if data was sent, any other err_t on error */ err_t -netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags) +netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags) { struct api_msg msg; diff --git a/net/lwip/src/api/api_msg.c b/net/lwip/src/api/api_msg.c index 04646a540..28d101019 100644 --- a/net/lwip/src/api/api_msg.c +++ b/net/lwip/src/api/api_msg.c @@ -52,6 +52,8 @@ #include "lwip/igmp.h" #include "lwip/dns.h" +#include + /* forward declarations */ #if LWIP_TCP static err_t do_writemore(struct netconn *conn); @@ -108,11 +110,13 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, buf->addr = &(((struct ip_hdr*)(q->payload))->src); buf->port = pcb->protocol; - SYS_ARCH_INC(conn->recv_avail, q->tot_len); - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len); if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); + return 0; + } else { + SYS_ARCH_INC(conn->recv_avail, q->tot_len); + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len); } } } @@ -166,12 +170,13 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, buf->port = port; } - SYS_ARCH_INC(conn->recv_avail, p->tot_len); - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); return; + } else { + SYS_ARCH_INC(conn->recv_avail, p->tot_len); + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); } } #endif /* LWIP_UDP */ @@ -206,10 +211,12 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) } else { len = 0; } - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) { return ERR_MEM; + } else { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); } return ERR_OK; @@ -365,8 +372,6 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) newconn->pcb.tcp = newpcb; setup_tcp(newconn); newconn->err = err; - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) { /* When returning != ERR_OK, the connection is aborted in tcp_process(), @@ -374,7 +379,11 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) newconn->pcb.tcp = NULL; netconn_free(newconn); return ERR_MEM; + } else { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); } + return ERR_OK; } #endif /* LWIP_TCP */ @@ -528,11 +537,18 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) conn->socket = -1; conn->callback = callback; conn->recv_avail = 0; +#if LWIP_TCP + conn->write_msg = NULL; + conn->write_offset = 0; +#if LWIP_TCPIP_CORE_LOCKING + conn->write_delayed = 0; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_TCP */ #if LWIP_SO_RCVTIMEO conn->recv_timeout = 0; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF - conn->recv_bufsize = INT_MAX; + conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; #endif /* LWIP_SO_RCVBUF */ return conn; } @@ -598,11 +614,16 @@ do_close_internal(struct netconn *conn) LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); /* Set back some callback pointers */ + tcp_arg(conn->pcb.tcp, NULL); if (conn->pcb.tcp->state == LISTEN) { - tcp_arg(conn->pcb.tcp, NULL); tcp_accept(conn->pcb.tcp, NULL); } else { tcp_recv(conn->pcb.tcp, NULL); + tcp_accept(conn->pcb.tcp, NULL); + /* some callbacks have to be reset if tcp_close is not successful */ + tcp_sent(conn->pcb.tcp, NULL); + tcp_poll(conn->pcb.tcp, NULL, 4); + tcp_err(conn->pcb.tcp, NULL); } /* Try to close the connection */ err = tcp_close(conn->pcb.tcp); @@ -610,11 +631,6 @@ do_close_internal(struct netconn *conn) /* Closing succeeded */ conn->state = NETCONN_NONE; /* Set back some callback pointers as conn is going away */ - tcp_err(conn->pcb.tcp, NULL); - tcp_poll(conn->pcb.tcp, NULL, 4); - tcp_sent(conn->pcb.tcp, NULL); - tcp_recv(conn->pcb.tcp, NULL); - tcp_arg(conn->pcb.tcp, NULL); conn->pcb.tcp = NULL; conn->err = ERR_OK; /* Trigger select() in socket layer. This send should something else so the @@ -623,6 +639,14 @@ do_close_internal(struct netconn *conn) API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); /* wake up the application task */ sys_sem_signal(conn->op_completed); + } else { + /* Closing failed, restore some of the callbacks */ + /* Closing of listen pcb will never fail! */ + LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); + tcp_sent(conn->pcb.tcp, sent_tcp); + tcp_poll(conn->pcb.tcp, poll_tcp, 4); + tcp_err(conn->pcb.tcp, err_tcp); + tcp_arg(conn->pcb.tcp, conn); } /* If closing didn't succeed, we get called again either from poll_tcp or from sent_tcp */ @@ -894,7 +918,7 @@ do_send(struct api_msg_msg *msg) } /** - * Recv some data from a RAW or UDP pcb contained in a netconn + * Indicate data has been received from a TCP pcb contained in a netconn * Called from netconn_recv * * @param msg the api_msg_msg pointing to the connection @@ -940,17 +964,19 @@ do_writemore(struct netconn *conn) void *dataptr; u16_t len, available; u8_t write_finished = 0; + size_t diff; LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset; - if ((conn->write_msg->msg.w.len - conn->write_offset > 0xffff)) { /* max_u16_t */ + diff = conn->write_msg->msg.w.len - conn->write_offset; + if (diff > 0xffffUL) { /* max_u16_t */ len = 0xffff; #if LWIP_TCPIP_CORE_LOCKING conn->write_delayed = 1; #endif } else { - len = conn->write_msg->msg.w.len - conn->write_offset; + len = (u16_t)diff; } available = tcp_sndbuf(conn->pcb.tcp); if (available < len) { @@ -970,6 +996,8 @@ do_writemore(struct netconn *conn) write_finished = 1; conn->write_msg = NULL; conn->write_offset = 0; + /* API_EVENT might call tcp_tmr, so reset conn->state now */ + conn->state = NETCONN_NONE; } err = tcp_output_nagle(conn->pcb.tcp); conn->err = err; @@ -1027,6 +1055,8 @@ do_write(struct api_msg_msg *msg) #if LWIP_TCP msg->conn->state = NETCONN_WRITE; /* set all the variables used by do_writemore */ + LWIP_ASSERT("already writing", msg->conn->write_msg == NULL && + msg->conn->write_offset == 0); msg->conn->write_msg = msg; msg->conn->write_offset = 0; #if LWIP_TCPIP_CORE_LOCKING diff --git a/net/lwip/src/api/err.c b/net/lwip/src/api/err.c index a803a729d..a90cb98c8 100644 --- a/net/lwip/src/api/err.c +++ b/net/lwip/src/api/err.c @@ -44,17 +44,17 @@ static const char *err_strerr[] = { "Ok.", /* ERR_OK 0 */ "Out of memory error.", /* ERR_MEM -1 */ "Buffer error.", /* ERR_BUF -2 */ - "Routing problem.", /* ERR_RTE -3 */ - "Connection aborted.", /* ERR_ABRT -4 */ - "Connection reset.", /* ERR_RST -5 */ - "Connection closed.", /* ERR_CLSD -6 */ - "Not connected.", /* ERR_CONN -7 */ - "Illegal value.", /* ERR_VAL -8 */ - "Illegal argument.", /* ERR_ARG -9 */ - "Address in use.", /* ERR_USE -10 */ - "Low-level netif error.", /* ERR_IF -11 */ - "Already connected.", /* ERR_ISCONN -12 */ - "Timeout.", /* ERR_TIMEOUT -13 */ + "Timeout.", /* ERR_TIMEOUT -3 */ + "Routing problem.", /* ERR_RTE -4 */ + "Connection aborted.", /* ERR_ABRT -5 */ + "Connection reset.", /* ERR_RST -6 */ + "Connection closed.", /* ERR_CLSD -7 */ + "Not connected.", /* ERR_CONN -8 */ + "Illegal value.", /* ERR_VAL -9 */ + "Illegal argument.", /* ERR_ARG -10 */ + "Address in use.", /* ERR_USE -11 */ + "Low-level netif error.", /* ERR_IF -12 */ + "Already connected.", /* ERR_ISCONN -13 */ "Operation in progress." /* ERR_INPROGRESS -14 */ }; diff --git a/net/lwip/src/api/netbuf.c b/net/lwip/src/api/netbuf.c index 27120eb51..af44eefc7 100644 --- a/net/lwip/src/api/netbuf.c +++ b/net/lwip/src/api/netbuf.c @@ -158,14 +158,14 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) * Chain one netbuf to another (@see pbuf_chain) * * @param head the first netbuf - * @param tail netbuf to chain after head + * @param tail netbuf to chain after head, freed by this function, may not be reference after returning */ void netbuf_chain(struct netbuf *head, struct netbuf *tail) { LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;); LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); - pbuf_chain(head->p, tail->p); + pbuf_cat(head->p, tail->p); head->ptr = head->p; memp_free(MEMP_NETBUF, tail); } diff --git a/net/lwip/src/api/netdb.c b/net/lwip/src/api/netdb.c index d1f134ce7..8aa237f4c 100644 --- a/net/lwip/src/api/netdb.c +++ b/net/lwip/src/api/netdb.c @@ -42,6 +42,9 @@ #include "lwip/ip_addr.h" #include "lwip/api.h" +#include +#include + /** helper struct for gethostbyname_r to access the char* buffer */ struct gethostbyname_r_helper { struct ip_addr *addrs; @@ -107,23 +110,23 @@ lwip_gethostbyname(const char *name) #if DNS_DEBUG /* dump hostent */ - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == 0x%08lX\n",(u32_t)(s_hostent.h_aliases))); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases)); if (s_hostent.h_aliases != NULL) { u8_t idx; for ( idx=0; s_hostent.h_aliases[idx]; idx++) { - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == 0x%08lX\n", idx, s_hostent.h_aliases[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_addrtype == %lu\n", (u32_t)(s_hostent.h_addrtype))); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %lu\n", (u32_t)(s_hostent.h_length))); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == 0x%08lX\n", s_hostent.h_addr_list)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list)); if (s_hostent.h_addr_list != NULL) { u8_t idx; for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == 0x%08lX\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] == %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]))))); } } #endif /* DNS_DEBUG */ @@ -326,7 +329,8 @@ lwip_getaddrinfo(const char *nodename, const char *servname, if (nodename != NULL) { /* copy nodename to canonname if specified */ size_t namelen = strlen(nodename); - ai->ai_canonname = mem_malloc(namelen + 1); + 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; } diff --git a/net/lwip/src/api/sockets.c b/net/lwip/src/api/sockets.c index 58c8e265d..f177261e1 100644 --- a/net/lwip/src/api/sockets.c +++ b/net/lwip/src/api/sockets.c @@ -66,7 +66,7 @@ struct lwip_socket { u16_t lastoffset; /** number of times data was received, set by event_callback(), tested by the receive and select functions */ - u16_t rcvevent; + s16_t rcvevent; /** number of times data was received, set by event_callback(), tested by select */ u16_t sendevent; @@ -128,17 +128,17 @@ static const int err_to_errno_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ ENOMEM, /* ERR_MEM -1 Out of memory error. */ ENOBUFS, /* ERR_BUF -2 Buffer error. */ - EHOSTUNREACH, /* ERR_RTE -3 Routing problem. */ - ECONNABORTED, /* ERR_ABRT -4 Connection aborted. */ - ECONNRESET, /* ERR_RST -5 Connection reset. */ - ESHUTDOWN, /* ERR_CLSD -6 Connection closed. */ - ENOTCONN, /* ERR_CONN -7 Not connected. */ - EINVAL, /* ERR_VAL -8 Illegal value. */ - EIO, /* ERR_ARG -9 Illegal argument. */ - EADDRINUSE, /* ERR_USE -10 Address in use. */ - -1, /* ERR_IF -11 Low-level netif error */ - -1, /* ERR_ISCONN -12 Already connected. */ - ETIMEDOUT, /* ERR_TIMEOUT -13 Timeout */ + ETIMEDOUT, /* ERR_TIMEOUT -3 Timeout */ + EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + ECONNABORTED, /* ERR_ABRT -5 Connection aborted. */ + ECONNRESET, /* ERR_RST -6 Connection reset. */ + ESHUTDOWN, /* ERR_CLSD -7 Connection closed. */ + ENOTCONN, /* ERR_CONN -8 Not connected. */ + EINVAL, /* ERR_VAL -9 Illegal value. */ + EIO, /* ERR_ARG -10 Illegal argument. */ + EADDRINUSE, /* ERR_USE -11 Address in use. */ + -1, /* ERR_IF -12 Low-level netif error */ + -1, /* ERR_ISCONN -13 Already connected. */ EINPROGRESS /* ERR_INPROGRESS -14 Operation in progress */ }; @@ -150,7 +150,9 @@ static const int err_to_errno_table[] = { err_to_errno_table[-(err)] : EIO) #ifdef ERRNO +#ifndef set_errno #define set_errno(err) errno = (err) +#endif #else #define set_errno(err) #endif @@ -258,6 +260,12 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) if (!sock) return -1; + if ((sock->flags & O_NONBLOCK) && (sock->rcvevent <= 0)) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); + sock_set_errno(sock, EWOULDBLOCK); + return -1; + } + newconn = netconn_accept(sock->conn); if (!newconn) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err)); @@ -273,16 +281,22 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) return -1; } - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = naddr.addr; + /* Note that POSIX only requires us to check addr is non-NULL. addrlen must + * not be NULL if addr is valid. + */ + if (NULL != addr) { + LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = naddr.addr; - if (*addrlen > sizeof(sin)) - *addrlen = sizeof(sin); + if (*addrlen > sizeof(sin)) + *addrlen = sizeof(sin); - SMEMCPY(addr, &sin, *addrlen); + MEMCPY(addr, &sin, *addrlen); + } newsock = alloc_socket(newconn); if (newsock == -1) { @@ -307,14 +321,14 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); ip_addr_debug_print(SOCKETS_DEBUG, &naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port)); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); sock_set_errno(sock, 0); return newsock; } int -lwip_bind(int s, struct sockaddr *name, socklen_t namelen) +lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) { struct lwip_socket *sock; struct ip_addr local_addr; @@ -326,15 +340,15 @@ lwip_bind(int s, struct sockaddr *name, socklen_t namelen) return -1; LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - ((((struct sockaddr_in *)name)->sin_family) == AF_INET)), + ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; - local_port = ((struct sockaddr_in *)name)->sin_port; + local_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr; + local_port = ((const struct sockaddr_in *)name)->sin_port; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port))); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); @@ -386,22 +400,22 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) return -1; LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - ((((struct sockaddr_in *)name)->sin_family) == AF_INET)), + ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) { + if (((const struct sockaddr_in *)name)->sin_family == AF_UNSPEC) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); err = netconn_disconnect(sock->conn); } else { struct ip_addr remote_addr; u16_t remote_port; - remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; - remote_port = ((struct sockaddr_in *)name)->sin_port; + remote_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr; + remote_port = ((const struct sockaddr_in *)name)->sin_port; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port))); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); } @@ -458,7 +472,7 @@ lwip_listen(int s, int backlog) } int -lwip_recvfrom(int s, void *mem, int len, unsigned int flags, +lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { struct lwip_socket *sock; @@ -468,7 +482,7 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags, u16_t port; u8_t done = 0; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); sock = get_socket(s); if (!sock) return -1; @@ -480,7 +494,13 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags, buf = sock->lastdata; } else { /* If this is non-blocking call, then check first */ - if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) { + if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && + (sock->rcvevent <= 0)) { + if (off > 0) { + /* already received data, return that */ + sock_set_errno(sock, 0); + return off; + } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); sock_set_errno(sock, EWOULDBLOCK); return -1; @@ -492,22 +512,29 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags, LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf)); if (!buf) { + if (off > 0) { + /* already received data, return that */ + sock_set_errno(sock, 0); + return off; + } /* We should really do some error checking here. */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s)); - sock_set_errno(sock, (((sock->conn->pcb.ip!=NULL) && (sock->conn->err==ERR_OK))?ETIMEDOUT:err_to_errno(sock->conn->err))); + sock_set_errno(sock, (((sock->conn->pcb.ip != NULL) && (sock->conn->err == ERR_OK)) + ? ETIMEDOUT : err_to_errno(sock->conn->err))); return 0; } } buflen = netbuf_len(buf); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%d len=%d off=%d sock->lastoffset=%d\n", buflen, len, off, sock->lastoffset)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%"U16_F" sock->lastoffset=%"U16_F"\n", + buflen, len, off, sock->lastoffset)); buflen -= sock->lastoffset; if (len > buflen) { copylen = buflen; } else { - copylen = len; + copylen = (u16_t)len; } /* copy the contents of the received buffer into @@ -517,20 +544,71 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags, off += copylen; 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) { + if ( (len <= 0) || + (buf->p->flags & PBUF_FLAG_PUSH) || + (sock->rcvevent <= 0) || + ((flags & MSG_PEEK)!=0)) { done = 1; } } else { done = 1; } + /* Check to see from where the data was.*/ + if (done) { + if (from && fromlen) { + struct sockaddr_in sin; + + if (netconn_type(sock->conn) == NETCONN_TCP) { + addr = (struct ip_addr*)&(sin.sin_addr.s_addr); + netconn_getaddr(sock->conn, addr, &port, 0); + } else { + addr = netbuf_fromaddr(buf); + port = netbuf_fromport(buf); + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = addr->addr; + + if (*fromlen > sizeof(sin)) { + *fromlen = sizeof(sin); + } + + MEMCPY(from, &sin, *fromlen); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off)); + } else { + #if SOCKETS_DEBUG + struct sockaddr_in sin; + + if (netconn_type(sock->conn) == NETCONN_TCP) { + addr = (struct ip_addr*)&(sin.sin_addr.s_addr); + netconn_getaddr(sock->conn, addr, &port, 0); + } else { + addr = netbuf_fromaddr(buf); + port = netbuf_fromport(buf); + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off)); + #endif /* SOCKETS_DEBUG */ + } + } + /* If we don't peek the incoming message... */ if ((flags & MSG_PEEK)==0) { /* If this is a TCP socket, check if there is data left in the buffer. If so, it should be saved in the sock structure for next time around. */ - if ((sock->conn->type == NETCONN_TCP) && (buflen - copylen > 0)) { + if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { sock->lastdata = buf; sock->lastoffset += copylen; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf)); @@ -540,85 +618,39 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags, LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf)); netbuf_delete(buf); } - } else { - done = 1; } } while (!done); - /* Check to see from where the data was.*/ - if (from && fromlen) { - struct sockaddr_in sin; - - if (netconn_type(sock->conn) == NETCONN_TCP) { - addr = (struct ip_addr*)&(sin.sin_addr.s_addr); - netconn_getaddr(sock->conn, addr, &port, 0); - } else { - addr = netbuf_fromaddr(buf); - port = netbuf_fromport(buf); - } - - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = addr->addr; - - if (*fromlen > sizeof(sin)) - *fromlen = sizeof(sin); - - SMEMCPY(from, &sin, *fromlen); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off)); - } else { -#if SOCKETS_DEBUG - struct sockaddr_in sin; - - if (netconn_type(sock->conn) == NETCONN_TCP) { - addr = (struct ip_addr*)&(sin.sin_addr.s_addr); - netconn_getaddr(sock->conn, addr, &port, 0); - } else { - addr = netbuf_fromaddr(buf); - port = netbuf_fromport(buf); - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off)); -#endif /* SOCKETS_DEBUG */ - } - sock_set_errno(sock, 0); return off; } int -lwip_read(int s, void *mem, int len) +lwip_read(int s, void *mem, size_t len) { return lwip_recvfrom(s, mem, len, 0, NULL, NULL); } int -lwip_recv(int s, void *mem, int len, unsigned int flags) +lwip_recv(int s, void *mem, size_t len, int flags) { return lwip_recvfrom(s, mem, len, flags, NULL, NULL); } int -lwip_send(int s, const void *data, int size, unsigned int flags) +lwip_send(int s, const void *data, size_t size, int flags) { struct lwip_socket *sock; err_t err; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", s, data, size, flags)); sock = get_socket(s); if (!sock) return -1; - if (sock->conn->type!=NETCONN_TCP) { + if (sock->conn->type != NETCONN_TCP) { #if (LWIP_UDP || LWIP_RAW) return lwip_sendto(s, data, size, flags, NULL, 0); #else @@ -629,18 +661,19 @@ lwip_send(int s, const void *data, int size, unsigned int flags) err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0)); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%d\n", s, err, size)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size)); sock_set_errno(sock, err_to_errno(err)); - return (err==ERR_OK?size:-1); + return (err == ERR_OK ? (int)size : -1); } int -lwip_sendto(int s, const void *data, int size, unsigned int flags, - struct sockaddr *to, socklen_t tolen) +lwip_sendto(int s, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) { struct lwip_socket *sock; struct ip_addr remote_addr; - int err; + err_t err; + u16_t short_size; #if !LWIP_TCPIP_CORE_LOCKING struct netbuf buf; u16_t remote_port; @@ -650,7 +683,7 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags, if (!sock) return -1; - if (sock->conn->type==NETCONN_TCP) { + if (sock->conn->type == NETCONN_TCP) { #if LWIP_TCP return lwip_send(s, data, size, flags); #else @@ -659,11 +692,11 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags, #endif /* LWIP_TCP */ } - LWIP_ASSERT("lwip_sendto: size must fit in u16_t", - ((size >= 0) && (size <= 0xffff))); + LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); + short_size = (u16_t)size; LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || ((tolen == sizeof(struct sockaddr_in)) && - ((((struct sockaddr_in *)to)->sin_family) == AF_INET))), + ((((const struct sockaddr_in *)to)->sin_family) == AF_INET))), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); #if LWIP_TCPIP_CORE_LOCKING @@ -675,15 +708,15 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags, err = ERR_MEM; } else { p->payload = (void*)data; - p->len = p->tot_len = size; + p->len = p->tot_len = short_size; - remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; + 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); } else { - err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((struct sockaddr_in *)to)->sin_port)); + err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((const struct sockaddr_in *)to)->sin_port)); } UNLOCK_TCPIP_CORE(); @@ -694,8 +727,8 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags, /* initialize a buffer */ buf.p = buf.ptr = NULL; if (to) { - remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; - remote_port = ntohs(((struct sockaddr_in *)to)->sin_port); + remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr; + remote_port = ntohs(((const struct sockaddr_in *)to)->sin_port); buf.addr = &remote_addr; buf.port = remote_port; } else { @@ -705,24 +738,32 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags, buf.port = 0; } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", - s, data, size, flags)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=", + s, data, short_size, flags)); ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", remote_port)); - + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); + /* make the buffer point to the data that should be sent */ - if ((err = netbuf_ref(&buf, data, size)) == ERR_OK) { +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Allocate a new netbuf and copy the data into it. */ + if (netbuf_alloc(&buf, short_size) == NULL) { + err = ERR_MEM; + } else { + err = netbuf_take(&buf, data, short_size); + } +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + err = netbuf_ref(&buf, data, short_size); +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (err == ERR_OK) { /* send the data */ err = netconn_send(sock->conn, &buf); } /* deallocated the buffer */ - if (buf.p != NULL) { - pbuf_free(buf.p); - } + netbuf_free(&buf); #endif /* LWIP_TCPIP_CORE_LOCKING */ sock_set_errno(sock, err_to_errno(err)); - return (err==ERR_OK?size:-1); + return (err == ERR_OK ? short_size : -1); } int @@ -778,7 +819,7 @@ lwip_socket(int domain, int type, int protocol) } int -lwip_write(int s, const void *data, int size) +lwip_write(int s, const void *data, size_t size) { return lwip_send(s, data, size, 0); } @@ -815,7 +856,7 @@ lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset) if (FD_ISSET(i, readset)) { /* See if netconn of this socket is ready for read */ p_sock = get_socket(i); - if (p_sock && (p_sock->lastdata || p_sock->rcvevent)) { + if (p_sock && (p_sock->lastdata || (p_sock->rcvevent > 0))) { FD_SET(i, &lreadset); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); nready++; @@ -855,7 +896,8 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, - timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L)); + timeout ? (long)timeout->tv_sec : (long)-1, + timeout ? (long)timeout->tv_usec : (long)-1)); select_cb.next = 0; select_cb.readset = readset; @@ -923,15 +965,8 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, if(msectimeout == 0) msectimeout = 1; } - - if (msectimeout > 0 && 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); - } - else { - /* it's a lwip thread, use os semaphore with timeout to handle it */ - i = sys_sem_wait_timeout(select_cb.sem, msectimeout); - } + + i = sys_sem_wait_timeout(select_cb.sem, msectimeout); /* Take us off the list */ sys_sem_wait(selectsem); @@ -1069,7 +1104,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) if (scb->sem_signalled == 0) { /* Test this select call for our socket */ if (scb->readset && FD_ISSET(s, scb->readset)) - if (sock->rcvevent) + if (sock->rcvevent > 0) break; if (scb->writeset && FD_ISSET(s, scb->writeset)) if (sock->sendevent) @@ -1078,8 +1113,8 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) } if (scb) { scb->sem_signalled = 1; - sys_sem_signal(selectsem); sys_sem_signal(scb->sem); + sys_sem_signal(selectsem); } else { sys_sem_signal(selectsem); break; @@ -1119,7 +1154,7 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, &naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port)); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); sin.sin_port = htons(sin.sin_port); sin.sin_addr.s_addr = naddr.addr; @@ -1127,7 +1162,7 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) if (*namelen > sizeof(sin)) *namelen = sizeof(sin); - SMEMCPY(name, &sin, *namelen); + MEMCPY(name, &sin, *namelen); sock_set_errno(sock, 0); return 0; } @@ -1444,7 +1479,7 @@ lwip_getsockopt_internal(void *arg) break; case IP_MULTICAST_IF: ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%x\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", s, *(u32_t *)optval)); break; #endif /* LWIP_IGMP */ @@ -1777,12 +1812,12 @@ lwip_setsockopt_internal(void *arg) switch (optname) { case IP_TTL: sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", s, sock->conn->pcb.ip->ttl)); break; case IP_TOS: sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", s, sock->conn->pcb.ip->tos)); break; #if LWIP_IGMP @@ -1826,24 +1861,24 @@ lwip_setsockopt_internal(void *arg) break; case TCP_KEEPALIVE: sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", s, sock->conn->pcb.tcp->keep_idle)); break; #if LWIP_TCP_KEEPALIVE case TCP_KEEPIDLE: sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %lu\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", s, sock->conn->pcb.tcp->keep_idle)); break; case TCP_KEEPINTVL: sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %lu\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", s, sock->conn->pcb.tcp->keep_intvl)); break; case TCP_KEEPCNT: sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %lu\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", s, sock->conn->pcb.tcp->keep_cnt)); break; #endif /* LWIP_TCP_KEEPALIVE */ @@ -1887,6 +1922,7 @@ lwip_ioctl(int s, long cmd, void *argp) { struct lwip_socket *sock = get_socket(s); u16_t buflen = 0; + s16_t recv_avail; if (!sock) return -1; @@ -1898,7 +1934,10 @@ lwip_ioctl(int s, long cmd, void *argp) return -1; } - SYS_ARCH_GET(sock->conn->recv_avail, *((u16_t*)argp)); + SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); + if (recv_avail < 0) + recv_avail = 0; + *((u16_t*)argp) = (u16_t)recv_avail; /* Check if there is data left from the last recv operation. /maq 041215 */ if (sock->lastdata) { @@ -1908,7 +1947,7 @@ lwip_ioctl(int s, long cmd, void *argp) *((u16_t*)argp) += buflen; } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp))); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); sock_set_errno(sock, 0); return 0; diff --git a/net/lwip/src/api/tcpip.c b/net/lwip/src/api/tcpip.c index 97ae41db5..002df90b2 100644 --- a/net/lwip/src/api/tcpip.c +++ b/net/lwip/src/api/tcpip.c @@ -297,11 +297,12 @@ tcpip_thread(void *arg) case TCPIP_MSG_TIMEOUT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); - - if(msg->msg.tmo.msecs != 0xffffffff) - sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); - else - sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg); + sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + case TCPIP_MSG_UNTIMEOUT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); + sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); memp_free(MEMP_TCPIP_MSG_API, msg); break; @@ -379,6 +380,14 @@ tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block) return ERR_VAL; } +/** + * call sys_timeout in tcpip_thread + * + * @param msec time in miliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) { @@ -400,6 +409,34 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) return ERR_VAL; } +/** + * call sys_untimeout in tcpip_thread + * + * @param msec time in miliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_untimeout(sys_timeout_handler h, void *arg) +{ + struct tcpip_msg *msg; + + if (mbox != SYS_MBOX_NULL) { + msg = memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_UNTIMEOUT; + msg->msg.tmo.h = h; + msg->msg.tmo.arg = arg; + sys_mbox_post(mbox, msg); + return ERR_OK; + } + return ERR_VAL; +} + #if LWIP_NETCONN /** * Call the lower part of a netconn_* function @@ -518,4 +555,42 @@ tcpip_init(void (* initfunc)(void *), void *arg) sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); } +/** + * Simple callback function used with tcpip_callback to free a pbuf + * (pbuf_free has a wrong signature for tcpip_callback) + * + * @param p The pbuf (chain) to be dereferenced. + */ +static void +pbuf_free_int(void *p) +{ + struct pbuf *q = p; + pbuf_free(q); +} + +/** + * A simple wrapper function that allows you to free a pbuf from interrupt context. + * + * @param p The pbuf (chain) to be dereferenced. + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +pbuf_free_callback(struct pbuf *p) +{ + return tcpip_callback_with_block(pbuf_free_int, p, 0); +} + +/** + * A simple wrapper function that allows you to free heap memory from + * interrupt context. + * + * @param m the heap memory to free + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +mem_free_callback(void *m) +{ + return tcpip_callback_with_block(mem_free, m, 0); +} + #endif /* !NO_SYS */ diff --git a/net/lwip/src/arch/include/arch/cc.h b/net/lwip/src/arch/include/arch/cc.h index 6fdb9f24c..00b14bd83 100644 --- a/net/lwip/src/arch/include/arch/cc.h +++ b/net/lwip/src/arch/include/arch/cc.h @@ -76,9 +76,10 @@ typedef rt_uint32_t mem_ptr_t; #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END #endif - + +void sys_arch_assert(const char* file, int line); #define LWIP_PLATFORM_DIAG(x) do {rt_kprintf x;} while(0) -#define LWIP_PLATFORM_ASSERT(x) {RT_ASSERT(x);} +#define LWIP_PLATFORM_ASSERT(x) { rt_kprintf(x); sys_arch_assert(__FILE__, __LINE__); } #define SYS_ARCH_DECL_PROTECT(x) #define SYS_ARCH_PROTECT(x) diff --git a/net/lwip/src/arch/sys.c b/net/lwip/src/arch/sys.c deleted file mode 100644 index e0b733f88..000000000 --- a/net/lwip/src/arch/sys.c +++ /dev/null @@ -1,137 +0,0 @@ -#include "lwip/opt.h" -#include - -#if (NO_SYS == 0) -/* don't build if not configured for use in lwipopts.h */ -#include "lwip/sys.h" -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/tcpip.h" - -/* RT-Thread kernel object */ -#define rt_list_entry(node, type, member) \ - ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member))) -extern struct rt_object_information rt_object_container[]; - -/** - * Wait (forever) for a message to arrive in an mbox. - * While waiting, timeouts (for this thread) are processed. - * - * @param mbox the mbox to fetch the message from - * @param msg the place to store the message - */ -void -sys_mbox_fetch(sys_mbox_t mbox, void **msg) -{ - rt_mb_recv(mbox, (rt_uint32_t *)msg, RT_WAITING_FOREVER); -} - -/** - * Wait (forever) for a semaphore to become available. - * While waiting, timeouts (for this thread) are processed. - * - * @param sem semaphore to wait for - */ -void -sys_sem_wait(sys_sem_t sem) -{ - rt_sem_take(sem, RT_WAITING_FOREVER); -} - -/** - * Create a one-shot timer (aka timeout). Timeouts are processed in the - * following cases: - * - while waiting for a message using sys_mbox_fetch() - * - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout() - * - while sleeping using the inbuilt sys_msleep() - * - * @param msecs time in milliseconds after that the timer should expire - * @param h callback function to call when msecs have elapsed - * @param arg argument to pass to the callback function - */ -void -sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg) -{ - rt_timer_t timer; - static int counter = 0; - char tname[RT_NAME_MAX]; - - rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_TIMER_NAME, counter); - counter ++; - - /* create timer and start it */ - timer = rt_timer_create(tname, h, arg, msecs, RT_TIMER_FLAG_ONE_SHOT); - rt_timer_start(timer); -} - -/** - * Go through timeout list (for this task only) and remove the first matching - * entry, even though the timeout has not triggered yet. - * - * @note This function only works as expected if there is only one timeout - * calling 'h' in the list of timeouts. - * - * @param h callback function that would be called by the timeout - * @param arg callback argument that would be passed to h -*/ -void -sys_untimeout(sys_timeout_handler h, void *arg) -{ - rt_base_t level; - struct rt_list_node *list, *node; - struct rt_timer *timer = RT_NULL; - - /* lock interrupt */ - level = rt_hw_interrupt_disable(); - - /* find related timer */ - list = &rt_object_container[RT_Object_Class_Timer].object_list; - for (node = list->next; node != list; node = node->next) - { - timer = (struct rt_timer*)(rt_list_entry(node, struct rt_object, list)); - if (timer->timeout_func == h && timer->parameter == arg) - { - break; - } - } - - /* enable interrupt */ - rt_hw_interrupt_enable(level); - - /* remove this timer */ - if (timer != RT_NULL) - rt_timer_delete(timer); -} - -/** - * Wait for a semaphore with timeout (specified in ms) - * - * @param sem semaphore to wait - * @param timeout timeout in ms (0: wait forever) - * @return 0 on timeout, 1 otherwise - */ -int -sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout) -{ - rt_err_t err; - - if (timeout == 0) err = rt_sem_take(sem, RT_WAITING_FOREVER); - else err = rt_sem_take(sem, timeout); - - if (err != RT_EOK) return 0; - - return 1; -} - -/** - * Sleep for some ms. Timeouts are processed while sleeping. - * - * @param ms number of milliseconds to sleep - */ -void -sys_msleep(u32_t ms) -{ - rt_thread_delay(ms); -} - -#endif diff --git a/net/lwip/src/arch/sys_arch.c b/net/lwip/src/arch/sys_arch.c index 0eb131f80..267d6ddaf 100644 --- a/net/lwip/src/arch/sys_arch.c +++ b/net/lwip/src/arch/sys_arch.c @@ -83,7 +83,10 @@ u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) { rt_err_t ret; s32_t t; + u32_t tick; + /* get the begin tick */ + tick = rt_tick_get(); #ifdef LWIP_DEBUG { struct rt_thread *thread; @@ -108,7 +111,14 @@ u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) if (ret == -RT_ETIMEOUT) return SYS_ARCH_TIMEOUT; else if (ret == RT_EOK) ret = 1; - return ret; + /* get elapse msecond */ + tick = rt_tick_get() - tick; + + /* convert tick to msecond */ + tick = tick * (1000/RT_TICK_PER_SECOND); + if (tick == 0) tick = 1; + + return tick; } sys_mbox_t sys_mbox_new(int size) @@ -187,6 +197,10 @@ u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) { rt_err_t ret; s32_t t; + u32_t tick; + + /* get the begin tick */ + tick = rt_tick_get(); if(timeout == 0) t = RT_WAITING_FOREVER; @@ -212,7 +226,14 @@ u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) } #endif - return ret; + /* get elapse msecond */ + tick = rt_tick_get() - tick; + + /* convert tick to msecond */ + tick = tick * (1000/RT_TICK_PER_SECOND); + if (tick == 0) tick = 1; + + return tick; } u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) @@ -290,3 +311,9 @@ void sys_arch_unprotect(sys_prot_t pval) return; } + +void sys_arch_assert(const char* file, int line) +{ + rt_kprintf("Assertion: %d in %s\n", line, file); + RT_ASSERT(0); +} diff --git a/net/lwip/src/core/dhcp.c b/net/lwip/src/core/dhcp.c index b11f668b7..df0f97881 100644 --- a/net/lwip/src/core/dhcp.c +++ b/net/lwip/src/core/dhcp.c @@ -86,10 +86,19 @@ #include -/** global transaction identifier, must be - * unique for each DHCP request. We simply increment, starting - * with this value (easy to match with a packet analyzer) */ -static u32_t xid = 0xABCD0000; +/** Default for DHCP_GLOBAL_XID is 0xABCD0000 + * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. + * #define DHCP_GLOBAL_XID_HEADER "stdlib.h" + * #define DHCP_GLOBAL_XID rand() + */ +#ifdef DHCP_GLOBAL_XID_HEADER +#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ +#endif + +/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU + * 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 /* DHCP client state machine functions */ static void dhcp_handle_ack(struct netif *netif); @@ -152,14 +161,14 @@ 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 | 3, ("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); /* remove IP address from interface */ netif_set_ipaddr(netif, IP_ADDR_ANY); netif_set_gw(netif, IP_ADDR_ANY); - netif_set_netmask(netif, IP_ADDR_ANY); + netif_set_netmask(netif, IP_ADDR_ANY); /* Change to a defined state */ dhcp_set_state(dhcp, DHCP_BACKING_OFF); /* We can immediately restart discovery */ @@ -183,6 +192,7 @@ dhcp_check(struct netif *netif) 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], (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); @@ -193,7 +203,6 @@ dhcp_check(struct netif *netif) 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)); - dhcp_set_state(dhcp, DHCP_CHECKING); } /** @@ -239,6 +248,7 @@ dhcp_select(struct netif *netif) #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)); + dhcp_set_state(dhcp, DHCP_REQUESTING); /* create and initialize the DHCP message header */ result = dhcp_create_request(netif); @@ -247,7 +257,7 @@ dhcp_select(struct netif *netif) 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_short(dhcp, DHCP_MAX_MSG_LEN(netif)); /* MUST request the offered IP address */ dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); @@ -264,7 +274,7 @@ dhcp_select(struct netif *netif) #if LWIP_NETIF_HOSTNAME p = (const char*)netif->hostname; - if (p!=NULL) { + if (p != NULL) { dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); while (*p) { dhcp_option_byte(dhcp, *p++); @@ -284,12 +294,11 @@ dhcp_select(struct netif *netif) 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")); - dhcp_set_state(dhcp, DHCP_REQUESTING); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n")); } dhcp->tries++; - msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000; + msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); return result; @@ -330,7 +339,7 @@ dhcp_coarse_tmr() * * A DHCP server is expected to respond within a short period of time. * This timer checks whether an outstanding DHCP request is timed out. - * + * */ void dhcp_fine_tmr() @@ -340,7 +349,7 @@ dhcp_fine_tmr() while (netif != NULL) { /* only act on DHCP configured interfaces */ if (netif->dhcp != NULL) { - /* timer is active (non zero), and is about to trigger now */ + /* timer is active (non zero), and is about to trigger now */ if (netif->dhcp->request_timeout > 1) { netif->dhcp->request_timeout--; } @@ -526,7 +535,7 @@ dhcp_handle_ack(struct netif *netif) if (option_ptr != NULL) { dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); } - + /* DNS servers */ option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER); if (option_ptr != NULL) { @@ -539,8 +548,6 @@ dhcp_handle_ack(struct netif *netif) dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4])); #if LWIP_DNS dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr))); - /* added by Puxiang Xiong */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_ack(): DNS server: 0x%08"X32_F"\n", dhcp->offered_dns_addr[n].addr)); #endif /* LWIP_DNS */ } #if LWIP_DNS @@ -570,8 +577,16 @@ dhcp_start(struct netif *netif) LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* Remove the flag that says this netif is handled by DHCP, + it is set when we succeeded starting. */ netif->flags &= ~NETIF_FLAG_DHCP; + /* check MTU of the netif */ + if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); + return ERR_MEM; + } + /* no DHCP client attached yet? */ if (dhcp == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); @@ -586,8 +601,14 @@ dhcp_start(struct netif *netif) /* already has DHCP client attached */ } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n")); + if (dhcp->pcb != NULL) { + udp_remove(dhcp->pcb); + } + if (dhcp->p != NULL) { + pbuf_free(dhcp->p); + } } - + /* clear data structure */ memset(dhcp, 0, sizeof(struct dhcp)); /* allocate UDP PCB */ @@ -598,6 +619,9 @@ dhcp_start(struct netif *netif) netif->dhcp = dhcp = NULL; return ERR_MEM; } +#if IP_SOF_BROADCAST + dhcp->pcb->so_options|=SOF_BROADCAST; +#endif /* IP_SOF_BROADCAST */ /* set up local and remote port for the pcb */ udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); @@ -611,6 +635,7 @@ dhcp_start(struct netif *netif) dhcp_stop(netif); return ERR_MEM; } + /* Set the flag that says this netif is handled by DHCP. */ netif->flags |= NETIF_FLAG_DHCP; return result; } @@ -653,13 +678,15 @@ dhcp_inform(struct netif *netif) dhcp_option_byte(dhcp, DHCP_INFORM); dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - /* TODO: use netif->mtu ?! */ - dhcp_option_short(dhcp, 576); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); dhcp_option_trailer(dhcp); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); +#if IP_SOF_BROADCAST + 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")); @@ -670,14 +697,12 @@ dhcp_inform(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n")); } - if (dhcp != NULL) { - if (dhcp->pcb != NULL) { - udp_remove(dhcp->pcb); - } - dhcp->pcb = NULL; - mem_free((void *)dhcp); - netif->dhcp = old_dhcp; + if (dhcp->pcb != NULL) { + udp_remove(dhcp->pcb); } + dhcp->pcb = NULL; + mem_free((void *)dhcp); + netif->dhcp = old_dhcp; } #if DHCP_DOES_ARP_CHECK @@ -727,9 +752,6 @@ dhcp_decline(struct netif *netif) dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); dhcp_option_byte(dhcp, DHCP_DECLINE); - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, 576); - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); @@ -768,6 +790,7 @@ dhcp_discover(struct netif *netif) u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("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 */ result = dhcp_create_request(netif); if (result == ERR_OK) { @@ -776,7 +799,7 @@ dhcp_discover(struct netif *netif) dhcp_option_byte(dhcp, DHCP_DISCOVER); dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, 576); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); @@ -795,19 +818,17 @@ dhcp_discover(struct netif *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")); - dhcp_set_state(dhcp, DHCP_SELECTING); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n")); } dhcp->tries++; #if LWIP_DHCP_AUTOIP_COOP - /* that means we waited 57 seconds */ - if(dhcp->tries >= 9 && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { + if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; autoip_start(netif); } #endif /* LWIP_DHCP_AUTOIP_COOP */ - msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000; + msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 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_discover(): set request timeout %"U16_F" msecs\n", msecs)); return result; @@ -883,6 +904,13 @@ dhcp_bind(struct netif *netif) gw_addr.addr |= htonl(0x00000001); } +#if LWIP_DHCP_AUTOIP_COOP + if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr)); netif_set_ipaddr(netif, &dhcp->offered_ip_addr); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr)); @@ -906,6 +934,9 @@ dhcp_renew(struct netif *netif) struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; +#if LWIP_NETIF_HOSTNAME + const char *p; +#endif /* LWIP_NETIF_HOSTNAME */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n")); dhcp_set_state(dhcp, DHCP_RENEWING); @@ -917,8 +948,17 @@ dhcp_renew(struct netif *netif) dhcp_option_byte(dhcp, DHCP_REQUEST); dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - /* TODO: use netif->mtu in some way */ - dhcp_option_short(dhcp, 576); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +#if LWIP_NETIF_HOSTNAME + p = (const char*)netif->hostname; + if (p != NULL) { + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } + } +#endif /* LWIP_NETIF_HOSTNAME */ #if 0 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); @@ -961,6 +1001,9 @@ dhcp_rebind(struct netif *netif) struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; +#if LWIP_NETIF_HOSTNAME + const char *p; +#endif /* LWIP_NETIF_HOSTNAME */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); dhcp_set_state(dhcp, DHCP_REBINDING); @@ -972,7 +1015,17 @@ dhcp_rebind(struct netif *netif) 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_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +#if LWIP_NETIF_HOSTNAME + p = (const char*)netif->hostname; + if (p != NULL) { + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } + } +#endif /* LWIP_NETIF_HOSTNAME */ #if 0 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); @@ -1022,7 +1075,7 @@ dhcp_release(struct netif *netif) dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0; dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; dhcp->dns_count = 0; - + /* create and initialize the DHCP message header */ result = dhcp_create_request(netif); if (result == ERR_OK) { @@ -1050,7 +1103,7 @@ dhcp_release(struct netif *netif) netif_set_ipaddr(netif, IP_ADDR_ANY); netif_set_gw(netif, IP_ADDR_ANY); netif_set_netmask(netif, IP_ADDR_ANY); - + /* TODO: netif_down(netif); */ return result; } @@ -1065,10 +1118,19 @@ dhcp_stop(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); + /* 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")); /* netif is DHCP configured? */ if (dhcp != NULL) { +#if LWIP_DHCP_AUTOIP_COOP + if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + if (dhcp->pcb != NULL) { udp_remove(dhcp->pcb); dhcp->pcb = NULL; @@ -1305,6 +1367,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_ dhcp_handle_offer(netif); } free_pbuf_and_return: + dhcp_free_reply(dhcp); pbuf_free(p); dhcp->p = NULL; } @@ -1319,6 +1382,20 @@ dhcp_create_request(struct netif *netif) { struct dhcp *dhcp; u16_t i; +#ifndef DHCP_GLOBAL_XID + /** default global transaction identifier starting value (easy to match + * with a packet analyser). We simply increment for each new request. + * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one + * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ + static u32_t xid = 0xABCD0000; +#else + static u32_t xid; + static u8_t xid_initialised = 0; + if (!xid_initialised) { + xid = DHCP_GLOBAL_XID; + xid_initialised = !xid_initialised; + } +#endif LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;); dhcp = netif->dhcp; LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); @@ -1332,9 +1409,12 @@ dhcp_create_request(struct netif *netif) LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg", (dhcp->p_out->len >= sizeof(struct dhcp_msg))); - /* give unique transaction identifier to this request */ - dhcp->xid = xid++; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid)); + /* reuse transaction identifier in retransmissions */ + if (dhcp->tries==0) + xid++; + dhcp->xid = xid; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, + ("transaction id xid(%"X32_F")\n", xid)); dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; @@ -1347,7 +1427,10 @@ dhcp_create_request(struct netif *netif) dhcp->msg_out->xid = htonl(dhcp->xid); dhcp->msg_out->secs = 0; dhcp->msg_out->flags = 0; - dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr; + dhcp->msg_out->ciaddr.addr = 0; + if (dhcp->state==DHCP_BOUND || dhcp->state==DHCP_RENEWING || dhcp->state==DHCP_REBINDING) { + dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr; + } dhcp->msg_out->yiaddr.addr = 0; dhcp->msg_out->siaddr.addr = 0; dhcp->msg_out->giaddr.addr = 0; diff --git a/net/lwip/src/core/dns.c b/net/lwip/src/core/dns.c index 3ba88db0a..62a2592e9 100644 --- a/net/lwip/src/core/dns.c +++ b/net/lwip/src/core/dns.c @@ -127,18 +127,19 @@ PACK_STRUCT_BEGIN /** DNS message header */ struct dns_hdr { - u16_t id; - u8_t flags1; - u8_t flags2; - u16_t numquestions; - u16_t numanswers; - u16_t numauthrr; - u16_t numextrarr; + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u8_t flags1); + PACK_STRUCT_FIELD(u8_t flags2); + PACK_STRUCT_FIELD(u16_t numquestions); + PACK_STRUCT_FIELD(u16_t numanswers); + PACK_STRUCT_FIELD(u16_t numauthrr); + PACK_STRUCT_FIELD(u16_t numextrarr); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif +#define SIZEOF_DNS_HDR 12 #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" @@ -148,13 +149,14 @@ PACK_STRUCT_BEGIN struct dns_query { /* DNS query record starts with either a domain name or a pointer to a name already present somewhere in the packet. */ - u16_t type; - u16_t class; + PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t class); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif +#define SIZEOF_DNS_QUERY 4 #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" @@ -164,15 +166,16 @@ PACK_STRUCT_BEGIN struct dns_answer { /* DNS answer record starts with either a domain name or a pointer to a name already present somewhere in the packet. */ - u16_t type; - u16_t class; - u32_t ttl; - u16_t len; + PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t class); + PACK_STRUCT_FIELD(u32_t ttl); + PACK_STRUCT_FIELD(u16_t len); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif +#define SIZEOF_DNS_ANSWER 10 /** DNS table entry */ struct dns_table_entry { @@ -190,6 +193,40 @@ struct dns_table_entry { void *arg; }; +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { + /** static hostname */ + const char *name; + /** static host address in network byteorder */ + u32_t addr; + struct local_hostlist_entry *next; +}; + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** Local host-list. For hostnames in this list, no + * external name resolution is performed */ +static struct local_hostlist_entry *local_hostlist_dynamic; +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE +#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST +#define DNS_LOCAL_HOSTLIST_STORAGE_POST +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ +DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] + DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; + +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +static void dns_init_local(); +#endif /* DNS_LOCAL_HOSTLIST */ + /* forward declarations */ static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); @@ -241,6 +278,9 @@ dns_init() dns_setserver(0, &dnsserver); } } +#if DNS_LOCAL_HOSTLIST + dns_init_local(); +#endif } /** @@ -288,6 +328,119 @@ dns_tmr(void) } } +#if DNS_LOCAL_HOSTLIST +static void +dns_init_local() +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) + int i; + struct local_hostlist_entry *entry; + /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ + struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; + for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) { + entry = mem_malloc(sizeof(struct local_hostlist_entry)); + LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); + if (entry != NULL) { + struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; + entry->name = init_entry->name; + entry->addr = init_entry->addr; + entry->next = local_hostlist_dynamic; + local_hostlist_dynamic = entry; + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ +} + +/** + * Scans the local host-list for a hostname. + * + * @param hostname Hostname to look for in the local host-list + * @return The first IP address for the hostname in the local host-list or + * INADDR_NONE if not found. + */ +static u32_t +dns_lookup_local(const char *hostname) +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC + struct local_hostlist_entry *entry = local_hostlist_dynamic; + while(entry != NULL) { + if(strcmp(entry->name, hostname) == 0) { + return entry->addr; + } + entry = entry->next; + } +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + int i; + for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) { + if(strcmp(local_hostlist_static[i].name, hostname) == 0) { + return local_hostlist_static[i].addr; + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + return INADDR_NONE; +} + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** Remove all entries from the local host-list for a specific hostname + * and/or IP addess + * + * @param hostname hostname for which entries shall be removed from the local + * host-list + * @param addr address for which entries shall be removed from the local host-list + * @return the number of removed entries + */ +int +dns_local_removehost(const char *hostname, const struct ip_addr *addr) +{ + int removed = 0; + struct local_hostlist_entry *entry = local_hostlist_dynamic; + struct local_hostlist_entry *last_entry = NULL; + while (entry != NULL) { + if (((hostname == NULL) || !strcmp(entry->name, hostname)) && + ((addr == NULL) || (entry->addr == addr->addr))) { + struct local_hostlist_entry *free_entry; + if (last_entry != NULL) { + last_entry->next = entry->next; + } else { + local_hostlist_dynamic = entry->next; + } + free_entry = entry; + entry = entry->next; + mem_free(free_entry); + removed++; + } else { + last_entry = entry; + entry = entry->next; + } + } + return removed; +} + +/** + * Add a hostname/IP address pair to the local host-list. + * Duplicates are not checked. + * + * @param hostname hostname of the new entry + * @param addr IP address of the new entry + * @return ERR_OK if succeeded or ERR_MEM on memory error + */ +err_t +dns_local_addhost(const char *hostname, const struct ip_addr *addr) +{ + struct local_hostlist_entry *entry; + entry = mem_malloc(sizeof(struct local_hostlist_entry)); + if (entry == NULL) { + return ERR_MEM; + } + entry->name = hostname; + entry->addr = addr->addr; + entry->next = local_hostlist_dynamic; + local_hostlist_dynamic = entry; + return ERR_OK; +} +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ +#endif /* DNS_LOCAL_HOSTLIST */ + /** * Look up a hostname in the array of known hostnames. * @@ -298,13 +451,26 @@ dns_tmr(void) * * @param name the hostname to look up * @return the hostname's IP address, as u32_t (instead of struct ip_addr to - * better check for failure: != 0) or 0 if the hostname was not found - * in the cached dns_table. + * better check for failure: != INADDR_NONE) or INADDR_NONE if the hostname + * was not found in the cached dns_table. */ static u32_t dns_lookup(const char *name) { u8_t i; +#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) + u32_t addr; +#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ +#if DNS_LOCAL_HOSTLIST + if ((addr = dns_lookup_local(name)) != INADDR_NONE) { + return addr; + } +#endif /* DNS_LOCAL_HOSTLIST */ +#ifdef DNS_LOOKUP_LOCAL_EXTERN + if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != INADDR_NONE) { + return addr; + } +#endif /* DNS_LOOKUP_LOCAL_EXTERN */ /* Walk through name list, return entry if found. If not, return NULL. */ for (i = 0; i < DNS_TABLE_SIZE; ++i) { @@ -317,7 +483,7 @@ dns_lookup(const char *name) } } - return 0; + return INADDR_NONE; } #if DNS_DOES_NAME_CHECK @@ -415,17 +581,17 @@ dns_send(u8_t numdns, const char* name, u8_t id) LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0); /* if here, we have either a new query or a retry on a previous query to process */ - p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dns_hdr) + DNS_MAX_NAME_LENGTH + - sizeof(struct dns_query), PBUF_RAM); + p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH + + SIZEOF_DNS_QUERY, PBUF_RAM); if (p != NULL) { LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); /* fill dns header */ hdr = (struct dns_hdr*)p->payload; - memset(hdr, 0, sizeof(struct dns_hdr)); + memset(hdr, 0, SIZEOF_DNS_HDR); hdr->id = htons(id); hdr->flags1 = DNS_FLAG1_RD; hdr->numquestions = htons(1); - query = (char*)hdr + sizeof(struct dns_hdr); + query = (char*)hdr + SIZEOF_DNS_HDR; pHostname = name; --pHostname; @@ -446,10 +612,10 @@ dns_send(u8_t numdns, const char* name, u8_t id) /* fill dns query */ qry.type = htons(DNS_RRTYPE_A); qry.class = htons(DNS_RRCLASS_IN); - MEMCPY( query, &qry, sizeof(struct dns_query)); + MEMCPY( query, &qry, SIZEOF_DNS_QUERY); /* resize pbuf to the exact dns query */ - pbuf_realloc(p, (query + sizeof(struct dns_query)) - ((char*)(p->payload))); + pbuf_realloc(p, (query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))); /* connect to the server for faster receiving */ udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT); @@ -591,7 +757,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u } /* is the dns message big enough ? */ - if (p->tot_len < (sizeof(struct dns_hdr) + sizeof(struct dns_query) + sizeof(struct dns_answer))) { + if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); /* free pbuf and return */ goto memerr1; @@ -632,7 +798,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u #if DNS_DOES_NAME_CHECK /* Check if the name in the "question" part match with the name in the entry. */ - if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + sizeof(struct dns_hdr)) != 0) { + if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name)); /* call callback to indicate error, clean up memory and return */ goto responseerr; @@ -640,14 +806,14 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u #endif /* DNS_DOES_NAME_CHECK */ /* Skip the name in the "question" part */ - pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + sizeof(struct dns_hdr)) + sizeof(struct dns_query); + pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY; while(nanswers > 0) { /* skip answer resource record's host name */ pHostname = (char *) dns_parse_name((unsigned char *)pHostname); /* Check for IP address type and Internet class. Others are discarded. */ - MEMCPY(&ans, pHostname, sizeof(struct dns_answer)); + MEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) { /* read the answer resource record's TTL, and maximize it if needed */ pEntry->ttl = ntohl(ans.ttl); @@ -655,7 +821,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u pEntry->ttl = DNS_MAX_TTL; } /* read the IP address after answer resource record's header */ - MEMCPY( &(pEntry->ipaddr), (pHostname+sizeof(struct dns_answer)), sizeof(struct ip_addr)); + MEMCPY( &(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(struct ip_addr)); LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name)); ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr))); LWIP_DEBUGF(DNS_DEBUG, ("\n")); @@ -666,7 +832,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u /* deallocate memory and return */ goto memerr2; } else { - pHostname = pHostname + sizeof(struct dns_answer) + htons(ans.len); + pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len); } --nanswers; } @@ -803,7 +969,7 @@ dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback /* host name already in octet notation? set ip addr and return ERR_OK * already have this address cached? */ if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) || - ((addr->addr = dns_lookup(hostname)) != 0)) { + ((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) { return ERR_OK; } diff --git a/net/lwip/src/core/init.c b/net/lwip/src/core/init.c index 5e0b522c5..277811a6a 100644 --- a/net/lwip/src/core/init.c +++ b/net/lwip/src/core/init.c @@ -50,6 +50,7 @@ #include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcp.h" +#include "lwip/snmp_msg.h" #include "lwip/autoip.h" #include "lwip/igmp.h" #include "lwip/dns.h" @@ -61,6 +62,9 @@ #ifndef BYTE_ORDER #error "BYTE_ORDER is not defined, you have to define it in your cc.h" #endif +#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) + #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" +#endif #if (!LWIP_ARP && ARP_QUEUEING) #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h" #endif @@ -155,6 +159,15 @@ #if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" #endif +#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) + #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" +#endif +#if (TCP_QUEUE_OOSEQ && !LWIP_TCP) + #error "TCP_QUEUE_OOSEQ requires LWIP_TCP" +#endif +#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 /* Compile-time checks for deprecated options. @@ -241,6 +254,9 @@ lwip_init(void) #if LWIP_TCP tcp_init(); #endif /* LWIP_TCP */ +#if LWIP_SNMP + snmp_init(); +#endif /* LWIP_SNMP */ #if LWIP_AUTOIP autoip_init(); #endif /* LWIP_AUTOIP */ diff --git a/net/lwip/src/core/ipv4/autoip.c b/net/lwip/src/core/ipv4/autoip.c index b3920f2ad..367adb060 100644 --- a/net/lwip/src/core/ipv4/autoip.c +++ b/net/lwip/src/core/ipv4/autoip.c @@ -76,7 +76,15 @@ #include #include -/* Pseudo random macro based on netif informations. +/* 169.254.0.0 */ +#define AUTOIP_NET 0xA9FE0000 +/* 169.254.1.0 */ +#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) +/* 169.254.254.255 */ +#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) + + +/** Pseudo random macro based on netif informations. * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ #ifndef LWIP_AUTOIP_RAND #define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ @@ -86,11 +94,21 @@ (netif->autoip?netif->autoip->tried_llipaddr:0)) #endif /* LWIP_AUTOIP_RAND */ +/** + * Macro that generates the initial IP address to be tried by AUTOIP. + * If you want to override this, define it to something else in lwipopts.h. + */ +#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR +#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ + (AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ + ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) +#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ + /* static functions */ static void autoip_handle_arp_conflict(struct netif *netif); -/* creates random LL IP-Address for a network interface */ -static void autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr); +/* creates a pseudo random LL IP-Address for a network interface */ +static void autoip_create_addr(struct netif *netif, struct ip_addr *IPAddr); /* sends an ARP announce */ static err_t autoip_arp_announce(struct netif *netif); @@ -144,30 +162,33 @@ 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 RandomIPAddr ip address to initialize + * @param IPAddr ip address to initialize */ static void -autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr) +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 - * We have 254 * 256 possibilities - */ - - RandomIPAddr->addr = (0xA9FE0100 + ((u32_t)(((u8_t)(netif->hwaddr[4])) | - ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)) + netif->autoip->tried_llipaddr); + * We have 254 * 256 possibilities */ - if (RandomIPAddr->addr>0xA9FEFEFF) { - RandomIPAddr->addr = (0xA9FE0100 + (RandomIPAddr->addr-0xA9FEFEFF)); + u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); + addr += netif->autoip->tried_llipaddr; + addr = AUTOIP_NET | (addr & 0xffff); + /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ + + if (addr < AUTOIP_RANGE_START) { + addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; } - if (RandomIPAddr->addr<0xA9FE0100) { - RandomIPAddr->addr = (0xA9FEFEFF - (0xA9FE0100-RandomIPAddr->addr)); + if (addr > AUTOIP_RANGE_END) { + addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; } - RandomIPAddr->addr = htonl(RandomIPAddr->addr); + LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && + (addr <= AUTOIP_RANGE_END)); + IPAddr->addr = htonl(addr); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, - ("autoip_create_rand_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n", - (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(RandomIPAddr->addr))); + ("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n", + (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(IPAddr->addr))); } /** @@ -258,7 +279,7 @@ autoip_start(struct netif *netif) autoip->lastconflict = 0; } - autoip_create_rand_addr(netif, &(autoip->llipaddr)); + autoip_create_addr(netif, &(autoip->llipaddr)); autoip->tried_llipaddr++; autoip->state = AUTOIP_STATE_PROBING; autoip->sent_num = 0; @@ -395,8 +416,8 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ - MEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); - MEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); + SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); + SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); if ((netif->autoip->state == AUTOIP_STATE_PROBING) || ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && diff --git a/net/lwip/src/core/ipv4/icmp.c b/net/lwip/src/core/ipv4/icmp.c index 6a72c7803..b97a587a7 100644 --- a/net/lwip/src/core/ipv4/icmp.c +++ b/net/lwip/src/core/ipv4/icmp.c @@ -53,9 +53,18 @@ #include +/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be + * used to modify and send a response packet (and to 1 if this is not the case, + * e.g. when link header is stripped of when receiving) */ +#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN +#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ + /* The amount of data from the original packet to return in a dest-unreachable */ #define ICMP_DEST_UNREACH_DATASIZE 8 +static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); + /** * Processes ICMP input packets, called from ip_input(). * @@ -94,13 +103,30 @@ icmp_input(struct pbuf *p, struct netif *inp) #endif /* LWIP_DEBUG */ switch (type) { case ICMP_ECHO: - /* broadcast or multicast destination address? */ - if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); - ICMP_STATS_INC(icmp.err); - pbuf_free(p); - return; +#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING + { + int accepted = 1; +#if !LWIP_MULTICAST_PING + /* multicast destination address? */ + if (ip_addr_ismulticast(&iphdr->dest)) { + accepted = 0; + } +#endif /* LWIP_MULTICAST_PING */ +#if !LWIP_BROADCAST_PING + /* broadcast destination address? */ + if (ip_addr_isbroadcast(&iphdr->dest, inp)) { + accepted = 0; + } +#endif /* LWIP_BROADCAST_PING */ + /* broadcast or multicast destination address not acceptd? */ + if (!accepted) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); + ICMP_STATS_INC(icmp.err); + pbuf_free(p); + return; + } } +#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); if (p->tot_len < sizeof(struct icmp_echo_hdr)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); @@ -113,6 +139,7 @@ icmp_input(struct pbuf *p, struct netif *inp) snmp_inc_icmpinerrors(); return; } +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { /* p is not big enough to contain link headers * allocate a new one and copy p into it @@ -153,6 +180,7 @@ icmp_input(struct pbuf *p, struct netif *inp) goto memerr; } } +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ /* At this point, all checks are OK. */ /* We generate an answer by switching the dest and src ip addresses, * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ @@ -205,11 +233,13 @@ lenerr: ICMP_STATS_INC(icmp.lenerr); snmp_inc_icmpinerrors(); return; +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN memerr: pbuf_free(p); ICMP_STATS_INC(icmp.err); snmp_inc_icmpinerrors(); return; +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ } /** @@ -224,40 +254,7 @@ memerr: void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) { - struct pbuf *q; - struct ip_hdr *iphdr; - struct icmp_dur_hdr *idur; - - /* ICMP header + IP header + 8 bytes of data */ - q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, - PBUF_RAM); - if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); - - iphdr = p->payload; - - idur = q->payload; - ICMPH_TYPE_SET(idur, ICMP_DUR); - ICMPH_CODE_SET(idur, t); - - SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), p->payload, - IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); - - /* calculate checksum */ - idur->chksum = 0; - idur->chksum = inet_chksum(idur, q->len); - ICMP_STATS_INC(icmp.xmit); - /* increase number of messages attempted to send */ - snmp_inc_icmpoutmsgs(); - /* increase number of destination unreachable messages attempted to send */ - snmp_inc_icmpoutdestunreachs(); - - ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); - pbuf_free(q); + icmp_send_response(p, ICMP_DUR, t); } #if IP_FORWARD || IP_REASSEMBLY @@ -270,20 +267,37 @@ icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) */ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +{ + icmp_send_response(p, ICMP_TE, t); +} + +#endif /* IP_FORWARD || IP_REASSEMBLY */ + +/** + * Send an icmp packet in response to an incoming packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IP header + * @param type Type of the ICMP header + * @param code Code of the ICMP header + */ +static void +icmp_send_response(struct pbuf *p, u8_t type, u8_t code) { struct pbuf *q; struct ip_hdr *iphdr; - struct icmp_te_hdr *tehdr; + /* we can use the echo header here */ + struct icmp_echo_hdr *icmphdr; /* ICMP header + IP header + 8 bytes of data */ - q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, PBUF_RAM); if (q == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); return; } LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); + (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); iphdr = p->payload; LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); @@ -292,17 +306,19 @@ icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); - tehdr = q->payload; - ICMPH_TYPE_SET(tehdr, ICMP_TE); - ICMPH_CODE_SET(tehdr, t); + icmphdr = q->payload; + icmphdr->type = type; + icmphdr->code = code; + icmphdr->id = 0; + icmphdr->seqno = 0; /* copy fields from original packet */ - SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), (u8_t *)p->payload, + SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); /* calculate checksum */ - tehdr->chksum = 0; - tehdr->chksum = inet_chksum(tehdr, q->len); + icmphdr->chksum = 0; + icmphdr->chksum = inet_chksum(icmphdr, q->len); ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); @@ -312,6 +328,4 @@ icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) pbuf_free(q); } -#endif /* IP_FORWARD */ - #endif /* LWIP_ICMP */ diff --git a/net/lwip/src/core/ipv4/igmp.c b/net/lwip/src/core/ipv4/igmp.c index fb54cc9a3..7c07bc465 100644 --- a/net/lwip/src/core/ipv4/igmp.c +++ b/net/lwip/src/core/ipv4/igmp.c @@ -128,7 +128,7 @@ igmp_dump_group_list() while (group != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); ip_addr_debug_print(IGMP_DEBUG, &group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface)); group = group->next; } LWIP_DEBUGF(IGMP_DEBUG, ("\n")); @@ -147,7 +147,7 @@ igmp_start(struct netif *netif) { struct igmp_group* group; - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %x\n", (int) netif)); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif)); group = igmp_lookup_group(netif, &allsystems); @@ -159,7 +159,7 @@ igmp_start(struct netif *netif) if (netif->igmp_mac_filter != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); ip_addr_debug_print(IGMP_DEBUG, &allsystems); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif)); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER); } @@ -198,7 +198,7 @@ igmp_stop(struct netif *netif) if (netif->igmp_mac_filter != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); ip_addr_debug_print(IGMP_DEBUG, &group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif)); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); } /* free group */ @@ -223,7 +223,7 @@ igmp_report_groups( struct netif *netif) { struct igmp_group *group = igmp_group_list; - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %x\n", (int) netif)); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); while (group != NULL) { if (group->interface == netif) { @@ -295,7 +295,7 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr) LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); ip_addr_debug_print(IGMP_DEBUG, addr); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) ifp)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp)); return group; } @@ -361,7 +361,7 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) inp)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); /* Now calculate and check the checksum */ igmp = (struct igmp_msg *)p->payload; @@ -439,7 +439,8 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) break; } default: { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %x in state %x on group %x on if %x\n", (int) igmp->igmp_msgtype, (int) group->group_state, (int) &group, (int) group->interface)); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", + igmp->igmp_msgtype, group->group_state, &group, group->interface)); break; } } @@ -488,7 +489,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD ")); ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif)); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); } @@ -563,7 +564,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) if (netif->igmp_mac_filter != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL ")); ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif)); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); } @@ -624,7 +625,7 @@ igmp_timeout(struct igmp_group *group) if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface)); igmp_send(group, IGMP_V2_MEMB_REPORT); } @@ -666,7 +667,8 @@ igmp_stop_timer(struct igmp_group *group) void igmp_delaying_member( struct igmp_group *group, u8_t maxresp) { - if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) { + if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || + ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) { igmp_start_timer(group, (maxresp)/2); group->group_state = IGMP_GROUP_DELAYING_MEMBER; } @@ -695,64 +697,11 @@ err_t igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif) { - static u16_t ip_id = 0; - struct ip_hdr * iphdr = NULL; - u16_t * ra = NULL; - - /* First write in the "router alert" */ - if (pbuf_header(p, ROUTER_ALERTLEN)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n")); - return ERR_BUF; - } - /* This is the "router alert" option */ - ra = p->payload; + u16_t ra[2]; ra[0] = htons (ROUTER_ALERT); ra[1] = 0x0000; /* Router shall examine packet */ - - /* now the normal ip header */ - if (pbuf_header(p, IP_HLEN)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n")); - return ERR_BUF; - } - - iphdr = p->payload; - - /* Should the IP header be generated or is it already included in p? */ - if (dest != IP_HDRINCL) { - /** @todo should be shared with ip.c - ip_output_if */ - IPH_TTL_SET(iphdr, ttl); - IPH_PROTO_SET(iphdr, proto); - - ip_addr_set(&(iphdr->dest), dest); - - IPH_VHLTOS_SET(iphdr, 4, ((IP_HLEN + ROUTER_ALERTLEN) / 4), 0/*tos*/); - IPH_LEN_SET(iphdr, htons(p->tot_len)); - IPH_OFFSET_SET(iphdr, 0); - IPH_ID_SET(iphdr, htons(ip_id)); - ++ip_id; - - if (ip_addr_isany(src)) { - ip_addr_set(&(iphdr->src), &(netif->ip_addr)); - } else { - ip_addr_set(&(iphdr->src), src); - } - - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, (IP_HLEN + ROUTER_ALERTLEN))); -#endif - } else { - dest = &(iphdr->dest); - } - -#if IP_DEBUG - ip_debug_print(p); -#endif - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: sending to if %x\n", (int) netif)); - - return netif->output(netif, p, dest); + return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN); } /** @@ -796,10 +745,10 @@ igmp_send(struct igmp_group *group, u8_t type) igmp->igmp_checksum = 0; igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN); - igmp_ip_output_if( p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface); + igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface); } - pbuf_free (p); + pbuf_free(p); } else { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); } diff --git a/net/lwip/src/core/ipv4/inet.c b/net/lwip/src/core/ipv4/inet.c index 24c7ff469..69baf1d50 100644 --- a/net/lwip/src/core/ipv4/inet.c +++ b/net/lwip/src/core/ipv4/inet.c @@ -83,7 +83,8 @@ int inet_aton(const char *cp, struct in_addr *addr) { u32_t val; - int base, n, c; + u8_t base; + char c; u32_t parts[4]; u32_t *pp = parts; @@ -133,14 +134,13 @@ inet_aton(const char *cp, struct in_addr *addr) /* * Check for trailing characters. */ - if (c != '\0' && (!isprint(c) || !isspace(c))) + if (c != '\0' && !isspace(c)) return (0); /* * Concoct the address according to * the number of parts specified. */ - n = pp - parts + 1; - switch (n) { + switch (pp - parts + 1) { case 0: return (0); /* initial nondigit */ diff --git a/net/lwip/src/core/ipv4/inet_chksum.c b/net/lwip/src/core/ipv4/inet_chksum.c index bc492fead..185881efd 100644 --- a/net/lwip/src/core/ipv4/inet_chksum.c +++ b/net/lwip/src/core/ipv4/inet_chksum.c @@ -41,7 +41,7 @@ #include "lwip/inet_chksum.h" #include "lwip/inet.h" -#include +#include /* These are some reference implementations of the checksum algorithm, with the * aim of being simple, correct and fully portable. Checksumming is the @@ -65,6 +65,18 @@ # define LWIP_CHKSUM_ALGORITHM 0 #endif +/** Like the name says... */ +#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) +/* little endian and PLATFORM_BYTESWAP defined */ +#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) +#else +/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ +#define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8) +#endif + +/** Split an u32_t in two u16_ts and add them up */ +#define FOLD_U32T(u) ((u >> 16) + (u & 0x0000ffffUL)) + #if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ /** * lwip checksum @@ -86,8 +98,7 @@ lwip_standard_chksum(void *dataptr, u16_t len) acc = 0; /* dataptr may be at odd or even addresses */ octetptr = (u8_t*)dataptr; - while (len > 1) - { + while (len > 1) { /* declare first octet as most significant thus assume network order, ignoring host order */ src = (*octetptr) << 8; @@ -98,15 +109,14 @@ lwip_standard_chksum(void *dataptr, u16_t len) acc += src; len -= 2; } - if (len > 0) - { + if (len > 0) { /* accumulate remaining octet */ src = (*octetptr) << 8; acc += src; } /* add deferred carry bits */ acc = (acc >> 16) + (acc & 0x0000ffffUL); - if ((acc & 0xffff0000) != 0) { + if ((acc & 0xffff0000UL) != 0) { acc = (acc >> 16) + (acc & 0x0000ffffUL); } /* This maybe a little confusing: reorder sum using htons() @@ -154,19 +164,22 @@ lwip_standard_chksum(void *dataptr, int len) } /* Consume left-over byte, if any */ - if (len > 0) + if (len > 0) { ((u8_t *)&t)[0] = *(u8_t *)ps;; + } /* Add end bytes */ sum += t; - /* Fold 32-bit sum to 16 bits */ - while ((sum >> 16) != 0) - sum = (sum & 0xffff) + (sum >> 16); + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + sum = FOLD_U32T(sum); + sum = FOLD_U32T(sum); /* Swap if alignment was odd */ - if (odd) - sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8); + if (odd) { + sum = SWAP_BYTES_IN_WORD(sum); + } return sum; } @@ -211,18 +224,20 @@ lwip_standard_chksum(void *dataptr, int len) while (len > 7) { tmp = sum + *pl++; /* ping */ - if (tmp < sum) + if (tmp < sum) { tmp++; /* add back carry */ + } sum = tmp + *pl++; /* pong */ - if (sum < tmp) + if (sum < tmp) { sum++; /* add back carry */ + } len -= 8; } /* make room in upper bits */ - sum = (sum >> 16) + (sum & 0xffff); + sum = FOLD_U32T(sum); ps = (u16_t *)pl; @@ -233,16 +248,20 @@ lwip_standard_chksum(void *dataptr, int len) } /* dangling tail byte remaining? */ - if (len > 0) /* include odd byte */ + if (len > 0) { /* include odd byte */ ((u8_t *)&t)[0] = *(u8_t *)ps; + } sum += t; /* add end bytes */ - while ((sum >> 16) != 0) /* combine halves */ - sum = (sum >> 16) + (sum & 0xffff); + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + sum = FOLD_U32T(sum); + sum = FOLD_U32T(sum); - if (odd) - sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8); + if (odd) { + sum = SWAP_BYTES_IN_WORD(sum); + } return sum; } @@ -277,18 +296,18 @@ inet_chksum_pseudo(struct pbuf *p, (void *)q, (void *)q->next)); acc += LWIP_CHKSUM(q->payload, q->len); /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ - while ((acc >> 16) != 0) { - acc = (acc & 0xffffUL) + (acc >> 16); - } + /* just executing this next line is probably faster that the if statement needed + to check whether we really need to execute it, and does no harm */ + acc = FOLD_U32T(acc); if (q->len % 2 != 0) { swapped = 1 - swapped; - acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8); + acc = SWAP_BYTES_IN_WORD(acc); } /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ } if (swapped) { - acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8); + acc = SWAP_BYTES_IN_WORD(acc); } acc += (src->addr & 0xffffUL); acc += ((src->addr >> 16) & 0xffffUL); @@ -297,9 +316,10 @@ inet_chksum_pseudo(struct pbuf *p, acc += (u32_t)htons((u16_t)proto); acc += (u32_t)htons(proto_len); - while ((acc >> 16) != 0) { - acc = (acc & 0xffffUL) + (acc >> 16); - } + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); return (u16_t)~(acc & 0xffffUL); } @@ -316,6 +336,8 @@ inet_chksum_pseudo(struct pbuf *p, * @param proto_len length of the ip data part (used for checksum of pseudo header) * @return checksum (as u16_t) to be saved directly in the protocol header */ +/* Currently only used by UDPLITE, although this could change in the future. */ +#if LWIP_UDPLITE u16_t inet_chksum_pseudo_partial(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, @@ -340,18 +362,17 @@ inet_chksum_pseudo_partial(struct pbuf *p, chksum_len -= chklen; LWIP_ASSERT("delete me", chksum_len < 0x7fff); /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ - while ((acc >> 16) != 0) { - acc = (acc & 0xffffUL) + (acc >> 16); - } + /* fold the upper bit down */ + acc = FOLD_U32T(acc); if (q->len % 2 != 0) { swapped = 1 - swapped; - acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8); + acc = SWAP_BYTES_IN_WORD(acc); } /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ } if (swapped) { - acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8); + acc = SWAP_BYTES_IN_WORD(acc); } acc += (src->addr & 0xffffUL); acc += ((src->addr >> 16) & 0xffffUL); @@ -360,12 +381,14 @@ inet_chksum_pseudo_partial(struct pbuf *p, acc += (u32_t)htons((u16_t)proto); acc += (u32_t)htons(proto_len); - while ((acc >> 16) != 0) { - acc = (acc & 0xffffUL) + (acc >> 16); - } + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); return (u16_t)~(acc & 0xffffUL); } +#endif /* LWIP_UDPLITE */ /* inet_chksum: * @@ -380,13 +403,7 @@ inet_chksum_pseudo_partial(struct pbuf *p, u16_t inet_chksum(void *dataptr, u16_t len) { - u32_t acc; - - acc = LWIP_CHKSUM(dataptr, len); - while ((acc >> 16) != 0) { - acc = (acc & 0xffff) + (acc >> 16); - } - return (u16_t)~(acc & 0xffff); + return ~LWIP_CHKSUM(dataptr, len); } /** @@ -407,17 +424,15 @@ inet_chksum_pbuf(struct pbuf *p) swapped = 0; for(q = p; q != NULL; q = q->next) { acc += LWIP_CHKSUM(q->payload, q->len); - while ((acc >> 16) != 0) { - acc = (acc & 0xffffUL) + (acc >> 16); - } + acc = FOLD_U32T(acc); if (q->len % 2 != 0) { swapped = 1 - swapped; - acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8); + acc = SWAP_BYTES_IN_WORD(acc); } } if (swapped) { - acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8); + acc = SWAP_BYTES_IN_WORD(acc); } return (u16_t)~(acc & 0xffffUL); } diff --git a/net/lwip/src/core/ipv4/ip.c b/net/lwip/src/core/ipv4/ip.c index fbcef5dc0..7e404a9f3 100644 --- a/net/lwip/src/core/ipv4/ip.c +++ b/net/lwip/src/core/ipv4/ip.c @@ -56,6 +56,47 @@ #include "lwip/stats.h" #include "arch/perf.h" +#include + +/** + * The interface that provided the packet for the current callback + * invocation. + */ +static 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; +} + /** * Finds the appropriate network interface for a given IP address. It * searches the list of network interfaces linearly. A match is found @@ -388,6 +429,9 @@ ip_input(struct pbuf *p, struct netif *inp) ip_debug_print(p); LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + current_netif = inp; + current_header = iphdr; + #if LWIP_RAW /* raw input did not eat the packet? */ if (raw_input(p, inp) == 0) @@ -440,6 +484,9 @@ ip_input(struct pbuf *p, struct netif *inp) } } + current_netif = NULL; + current_header = NULL; + return ERR_OK; } @@ -473,6 +520,21 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) { +#if IP_OPTIONS_SEND + return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if() but with the possibility to include IP options: + * + * @ param ip_options pointer to the IP options, copied into the IP header + * @ param optlen length of ip_options + */ +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 ip_hdr *iphdr; static u16_t ip_id = 0; @@ -480,6 +542,27 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, /* Should the IP header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { + u16_t ip_hlen = IP_HLEN; +#if IP_OPTIONS_SEND + u16_t optlen_aligned = 0; + if (optlen != 0) { + /* round up to a multiple of 4 */ + optlen_aligned = ((optlen + 3) & ~3); + 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")); + IP_STATS_INC(ip.err); + snmp_inc_ipoutdiscards(); + return ERR_BUF; + } + MEMCPY(p->payload, ip_options, optlen); + if (optlen < optlen_aligned) { + /* zero the remaining bytes */ + memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); + } + } +#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")); @@ -498,7 +581,7 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, ip_addr_set(&(iphdr->dest), dest); - IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos); + IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_OFFSET_SET(iphdr, 0); IPH_ID_SET(iphdr, htons(ip_id)); @@ -512,7 +595,7 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); #endif } else { /* IP header already included in p */ @@ -531,9 +614,19 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip_debug_print(p); - LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); +#if (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + if (ip_addr_cmp(dest, &netif->ip_addr)) { + /* Packet to self, enqueue it for loopback */ + LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); - return netif->output(netif, p, dest); + 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); + } } /** @@ -560,12 +653,54 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, struct netif *netif; if ((netif = ip_route(dest)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); + IP_STATS_INC(ip.rterr); return ERR_RTE; } return ip_output_if(p, src, dest, ttl, tos, proto, netif); } +#if LWIP_NETIF_HWADDRHINT +/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint + * before calling ip_output_if. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an IP + header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param addr_hint address hint pointer set to netif->addr_hint before + * calling ip_output_if() + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) +{ + struct netif *netif; + err_t err; + + if ((netif = ip_route(dest)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); + IP_STATS_INC(ip.rterr); + return ERR_RTE; + } + + netif->addr_hint = addr_hint; + err = ip_output_if(p, src, dest, ttl, tos, proto, netif); + netif->addr_hint = NULL; + + return err; +} +#endif /* LWIP_NETIF_HWADDRHINT*/ + #if IP_DEBUG /* Print an IP header by using LWIP_DEBUGF * @param p an IP packet, p->payload pointing to the IP header diff --git a/net/lwip/src/core/ipv4/ip_frag.c b/net/lwip/src/core/ipv4/ip_frag.c index e06ba009b..1939d831b 100644 --- a/net/lwip/src/core/ipv4/ip_frag.c +++ b/net/lwip/src/core/ipv4/ip_frag.c @@ -81,12 +81,21 @@ /** This is a helper struct which holds the starting * offset and the ending offset of this fragment to * easily chain the fragments. + * It has to be packed since it has to fit inside the IP header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN struct ip_reass_helper { - struct pbuf *next_pbuf; - u16_t start; - u16_t end; -}; + PACK_STRUCT_FIELD(struct pbuf *next_pbuf); + PACK_STRUCT_FIELD(u16_t start); + PACK_STRUCT_FIELD(u16_t end); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif #define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ @@ -599,7 +608,7 @@ nullreturn: #if IP_FRAG #if IP_FRAG_USES_STATIC_BUF -static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)]; +static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)]; #endif /* IP_FRAG_USES_STATIC_BUF */ /** diff --git a/net/lwip/src/core/ipv6/ip6.c b/net/lwip/src/core/ipv6/ip6.c index ce5b501ff..7e4342001 100644 --- a/net/lwip/src/core/ipv6/ip6.c +++ b/net/lwip/src/core/ipv6/ip6.c @@ -327,6 +327,28 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, return ip_output_if (p, src, dest, ttl, proto, netif); } +#if LWIP_NETIF_HWADDRHINT +err_t +ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) +{ + struct netif *netif; + err_t err; + + if ((netif = ip_route(dest)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); + IP_STATS_INC(ip.rterr); + return ERR_RTE; + } + + netif->addr_hint = addr_hint; + err = ip_output_if(p, src, dest, ttl, tos, proto, netif); + netif->addr_hint = NULL; + + return err; +} +#endif /* LWIP_NETIF_HWADDRHINT*/ + #if IP_DEBUG void ip_debug_print(struct pbuf *p) diff --git a/net/lwip/src/core/mem.c b/net/lwip/src/core/mem.c index 9783c5d6e..b5f13ab3b 100644 --- a/net/lwip/src/core/mem.c +++ b/net/lwip/src/core/mem.c @@ -67,14 +67,6 @@ #if MEM_USE_POOLS /* lwIP head implemented with different sized pools */ -/** - * This structure is used to save the pool one element came from. - */ -struct mem_helper -{ - memp_t poolnr; -}; - /** * Allocate memory: determine the smallest pool that is big enough * to contain an element of 'size' and get an element from that pool. @@ -85,13 +77,17 @@ struct mem_helper void * mem_malloc(mem_size_t size) { - struct mem_helper *element; + struct memp_malloc_helper *element; memp_t poolnr; + mem_size_t required_size = size + sizeof(struct memp_malloc_helper); for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) { +#if MEM_USE_POOLS_TRY_BIGGER_POOL +again: +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ /* is this pool big enough to hold an element of the required size - plus a struct mem_helper that saves the pool this element came from? */ - if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) { + plus a struct memp_malloc_helper that saves the pool this element came from? */ + if (required_size <= memp_sizes[poolnr]) { break; } } @@ -99,17 +95,23 @@ mem_malloc(mem_size_t size) LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); return NULL; } - element = (struct mem_helper*)memp_malloc(poolnr); + element = (struct memp_malloc_helper*)memp_malloc(poolnr); if (element == NULL) { /* No need to DEBUGF or ASSERT: This error is already taken care of in memp.c */ - /** @todo: we could try a bigger pool if this one is empty! */ +#if MEM_USE_POOLS_TRY_BIGGER_POOL + /** Try a bigger pool if this one is empty! */ + if (poolnr < MEMP_POOL_LAST) { + poolnr++; + goto again; + } +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ return NULL; } /* save the pool number this element came from */ element->poolnr = poolnr; - /* and return a pointer to the memory directly after the struct mem_helper */ + /* and return a pointer to the memory directly after the struct memp_malloc_helper */ element++; return element; @@ -125,12 +127,12 @@ mem_malloc(mem_size_t size) void mem_free(void *rmem) { - struct mem_helper *hmem = (struct mem_helper*)rmem; + struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem; LWIP_ASSERT("rmem != NULL", (rmem != NULL)); LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); - /* get the original struct mem_helper */ + /* get the original struct memp_malloc_helper */ hmem--; LWIP_ASSERT("hmem != NULL", (hmem != NULL)); @@ -177,9 +179,36 @@ static u8_t *ram; static struct mem *ram_end; /** pointer to the lowest free block, this is used for faster search */ static struct mem *lfree; + /** concurrent access protection */ static sys_sem_t mem_sem; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + +static volatile u8_t mem_free_count; + +/* Allow mem_free from other (e.g. interrupt) context */ +#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) +#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) +#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) +#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) + +#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +/* Protect the heap only by using a semaphore */ +#define LWIP_MEM_FREE_DECL_PROTECT() +#define LWIP_MEM_FREE_PROTECT() sys_arch_sem_wait(mem_sem, 0) +#define LWIP_MEM_FREE_UNPROTECT() sys_sem_signal(mem_sem) +/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ +#define LWIP_MEM_ALLOC_DECL_PROTECT() +#define LWIP_MEM_ALLOC_PROTECT() +#define LWIP_MEM_ALLOC_UNPROTECT() + +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + /** * "Plug holes" by combining adjacent empty struct mems. * After this function is through, there should not exist @@ -255,9 +284,7 @@ mem_init(void) /* initialize the lowest-free pointer to the start of the heap */ lfree = (struct mem *)ram; -#if MEM_STATS - lwip_stats.mem.avail = MEM_SIZE_ALIGNED; -#endif /* MEM_STATS */ + MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); } /** @@ -270,6 +297,7 @@ void mem_free(void *rmem) { struct mem *mem; + LWIP_MEM_FREE_DECL_PROTECT(); if (rmem == NULL) { LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n")); @@ -277,20 +305,20 @@ mem_free(void *rmem) } LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); - /* protect the heap from concurrent access */ - sys_arch_sem_wait(mem_sem, 0); - LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && (u8_t *)rmem < (u8_t *)ram_end); if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + SYS_ARCH_DECL_PROTECT(lev); LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n")); -#if MEM_STATS - ++lwip_stats.mem.err; -#endif /* MEM_STATS */ - sys_sem_signal(mem_sem); + /* protect mem stats from concurrent access */ + SYS_ARCH_PROTECT(lev); + MEM_STATS_INC(illegal); + SYS_ARCH_UNPROTECT(lev); return; } + /* protect the heap from concurrent access */ + LWIP_MEM_FREE_PROTECT(); /* Get the corresponding struct mem ... */ mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); /* ... which has to be in a used state ... */ @@ -303,13 +331,14 @@ mem_free(void *rmem) lfree = mem; } -#if MEM_STATS - lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram); -#endif /* MEM_STATS */ + MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram)); /* finally, see if prev or next are free also */ plug_holes(mem); - sys_sem_signal(mem_sem); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_FREE_UNPROTECT(); } /** @@ -321,6 +350,8 @@ mem_free(void *rmem) * @param newsize required size after shrinking (needs to be smaller than or * equal to the previous size) * @return for compatibility reasons: is always == rmem, at the moment + * or NULL if newsize is > old size, in which case rmem is NOT touched + * or freed! */ void * mem_realloc(void *rmem, mem_size_t newsize) @@ -328,6 +359,8 @@ mem_realloc(void *rmem, mem_size_t newsize) mem_size_t size; mem_size_t ptr, ptr2; struct mem *mem, *mem2; + /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ + LWIP_MEM_FREE_DECL_PROTECT(); /* Expand the size of the allocated memory region so that we can adjust for alignment. */ @@ -346,7 +379,12 @@ mem_realloc(void *rmem, mem_size_t newsize) (u8_t *)rmem < (u8_t *)ram_end); 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")); + /* protect mem stats from concurrent access */ + SYS_ARCH_PROTECT(lev); + MEM_STATS_INC(illegal); + SYS_ARCH_UNPROTECT(lev); return rmem; } /* Get the corresponding struct mem ... */ @@ -366,11 +404,9 @@ mem_realloc(void *rmem, mem_size_t newsize) } /* protect the heap from concurrent access */ - sys_arch_sem_wait(mem_sem, 0); + LWIP_MEM_FREE_PROTECT(); -#if MEM_STATS - lwip_stats.mem.used -= (size - newsize); -#endif /* MEM_STATS */ + MEM_STATS_DEC_USED(used, (size - newsize)); mem2 = (struct mem *)&ram[mem->next]; if(mem2->used == 0) { @@ -426,7 +462,10 @@ mem_realloc(void *rmem, mem_size_t newsize) -> don't do anyhting. -> the remaining space stays unused since it is too small } */ - sys_sem_signal(mem_sem); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_FREE_UNPROTECT(); return rmem; } @@ -444,6 +483,10 @@ mem_malloc(mem_size_t size) { mem_size_t ptr, ptr2; struct mem *mem, *mem2; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + u8_t local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_ALLOC_DECL_PROTECT(); if (size == 0) { return NULL; @@ -464,88 +507,101 @@ mem_malloc(mem_size_t size) /* protect the heap from concurrent access */ sys_arch_sem_wait(mem_sem, 0); + LWIP_MEM_ALLOC_PROTECT(); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + /* run as long as a mem_free disturbed mem_malloc */ + do { + local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - /* Scan through the heap searching for a free block that is big enough, - * beginning with the lowest free block. - */ - for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size; - ptr = ((struct mem *)&ram[ptr])->next) { - mem = (struct mem *)&ram[ptr]; - - if ((!mem->used) && - (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { - /* mem is not used and at least perfect fit is possible: - * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ - - if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { - /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing - * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') - * -> split large block, create empty remainder, - * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if - * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, - * struct mem would fit in but no data between mem2 and mem2->next - * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty - * region that couldn't hold data, but when mem->next gets freed, - * the 2 regions would be combined, resulting in more free memory - */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + size; - /* create mem2 struct */ - mem2 = (struct mem *)&ram[ptr2]; - mem2->used = 0; - mem2->next = mem->next; - mem2->prev = ptr; - /* and insert it between mem and mem->next */ - mem->next = ptr2; - mem->used = 1; - - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)&ram[mem2->next])->prev = ptr2; - } -#if MEM_STATS - lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM); - if (lwip_stats.mem.max < lwip_stats.mem.used) { - lwip_stats.mem.max = lwip_stats.mem.used; - } -#endif /* MEM_STATS */ - } else { - /* (a mem2 struct does no fit into the user data space of mem and mem->next will always - * be used at this point: if not we have 2 unused structs in a row, plug_holes should have - * take care of this). - * -> near fit or excact fit: do not split, no mem2 creation - * also can't move mem->next directly behind mem, since mem->next - * will always be used at this point! - */ - mem->used = 1; -#if MEM_STATS - lwip_stats.mem.used += mem->next - ((u8_t *)mem - ram); - if (lwip_stats.mem.max < lwip_stats.mem.used) { - lwip_stats.mem.max = lwip_stats.mem.used; - } -#endif /* MEM_STATS */ + /* Scan through the heap searching for a free block that is big enough, + * beginning with the lowest free block. + */ + for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size; + ptr = ((struct mem *)&ram[ptr])->next) { + mem = (struct mem *)&ram[ptr]; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 0; + LWIP_MEM_ALLOC_UNPROTECT(); + /* allow mem_free to run */ + LWIP_MEM_ALLOC_PROTECT(); + if (mem_free_count != 0) { + local_mem_free_count = mem_free_count; } + mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - if (mem == lfree) { - /* Find next free block after mem and update lowest free pointer */ - while (lfree->used && lfree != ram_end) { - lfree = (struct mem *)&ram[lfree->next]; + if ((!mem->used) && + (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { + /* mem is not used and at least perfect fit is possible: + * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ + + if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { + /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing + * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') + * -> split large block, create empty remainder, + * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if + * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, + * struct mem would fit in but no data between mem2 and mem2->next + * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty + * region that couldn't hold data, but when mem->next gets freed, + * the 2 regions would be combined, resulting in more free memory + */ + ptr2 = ptr + SIZEOF_STRUCT_MEM + size; + /* create mem2 struct */ + mem2 = (struct mem *)&ram[ptr2]; + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; + /* and insert it between mem and mem->next */ + mem->next = ptr2; + mem->used = 1; + + if (mem2->next != MEM_SIZE_ALIGNED) { + ((struct mem *)&ram[mem2->next])->prev = ptr2; + } + MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); + } else { + /* (a mem2 struct does no fit into the user data space of mem and mem->next will always + * be used at this point: if not we have 2 unused structs in a row, plug_holes should have + * take care of this). + * -> near fit or excact fit: do not split, no mem2 creation + * also can't move mem->next directly behind mem, since mem->next + * will always be used at this point! + */ + mem->used = 1; + MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram)); } - LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); - } - sys_sem_signal(mem_sem); - LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", - (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); - LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", - (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); - LWIP_ASSERT("mem_malloc: sanity check alignment", - (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); - return (u8_t *)mem + SIZEOF_STRUCT_MEM; + if (mem == lfree) { + /* Find next free block after mem and update lowest free pointer */ + while (lfree->used && lfree != ram_end) { + LWIP_MEM_ALLOC_UNPROTECT(); + /* prevent high interrupt latency... */ + LWIP_MEM_ALLOC_PROTECT(); + lfree = (struct mem *)&ram[lfree->next]; + } + LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); + } + LWIP_MEM_ALLOC_UNPROTECT(); + sys_sem_signal(mem_sem); + LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", + (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); + LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", + ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); + LWIP_ASSERT("mem_malloc: sanity check alignment", + (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); + + return (u8_t *)mem + SIZEOF_STRUCT_MEM; + } } - } +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + /* 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)); -#if MEM_STATS - ++lwip_stats.mem.err; -#endif /* MEM_STATS */ + MEM_STATS_INC(err); + LWIP_MEM_ALLOC_UNPROTECT(); sys_sem_signal(mem_sem); return NULL; } diff --git a/net/lwip/src/core/memp.c b/net/lwip/src/core/memp.c index 0ef283999..dfc32213d 100644 --- a/net/lwip/src/core/memp.c +++ b/net/lwip/src/core/memp.c @@ -56,6 +56,8 @@ #include +#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ + struct memp { struct memp *next; #if MEMP_OVERFLOW_CHECK @@ -109,15 +111,23 @@ struct memp { * Elements form a linked list. */ static struct memp *memp_tab[MEMP_MAX]; +#else /* MEMP_MEM_MALLOC */ + +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_MEM_MALLOC */ + /** This array holds the element sizes of each pool. */ -#if !MEM_USE_POOLS +#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC static #endif const u16_t memp_sizes[MEMP_MAX] = { -#define LWIP_MEMPOOL(name,num,size,desc) MEMP_ALIGN_SIZE(size), +#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size), #include "lwip/memp_std.h" }; +#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ + /** This array holds the number of elements in each pool. */ static const u16_t memp_num[MEMP_MAX] = { #define LWIP_MEMPOOL(name,num,size,desc) (num), @@ -183,7 +193,7 @@ memp_overflow_check_element(struct memp *p, u16_t memp_size) } #endif #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE + memp_size - MEMP_SANITY_REGION_AFTER_ALIGNED; + m = (u8_t*)p + MEMP_SIZE + memp_size; for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { if (m[k] != 0xcd) { LWIP_ASSERT("detected memp overflow!", 0); @@ -208,7 +218,7 @@ memp_overflow_check_all(void) p = p; for (j = 0; j < memp_num[i]; ++j) { memp_overflow_check_element(p, memp_sizes[i]); - p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]); + p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } } @@ -232,10 +242,10 @@ memp_overflow_init(void) memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); #endif #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE + memp_sizes[i] - MEMP_SANITY_REGION_AFTER_ALIGNED; + m = (u8_t*)p + MEMP_SIZE + memp_sizes[i]; memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); #endif - p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]); + p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } } @@ -252,13 +262,12 @@ memp_init(void) struct memp *memp; u16_t i, j; -#if MEMP_STATS for (i = 0; i < MEMP_MAX; ++i) { - lwip_stats.memp[i].used = lwip_stats.memp[i].max = - lwip_stats.memp[i].err = 0; - lwip_stats.memp[i].avail = memp_num[i]; + MEMP_STATS_AVAIL(used, i, 0); + MEMP_STATS_AVAIL(max, i, 0); + MEMP_STATS_AVAIL(err, i, 0); + MEMP_STATS_AVAIL(avail, i, memp_num[i]); } -#endif /* MEMP_STATS */ memp = LWIP_MEM_ALIGN(memp_memory); /* for every pool: */ @@ -268,7 +277,11 @@ memp_init(void) for (j = 0; j < memp_num[i]; ++j) { memp->next = memp_tab[i]; memp_tab[i] = memp; - memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]); + memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] +#if MEMP_OVERFLOW_CHECK + + MEMP_SANITY_REGION_AFTER_ALIGNED +#endif + ); } } #if MEMP_OVERFLOW_CHECK @@ -308,27 +321,20 @@ memp_malloc_fn(memp_t type, const char* file, const int line) memp = memp_tab[type]; - if (memp != NULL) { - memp_tab[type] = memp->next; + if (memp != NULL) { + memp_tab[type] = memp->next; #if MEMP_OVERFLOW_CHECK memp->next = NULL; memp->file = file; memp->line = line; #endif /* MEMP_OVERFLOW_CHECK */ -#if MEMP_STATS - ++lwip_stats.memp[type].used; - if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) { - lwip_stats.memp[type].max = lwip_stats.memp[type].used; - } -#endif /* MEMP_STATS */ + MEMP_STATS_INC_USED(used, type); LWIP_ASSERT("memp_malloc: memp properly aligned", ((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])); -#if MEMP_STATS - ++lwip_stats.memp[type].err; -#endif /* MEMP_STATS */ + MEMP_STATS_INC(err, type); } SYS_ARCH_UNPROTECT(old_level); @@ -365,9 +371,7 @@ memp_free(memp_t type, void *mem) #endif /* MEMP_OVERFLOW_CHECK >= 2 */ #endif /* MEMP_OVERFLOW_CHECK */ -#if MEMP_STATS - lwip_stats.memp[type].used--; -#endif /* MEMP_STATS */ + MEMP_STATS_DEC(used, type); memp->next = memp_tab[type]; memp_tab[type] = memp; @@ -378,3 +382,5 @@ memp_free(memp_t type, void *mem) SYS_ARCH_UNPROTECT(old_level); } + +#endif /* MEMP_MEM_MALLOC */ diff --git a/net/lwip/src/core/netif.c b/net/lwip/src/core/netif.c index aae68b451..c9b6b9b5e 100644 --- a/net/lwip/src/core/netif.c +++ b/net/lwip/src/core/netif.c @@ -45,6 +45,12 @@ #include "lwip/snmp.h" #include "lwip/igmp.h" #include "netif/etharp.h" +#if ENABLE_LOOPBACK +#include "lwip/sys.h" +#if LWIP_NETIF_LOOPBACK_MULTITHREADING +#include "lwip/tcpip.h" +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ #if LWIP_NETIF_STATUS_CALLBACK #define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); } @@ -106,6 +112,10 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, #if LWIP_IGMP netif->igmp_mac_filter = NULL; #endif /* LWIP_IGMP */ +#if ENABLE_LOOPBACK + netif->loop_first = NULL; + netif->loop_last = NULL; +#endif /* ENABLE_LOOPBACK */ /* remember netif specific state information data */ netif->state = state; @@ -114,6 +124,9 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ +#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS + netif->loop_cnt_current = 0; +#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ netif_set_addr(netif, ipaddr, netmask, gw); @@ -388,13 +401,9 @@ void netif_set_up(struct netif *netif) NETIF_STATUS_CALLBACK(netif); #if LWIP_ARP - /** For Ethernet network interfaces, we would like to send a - * "gratuitous ARP"; this is an ARP packet sent by a node in order - * to spontaneously cause other nodes to update an entry in their - * ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6. - */ + /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_query(netif, &(netif->ip_addr), NULL); + etharp_gratuitous(netif); } #endif /* LWIP_ARP */ @@ -451,13 +460,9 @@ void netif_set_link_up(struct netif *netif ) netif->flags |= NETIF_FLAG_LINK_UP; #if LWIP_ARP - /** For Ethernet network interfaces, we would like to send a - * "gratuitous ARP"; this is an ARP packet sent by a node in order - * to spontaneously cause other nodes to update an entry in their - * ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6. - */ + /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_query(netif, &(netif->ip_addr), NULL); + etharp_gratuitous(netif); } #endif /* LWIP_ARP */ @@ -493,7 +498,158 @@ u8_t netif_is_link_up(struct netif *netif) */ void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif )) { - if ( netif ) - netif->link_callback = link_callback; + if (netif) { + netif->link_callback = link_callback; + } } #endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if ENABLE_LOOPBACK +/** + * Send an IP packet to be received on the same netif (loopif-like). + * The pbuf is simply copied and handed back to netif->input. + * In multithreaded mode, this is done directly since netif->input must put + * the packet on a queue. + * In callback mode, the packet is put on an internal queue and is fed to + * netif->input by netif_poll(). + * + * @param netif the lwip network interface structure + * @param p the (IP) packet to 'send' + * @param ipaddr the ip address to send the packet to (not used) + * @return ERR_OK if the packet has been sent + * ERR_MEM if the pbuf used to copy the packet couldn't be allocated + */ +err_t +netif_loop_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + struct pbuf *r; + err_t err; + struct pbuf *last; +#if LWIP_LOOPBACK_MAX_PBUFS + u8_t clen = 0; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + SYS_ARCH_DECL_PROTECT(lev); + LWIP_UNUSED_ARG(ipaddr); + + /* Allocate a new pbuf */ + r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + if (r == NULL) { + return ERR_MEM; + } +#if LWIP_LOOPBACK_MAX_PBUFS + clen = pbuf_clen(r); + /* check for overflow or too many pbuf on queue */ + if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || + ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { + pbuf_free(r); + r = NULL; + return ERR_MEM; + } + netif->loop_cnt_current += clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + /* Copy the whole pbuf queue p into the single pbuf r */ + if ((err = pbuf_copy(r, p)) != ERR_OK) { + pbuf_free(r); + r = NULL; + return err; + } + + /* Put the packet on a linked list which gets emptied through calling + netif_poll(). */ + + /* let last point to the last pbuf in chain r */ + for (last = r; last->next != NULL; last = last->next); + + SYS_ARCH_PROTECT(lev); + if(netif->loop_first != NULL) { + LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); + netif->loop_last->next = r; + netif->loop_last = last; + } else { + netif->loop_first = r; + netif->loop_last = last; + } + SYS_ARCH_UNPROTECT(lev); + +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + /* For multithreading environment, schedule a call to netif_poll */ + tcpip_callback((void (*)(void *))(netif_poll), netif); +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + + return ERR_OK; +} + +/** + * Call netif_poll() in the main loop of your application. This is to prevent + * reentering non-reentrant functions like tcp_input(). Packets passed to + * netif_loop_output() are put on a list that is passed to netif->input() by + * netif_poll(). + */ +void +netif_poll(struct netif *netif) +{ + struct pbuf *in; + SYS_ARCH_DECL_PROTECT(lev); + + do { + /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ + SYS_ARCH_PROTECT(lev); + in = netif->loop_first; + if(in != NULL) { + struct pbuf *in_end = in; +#if LWIP_LOOPBACK_MAX_PBUFS + u8_t clen = pbuf_clen(in); + /* adjust the number of pbufs on queue */ + LWIP_ASSERT("netif->loop_cnt_current underflow", + ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); + netif->loop_cnt_current -= clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + while(in_end->len != in_end->tot_len) { + LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); + in_end = in_end->next; + } + /* 'in_end' now points to the last pbuf from 'in' */ + if(in_end == netif->loop_last) { + /* this was the last pbuf in the list */ + netif->loop_first = netif->loop_last = NULL; + } else { + /* pop the pbuf off the list */ + netif->loop_first = in_end->next; + LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); + } + /* De-queue the pbuf from its successors on the 'loop_' list. */ + in_end->next = NULL; + } + SYS_ARCH_UNPROTECT(lev); + + if(in != NULL) { + /* loopback packets are always IP packets! */ + if(ip_input(in, netif) != ERR_OK) { + pbuf_free(in); + } + /* Don't reference the packet any more! */ + in = NULL; + } + /* go on while there is a packet on the list */ + } while(netif->loop_first != NULL); +} + +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +/** + * Calls netif_poll() for every netif on the netif_list. + */ +void +netif_poll_all(void) +{ + struct netif *netif = netif_list; + /* loop through netifs */ + while (netif != NULL) { + netif_poll(netif); + /* proceed to next network interface */ + netif = netif->next; + } +} +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ diff --git a/net/lwip/src/core/pbuf.c b/net/lwip/src/core/pbuf.c index 8d935b023..50b22c354 100644 --- a/net/lwip/src/core/pbuf.c +++ b/net/lwip/src/core/pbuf.c @@ -70,6 +70,9 @@ #include "lwip/pbuf.h" #include "lwip/sys.h" #include "arch/perf.h" +#if TCP_QUEUE_OOSEQ +#include "lwip/tcp.h" +#endif #include @@ -78,6 +81,42 @@ 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 +/** + * 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. + */ +static struct pbuf * +alloc_pool_pbuf(void) +{ + struct tcp_pcb *pcb; + struct pbuf *p; + +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; + } + } + } + return p; +} +#endif /* TCP_QUEUE_OOSEQ */ + /** * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). * @@ -142,7 +181,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) switch (type) { case PBUF_POOL: /* allocate head of pbuf chain into p */ - p = memp_malloc(MEMP_PBUF_POOL); + ALLOC_POOL_PBUF(p); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); if (p == NULL) { return NULL; @@ -161,6 +200,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", ((u8_t*)p->payload + p->len <= (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); + LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", + (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); /* set reference count (needed here in case we fail) */ p->ref = 1; @@ -172,7 +213,7 @@ 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) { - q = memp_malloc(MEMP_PBUF_POOL); + ALLOC_POOL_PBUF(q); if (q == NULL) { /* free chain so far allocated */ pbuf_free(p); @@ -272,6 +313,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len) u16_t rem_len; /* remaining length */ s32_t grow; + LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || p->type == PBUF_ROM || p->type == PBUF_RAM || @@ -299,6 +341,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len) q->tot_len += (u16_t)grow; /* proceed to next pbuf in chain */ q = q->next; + LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); } /* we have now reached the new last pbuf (in q) */ /* rem_len == desired length for pbuf q */ @@ -667,8 +710,8 @@ pbuf_dechain(struct pbuf *p) * * @note Only one packet is copied, no packet queue! * - * @param p_to pbuf source of the copy - * @param p_from pbuf destination of the copy + * @param p_to pbuf destination of the copy + * @param p_from pbuf source of the copy * * @return ERR_OK if pbuf was copied * ERR_ARG if one of the pbufs is NULL or p_to is not big @@ -735,8 +778,10 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) * * @param buf the pbuf from which to copy data * @param dataptr the application supplied buffer - * @param len length of data to copy (dataptr must be big enough) + * @param len length of data to copy (dataptr must be big enough). No more + * than buf->tot_len will be copied, irrespective of len * @param offset offset into the packet buffer from where to begin copying len bytes + * @return the number of bytes copied, or 0 on failure */ u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) @@ -746,8 +791,8 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) u16_t buf_copy_len; u16_t copied_total = 0; - LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;); - LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); + LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); + LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); left = 0; @@ -775,3 +820,76 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) } return copied_total; } + +/** + * Copy application supplied data into a pbuf. + * This function can only be used to copy the equivalent of buf->tot_len data. + * + * @param buf pbuf to fill with data + * @param dataptr application supplied data buffer + * @param len length of the application supplied data buffer + * + * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough + */ +err_t +pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) +{ + struct pbuf *p; + u16_t buf_copy_len; + u16_t total_copy_len = len; + u16_t copied_total = 0; + + LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); + LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); + + if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { + return ERR_ARG; + } + + /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ + for(p = buf; total_copy_len != 0; p = p->next) { + LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); + buf_copy_len = total_copy_len; + if (buf_copy_len > p->len) { + /* this pbuf cannot hold all remaining data */ + buf_copy_len = p->len; + } + /* copy the necessary parts of the buffer */ + MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); + total_copy_len -= buf_copy_len; + copied_total += buf_copy_len; + } + LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); + return ERR_OK; +} + +/** + * Creates a single pbuf out of a queue of pbufs. + * + * @remark: The source pbuf 'p' is not freed by this function because that can + * be illegal in some places! + * + * @param p the source pbuf + * @param layer pbuf_layer of the new pbuf + * + * @return a new, single pbuf (p->next is NULL) + * or the old pbuf if allocation fails + */ +struct pbuf* +pbuf_coalesce(struct pbuf *p, pbuf_layer layer) +{ + struct pbuf *q; + err_t err; + if (p->next == NULL) { + return p; + } + q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); + if (q == NULL) { + /* @todo: what do we do now? */ + return p; + } + err = pbuf_copy(q, p); + LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); + pbuf_free(p); + return q; +} diff --git a/net/lwip/src/core/raw.c b/net/lwip/src/core/raw.c index 5131c702b..589950e75 100644 --- a/net/lwip/src/core/raw.c +++ b/net/lwip/src/core/raw.c @@ -93,24 +93,29 @@ raw_input(struct pbuf *p, struct netif *inp) /* this allows multiple pcbs to match against the packet by design */ while ((eaten == 0) && (pcb != NULL)) { if (pcb->protocol == proto) { - /* receive callback function available? */ - if (pcb->recv != NULL) { - /* the receive callback function did not eat the packet? */ - if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) - { - /* receive function ate the packet */ - p = NULL; - eaten = 1; - if (prev != NULL) { - /* move the pcb to the front of raw_pcbs so that is - found faster next time */ - prev->next = pcb->next; - pcb->next = raw_pcbs; - raw_pcbs = pcb; +#if IP_SOF_BROADCAST_RECV + /* broadcast filter? */ + if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp)) +#endif /* IP_SOF_BROADCAST_RECV */ + { + /* receive callback function available? */ + if (pcb->recv != NULL) { + /* the receive callback function did not eat the packet? */ + if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) { + /* receive function ate the packet */ + p = NULL; + eaten = 1; + if (prev != NULL) { + /* move the pcb to the front of raw_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } } } + /* no receive callback function was set for this raw PCB */ } - /* no receive callback function was set for this raw PCB */ /* drop the packet */ } prev = pcb; @@ -228,7 +233,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) return ERR_MEM; } } - + if ((netif = ip_route(ipaddr)) == NULL) { LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr)); /* free any temporary header pbuf allocated by pbuf_header() */ @@ -238,6 +243,18 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) return ERR_RTE; } +#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)); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_VAL; + } +#endif /* IP_SOF_BROADCAST */ + if (ip_addr_isany(&pcb->local_ip)) { /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); diff --git a/net/lwip/src/core/snmp/mib2.c b/net/lwip/src/core/snmp/mib2.c index c5c2f362e..33eeee66c 100644 --- a/net/lwip/src/core/snmp/mib2.c +++ b/net/lwip/src/core/snmp/mib2.c @@ -2205,10 +2205,10 @@ system_get_value(struct obj_def *od, u16_t len, void *value) switch (id) { case 1: /* sysDescr */ - ocstrncpy(value,sysdescr_ptr,len); + ocstrncpy(value,sysdescr_ptr, len); break; case 2: /* sysObjectID */ - objectidncpy((s32_t*)value,(s32_t*)sysobjid.id,len / sizeof(s32_t)); + objectidncpy((s32_t*)value, (s32_t*)sysobjid.id, (u8_t)(len / sizeof(s32_t))); break; case 3: /* sysUpTime */ { @@ -2606,7 +2606,7 @@ ifentry_get_value(struct obj_def *od, u16_t len, void *value) } break; case 22: /* ifSpecific */ - objectidncpy((s32_t*)value,(s32_t*)ifspecific.id,len / sizeof(s32_t)); + objectidncpy((s32_t*)value, (s32_t*)ifspecific.id, (u8_t)(len / sizeof(s32_t))); break; }; } @@ -3342,7 +3342,7 @@ ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) } break; case 13: /* ipRouteInfo */ - objectidncpy((s32_t*)value,(s32_t*)iprouteinfo.id,len / sizeof(s32_t)); + objectidncpy((s32_t*)value, (s32_t*)iprouteinfo.id, (u8_t)(len / sizeof(s32_t))); break; } } diff --git a/net/lwip/src/core/snmp/msg_in.c b/net/lwip/src/core/snmp/msg_in.c index bf2b1964b..d0c3c7534 100644 --- a/net/lwip/src/core/snmp/msg_in.c +++ b/net/lwip/src/core/snmp/msg_in.c @@ -589,9 +589,10 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) { struct mib_external_node *en; - /** set_value_a() @todo: use reply value?? */ + /** set_value_a() */ en = msg_ps->ext_mib_node; - en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL); + en->set_value_a(request_id, &msg_ps->ext_object_def, + msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value); /** @todo use set_value_pc() if toobig */ msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; @@ -1145,7 +1146,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) || - (len <= 0) || (len > vb_len)) + (len == 0) || (len > vb_len)) { snmp_inc_snmpinasnparseerrs(); /* free varbinds (if available) */ diff --git a/net/lwip/src/core/stats.c b/net/lwip/src/core/stats.c index 0604468dd..a036d83bb 100644 --- a/net/lwip/src/core/stats.c +++ b/net/lwip/src/core/stats.c @@ -54,7 +54,6 @@ stats_display_proto(struct stats_proto *proto, char *name) { LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); - LWIP_PLATFORM_DIAG(("rexmit: %"STAT_COUNTER_F"\n\t", proto->rexmit)); LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv)); LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw)); LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop)); @@ -68,6 +67,7 @@ stats_display_proto(struct stats_proto *proto, char *name) LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit)); } +#if IGMP_STATS void stats_display_igmp(struct stats_igmp *igmp) { @@ -82,7 +82,9 @@ stats_display_igmp(struct stats_igmp *igmp) LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed)); LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed)); } +#endif /* IGMP_STATS */ +#if MEM_STATS || MEMP_STATS void stats_display_mem(struct stats_mem *mem, char *name) { @@ -93,48 +95,53 @@ stats_display_mem(struct stats_mem *mem, char *name) LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err)); } -void -stats_display(void) -{ #if MEMP_STATS - s16_t i; +void +stats_display_memp(struct stats_mem *mem, int index) +{ char * memp_names[] = { #define LWIP_MEMPOOL(name,num,size,desc) desc, #include "lwip/memp_std.h" }; -#endif -#if LINK_STATS - stats_display_proto(&lwip_stats.link, "LINK"); -#endif -#if ETHARP_STATS - stats_display_proto(&lwip_stats.etharp, "ETHARP"); -#endif -#if IPFRAG_STATS - stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG"); -#endif -#if IP_STATS - stats_display_proto(&lwip_stats.ip, "IP"); -#endif -#if ICMP_STATS - stats_display_proto(&lwip_stats.icmp, "ICMP"); -#endif -#if IGMP_STATS - stats_display_igmp(&lwip_stats.igmp); -#endif -#if UDP_STATS - stats_display_proto(&lwip_stats.udp, "UDP"); -#endif -#if TCP_STATS - stats_display_proto(&lwip_stats.tcp, "TCP"); -#endif -#if MEM_STATS - stats_display_mem(&lwip_stats.mem, "HEAP"); -#endif -#if MEMP_STATS - for (i = 0; i < MEMP_MAX; i++) { - stats_display_mem(&lwip_stats.memp[i], memp_names[i]); + if(index < MEMP_MAX) { + stats_display_mem(mem, memp_names[index]); } -#endif +} +#endif /* MEMP_STATS */ +#endif /* MEM_STATS || MEMP_STATS */ + +#if SYS_STATS +void +stats_display_sys(struct stats_sys *sys) +{ + LWIP_PLATFORM_DIAG(("\nSYS\n\t")); + LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); + LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); + LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); + LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); + LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); + LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); +} +#endif /* SYS_STATS */ + +void +stats_display(void) +{ + s16_t i; + + LINK_STATS_DISPLAY(); + ETHARP_STATS_DISPLAY(); + IPFRAG_STATS_DISPLAY(); + IP_STATS_DISPLAY(); + IGMP_STATS_DISPLAY(); + ICMP_STATS_DISPLAY(); + UDP_STATS_DISPLAY(); + TCP_STATS_DISPLAY(); + MEM_STATS_DISPLAY(); + for (i = 0; i < MEMP_MAX; i++) { + MEMP_STATS_DISPLAY(i); + } + SYS_STATS_DISPLAY(); } #endif /* LWIP_STATS_DISPLAY */ diff --git a/net/lwip/src/core/sys.c b/net/lwip/src/core/sys.c index c5a643b95..d1fbda4e6 100644 --- a/net/lwip/src/core/sys.c +++ b/net/lwip/src/core/sys.c @@ -65,7 +65,7 @@ struct sswt_cb void sys_mbox_fetch(sys_mbox_t mbox, void **msg) { - u32_t time; + u32_t time_needed; struct sys_timeouts *timeouts; struct sys_timeo *tmptimeout; sys_timeout_handler h; @@ -76,18 +76,18 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg) if (!timeouts || !timeouts->next) { UNLOCK_TCPIP_CORE(); - time = sys_arch_mbox_fetch(mbox, msg, 0); + time_needed = sys_arch_mbox_fetch(mbox, msg, 0); LOCK_TCPIP_CORE(); } else { if (timeouts->next->time > 0) { UNLOCK_TCPIP_CORE(); - time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time); + time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time); LOCK_TCPIP_CORE(); } else { - time = SYS_ARCH_TIMEOUT; + time_needed = SYS_ARCH_TIMEOUT; } - if (time == SYS_ARCH_TIMEOUT) { + if (time_needed == SYS_ARCH_TIMEOUT) { /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message could be fetched. We should now call the timeout handler and deallocate the memory allocated for the timeout. */ @@ -107,8 +107,8 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg) /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout occured. The time variable is set to the number of milliseconds we waited for the message. */ - if (time < timeouts->next->time) { - timeouts->next->time -= time; + if (time_needed < timeouts->next->time) { + timeouts->next->time -= time_needed; } else { timeouts->next->time = 0; } @@ -125,7 +125,7 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg) void sys_sem_wait(sys_sem_t sem) { - u32_t time; + u32_t time_needed; struct sys_timeouts *timeouts; struct sys_timeo *tmptimeout; sys_timeout_handler h; @@ -139,12 +139,12 @@ sys_sem_wait(sys_sem_t sem) sys_arch_sem_wait(sem, 0); } else { if (timeouts->next->time > 0) { - time = sys_arch_sem_wait(sem, timeouts->next->time); + time_needed = sys_arch_sem_wait(sem, timeouts->next->time); } else { - time = SYS_ARCH_TIMEOUT; + time_needed = SYS_ARCH_TIMEOUT; } - if (time == SYS_ARCH_TIMEOUT) { + if (time_needed == SYS_ARCH_TIMEOUT) { /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message could be fetched. We should now call the timeout handler and deallocate the memory allocated for the timeout. */ @@ -164,8 +164,8 @@ sys_sem_wait(sys_sem_t sem) /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout occured. The time variable is set to the number of milliseconds we waited for the message. */ - if (time < timeouts->next->time) { - timeouts->next->time -= time; + if (time_needed < timeouts->next->time) { + timeouts->next->time -= time_needed; } else { timeouts->next->time = 0; } diff --git a/net/lwip/src/core/tcp.c b/net/lwip/src/core/tcp.c index cfa0bd095..0f3fd41c3 100644 --- a/net/lwip/src/core/tcp.c +++ b/net/lwip/src/core/tcp.c @@ -49,6 +49,7 @@ #include "lwip/memp.h" #include "lwip/snmp.h" #include "lwip/tcp.h" +#include "lwip/debug.h" #include @@ -186,14 +187,15 @@ tcp_close(struct tcp_pcb *pcb) } /** - * Aborts a connection by sending a RST to the remote host and deletes - * the local protocol control block. This is done when a connection is - * killed because of shortage of memory. + * Abandons a connection and optionally sends a RST to the remote + * host. Deletes the local protocol control block. This is done when + * a connection is killed because of shortage of memory. * * @param pcb the tcp_pcb to abort + * @param reset boolean to indicate whether a reset should be sent */ void -tcp_abort(struct tcp_pcb *pcb) +tcp_abandon(struct tcp_pcb *pcb, int reset) { u32_t seqno, ackno; u16_t remote_port, local_port; @@ -235,8 +237,10 @@ tcp_abort(struct tcp_pcb *pcb) #endif /* TCP_QUEUE_OOSEQ */ memp_free(MEMP_TCP_PCB, pcb); TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n")); - tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); + if (reset) { + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); + tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); + } } } @@ -258,7 +262,7 @@ tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) { struct tcp_pcb *cpcb; - LWIP_ERROR("tcp_connect: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); if (port == 0) { port = tcp_new_port(); @@ -380,6 +384,33 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) return (struct tcp_pcb *)lpcb; } +/** + * Update the state that tracks the available window space to advertise. + * + * Returns how much extra window would be advertised if we sent an + * update now. + */ +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)) { + /* we can advertise more window */ + pcb->rcv_ann_wnd = pcb->rcv_wnd; + return new_right_edge - pcb->rcv_ann_right_edge; + } else { + if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { + /* Can happen due to other end sending out of advertised window, + * but within actual available (but not yet advertised) window */ + pcb->rcv_ann_wnd = 0; + } else { + /* keep the right edge of window constant */ + pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; + } + return 0; + } +} + /** * This function should be called by the application when it has * processed the data. The purpose is to advertise a larger window @@ -391,40 +422,23 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) void tcp_recved(struct tcp_pcb *pcb, u16_t len) { - if ((u32_t)pcb->rcv_wnd + len > TCP_WND) { - pcb->rcv_wnd = TCP_WND; - pcb->rcv_ann_wnd = TCP_WND; - } else { - pcb->rcv_wnd += len; - if (pcb->rcv_wnd >= pcb->mss) { - pcb->rcv_ann_wnd = pcb->rcv_wnd; - } - } + int wnd_inflation; - if (!(pcb->flags & TF_ACK_DELAY) && - !(pcb->flags & TF_ACK_NOW)) { - /* - * We send an ACK here (if one is not already pending, hence - * the above tests) as tcp_recved() implies that the application - * has processed some data, and so we can open the receiver's - * window to allow more to be transmitted. This could result in - * two ACKs being sent for each received packet in some limited cases - * (where the application is only receiving data, and is slow to - * process it) but it is necessary to guarantee that the sender can - * continue to transmit. - */ - tcp_ack(pcb); - } - else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) { - /* If we can send a window update such that there is a full - * segment available in the window, do so now. This is sort of - * nagle-like in its goals, and tries to hit a compromise between - * sending acks each time the window is updated, and only sending - * window updates when a timer expires. The "threshold" used - * above (currently TCP_WND/2) can be tuned to be more or less - * aggressive */ + LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n", + len <= 0xffff - pcb->rcv_wnd ); + + pcb->rcv_wnd += len; + if (pcb->rcv_wnd > TCP_WND) + pcb->rcv_wnd = TCP_WND; + + wnd_inflation = tcp_update_rcv_ann_wnd(pcb); + + /* If the change in the right edge of window is significant (default + * watermark is TCP_WND/2), then send an explicit update now. + * Otherwise wait for a packet to be sent in the normal course of + * events (or more window to be available later) */ + if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) tcp_ack_now(pcb); - } LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); @@ -485,7 +499,6 @@ err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) { - u32_t optdata; err_t ret; u32_t iss; @@ -508,8 +521,10 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, pcb->snd_lbb = iss - 1; pcb->rcv_wnd = TCP_WND; pcb->rcv_ann_wnd = TCP_WND; + pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->snd_wnd = TCP_WND; - /* The send MSS is updated when an MSS option is received. */ + /* As initial send MSS, we use TCP_MSS but limit it to 536. + The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; #if TCP_CALCULATE_EFF_SEND_MSS pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); @@ -525,10 +540,11 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, snmp_inc_tcpactiveopens(); - /* Build an MSS option */ - optdata = TCP_BUILD_MSS_OPTION(); - - ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4); + ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS +#if LWIP_TCP_TIMESTAMPS + | TF_SEG_OPTS_TS +#endif + ); if (ret == ERR_OK) { tcp_output(pcb); } @@ -991,7 +1007,8 @@ tcp_alloc(u8_t prio) pcb->rcv_ann_wnd = TCP_WND; pcb->tos = 0; pcb->ttl = TCP_TTL; - /* The send MSS is updated when an MSS option is received. */ + /* As initial send MSS, we use TCP_MSS but limit it to 536. + The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; pcb->rto = 3000 / TCP_SLOW_INTERVAL; pcb->sa = 0; @@ -1001,7 +1018,6 @@ tcp_alloc(u8_t prio) iss = tcp_next_iss(); pcb->snd_wl2 = iss; pcb->snd_nxt = iss; - pcb->snd_max = iss; pcb->lastack = iss; pcb->snd_lbb = iss; pcb->tmr = tcp_ticks; @@ -1112,7 +1128,7 @@ void tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) { - ((struct tcp_pcb_listen *)pcb)->accept = accept; + pcb->accept = accept; } #endif /* LWIP_CALLBACK_API */ @@ -1148,6 +1164,27 @@ tcp_pcb_purge(struct tcp_pcb *pcb) LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); +#if TCP_LISTEN_BACKLOG + if (pcb->state == SYN_RCVD) { + /* Need to find the corresponding listen_pcb and decrease its accepts_pending */ + struct tcp_pcb_listen *lpcb; + LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL", + tcp_listen_pcbs.listen_pcbs != NULL); + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if ((lpcb->local_port == pcb->local_port) && + (ip_addr_isany(&lpcb->local_ip) || + ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) { + /* port and address of the listen pcb match the timed-out pcb */ + LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", + lpcb->accepts_pending > 0); + lpcb->accepts_pending--; + break; + } + } + } +#endif /* TCP_LISTEN_BACKLOG */ + + if (pcb->refused_data != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); pbuf_free(pcb->refused_data); @@ -1242,7 +1279,9 @@ tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr) mss_s = outif->mtu - IP_HLEN - TCP_HLEN; /* RFC 1122, chap 4.2.2.6: * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize - * but we only send options with SYN and that is never filled with data! */ + * We correct for TCP options in tcp_enqueue(), and don't support + * IP options + */ sendmss = LWIP_MIN(sendmss, mss_s); } return sendmss; @@ -1364,6 +1403,7 @@ tcp_debug_print_flags(u8_t flags) if (flags & TCP_CWR) { LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); } + LWIP_DEBUGF(TCP_DEBUG, ("\n")); } /** diff --git a/net/lwip/src/core/tcp_in.c b/net/lwip/src/core/tcp_in.c index a06d9ae11..362a4a62d 100644 --- a/net/lwip/src/core/tcp_in.c +++ b/net/lwip/src/core/tcp_in.c @@ -169,8 +169,8 @@ tcp_input(struct pbuf *p, struct netif *inp) ackno = tcphdr->ackno = ntohl(tcphdr->ackno); tcphdr->wnd = ntohs(tcphdr->wnd); - flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS; - tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0); + flags = TCPH_FLAGS(tcphdr); + tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0); /* Demultiplex an incoming segment. First, we check if it is destined for an active connection. */ @@ -393,7 +393,7 @@ static err_t tcp_listen_input(struct tcp_pcb_listen *pcb) { struct tcp_pcb *npcb; - u32_t optdata; + err_t rc; /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ @@ -408,6 +408,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); #if TCP_LISTEN_BACKLOG if (pcb->accepts_pending >= pcb->backlog) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); return ERR_ABRT; } #endif /* TCP_LISTEN_BACKLOG */ @@ -430,6 +431,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) npcb->remote_port = tcphdr->src; npcb->state = SYN_RCVD; npcb->rcv_nxt = seqno + 1; + npcb->rcv_ann_right_edge = npcb->rcv_nxt; npcb->snd_wnd = tcphdr->wnd; npcb->ssthresh = npcb->snd_wnd; npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ @@ -451,10 +453,17 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) snmp_inc_tcppassiveopens(); - /* Build an MSS option. */ - optdata = TCP_BUILD_MSS_OPTION(); /* Send a SYN|ACK together with the MSS option. */ - tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4); + rc = tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS +#if LWIP_TCP_TIMESTAMPS + /* and maybe include the TIMESTAMP option */ + | (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0) +#endif + ); + if (rc != ERR_OK) { + tcp_abandon(npcb, 0); + return rc; + } return tcp_output(npcb); } return ERR_OK; @@ -498,7 +507,6 @@ tcp_process(struct tcp_pcb *pcb) struct tcp_seg *rseg; u8_t acceptable = 0; err_t err; - u8_t accepted_inseq; err = ERR_OK; @@ -511,7 +519,7 @@ tcp_process(struct tcp_pcb *pcb) } } else { if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, - pcb->rcv_nxt+pcb->rcv_ann_wnd)) { + pcb->rcv_nxt+pcb->rcv_wnd)) { acceptable = 1; } } @@ -519,7 +527,7 @@ tcp_process(struct tcp_pcb *pcb) if (acceptable) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); - recv_flags = TF_RESET; + recv_flags |= TF_RESET; pcb->flags &= ~TF_ACK_DELAY; return ERR_RST; } else { @@ -531,10 +539,18 @@ tcp_process(struct tcp_pcb *pcb) } } + if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { + /* Cope with new connection attempt after remote end crashed */ + tcp_ack_now(pcb); + return ERR_OK; + } + /* Update the PCB (in)activity timer. */ pcb->tmr = tcp_ticks; pcb->keep_cnt_sent = 0; + tcp_parseopt(pcb); + /* Do different things depending on the TCP state. */ switch (pcb->state) { case SYN_SENT: @@ -545,14 +561,12 @@ tcp_process(struct tcp_pcb *pcb) && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { pcb->snd_buf++; pcb->rcv_nxt = seqno + 1; + pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->lastack = ackno; pcb->snd_wnd = tcphdr->wnd; pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ pcb->state = ESTABLISHED; - /* Parse any options in the SYNACK before using pcb->mss since that - * can be changed by the received options! */ - tcp_parseopt(pcb); #if TCP_CALCULATE_EFF_SEND_MSS pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ @@ -592,8 +606,7 @@ tcp_process(struct tcp_pcb *pcb) } break; case SYN_RCVD: - if (flags & TCP_ACK && - !(flags & TCP_RST)) { + if (flags & TCP_ACK) { /* expected ACK number? */ if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { u16_t old_cwnd; @@ -613,11 +626,11 @@ tcp_process(struct tcp_pcb *pcb) old_cwnd = pcb->cwnd; /* If there was any data contained within this ACK, * we'd better pass it on to the application as well. */ - accepted_inseq = tcp_receive(pcb); + tcp_receive(pcb); pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); - if ((flags & TCP_FIN) && accepted_inseq) { + if (recv_flags & TF_GOT_FIN) { tcp_ack_now(pcb); pcb->state = CLOSE_WAIT; } @@ -628,21 +641,24 @@ tcp_process(struct tcp_pcb *pcb) tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), tcphdr->dest, tcphdr->src); } + } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { + /* Looks like another copy of the SYN - retransmit our SYN-ACK */ + tcp_rexmit(pcb); } break; case CLOSE_WAIT: /* FALLTHROUGH */ case ESTABLISHED: - accepted_inseq = tcp_receive(pcb); - if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */ + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { /* passive close */ tcp_ack_now(pcb); pcb->state = CLOSE_WAIT; } break; case FIN_WAIT_1: tcp_receive(pcb); - if (flags & TCP_FIN) { - if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + 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_ack_now(pcb); @@ -654,13 +670,13 @@ tcp_process(struct tcp_pcb *pcb) tcp_ack_now(pcb); pcb->state = CLOSING; } - } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { pcb->state = FIN_WAIT_2; } break; case FIN_WAIT_2: tcp_receive(pcb); - if (flags & TCP_FIN) { + if (recv_flags & TF_GOT_FIN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); tcp_ack_now(pcb); tcp_pcb_purge(pcb); @@ -673,7 +689,6 @@ tcp_process(struct tcp_pcb *pcb) tcp_receive(pcb); if (flags & TCP_ACK && ackno == pcb->snd_nxt) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); tcp_pcb_purge(pcb); TCP_RMV(&tcp_active_pcbs, pcb); pcb->state = TIME_WAIT; @@ -685,7 +700,7 @@ tcp_process(struct tcp_pcb *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)); /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ - recv_flags = TF_CLOSED; + recv_flags |= TF_CLOSED; } break; default: @@ -723,7 +738,7 @@ tcp_receive(struct tcp_pcb *pcb) u8_t accepted_inseq = 0; if (flags & TCP_ACK) { - right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1; + right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; /* Update window. */ if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || @@ -739,8 +754,10 @@ tcp_receive(struct tcp_pcb *pcb) #if TCP_WND_DEBUG } else { if (pcb->snd_wnd != tcphdr->wnd) { - LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" snd_max %"U32_F" ackno %"U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", - pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); + LWIP_DEBUGF(TCP_WND_DEBUG, + ("tcp_receive: no window update lastack %"U32_F" ackno %" + U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", + pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); } #endif /* TCP_WND_DEBUG */ } @@ -748,7 +765,7 @@ tcp_receive(struct tcp_pcb *pcb) if (pcb->lastack == ackno) { pcb->acked = 0; - if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){ + if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ ++pcb->dupacks; if (pcb->dupacks >= 3 && pcb->unacked != NULL) { if (!(pcb->flags & TF_INFR)) { @@ -785,9 +802,9 @@ tcp_receive(struct tcp_pcb *pcb) } } else { LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n", - pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge)); + pcb->snd_wl2 + pcb->snd_wnd, right_wnd_edge)); } - } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){ + } 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 @@ -881,10 +898,8 @@ tcp_receive(struct tcp_pcb *pcb) ->unsent list after a retransmission, so these segments may in fact have been sent once. */ while (pcb->unsent != NULL && - /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) && - TCP_SEQ_LEQ(ackno, pcb->snd_max)*/ - TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max) - ) { + TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent))); @@ -900,10 +915,6 @@ tcp_receive(struct tcp_pcb *pcb) LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } - - if (pcb->unsent != NULL) { - pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno); - } } /* End of ACK for new data processing. */ @@ -1038,53 +1049,81 @@ tcp_receive(struct tcp_pcb *pcb) and below rcv_nxt + rcv_wnd) in order to be further processed. */ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, - pcb->rcv_nxt + pcb->rcv_ann_wnd - 1)){ + 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. */ + tcplen = TCP_TCPLEN(&inseg); + + if (tcplen > pcb->rcv_wnd) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U32_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + inseg.len = pcb->rcv_wnd; + if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { + inseg.len -= 1; + } + pbuf_realloc(inseg.p, inseg.len); + tcplen = TCP_TCPLEN(&inseg); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } #if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL && - TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) { - if (pcb->ooseq->len > 0) { - /* We have to trim the second edge of the incoming - segment. */ - inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno); - pbuf_realloc(inseg.p, inseg.len); - } 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))) { + if (pcb->ooseq != NULL) { + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("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 */ + while (pcb->ooseq != NULL) { struct tcp_seg *old_ooseq = pcb->ooseq; pcb->ooseq = pcb->ooseq->next; memp_free(MEMP_TCP_SEG, 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)); + /* 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) { + inseg.len -= 1; + } + pbuf_realloc(inseg.p, inseg.len); + 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); + } } } } #endif /* TCP_QUEUE_OOSEQ */ - tcplen = TCP_TCPLEN(&inseg); - - /* First received FIN will be ACKed +1, on any successive (duplicate) - * FINs we are already in CLOSE_WAIT and have already done +1. - */ - if (pcb->state != CLOSE_WAIT) { - pcb->rcv_nxt += tcplen; - } + pcb->rcv_nxt = seqno + tcplen; /* Update the receiver's (our) window. */ - if (pcb->rcv_wnd < tcplen) { - pcb->rcv_wnd = 0; - } else { - pcb->rcv_wnd -= tcplen; - } + LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); + pcb->rcv_wnd -= tcplen; - if (pcb->rcv_ann_wnd < tcplen) { - pcb->rcv_ann_wnd = 0; - } else { - pcb->rcv_ann_wnd -= tcplen; - } + tcp_update_rcv_ann_wnd(pcb); /* If there is data in the segment, we make preparations to pass this up to the application. The ->recv_data variable @@ -1104,7 +1143,7 @@ tcp_receive(struct tcp_pcb *pcb) } if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); - recv_flags = TF_GOT_FIN; + recv_flags |= TF_GOT_FIN; } #if TCP_QUEUE_OOSEQ @@ -1117,16 +1156,11 @@ tcp_receive(struct tcp_pcb *pcb) seqno = pcb->ooseq->tcphdr->seqno; pcb->rcv_nxt += TCP_TCPLEN(cseg); - if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) { - pcb->rcv_wnd = 0; - } else { - pcb->rcv_wnd -= TCP_TCPLEN(cseg); - } - if (pcb->rcv_ann_wnd < TCP_TCPLEN(cseg)) { - pcb->rcv_ann_wnd = 0; - } else { - pcb->rcv_ann_wnd -= TCP_TCPLEN(cseg); - } + LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", + pcb->rcv_wnd >= TCP_TCPLEN(cseg)); + pcb->rcv_wnd -= TCP_TCPLEN(cseg); + + tcp_update_rcv_ann_wnd(pcb); if (cseg->p->tot_len > 0) { /* Chain this pbuf onto the pbuf that we will pass to @@ -1140,7 +1174,7 @@ tcp_receive(struct tcp_pcb *pcb) } if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); - recv_flags = TF_GOT_FIN; + recv_flags |= TF_GOT_FIN; if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ pcb->state = CLOSE_WAIT; } @@ -1195,14 +1229,14 @@ tcp_receive(struct tcp_pcb *pcb) } 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_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); + } } } break; @@ -1282,10 +1316,7 @@ tcp_receive(struct tcp_pcb *pcb) } } else { - if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, - pcb->rcv_nxt + pcb->rcv_ann_wnd-1)){ - tcp_ack_now(pcb); - } + tcp_ack_now(pcb); } } else { /* Segments with length 0 is taken care of here. Segments that @@ -1300,8 +1331,7 @@ tcp_receive(struct tcp_pcb *pcb) } /** - * Parses the options contained in the incoming segment. (Code taken - * from uIP with only small changes.) + * Parses the options contained in the incoming segment. * * Called from tcp_listen_input() and tcp_process(). * Currently, only the MSS option is supported! @@ -1311,35 +1341,72 @@ tcp_receive(struct tcp_pcb *pcb) static void tcp_parseopt(struct tcp_pcb *pcb) { - u8_t c; - u8_t *opts, opt; + u16_t c, max_c; u16_t mss; + u8_t *opts, opt; +#if LWIP_TCP_TIMESTAMPS + u32_t tsval; +#endif opts = (u8_t *)tcphdr + TCP_HLEN; /* Parse the TCP MSS option, if present. */ if(TCPH_HDRLEN(tcphdr) > 0x5) { - for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) { + max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2; + for (c = 0; c < max_c; ) { opt = opts[c]; - if (opt == 0x00) { + switch (opt) { + case 0x00: /* End of options. */ - break; - } else if (opt == 0x01) { - ++c; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); + return; + case 0x01: /* NOP option. */ - } else if (opt == 0x02 && - opts[c + 1] == 0x04) { + ++c; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); + break; + case 0x02: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); + if (opts[c + 1] != 0x04 || c + 0x04 > max_c) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } /* An MSS option with the right option length. */ mss = (opts[c + 2] << 8) | opts[c + 3]; - pcb->mss = mss > TCP_MSS? TCP_MSS: mss; - - /* And we are done processing options. */ + /* Limit the mss to the configured TCP_MSS and prevent division by zero */ + pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; + /* Advance to next option */ + c += 0x04; break; - } else { +#if LWIP_TCP_TIMESTAMPS + case 0x08: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); + if (opts[c + 1] != 0x0A || c + 0x0A > max_c) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* TCP timestamp option with valid length */ + tsval = (opts[c+2]) | (opts[c+3] << 8) | + (opts[c+4] << 16) | (opts[c+5] << 24); + if (flags & TCP_SYN) { + pcb->ts_recent = ntohl(tsval); + pcb->flags |= TF_TIMESTAMP; + } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { + pcb->ts_recent = ntohl(tsval); + } + /* Advance to next option */ + c += 0x0A; + break; +#endif + default: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); if (opts[c + 1] == 0) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); /* If the length field is zero, the options are malformed and we don't process them further. */ - break; + return; } /* All other options have a length field, so that we easily can skip past them. */ diff --git a/net/lwip/src/core/tcp_out.c b/net/lwip/src/core/tcp_out.c index c46e4b852..ca72d9dcc 100644 --- a/net/lwip/src/core/tcp_out.c +++ b/net/lwip/src/core/tcp_out.c @@ -59,6 +59,27 @@ /* Forward declarations.*/ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); +static struct tcp_hdr * +tcp_output_set_header(struct tcp_pcb *pcb, struct pbuf *p, int optlen, + u32_t seqno_be /* already in network byte order */) +{ + struct tcp_hdr *tcphdr = p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dest = htons(pcb->remote_port); + tcphdr->seqno = seqno_be; + tcphdr->ackno = htonl(pcb->rcv_nxt); + TCPH_FLAGS_SET(tcphdr, TCP_ACK); + tcphdr->wnd = htons(pcb->rcv_ann_wnd); + tcphdr->urgp = 0; + TCPH_HDRLEN_SET(tcphdr, (5 + optlen / 4)); + tcphdr->chksum = 0; + + /* If we're sending a packet, update the announced right window edge */ + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + + return tcphdr; +} + /** * Called by tcp_close() to send a segment including flags but not data. * @@ -69,8 +90,8 @@ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) { - /* no data, no length, flags, copy=1, no optdata, no optdatalen */ - return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, NULL, 0); + /* no data, no length, flags, copy=1, no optdata */ + return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, 0); } /** @@ -102,7 +123,12 @@ tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags) pcb->state == SYN_SENT || pcb->state == SYN_RCVD) { if (len > 0) { - return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, NULL, 0); +#if LWIP_TCP_TIMESTAMPS + return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, + pcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0); +#else + return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, 0); +#endif } return ERR_OK; } else { @@ -112,7 +138,7 @@ tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags) } /** - * Enqueue either data or TCP options (but not both) for tranmission + * Enqueue data and/or TCP options for transmission * * Called by tcp_connect(), tcp_listen_input(), tcp_send_ctrl() and tcp_write(). * @@ -123,13 +149,11 @@ tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags) * @param apiflags combination of following flags : * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, - * @param optdata - * @param optlen + * @param optflags options to include in segment later on (see definition of struct tcp_seg) */ err_t tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, - u8_t flags, u8_t apiflags, - u8_t *optdata, u8_t optlen) + u8_t flags, u8_t apiflags, u8_t optflags) { struct pbuf *p; struct tcp_seg *seg, *useg, *queue; @@ -137,13 +161,17 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, u16_t left, seglen; void *ptr; u16_t queuelen; + u8_t optlen; + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, + ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n", + (void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags)); + LWIP_ERROR("tcp_enqueue: packet needs payload, options, or SYN/FIN (programmer violates API)", + ((len != 0) || (optflags != 0) || ((flags & (TCP_SYN | TCP_FIN)) != 0)), + return ERR_ARG;); + LWIP_ERROR("tcp_enqueue: len != 0 || arg == NULL (programmer violates API)", + ((len != 0) || (arg == NULL)), return ERR_ARG;); - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n", - (void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags)); - LWIP_ERROR("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)", - ((len == 0) || (optlen == 0)), return ERR_ARG;); - LWIP_ERROR("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)", - ((arg == NULL) || (optdata == NULL)), return ERR_ARG;); /* 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)); @@ -153,6 +181,8 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, left = len; ptr = arg; + optlen = LWIP_TCP_OPT_LENGTH(optflags); + /* seqno will be the sequence number of the first segment enqueued * by the call to this function. */ seqno = pcb->snd_lbb; @@ -182,15 +212,14 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, useg = queue = seg = NULL; seglen = 0; while (queue == NULL || left > 0) { - - /* The segment length should be the MSS if the data to be enqueued - * is larger than the MSS. */ - seglen = left > pcb->mss? pcb->mss: left; + /* The segment length (including options) should be at most the MSS */ + seglen = left > (pcb->mss - optlen) ? (pcb->mss - optlen) : left; /* Allocate memory for tcp_seg, and fill in fields. */ seg = memp_malloc(MEMP_TCP_SEG); if (seg == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n")); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, + ("tcp_enqueue: could not allocate memory for tcp_seg\n")); goto memerr; } seg->next = NULL; @@ -211,62 +240,54 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, /* If copy is set, memory should be allocated * and data copied into pbuf, otherwise data comes from - * ROM or other static memory, and need not be copied. If - * optdata is != NULL, we have options instead of data. */ - - /* options? */ - if (optdata != NULL) { - if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { - goto memerr; - } - LWIP_ASSERT("check that first pbuf can hold optlen", - (seg->p->len >= optlen)); - queuelen += pbuf_clen(seg->p); - seg->dataptr = seg->p->payload; - } - /* copy from volatile memory? */ - else if (apiflags & TCP_WRITE_FLAG_COPY) { - if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); + * 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, + ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); goto memerr; } LWIP_ASSERT("check that first pbuf can hold the complete seglen", - (seg->p->len >= seglen)); + (seg->p->len >= seglen + optlen)); queuelen += pbuf_clen(seg->p); if (arg != NULL) { - MEMCPY(seg->p->payload, ptr, seglen); + MEMCPY((char *)seg->p->payload + optlen, ptr, seglen); } seg->dataptr = seg->p->payload; } /* do not copy data */ else { - /* First, allocate a pbuf for holding the data. - * since the referenced data is available at least until it is sent out on the - * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM - * instead of PBUF_REF here. - */ - if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); - goto memerr; - } - ++queuelen; - /* reference the non-volatile payload data */ - p->payload = ptr; - seg->dataptr = ptr; - - /* Second, allocate a pbuf for the headers. */ - if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) { - /* If allocation fails, we have to deallocate the data pbuf as - * well. */ - pbuf_free(p); - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n")); + /* First, allocate a pbuf for the headers. */ + if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, + ("tcp_enqueue: could not allocate memory for header pbuf\n")); goto memerr; } queuelen += pbuf_clen(seg->p); - /* Concatenate the headers and data pbufs together. */ - pbuf_cat(seg->p/*header*/, p/*data*/); - p = NULL; + /* Second, allocate a pbuf for holding the data. + * since the referenced data is available at least until it is sent out on the + * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM + * instead of PBUF_REF here. + */ + if (left > 0) { + if ((p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { + /* 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, + ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } + ++queuelen; + /* reference the non-volatile payload data */ + p->payload = ptr; + seg->dataptr = ptr; + + /* Concatenate the headers and data pbufs together. */ + pbuf_cat(seg->p/*header*/, p/*data*/); + p = NULL; + } } /* Now that there are more segments queued, we check again if the @@ -292,17 +313,10 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, TCPH_FLAGS_SET(seg->tcphdr, flags); /* don't fill in tcphdr->ackno and tcphdr->wnd until later */ - /* Copy the options into the header, if they are present. */ - if (optdata == NULL) { - TCPH_HDRLEN_SET(seg->tcphdr, 5); - } - else { - TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4)); - /* Copy options into data portion of segment. - Options can thus only be sent in non data carrying - segments such as SYN|ACK. */ - SMEMCPY(seg->dataptr, optdata, optlen); - } + seg->flags = optflags; + + /* Set the length of the header */ + TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4)); LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", ntohl(seg->tcphdr->seqno), ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), @@ -331,21 +345,33 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) && !(flags & (TCP_SYN | TCP_FIN)) && /* fit within max seg size */ - useg->len + queue->len <= pcb->mss) { + (useg->len + queue->len <= pcb->mss) && + /* only concatenate segments with the same options */ + (useg->flags == queue->flags)) { /* Remove TCP header from first segment of our to-be-queued list */ - if(pbuf_header(queue->p, -TCP_HLEN)) { + if(pbuf_header(queue->p, -(TCP_HLEN + optlen))) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); TCP_STATS_INC(tcp.err); goto memerr; } + if (queue->p->len == 0) { + /* free the first (header-only) pbuf if it is now empty (contained only headers) */ + struct pbuf *old_q = queue->p; + queue->p = queue->p->next; + old_q->next = NULL; + 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; 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) { - seg = NULL; + seg = useg; + seglen = useg->len; } memp_free(MEMP_TCP_SEG, queue); } @@ -400,6 +426,24 @@ memerr: return ERR_MEM; } + +#if LWIP_TCP_TIMESTAMPS +/* Build a timestamp option (12 bytes long) at the specified options pointer) + * + * @param pcb tcp_pcb + * @param opts option pointer where to store the timestamp option + */ +static void +tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) +{ + /* Pad with two NOP options to make everything nicely aligned */ + opts[0] = htonl(0x0101080A); + opts[1] = htonl(sys_now()); + opts[2] = htonl(pcb->ts_recent); +} +#endif + + /** * Find out what we can send and send it * @@ -413,10 +457,11 @@ tcp_output(struct tcp_pcb *pcb) struct pbuf *p; struct tcp_hdr *tcphdr; struct tcp_seg *seg, *useg; - u32_t wnd; + 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 @@ -434,8 +479,8 @@ tcp_output(struct tcp_pcb *pcb) 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. @@ -445,41 +490,37 @@ tcp_output(struct tcp_pcb *pcb) if (pcb->flags & TF_ACK_NOW && (seg == NULL || ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { - p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); +#if 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)); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, + ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); /* remove ACK flags from the PCB, as we send an empty ACK now */ pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - tcphdr = p->payload; - tcphdr->src = htons(pcb->local_port); - tcphdr->dest = htons(pcb->remote_port); - tcphdr->seqno = htonl(pcb->snd_nxt); - tcphdr->ackno = htonl(pcb->rcv_nxt); - TCPH_FLAGS_SET(tcphdr, TCP_ACK); - tcphdr->wnd = htons(pcb->rcv_ann_wnd); - tcphdr->urgp = 0; - TCPH_HDRLEN_SET(tcphdr, 5); + 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 - tcphdr->chksum = 0; #if CHECKSUM_GEN_TCP tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), IP_PROTO_TCP, p->tot_len); #endif #if LWIP_NETIF_HWADDRHINT - { - struct netif *netif; - netif = ip_route(&pcb->remote_ip); - if(netif != NULL){ - netif->addr_hint = &(pcb->addr_hint); - ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, - pcb->tos, IP_PROTO_TCP, netif); - netif->addr_hint = NULL; - } - } + 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); @@ -543,9 +584,9 @@ tcp_output(struct tcp_pcb *pcb) } tcp_output_segment(seg, pcb); - pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); - if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) { - pcb->snd_max = pcb->snd_nxt; + snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); + if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { + pcb->snd_nxt = snd_nxt; } /* put segment on unacknowledged list if length > 0 */ if (TCP_TCPLEN(seg) > 0) { @@ -557,12 +598,17 @@ tcp_output(struct tcp_pcb *pcb) /* unacked list is not empty? */ } else { /* In the case of fast retransmit, the packet should not go to the tail - * of the unacked queue, but rather at the head. We need to check for + * of the unacked queue, but rather somewhere before it. We need to check for * this case. -STJ Jul 27, 2004 */ if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){ - /* add segment to head of unacked list */ - seg->next = pcb->unacked; - pcb->unacked = seg; + /* add segment to before tail of unacked list, keeping the list sorted */ + struct tcp_seg **cur_seg = &(pcb->unacked); + while (*cur_seg && + TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = (*cur_seg); + (*cur_seg) = seg; } else { /* add segment to tail of unacked list */ useg->next = seg; @@ -598,6 +644,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) { u16_t len; struct netif *netif; + u32_t *opts; /** @bug Exclude retransmitted segments from this count. */ snmp_inc_tcpoutsegs(); @@ -609,6 +656,24 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) /* advertise our receive window size in this TCP segment */ seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd); + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + + /* Add any requested options. NB MSS option is only set on SYN + packets, so ignore it here */ + opts = (u32_t *)(seg->tcphdr + 1); + if (seg->flags & TF_SEG_OPTS_MSS) { + TCP_BUILD_MSS_OPTION(*opts); + opts += 1; + } +#if LWIP_TCP_TIMESTAMPS + pcb->ts_lastacksent = pcb->rcv_nxt; + + if (seg->flags & TF_SEG_OPTS_TS) { + tcp_build_timestamp_option(pcb, opts); + opts += 3; + } +#endif + /* If we don't have a local IP address, we get one by calling ip_route(). */ if (ip_addr_isany(&(pcb->local_ip))) { @@ -650,16 +715,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) TCP_STATS_INC(tcp.xmit); #if LWIP_NETIF_HWADDRHINT - { - struct netif *netif; - netif = ip_route(&pcb->remote_ip); - if(netif != NULL){ - netif->addr_hint = &(pcb->addr_hint); - ip_output_if(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, - pcb->tos, IP_PROTO_TCP, netif); - netif->addr_hint = NULL; - } - } + ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, + IP_PROTO_TCP, &(pcb->addr_hint)); #else /* LWIP_NETIF_HWADDRHINT*/ ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, IP_PROTO_TCP); @@ -749,7 +806,6 @@ tcp_rexmit_rto(struct tcp_pcb *pcb) /* unacked queue is now empty */ pcb->unacked = NULL; - pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); /* increment number of retransmissions */ ++pcb->nrtx; @@ -771,18 +827,24 @@ void tcp_rexmit(struct tcp_pcb *pcb) { struct tcp_seg *seg; + struct tcp_seg **cur_seg; if (pcb->unacked == NULL) { return; } /* Move the first unacked segment to the unsent queue */ - seg = pcb->unacked->next; - pcb->unacked->next = pcb->unsent; - pcb->unsent = pcb->unacked; - pcb->unacked = seg; + /* Keep the unsent queue sorted. */ + seg = pcb->unacked; + pcb->unacked = seg->next; - pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); + cur_seg = &(pcb->unsent); + while (*cur_seg && + TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = *cur_seg; + *cur_seg = seg; ++pcb->nrtx; @@ -825,17 +887,8 @@ tcp_keepalive(struct tcp_pcb *pcb) LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", (p->len >= sizeof(struct tcp_hdr))); - tcphdr = p->payload; - tcphdr->src = htons(pcb->local_port); - tcphdr->dest = htons(pcb->remote_port); - tcphdr->seqno = htonl(pcb->snd_nxt - 1); - tcphdr->ackno = htonl(pcb->rcv_nxt); - TCPH_FLAGS_SET(tcphdr, 0); - tcphdr->wnd = htons(pcb->rcv_ann_wnd); - tcphdr->urgp = 0; - TCPH_HDRLEN_SET(tcphdr, 5); + tcphdr = tcp_output_set_header(pcb, p, 0, htonl(pcb->snd_nxt - 1)); - tcphdr->chksum = 0; #if CHECKSUM_GEN_TCP tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len); @@ -844,16 +897,8 @@ tcp_keepalive(struct tcp_pcb *pcb) /* Send output to IP */ #if LWIP_NETIF_HWADDRHINT - { - struct netif *netif; - netif = ip_route(&pcb->remote_ip); - if(netif != NULL){ - netif->addr_hint = &(pcb->addr_hint); - ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, - 0, IP_PROTO_TCP, netif); - netif->addr_hint = NULL; - } - } + ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, + &(pcb->addr_hint)); #else /* LWIP_NETIF_HWADDRHINT*/ ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ @@ -908,20 +953,11 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", (p->len >= sizeof(struct tcp_hdr))); - tcphdr = p->payload; - tcphdr->src = htons(pcb->local_port); - tcphdr->dest = htons(pcb->remote_port); - tcphdr->seqno = seg->tcphdr->seqno; - tcphdr->ackno = htonl(pcb->rcv_nxt); - TCPH_FLAGS_SET(tcphdr, 0); - tcphdr->wnd = htons(pcb->rcv_ann_wnd); - tcphdr->urgp = 0; - TCPH_HDRLEN_SET(tcphdr, 5); + 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; - tcphdr->chksum = 0; #if CHECKSUM_GEN_TCP tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len); @@ -930,16 +966,8 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) /* Send output to IP */ #if LWIP_NETIF_HWADDRHINT - { - struct netif *netif; - netif = ip_route(&pcb->remote_ip); - if(netif != NULL){ - netif->addr_hint = &(pcb->addr_hint); - ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, - 0, IP_PROTO_TCP, netif); - netif->addr_hint = NULL; - } - } + ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, + &(pcb->addr_hint)); #else /* LWIP_NETIF_HWADDRHINT*/ ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ diff --git a/net/lwip/src/core/udp.c b/net/lwip/src/core/udp.c index 2f36c7458..d8d644d44 100644 --- a/net/lwip/src/core/udp.c +++ b/net/lwip/src/core/udp.c @@ -90,6 +90,7 @@ udp_input(struct pbuf *p, struct netif *inp) struct ip_hdr *iphdr; u16_t src, dest; u8_t local_match; + u8_t broadcast; PERF_START; @@ -112,6 +113,9 @@ udp_input(struct pbuf *p, struct netif *inp) udphdr = (struct udp_hdr *)p->payload; + /* is broadcast packet ? */ + broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp); + LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); /* convert src and dest ports to host byte order */ @@ -169,16 +173,20 @@ udp_input(struct pbuf *p, struct netif *inp) /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && - (ip_addr_isany(&pcb->local_ip) || - ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || + ((!broadcast && ip_addr_isany(&pcb->local_ip)) || + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || #if LWIP_IGMP ip_addr_ismulticast(&(iphdr->dest)) || #endif /* LWIP_IGMP */ - ip_addr_isbroadcast(&(iphdr->dest), inp))) { +#if IP_SOF_BROADCAST_RECV + (broadcast && (pcb->so_options & SOF_BROADCAST)))) { +#else /* IP_SOF_BROADCAST_RECV */ + (broadcast))) { +#endif /* IP_SOF_BROADCAST_RECV */ local_match = 1; if ((uncon_pcb == NULL) && ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { - /* the first unconnected matching PCB */ + /* the first unconnected matching PCB */ uncon_pcb = pcb; } } @@ -286,7 +294,7 @@ udp_input(struct pbuf *p, struct netif *inp) #if LWIP_ICMP /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ - if (!ip_addr_isbroadcast(&iphdr->dest, inp) && + if (!broadcast && !ip_addr_ismulticast(&iphdr->dest)) { /* move payload pointer back to ip header */ pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); @@ -400,6 +408,14 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, err_t err; struct pbuf *q; /* q will be sent down the stack */ +#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)); + 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")); @@ -496,7 +512,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); + err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ @@ -519,7 +535,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); + err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ @@ -635,9 +651,9 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) } LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", - (u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff), - (u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff), - (u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff), + (u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff), + (u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff), + (u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff), (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port)); return ERR_OK; } @@ -693,9 +709,9 @@ udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) #endif LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n", - (u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff), - (u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff), - (u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff), + (u16_t)((ntohl(pcb->remote_ip.addr) >> 24) & 0xff), + (u16_t)((ntohl(pcb->remote_ip.addr) >> 16) & 0xff), + (u16_t)((ntohl(pcb->remote_ip.addr) >> 8) & 0xff), (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port)); /* Insert UDP PCB into the list of active UDP PCBs. */ diff --git a/net/lwip/src/include/ipv4/lwip/icmp.h b/net/lwip/src/include/ipv4/lwip/icmp.h index 59a31f9c6..ff838f43a 100644 --- a/net/lwip/src/include/ipv4/lwip/icmp.h +++ b/net/lwip/src/include/ipv4/lwip/icmp.h @@ -78,39 +78,30 @@ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif +/** This is the standard ICMP header only that the u32_t data + * is splitted to two u16_t like ICMP echo needs it. + * This header is also used for other ICMP types that do not + * use the data part. + */ PACK_STRUCT_BEGIN struct icmp_echo_hdr { - PACK_STRUCT_FIELD(u16_t _type_code); + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u16_t id); PACK_STRUCT_FIELD(u16_t seqno); } PACK_STRUCT_STRUCT; PACK_STRUCT_END - -PACK_STRUCT_BEGIN -struct icmp_dur_hdr { - PACK_STRUCT_FIELD(u16_t _type_code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u32_t unused); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END - -PACK_STRUCT_BEGIN -struct icmp_te_hdr { - PACK_STRUCT_FIELD(u16_t _type_code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u32_t unused); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif -#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8) -#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff) +#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) -#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8))) -#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8))) +/** Combines type and code to an u16_t */ +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) #ifdef __cplusplus } diff --git a/net/lwip/src/include/ipv4/lwip/inet.h b/net/lwip/src/include/ipv4/lwip/inet.h index 1ffcf7070..6f30d0d12 100644 --- a/net/lwip/src/include/ipv4/lwip/inet.h +++ b/net/lwip/src/include/ipv4/lwip/inet.h @@ -34,12 +34,20 @@ #include "lwip/opt.h" -#include "lwip/ip_addr.h" - #ifdef __cplusplus extern "C" { #endif +/* For compatibility with BSD code */ +struct in_addr { + u32_t s_addr; +}; + +#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */ +#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */ +#define INADDR_ANY ((u32_t)0x00000000UL) /* 0.0.0.0 */ +#define INADDR_BROADCAST ((u32_t)0xffffffffUL) /* 255.255.255.255 */ + u32_t inet_addr(const char *cp); int inet_aton(const char *cp, struct in_addr *addr); char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */ diff --git a/net/lwip/src/include/ipv4/lwip/inet_chksum.h b/net/lwip/src/include/ipv4/lwip/inet_chksum.h index d7c749269..5cae59cbd 100644 --- a/net/lwip/src/include/ipv4/lwip/inet_chksum.h +++ b/net/lwip/src/include/ipv4/lwip/inet_chksum.h @@ -46,9 +46,11 @@ u16_t inet_chksum_pbuf(struct pbuf *p); u16_t inet_chksum_pseudo(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t proto, u16_t proto_len); +#if LWIP_UDPLITE u16_t inet_chksum_pseudo_partial(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t proto, u16_t proto_len, u16_t chksum_len); +#endif #ifdef __cplusplus } diff --git a/net/lwip/src/include/ipv4/lwip/ip.h b/net/lwip/src/include/ipv4/lwip/ip.h index 3b760f006..14eba3ca5 100644 --- a/net/lwip/src/include/ipv4/lwip/ip.h +++ b/net/lwip/src/include/ipv4/lwip/ip.h @@ -38,19 +38,14 @@ #include "lwip/pbuf.h" #include "lwip/ip_addr.h" #include "lwip/err.h" +#include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif -#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); -err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t tos, u8_t proto); -err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t tos, u8_t proto, - struct netif *netif); +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND LWIP_IGMP #define IP_HLEN 20 @@ -103,7 +98,7 @@ struct ip_pcb { #define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */ #define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */ #define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */ -#define SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */ +#define SOF_BROADCAST (u16_t)0x0020U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ #define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */ #define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */ #define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */ @@ -158,6 +153,25 @@ 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) +#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); +err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto); +err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto, + struct netif *netif); +#if LWIP_NETIF_HWADDRHINT +err_t ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +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); #if IP_DEBUG void ip_debug_print(struct pbuf *p); #else diff --git a/net/lwip/src/include/ipv4/lwip/ip_addr.h b/net/lwip/src/include/ipv4/lwip/ip_addr.h index 7f2433638..f2e4c2233 100644 --- a/net/lwip/src/include/ipv4/lwip/ip_addr.h +++ b/net/lwip/src/include/ipv4/lwip/ip_addr.h @@ -34,6 +34,8 @@ #include "lwip/opt.h" +#include "lwip/inet.h" + #ifdef __cplusplus extern "C" { #endif @@ -66,11 +68,6 @@ PACK_STRUCT_END # include "arch/epstruct.h" #endif -/* For compatibility with BSD code */ -struct in_addr { - u32_t s_addr; -}; - struct netif; extern const struct ip_addr ip_addr_any; @@ -82,9 +79,6 @@ extern const struct ip_addr ip_addr_broadcast; #define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any) #define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast) -#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */ -#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */ - /* Definitions of the bits in an Internet address integer. On subnets, host and network parts are found according to @@ -150,11 +144,15 @@ u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *); #define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL)) #define ip_addr_debug_print(debug, ipaddr) \ - LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \ - ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \ - ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \ - ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \ - ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0)) + LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \ + ipaddr != NULL ? \ + (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \ + ipaddr != NULL ? \ + (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \ + ipaddr != NULL ? \ + (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \ + ipaddr != NULL ? \ + (u16_t)ntohl((ipaddr)->addr) & 0xff : 0)) /* These are cast to u16_t, with the intent that they are often arguments * to printf using the U16_F format from cc.h. */ diff --git a/net/lwip/src/include/ipv6/lwip/ip.h b/net/lwip/src/include/ipv6/lwip/ip.h index f6e59cc64..a01cfc65b 100644 --- a/net/lwip/src/include/ipv6/lwip/ip.h +++ b/net/lwip/src/include/ipv6/lwip/ip.h @@ -114,6 +114,9 @@ err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif); +#define ip_current_netif() NULL +#define ip_current_header() NULL + #if IP_DEBUG void ip_debug_print(struct pbuf *p); #endif /* IP_DEBUG */ diff --git a/net/lwip/src/include/lwip/api.h b/net/lwip/src/include/lwip/api.h index 31d767f21..f6b1f7434 100644 --- a/net/lwip/src/include/lwip/api.h +++ b/net/lwip/src/include/lwip/api.h @@ -36,6 +36,8 @@ #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ +#include /* for size_t */ + #include "lwip/netbuf.h" #include "lwip/sys.h" #include "lwip/ip_addr.h" @@ -137,19 +139,21 @@ struct netconn { /** maximum amount of bytes queued in recvmbox */ int recv_bufsize; #endif /* LWIP_SO_RCVBUF */ - u16_t recv_avail; + s16_t recv_avail; +#if LWIP_TCP /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores the message. */ struct api_msg_msg *write_msg; /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores how much is already sent. */ - int write_offset; + size_t write_offset; #if LWIP_TCPIP_CORE_LOCKING /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores whether to wake up the original application task if data couldn't be sent in the first try. */ u8_t write_delayed; #endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_TCP */ /** A callback function that is informed about events for this netconn */ netconn_callback callback; }; @@ -166,7 +170,8 @@ struct netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback); err_t netconn_delete (struct netconn *conn); -enum netconn_type netconn_type (struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) err_t netconn_getaddr (struct netconn *conn, struct ip_addr *addr, @@ -191,7 +196,7 @@ err_t netconn_sendto (struct netconn *conn, err_t netconn_send (struct netconn *conn, struct netbuf *buf); err_t netconn_write (struct netconn *conn, - const void *dataptr, int size, + const void *dataptr, size_t size, u8_t apiflags); err_t netconn_close (struct netconn *conn); diff --git a/net/lwip/src/include/lwip/api_msg.h b/net/lwip/src/include/lwip/api_msg.h index 4c9b48ef5..4272d77cc 100644 --- a/net/lwip/src/include/lwip/api_msg.h +++ b/net/lwip/src/include/lwip/api_msg.h @@ -36,6 +36,8 @@ #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ +#include /* for size_t */ + #include "lwip/ip_addr.h" #include "lwip/err.h" #include "lwip/sys.h" @@ -78,7 +80,7 @@ struct api_msg_msg { /** used for do_write */ struct { const void *dataptr; - int len; + size_t len; u8_t apiflags; } w; /** used ofr do_recv */ diff --git a/net/lwip/src/include/lwip/arch.h b/net/lwip/src/include/lwip/arch.h index 32018e47c..3a5a0e4f2 100644 --- a/net/lwip/src/include/lwip/arch.h +++ b/net/lwip/src/include/lwip/arch.h @@ -42,6 +42,11 @@ #include "arch/cc.h" +/** Temporary: define format string for size_t if not defined in cc.h */ +#ifndef SZT_F +#define SZT_F U32_F +#endif /* SZT_F */ + #ifdef __cplusplus extern "C" { #endif @@ -194,13 +199,7 @@ extern "C" { #define ENOMEDIUM 123 /* No medium found */ #define EMEDIUMTYPE 124 /* Wrong medium type */ -#ifndef errno -extern int errno; -#endif -#endif /* LWIP_PROVIDE_ERRNO */ - -/*yi.qiu@2008.09.08, Newlib does not provide following errno*/ #define ENSROK 0 /* DNS server returned answer with no data */ #define ENSRNODATA 160 /* DNS server returned answer with no data */ #define ENSRFORMERR 161 /* DNS server claims query was misformatted */ @@ -221,6 +220,12 @@ extern int errno; #define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */ #define ENSRCNAMELOOP 177 /* Domain name is too long */ +#ifndef errno +extern int errno; +#endif + +#endif /* LWIP_PROVIDE_ERRNO */ + #ifdef __cplusplus } #endif diff --git a/net/lwip/src/include/lwip/debug.h b/net/lwip/src/include/lwip/debug.h index 8070027d1..d5c4e4747 100644 --- a/net/lwip/src/include/lwip/debug.h +++ b/net/lwip/src/include/lwip/debug.h @@ -61,26 +61,28 @@ #define LWIP_DBG_HALT 0x08U #ifndef LWIP_NOASSERT -#define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0) +#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ + LWIP_PLATFORM_ASSERT(message); } while(0) #else /* LWIP_NOASSERT */ -#define LWIP_ASSERT(x,y) +#define LWIP_ASSERT(message, assertion) #endif /* LWIP_NOASSERT */ -/** print "m" message only if "e" is true, and execute "h" expression */ +/** if "expression" isn't true, then print "message" and execute "handler" expression */ #ifndef LWIP_ERROR -#define LWIP_ERROR(m,e,h) do { if (!(e)) { LWIP_PLATFORM_ASSERT(m); h;}} while(0) +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + LWIP_PLATFORM_ASSERT(message); handler;}} while(0) #endif /* LWIP_ERROR */ #ifdef LWIP_DEBUG /** print debug message only if debug message type is enabled... * AND is of correct type AND is at least LWIP_DBG_LEVEL */ -#define LWIP_DEBUGF(debug,x) do { \ +#define LWIP_DEBUGF(debug, message) do { \ if ( \ ((debug) & LWIP_DBG_ON) && \ ((debug) & LWIP_DBG_TYPES_ON) && \ ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ - LWIP_PLATFORM_DIAG(x); \ + LWIP_PLATFORM_DIAG(message); \ if ((debug) & LWIP_DBG_HALT) { \ while(1); \ } \ @@ -88,7 +90,7 @@ } while(0) #else /* LWIP_DEBUG */ -#define LWIP_DEBUGF(debug,x) +#define LWIP_DEBUGF(debug, message) #endif /* LWIP_DEBUG */ #endif /* __LWIP_DEBUG_H__ */ diff --git a/net/lwip/src/include/lwip/dhcp.h b/net/lwip/src/include/lwip/dhcp.h index 400f81fdf..825dba6ec 100644 --- a/net/lwip/src/include/lwip/dhcp.h +++ b/net/lwip/src/include/lwip/dhcp.h @@ -18,7 +18,7 @@ extern "C" { /** period (in seconds) of the application calling dhcp_coarse_tmr() */ #define DHCP_COARSE_TIMER_SECS 60 /** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ -#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS*1000) +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) /** period (in milliseconds) of the application calling dhcp_fine_tmr() */ #define DHCP_FINE_TIMER_MSECS 500 diff --git a/net/lwip/src/include/lwip/dns.h b/net/lwip/src/include/lwip/dns.h index 619674292..e5f4b7a3d 100644 --- a/net/lwip/src/include/lwip/dns.h +++ b/net/lwip/src/include/lwip/dns.h @@ -87,6 +87,11 @@ struct ip_addr dns_getserver(u8_t numdns); err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found, void *callback_arg); +#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int dns_local_removehost(const char *hostname, const struct ip_addr *addr); +err_t dns_local_addhost(const char *hostname, const struct ip_addr *addr); +#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + #endif /* LWIP_DNS */ #endif /* __LWIP_DNS_H__ */ diff --git a/net/lwip/src/include/lwip/err.h b/net/lwip/src/include/lwip/err.h index e50632352..696764454 100644 --- a/net/lwip/src/include/lwip/err.h +++ b/net/lwip/src/include/lwip/err.h @@ -33,37 +33,43 @@ #define __LWIP_ERR_H__ #include "lwip/opt.h" +#include "lwip/arch.h" #ifdef __cplusplus extern "C" { #endif -typedef s8_t err_t; +/** Define LWIP_ERR_T in cc.h if you want to use + * a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ + typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ /* Definitions for error constants. */ #define ERR_OK 0 /* No error, everything OK. */ #define ERR_MEM -1 /* Out of memory error. */ #define ERR_BUF -2 /* Buffer error. */ -#define ERR_RTE -3 /* Routing problem. */ +#define ERR_TIMEOUT -3 /* Timeout. */ +#define ERR_RTE -4 /* Routing problem. */ #define ERR_IS_FATAL(e) ((e) < ERR_RTE) -#define ERR_ABRT -4 /* Connection aborted. */ -#define ERR_RST -5 /* Connection reset. */ -#define ERR_CLSD -6 /* Connection closed. */ -#define ERR_CONN -7 /* Not connected. */ +#define ERR_ABRT -5 /* Connection aborted. */ +#define ERR_RST -6 /* Connection reset. */ +#define ERR_CLSD -7 /* Connection closed. */ +#define ERR_CONN -8 /* Not connected. */ -#define ERR_VAL -8 /* Illegal value. */ +#define ERR_VAL -9 /* Illegal value. */ -#define ERR_ARG -9 /* Illegal argument. */ +#define ERR_ARG -10 /* Illegal argument. */ -#define ERR_USE -10 /* Address in use. */ +#define ERR_USE -11 /* Address in use. */ -#define ERR_IF -11 /* Low-level netif error */ -#define ERR_ISCONN -12 /* Already connected. */ - -#define ERR_TIMEOUT -13 /* Timeout. */ +#define ERR_IF -12 /* Low-level netif error */ +#define ERR_ISCONN -13 /* Already connected. */ #define ERR_INPROGRESS -14 /* Operation in progress */ diff --git a/net/lwip/src/include/lwip/init.h b/net/lwip/src/include/lwip/init.h index c0869cfd8..a4dc0577f 100644 --- a/net/lwip/src/include/lwip/init.h +++ b/net/lwip/src/include/lwip/init.h @@ -38,6 +38,30 @@ extern "C" { #endif +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR 1U +/** 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 +/** 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) */ +#define LWIP_VERSION_RC 255U + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE 255U +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */ +#define LWIP_RC_DEVELOPMENT 0U + +#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/** Provides the version of the stack */ +#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \ + LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + /* Modules initialization */ void lwip_init(void); diff --git a/net/lwip/src/include/lwip/mem.h b/net/lwip/src/include/lwip/mem.h index cf9173349..327c2049f 100644 --- a/net/lwip/src/include/lwip/mem.h +++ b/net/lwip/src/include/lwip/mem.h @@ -50,16 +50,20 @@ typedef size_t mem_size_t; * allow these defines to be overridden. */ #ifndef mem_free -#define mem_free(x) free(x) +#define mem_free free #endif #ifndef mem_malloc -#define mem_malloc(x) malloc(x) +#define mem_malloc malloc #endif #ifndef mem_calloc -#define mem_calloc(x, y) calloc(x, y) +#define mem_calloc calloc #endif #ifndef mem_realloc -#define mem_realloc(x, size) (x) +static void *mem_realloc(void *mem, mem_size_t size) +{ + LWIP_UNUSED_ARG(size); + return mem; +} #endif #else /* MEM_LIBC_MALLOC */ diff --git a/net/lwip/src/include/lwip/memp.h b/net/lwip/src/include/lwip/memp.h index a04386335..f0d073994 100644 --- a/net/lwip/src/include/lwip/memp.h +++ b/net/lwip/src/include/lwip/memp.h @@ -73,8 +73,28 @@ typedef enum { We use this helper type and these defines so we can avoid using const memp_t values */ #define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) #define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS */ +#if MEMP_MEM_MALLOC || MEM_USE_POOLS extern const u16_t memp_sizes[MEMP_MAX]; +#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC + +#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 */ + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. */ +struct memp_malloc_helper +{ + memp_t poolnr; +}; #endif /* MEM_USE_POOLS */ void memp_init(void); @@ -87,6 +107,8 @@ void *memp_malloc(memp_t type); #endif void memp_free(memp_t type, void *mem); +#endif /* MEMP_MEM_MALLOC */ + #ifdef __cplusplus } #endif diff --git a/net/lwip/src/include/lwip/memp_std.h b/net/lwip/src/include/lwip/memp_std.h index c314bf879..344690328 100644 --- a/net/lwip/src/include/lwip/memp_std.h +++ b/net/lwip/src/include/lwip/memp_std.h @@ -10,8 +10,9 @@ * above, then will declare #2 & #3 to be just standard mempools. */ #ifndef LWIP_MALLOC_MEMPOOL -/* This treats "malloc pools" just like any other pool */ -#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, size, "MALLOC_"#size) +/* This treats "malloc pools" just like any other pool. + The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size) #define LWIP_MALLOC_MEMPOOL_START #define LWIP_MALLOC_MEMPOOL_END #endif /* LWIP_MALLOC_MEMPOOL */ diff --git a/net/lwip/src/include/lwip/netbuf.h b/net/lwip/src/include/lwip/netbuf.h index f6de3a4f6..6d84dd073 100644 --- a/net/lwip/src/include/lwip/netbuf.h +++ b/net/lwip/src/include/lwip/netbuf.h @@ -65,6 +65,7 @@ void netbuf_first (struct netbuf *buf); #define netbuf_copy_partial(buf, dataptr, len, offset) \ pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) #define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) #define netbuf_len(buf) ((buf)->p->tot_len) #define netbuf_fromaddr(buf) ((buf)->addr) #define netbuf_fromport(buf) ((buf)->port) diff --git a/net/lwip/src/include/lwip/netdb.h b/net/lwip/src/include/lwip/netdb.h index ce175ce4f..0f7b2ec04 100644 --- a/net/lwip/src/include/lwip/netdb.h +++ b/net/lwip/src/include/lwip/netdb.h @@ -31,6 +31,8 @@ #if LWIP_DNS && LWIP_SOCKET +#include /* for size_t */ + #include "lwip/sockets.h" /* some rarely used options */ diff --git a/net/lwip/src/include/lwip/netif.h b/net/lwip/src/include/lwip/netif.h index 19c38087b..a32503052 100644 --- a/net/lwip/src/include/lwip/netif.h +++ b/net/lwip/src/include/lwip/netif.h @@ -34,6 +34,8 @@ #include "lwip/opt.h" +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + #include "lwip/err.h" #include "lwip/ip_addr.h" @@ -165,6 +167,14 @@ struct netif { #if LWIP_NETIF_HWADDRHINT u8_t *addr_hint; #endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK + /* List of packets to be queued for ourselves. */ + struct pbuf *loop_first; + struct pbuf *loop_last; +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#endif /* ENABLE_LOOPBACK */ }; #if LWIP_SNMP @@ -242,4 +252,12 @@ void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct } #endif +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip); +void netif_poll(struct netif *netif); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void); +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + #endif /* __LWIP_NETIF_H__ */ diff --git a/net/lwip/src/include/lwip/opt.h b/net/lwip/src/include/lwip/opt.h index df83afe29..e8bd8b89e 100644 --- a/net/lwip/src/include/lwip/opt.h +++ b/net/lwip/src/include/lwip/opt.h @@ -98,6 +98,15 @@ #define MEM_LIBC_MALLOC 0 #endif +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC 0 +#endif + /** * MEM_ALIGNMENT: should be set to the alignment of the CPU * 4 byte alignment -> #define MEM_ALIGNMENT 4 @@ -139,12 +148,21 @@ /** * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set * of memory pools of various sizes. When mem_malloc is called, an element of - * the smallest pool that can provide the lenght needed is returned. + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. */ #ifndef MEM_USE_POOLS #define MEM_USE_POOLS 0 #endif +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + /** * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h * that defines additional pools beyond the "standard" ones required @@ -155,6 +173,27 @@ #define MEMP_USE_CUSTOM_POOLS 0 #endif +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif /* ------------------------------------------------ @@ -411,6 +450,23 @@ #define IP_DEFAULT_TTL 255 #endif +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV 0 +#endif + /* ---------------------------------- ---------- ICMP options ---------- @@ -431,6 +487,20 @@ #define ICMP_TTL (IP_DEFAULT_TTL) #endif +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING 0 +#endif + /* --------------------------------- ---------- RAW options ---------- @@ -489,6 +559,17 @@ #define LWIP_DHCP_AUTOIP_COOP 0 #endif +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif + /* ---------------------------------- ---------- SNMP options ---------- @@ -591,6 +672,26 @@ #define DNS_MSG_SIZE 512 #endif +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + * you have to define + * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + * (an array of structs name/address, where address is an u32_t in network + * byte order). + * + * Instead, you can also use an external function: + * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + * that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + /* --------------------------------- ---------- UDP options ---------- @@ -637,7 +738,8 @@ #endif /** - * TCP_WND: The size of a TCP window. + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well */ #ifndef TCP_WND #define TCP_WND 2048 @@ -662,7 +764,7 @@ * Define to 0 if your device is low on memory. */ #ifndef TCP_QUEUE_OOSEQ -#define TCP_QUEUE_OOSEQ 1 +#define TCP_QUEUE_OOSEQ (LWIP_TCP) #endif /** @@ -729,6 +831,21 @@ #define TCP_DEFAULT_LISTEN_BACKLOG 0xff #endif +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) +#endif + /** * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all @@ -815,6 +932,52 @@ #define LWIP_NETIF_HWADDRHINT 0 #endif +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + /* ------------------------------------ ---------- LOOPIF options ---------- @@ -827,20 +990,16 @@ #define LWIP_HAVE_LOOPIF 0 #endif +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ /** - * LWIP_LOOPIF_MULTITHREADING: Indicates whether threading is enabled in - * the system, as LOOPIF must change how it behaves depending on this setting. - * Setting this is needed to avoid reentering non-reentrant functions like - * tcp_input(). - * LWIP_LOOPIF_MULTITHREADING==1: Indicates that the user is using a - * multithreaded environment like tcpip.c. In this case, netif->input() - * is called directly. - * LWIP_LOOPIF_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. - * The packets are put on a list and loopif_poll() must be called in - * the main application loop. + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c */ -#ifndef LWIP_LOOPIF_MULTITHREADING -#define LWIP_LOOPIF_MULTITHREADING 1 +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF 0 #endif /* @@ -1039,7 +1198,7 @@ * names (read, write & close). (only used if you use sockets.c) */ #ifndef LWIP_POSIX_SOCKETS_IO_NAMES -#define LWIP_POSIX_SOCKETS_IO_NAMES 0 +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 #endif /** @@ -1065,6 +1224,13 @@ #define LWIP_SO_RCVBUF 0 #endif +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + /** * SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE! */ diff --git a/net/lwip/src/include/lwip/pbuf.h b/net/lwip/src/include/lwip/pbuf.h index 57a1e9991..8380f65da 100644 --- a/net/lwip/src/include/lwip/pbuf.h +++ b/net/lwip/src/include/lwip/pbuf.h @@ -110,6 +110,8 @@ void pbuf_chain(struct pbuf *head, struct pbuf *tail); struct pbuf *pbuf_dechain(struct pbuf *p); err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset); +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); #ifdef __cplusplus } diff --git a/net/lwip/src/include/lwip/sio.h b/net/lwip/src/include/lwip/sio.h index 7437522c7..7d9162e49 100644 --- a/net/lwip/src/include/lwip/sio.h +++ b/net/lwip/src/include/lwip/sio.h @@ -32,16 +32,24 @@ * It needs to be implemented by those platforms which need SLIP or PPP */ +#ifndef __SIO_H__ +#define __SIO_H__ + #include "lwip/arch.h" #ifdef __cplusplus extern "C" { #endif +/* If you want to define sio_fd_t elsewhere or differently, + define this in your cc.h file. */ #ifndef __sio_fd_t_defined typedef void * sio_fd_t; #endif +/* The following functions can be defined to something else in your cc.h file + or be implemented in your custom sio.c file. */ + #ifndef sio_open sio_fd_t sio_open(u8_t); #endif @@ -69,3 +77,5 @@ void sio_read_abort(sio_fd_t); #ifdef __cplusplus } #endif + +#endif /* __SIO_H__ */ diff --git a/net/lwip/src/include/lwip/snmp_asn1.h b/net/lwip/src/include/lwip/snmp_asn1.h index 3d70d330e..8a602881f 100644 --- a/net/lwip/src/include/lwip/snmp_asn1.h +++ b/net/lwip/src/include/lwip/snmp_asn1.h @@ -40,6 +40,8 @@ #include "lwip/pbuf.h" #include "lwip/snmp.h" +#if LWIP_SNMP + #ifdef __cplusplus extern "C" { #endif @@ -94,4 +96,6 @@ err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw); } #endif +#endif /* LWIP_SNMP */ + #endif /* __LWIP_SNMP_ASN1_H__ */ diff --git a/net/lwip/src/include/lwip/snmp_msg.h b/net/lwip/src/include/lwip/snmp_msg.h index d20282558..b2f69c4be 100644 --- a/net/lwip/src/include/lwip/snmp_msg.h +++ b/net/lwip/src/include/lwip/snmp_msg.h @@ -39,6 +39,8 @@ #include "lwip/snmp.h" #include "lwip/snmp_structs.h" +#if LWIP_SNMP + #if SNMP_PRIVATE_MIB #include "private_mib.h" #endif @@ -304,4 +306,6 @@ void snmp_authfail_trap(void); } #endif +#endif /* LWIP_SNMP */ + #endif /* __LWIP_SNMP_MSG_H__ */ diff --git a/net/lwip/src/include/lwip/sockets.h b/net/lwip/src/include/lwip/sockets.h index f105d5b52..7b52e151c 100644 --- a/net/lwip/src/include/lwip/sockets.h +++ b/net/lwip/src/include/lwip/sockets.h @@ -38,6 +38,8 @@ #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +#include /* for size_t */ + #include "lwip/ip_addr.h" #include "lwip/inet.h" @@ -69,13 +71,6 @@ struct sockaddr { #define SOCK_DGRAM 2 #define SOCK_RAW 3 -/* - * Maximum queue length specifiable by listen(2). - */ -#ifndef SOMAXCONN -#define SOMAXCONN 128 -#endif - /* * Option flags per-socket. These must match the SOF_ flags in ip.h! */ @@ -84,7 +79,7 @@ struct sockaddr { #define SO_REUSEADDR 0x0004 /* Unimplemented: allow local address reuse */ #define SO_KEEPALIVE 0x0008 /* keep connections alive */ #define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ -#define SO_BROADCAST 0x0020 /* Unimplemented: permit sending of broadcast msgs */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ #define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ #define SO_LINGER 0x0080 /* linger on close if data present */ #define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ @@ -131,9 +126,6 @@ struct linger { #define IPPROTO_UDP 17 #define IPPROTO_UDPLITE 136 -#define INADDR_ANY 0 -#define INADDR_BROADCAST 0xffffffff - /* Flags we can use with send and recv. */ #define MSG_PEEK 0x01 /* Peeks at an incoming message */ #define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ @@ -184,7 +176,22 @@ typedef struct ip_mreq { } ip_mreq; #endif /* LWIP_IGMP */ -/* Unimplemented for now... */ +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired. These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network. Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load). The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service. In many networks + * better performance for one of these parameters is coupled with worse + * performance on another. Except for very unusual cases at most two + * of these three indications should be set. + */ #define IPTOS_TOS_MASK 0x1E #define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) #define IPTOS_LOWDELAY 0x10 @@ -194,7 +201,13 @@ typedef struct ip_mreq { #define IPTOS_MINCOST IPTOS_LOWCOST /* - * Definitions for IP precedence (also in ip_tos) (Unimplemented) + * The Network Control precedence designation is intended to be used + * within a network only. The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. */ #define IPTOS_PREC_MASK 0xe0 #define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) @@ -286,7 +299,7 @@ struct timeval { void lwip_socket_init(void); int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); -int lwip_bind(int s, struct sockaddr *name, socklen_t namelen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); int lwip_shutdown(int s, int how); int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); @@ -295,15 +308,15 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_ int lwip_close(int s); int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); int lwip_listen(int s, int backlog); -int lwip_recv(int s, void *mem, int len, unsigned int flags); -int lwip_read(int s, void *mem, int len); -int lwip_recvfrom(int s, void *mem, int len, unsigned int flags, +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); -int lwip_send(int s, const void *dataptr, int size, unsigned int flags); -int lwip_sendto(int s, const void *dataptr, int size, unsigned int flags, - struct sockaddr *to, socklen_t tolen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); int lwip_socket(int domain, int type, int protocol); -int lwip_write(int s, const void *dataptr, int size); +int lwip_write(int s, const void *dataptr, size_t size); int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout); int lwip_ioctl(int s, long cmd, void *argp); diff --git a/net/lwip/src/include/lwip/stats.h b/net/lwip/src/include/lwip/stats.h index 755092ece..aa179f5c0 100644 --- a/net/lwip/src/include/lwip/stats.h +++ b/net/lwip/src/include/lwip/stats.h @@ -57,7 +57,6 @@ extern "C" { struct stats_proto { STAT_COUNTER xmit; /* Transmitted packets. */ - STAT_COUNTER rexmit; /* Retransmitted packets. */ STAT_COUNTER recv; /* Received packets. */ STAT_COUNTER fw; /* Forwarded packets. */ STAT_COUNTER drop; /* Dropped packets. */ @@ -87,7 +86,8 @@ struct stats_mem { mem_size_t avail; mem_size_t used; mem_size_t max; - mem_size_t err; + STAT_COUNTER err; + STAT_COUNTER illegal; }; struct stats_syselem { @@ -142,64 +142,138 @@ extern struct stats_ lwip_stats; #define stats_init() /* Compatibility define, not init needed. */ #define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x #else #define stats_init() #define STATS_INC(x) +#define STATS_DEC(x) #endif /* LWIP_STATS */ #if TCP_STATS #define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") #else #define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() #endif #if UDP_STATS #define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") #else #define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() #endif #if ICMP_STATS #define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") #else #define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() #endif #if IGMP_STATS #define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp) #else #define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() #endif #if IP_STATS #define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") #else #define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() #endif #if IPFRAG_STATS #define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") #else #define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() #endif #if ETHARP_STATS #define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") #else #define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() #endif #if LINK_STATS #define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") #else #define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#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) do { lwip_stats.mem.used += y; \ + if (lwip_stats.mem.max < lwip_stats.mem.used) { \ + lwip_stats.mem.max = lwip_stats.mem.used; \ + } \ + } while(0) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + +#if MEMP_STATS +#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y +#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) +#define MEMP_STATS_INC_USED(x, i) do { ++lwip_stats.memp[i].used; \ + if (lwip_stats.memp[i].max < lwip_stats.memp[i].used) { \ + lwip_stats.memp[i].max = lwip_stats.memp[i].used; \ + } \ + } while(0) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) +#else +#define MEMP_STATS_AVAIL(x, i, y) +#define MEMP_STATS_INC(x, i) +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_INC_USED(x, i) +#define MEMP_STATS_DISPLAY(i) +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_DISPLAY() #endif /* Display of statistics */ #if LWIP_STATS_DISPLAY void stats_display(void); +void stats_display_proto(struct stats_proto *proto, char *name); +void stats_display_igmp(struct stats_igmp *igmp); +void stats_display_mem(struct stats_mem *mem, char *name); +void stats_display_memp(struct stats_mem *mem, int index); +void stats_display_sys(struct stats_sys *sys); #else #define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) #endif /* LWIP_STATS_DISPLAY */ #ifdef __cplusplus diff --git a/net/lwip/src/include/lwip/sys.h b/net/lwip/src/include/lwip/sys.h index ce73beacf..0cc84ddf1 100644 --- a/net/lwip/src/include/lwip/sys.h +++ b/net/lwip/src/include/lwip/sys.h @@ -44,7 +44,6 @@ extern "C" { definitions of the sys_ functions. */ typedef u8_t sys_sem_t; typedef u8_t sys_mbox_t; -typedef u8_t sys_prot_t; struct sys_timeo {u8_t dummy;}; #define sys_init() @@ -139,13 +138,11 @@ void sys_mbox_fetch(sys_mbox_t mbox, void **msg); /* Thread functions. */ sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio); -/* The following functions are used only in Unix code, and - can be omitted when porting the stack. */ -/* Returns the current time in microseconds. */ -unsigned long sys_now(void); - #endif /* NO_SYS */ +/** Returns the current time in milliseconds. */ +u32_t sys_now(void); + /* Critical Region Protection */ /* These functions must be implemented in the sys_arch.c file. In some implementations they can provide a more light-weight protection diff --git a/net/lwip/src/include/lwip/tcp.h b/net/lwip/src/include/lwip/tcp.h index 883b0b831..8f6b9d3c1 100644 --- a/net/lwip/src/include/lwip/tcp.h +++ b/net/lwip/src/include/lwip/tcp.h @@ -96,7 +96,8 @@ err_t tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr, struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); #define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) -void tcp_abort (struct tcp_pcb *pcb); +void tcp_abandon (struct tcp_pcb *pcb, int reset); +#define tcp_abort(pcb) tcp_abandon((pcb), 1) err_t tcp_close (struct tcp_pcb *pcb); /* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */ @@ -124,26 +125,24 @@ void tcp_input (struct pbuf *p, struct netif *inp); err_t tcp_output (struct tcp_pcb *pcb); void tcp_rexmit (struct tcp_pcb *pcb); void tcp_rexmit_rto (struct tcp_pcb *pcb); +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); /** - * This is the Nagle algorithm: inhibit the sending of new TCP - * segments when new outgoing data arrives from the user if any - * previously transmitted data on the connection remains - * unacknowledged. + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - 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) */ #define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ ((tpcb)->flags & TF_NODELAY) || \ - (((tpcb)->unsent != NULL) && ((tpcb)->unsent->next != NULL))) ? \ - 1 : 0) + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) \ + ) ? 1 : 0) #define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) -/** This returns a TCP header option for MSS in an u32_t */ -#define TCP_BUILD_MSS_OPTION() htonl(((u32_t)2 << 24) | \ - ((u32_t)4 << 16) | \ - (((u32_t)TCP_MSS / 256) << 8) | \ - (TCP_MSS & 255)) - #define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) #define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) #define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) @@ -185,7 +184,7 @@ void tcp_rexmit_rto (struct tcp_pcb *pcb); #define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ #ifndef TCP_MSL -#define TCP_MSL 60000U /* The maximum segment lifetime in milliseconds */ +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ #endif /* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ @@ -258,6 +257,20 @@ enum tcp_state { #define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ #define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ + +#if LWIP_CALLBACK_API + /* Function to call when a listener has been connected. + * @param arg user-supplied argument (tcp_pcb.callback_arg) + * @param pcb a new tcp_pcb that now is connected + * @param err an error argument (TODO: that is current always ERR_OK?) + * @return ERR_OK: accept the new connection, + * any other err_t abortsthe new connection + */ +#define DEF_ACCEPT_CALLBACK err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err) +#else /* LWIP_CALLBACK_API */ +#define DEF_ACCEPT_CALLBACK +#endif /* LWIP_CALLBACK_API */ + /** * members common to struct tcp_pcb and struct tcp_listen_pcb */ @@ -267,7 +280,10 @@ enum tcp_state { u8_t prio; \ void *callback_arg; \ /* ports are in host byte order */ \ - u16_t local_port + u16_t local_port; \ + /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ + DEF_ACCEPT_CALLBACK + /* the TCP protocol control block */ struct tcp_pcb { @@ -280,19 +296,21 @@ struct tcp_pcb { u16_t remote_port; u8_t flags; -#define TF_ACK_DELAY (u8_t)0x01U /* Delayed ACK. */ -#define TF_ACK_NOW (u8_t)0x02U /* Immediate ACK. */ -#define TF_INFR (u8_t)0x04U /* In fast recovery. */ -#define TF_FIN (u8_t)0x20U /* Connection was closed locally (FIN segment enqueued). */ -#define TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */ -#define TF_NAGLEMEMERR (u8_t)0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ +#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */ +#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */ +#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */ +#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */ +#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ /* the rest of the fields are in host byte order as we have to do some math with them */ /* receiver variables */ u32_t rcv_nxt; /* next seqno expected */ - u16_t rcv_wnd; /* receiver window */ - u16_t rcv_ann_wnd; /* announced receive window */ + u16_t rcv_wnd; /* receiver window available */ + u16_t rcv_ann_wnd; /* receiver window to announce */ + u32_t rcv_ann_right_edge; /* announced right edge of window */ /* Timers */ u32_t tmr; @@ -320,12 +338,11 @@ struct tcp_pcb { u16_t ssthresh; /* sender variables */ - u32_t snd_nxt, /* next seqno to be sent */ - snd_max; /* Highest seqno sent. */ + u32_t snd_nxt; /* next new seqno to be sent */ u16_t snd_wnd; /* sender window */ - u32_t snd_wl1, snd_wl2, /* Sequence and acknowledgement numbers of last + u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last window update. */ - snd_lbb; /* Sequence number of next byte to be buffered. */ + u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ u16_t acked; @@ -369,15 +386,6 @@ struct tcp_pcb { */ err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err); - /* Function to call when a listener has been connected. - * @param arg user-supplied argument (tcp_pcb.callback_arg) - * @param pcb a new tcp_pcb that now is connected - * @param err an error argument (TODO: that is current always ERR_OK?) - * @return ERR_OK: accept the new connection, - * any other err_t abortsthe new connection - */ - err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err); - /* Function which is called periodically. * The period can be adjusted in multiples of the TCP slow timer interval * by changing tcp_pcb.polltmr. @@ -398,6 +406,11 @@ struct tcp_pcb { void (* errf)(void *arg, err_t err); #endif /* LWIP_CALLBACK_API */ +#if LWIP_TCP_TIMESTAMPS + u32_t ts_lastacksent; + u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + /* idle time before KEEPALIVE is sent */ u32_t keep_idle; #if LWIP_TCP_KEEPALIVE @@ -420,16 +433,6 @@ struct tcp_pcb_listen { /* Protocol specific PCB members */ TCP_PCB_COMMON(struct tcp_pcb_listen); -#if LWIP_CALLBACK_API - /* Function to call when a listener has been connected. - * @param arg user-supplied argument (tcp_pcb.callback_arg) - * @param pcb a new tcp_pcb that now is connected - * @param err an error argument (TODO: that is current always ERR_OK?) - * @return ERR_OK: accept the new connection, - * any other err_t abortsthe new connection - */ - err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err); -#endif /* LWIP_CALLBACK_API */ #if TCP_LISTEN_BACKLOG u8_t backlog; u8_t accepts_pending; @@ -466,26 +469,52 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, #define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ LWIP_EVENT_ERR, NULL, 0, (err)) #else /* LWIP_EVENT_API */ -#define TCP_EVENT_ACCEPT(pcb,err,ret) \ - if((pcb)->accept != NULL) \ - (ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err))) -#define TCP_EVENT_SENT(pcb,space,ret) \ - if((pcb)->sent != NULL) \ - (ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space))) -#define TCP_EVENT_RECV(pcb,p,err,ret) \ - if((pcb)->recv != NULL) \ - { ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \ - ret = ERR_OK; \ - if (p) pbuf_free(p); } -#define TCP_EVENT_CONNECTED(pcb,err,ret) \ - if((pcb)->connected != NULL) \ - (ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err))) -#define TCP_EVENT_POLL(pcb,ret) \ - if((pcb)->poll != NULL) \ - (ret = (pcb)->poll((pcb)->callback_arg,(pcb))) -#define TCP_EVENT_ERR(errf,arg,err) \ - if((errf) != NULL) \ - (errf)((arg),(err)) + +#define TCP_EVENT_ACCEPT(pcb,err,ret) \ + do { \ + if((pcb)->accept != NULL) \ + (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret) \ + do { \ + if((pcb)->sent != NULL) \ + (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + do { \ + if((pcb)->recv != NULL) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \ + } else { \ + (ret) = ERR_OK; \ + if (p != NULL) \ + pbuf_free(p); \ + } \ + } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + do { \ + if((pcb)->connected != NULL) \ + (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_POLL(pcb,ret) \ + do { \ + if((pcb)->poll != NULL) \ + (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_ERR(errf,arg,err) \ + do { \ + if((errf) != NULL) \ + (errf)((arg),(err)); \ + } while (0) + #endif /* LWIP_EVENT_API */ /* This structure represents a TCP segment on the unsent and unacked queues */ @@ -494,9 +523,22 @@ struct tcp_seg { struct pbuf *p; /* buffer containing data + TCP header */ void *dataptr; /* pointer to the TCP data in the pbuf */ u16_t len; /* the TCP length of this segment */ + u8_t flags; +#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ +#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ struct tcp_hdr *tcphdr; /* the TCP header */ }; +#define LWIP_TCP_OPT_LENGTH(flags) \ + (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \ + (flags & TF_SEG_OPTS_TS ? 12 : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(x) (x) = htonl(((u32_t)2 << 24) | \ + ((u32_t)4 << 16) | \ + (((u32_t)TCP_MSS / 256) << 8) | \ + (TCP_MSS & 255)) + /* Internal functions and global variables: */ struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); void tcp_pcb_purge(struct tcp_pcb *pcb); @@ -506,21 +548,27 @@ u8_t tcp_segs_free(struct tcp_seg *seg); u8_t tcp_seg_free(struct tcp_seg *seg); struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); -#define tcp_ack(pcb) if((pcb)->flags & TF_ACK_DELAY) { \ - (pcb)->flags &= ~TF_ACK_DELAY; \ - (pcb)->flags |= TF_ACK_NOW; \ - tcp_output(pcb); \ - } else { \ - (pcb)->flags |= TF_ACK_DELAY; \ - } +#define tcp_ack(pcb) \ + do { \ + if((pcb)->flags & TF_ACK_DELAY) { \ + (pcb)->flags &= ~TF_ACK_DELAY; \ + (pcb)->flags |= TF_ACK_NOW; \ + tcp_output(pcb); \ + } \ + else { \ + (pcb)->flags |= TF_ACK_DELAY; \ + } \ + } while (0) -#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \ - tcp_output(pcb) +#define tcp_ack_now(pcb) \ + do { \ + (pcb)->flags |= TF_ACK_NOW; \ + tcp_output(pcb); \ + } while (0) err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags); err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len, - u8_t flags, u8_t apiflags, - u8_t *optdata, u8_t optlen); + u8_t flags, u8_t apiflags, u8_t optflags); void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); @@ -614,22 +662,32 @@ extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ } while(0) #else /* LWIP_DEBUG */ -#define TCP_REG(pcbs, npcb) do { \ - npcb->next = *pcbs; \ - *(pcbs) = npcb; \ - tcp_timer_needed(); \ - } while(0) -#define TCP_RMV(pcbs, npcb) do { \ - if(*(pcbs) == npcb) { \ - (*(pcbs)) = (*pcbs)->next; \ - } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \ - tcp_tmp_pcb->next = npcb->next; \ - break; \ - } \ - } \ - npcb->next = NULL; \ - } while(0) + +#define TCP_REG(pcbs, npcb) \ + do { \ + npcb->next = *pcbs; \ + *(pcbs) = npcb; \ + tcp_timer_needed(); \ + } while (0) + +#define TCP_RMV(pcbs, npcb) \ + do { \ + if(*(pcbs) == npcb) { \ + (*(pcbs)) = (*pcbs)->next; \ + } \ + else { \ + for(tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \ + tcp_tmp_pcb->next = npcb->next; \ + break; \ + } \ + } \ + } \ + npcb->next = NULL; \ + } while(0) + #endif /* LWIP_DEBUG */ #ifdef __cplusplus diff --git a/net/lwip/src/include/lwip/tcpip.h b/net/lwip/src/include/lwip/tcpip.h index 541d28ac6..75393ee91 100644 --- a/net/lwip/src/include/lwip/tcpip.h +++ b/net/lwip/src/include/lwip/tcpip.h @@ -41,6 +41,7 @@ #include "lwip/pbuf.h" #include "lwip/api.h" #include "lwip/sys.h" +#include "lwip/netif.h" #ifdef __cplusplus extern "C" { @@ -83,10 +84,14 @@ err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); #endif /* LWIP_NETIF_API */ err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block); -#define tcpip_callback(f,ctx) tcpip_callback_with_block(f,ctx,1) +#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); -#define tcpip_untimeout(h, arg) tcpip_timeout(0xffffffff, h, arg) +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); enum tcpip_msg_type { #if LWIP_NETCONN @@ -97,7 +102,8 @@ enum tcpip_msg_type { TCPIP_MSG_NETIFAPI, #endif /* LWIP_NETIF_API */ TCPIP_MSG_CALLBACK, - TCPIP_MSG_TIMEOUT + TCPIP_MSG_TIMEOUT, + TCPIP_MSG_UNTIMEOUT }; struct tcpip_msg { diff --git a/net/lwip/src/include/netif/etharp.h b/net/lwip/src/include/netif/etharp.h index 2b76823bb..db691d91d 100644 --- a/net/lwip/src/include/netif/etharp.h +++ b/net/lwip/src/include/netif/etharp.h @@ -151,6 +151,11 @@ void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr); err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q); err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr); +/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; + * this is an ARP packet sent by a node in order to spontaneously cause other + * nodes to update an entry in their ARP cache. + * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ +#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) err_t ethernet_input(struct pbuf *p, struct netif *netif); diff --git a/net/lwip/src/include/netif/loopif.h b/net/lwip/src/include/netif/loopif.h index 68fc7b399..304af4b39 100644 --- a/net/lwip/src/include/netif/loopif.h +++ b/net/lwip/src/include/netif/loopif.h @@ -32,6 +32,7 @@ #ifndef __NETIF_LOOPIF_H__ #define __NETIF_LOOPIF_H__ +#include "lwip/opt.h" #include "lwip/netif.h" #include "lwip/err.h" @@ -39,9 +40,9 @@ extern "C" { #endif -#if !LWIP_LOOPIF_MULTITHREADING -void loopif_poll(struct netif *netif); -#endif +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +#define loopif_poll netif_poll +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ err_t loopif_init(struct netif *netif); diff --git a/net/lwip/src/netif/etharp.c b/net/lwip/src/netif/etharp.c index 070b91390..73ea21173 100644 --- a/net/lwip/src/netif/etharp.c +++ b/net/lwip/src/netif/etharp.c @@ -8,8 +8,7 @@ * * This implementation complies with RFC 826 (Ethernet ARP). It supports * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 - * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon - * address change. + * if an interface calls etharp_gratuitous(our_netif) upon address change. */ /* @@ -353,7 +352,7 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) * 1) empty entry * 2) oldest stable entry * 3) oldest pending entry without queued packets - * 4) oldest pending entry without queued packets + * 4) oldest pending entry with queued packets * * { ETHARP_TRY_HARD is set at this point } */ @@ -705,7 +704,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) hdr->opcode = htons(ARP_REPLY); hdr->dipaddr = hdr->sipaddr; - hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr; + SMEMCPY(&hdr->sipaddr, &netif->ip_addr, sizeof(hdr->sipaddr)); LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN)); @@ -1041,7 +1040,7 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, #endif /* LWIP_AUTOIP */ /* allocate a pbuf for the outgoing ARP request packet */ - p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); + p = pbuf_alloc(PBUF_RAW, sizeof(struct etharp_hdr), 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")); @@ -1130,7 +1129,14 @@ ethernet_input(struct pbuf *p, struct netif *netif) /* points to packet payload, which starts with an Ethernet header */ ethhdr = p->payload; - + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, + ("ethernet_input: dest:%02x:%02x:%02x:%02x:%02x:%02x, src:%02x:%02x:%02x:%02x:%02x:%02x, type:%2hx\n", + (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], + (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], + (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], + (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], + (unsigned)htons(ethhdr->type))); + switch (htons(ethhdr->type)) { /* IP packet? */ case ETHTYPE_IP: @@ -1165,6 +1171,8 @@ ethernet_input(struct pbuf *p, struct netif *netif) #endif /* PPPOE_SUPPORT */ default: + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); pbuf_free(p); p = NULL; break; diff --git a/net/lwip/src/netif/loopif.c b/net/lwip/src/netif/loopif.c index adffdcf39..1e1f28cf1 100644 --- a/net/lwip/src/netif/loopif.c +++ b/net/lwip/src/netif/loopif.c @@ -40,149 +40,8 @@ #if LWIP_HAVE_LOOPIF #include "netif/loopif.h" -#include "lwip/pbuf.h" #include "lwip/snmp.h" -#include - -#if !LWIP_LOOPIF_MULTITHREADING - -#include "lwip/sys.h" -#include "lwip/mem.h" - -/* helper struct for the linked list of pbufs */ -struct loopif_private { - struct pbuf *first; - struct pbuf *last; -}; - -/** - * Call loopif_poll() in the main loop of your application. This is to prevent - * reentering non-reentrant functions like tcp_input(). Packets passed to - * loopif_output() are put on a list that is passed to netif->input() by - * loopif_poll(). - * - * @param netif the lwip network interface structure for this loopif - */ -void -loopif_poll(struct netif *netif) -{ - SYS_ARCH_DECL_PROTECT(lev); - struct pbuf *in, *in_end; - struct loopif_private *priv = (struct loopif_private*)netif->state; - - LWIP_ERROR("priv != NULL", (priv != NULL), return;); - - do { - /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ - SYS_ARCH_PROTECT(lev); - in = priv->first; - if(in) { - in_end = in; - while(in_end->len != in_end->tot_len) { - LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); - in_end = in_end->next; - } - /* 'in_end' now points to the last pbuf from 'in' */ - if(in_end == priv->last) { - /* this was the last pbuf in the list */ - priv->first = priv->last = NULL; - } else { - /* pop the pbuf off the list */ - priv->first = in_end->next; - LWIP_ASSERT("should not be null since first != last!", priv->first != NULL); - } - } - SYS_ARCH_UNPROTECT(lev); - - if(in != NULL) { - if(in_end->next != NULL) { - /* De-queue the pbuf from its successors on the 'priv' list. */ - in_end->next = NULL; - } - if(netif->input(in, netif) != ERR_OK) { - pbuf_free(in); - } - /* Don't reference the packet any more! */ - in = NULL; - in_end = NULL; - } - /* go on while there is a packet on the list */ - } while(priv->first != NULL); -} -#endif /* LWIP_LOOPIF_MULTITHREADING */ - -/** - * Send an IP packet over the loopback interface. - * The pbuf is simply copied and handed back to netif->input. - * In multithreaded mode, this is done directly since netif->input must put - * the packet on a queue. - * In callback mode, the packet is put on an internal queue and is fed to - * netif->input by loopif_poll(). - * - * @param netif the lwip network interface structure for this loopif - * @param p the (IP) packet to 'send' - * @param ipaddr the ip address to send the packet to (not used for loopif) - * @return ERR_OK if the packet has been sent - * ERR_MEM if the pbuf used to copy the packet couldn't be allocated - */ -static err_t -loopif_output(struct netif *netif, struct pbuf *p, - struct ip_addr *ipaddr) -{ -#if !LWIP_LOOPIF_MULTITHREADING - SYS_ARCH_DECL_PROTECT(lev); - struct loopif_private *priv; - struct pbuf *last; -#endif /* LWIP_LOOPIF_MULTITHREADING */ - struct pbuf *r; - err_t err; - - LWIP_UNUSED_ARG(ipaddr); - - /* Allocate a new pbuf */ - r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if (r == NULL) { - return ERR_MEM; - } - - /* Copy the whole pbuf queue p into the single pbuf r */ - if ((err = pbuf_copy(r, p)) != ERR_OK) { - pbuf_free(r); - r = NULL; - return err; - } - -#if LWIP_LOOPIF_MULTITHREADING - /* Multithreading environment, netif->input() is supposed to put the packet - into a mailbox, so we can safely call it here without risking to re-enter - functions that are not reentrant (TCP!!!) */ - if(netif->input(r, netif) != ERR_OK) { - pbuf_free(r); - r = NULL; - } -#else /* LWIP_LOOPIF_MULTITHREADING */ - /* Raw API without threads: put the packet on a linked list which gets emptied - through calling loopif_poll(). */ - priv = (struct loopif_private*)netif->state; - - /* let last point to the last pbuf in chain r */ - for (last = r; last->next != NULL; last = last->next); - SYS_ARCH_PROTECT(lev); - if(priv->first != NULL) { - LWIP_ASSERT("if first != NULL, last must also be != NULL", priv->last != NULL); - priv->last->next = r; - priv->last = last; - } else { - priv->first = r; - priv->last = last; - } - SYS_ARCH_UNPROTECT(lev); -#endif /* LWIP_LOOPIF_MULTITHREADING */ - - return ERR_OK; -} - /** * Initialize a lwip network interface structure for a loopback interface * @@ -193,16 +52,6 @@ loopif_output(struct netif *netif, struct pbuf *p, err_t loopif_init(struct netif *netif) { -#if !LWIP_LOOPIF_MULTITHREADING - struct loopif_private *priv; - - priv = (struct loopif_private*)mem_malloc(sizeof(struct loopif_private)); - if(priv == NULL) - return ERR_MEM; - priv->first = priv->last = NULL; - netif->state = priv; -#endif /* LWIP_LOOPIF_MULTITHREADING */ - /* initialize the snmp variables and counters inside the struct netif * ifSpeed: no assumption can be made! */ @@ -210,7 +59,7 @@ loopif_init(struct netif *netif) netif->name[0] = 'l'; netif->name[1] = 'o'; - netif->output = loopif_output; + netif->output = netif_loop_output; return ERR_OK; } diff --git a/net/lwip/src/netif/ppp/pap.c b/net/lwip/src/netif/ppp/pap.c index b38abd1d4..7c3fd7e4c 100644 --- a/net/lwip/src/netif/ppp/pap.c +++ b/net/lwip/src/netif/ppp/pap.c @@ -518,16 +518,18 @@ upap_rauthnak(upap_state *u, u_char *inp, int id, int len) */ if (len < sizeof (u_char)) { UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); - return; + } else { + GETCHAR(msglen, inp); + if(msglen > 0) { + len -= sizeof (u_char); + if (len < msglen) { + UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); + return; + } + msg = (char *) inp; + PRINTMSG(msg, msglen); + } } - GETCHAR(msglen, inp); - len -= sizeof (u_char); - if (len < msglen) { - UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); - return; - } - msg = (char *) inp; - PRINTMSG(msg, msglen); u->us_clientstate = UPAPCS_BADAUTH; diff --git a/net/lwip/src/netif/ppp/ppp.c b/net/lwip/src/netif/ppp/ppp.c index a3817dad7..8720c3368 100644 --- a/net/lwip/src/netif/ppp/ppp.c +++ b/net/lwip/src/netif/ppp/ppp.c @@ -1056,7 +1056,7 @@ pppWriteOverEthernet(int pd, const u_char *s, int n) pc->lastXMit = sys_jiffies(); - SMEMCPY(pb->payload, s, n); + MEMCPY(pb->payload, s, n); if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { LINK_STATS_INC(link.err); @@ -1339,10 +1339,6 @@ sifup(int pd) netif_remove(&pc->netif); if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) { netif_set_up(&pc->netif); -#if LWIP_DHCP - /* ugly workaround for storing a reference to the ppp related info*/ - pc->netif.dhcp = (struct dhcp *) &pc->addrs; -#endif /* LWIP_DHCP */ pc->if_up = 1; pc->errCode = PPPERR_NONE; diff --git a/net/lwip/src/netif/slipif.c b/net/lwip/src/netif/slipif.c index b37885932..6cb2db442 100644 --- a/net/lwip/src/netif/slipif.c +++ b/net/lwip/src/netif/slipif.c @@ -44,6 +44,9 @@ #include "netif/slipif.h" #include "lwip/opt.h" + +#if LWIP_HAVE_SLIPIF + #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/sys.h" @@ -273,3 +276,4 @@ slipif_init(struct netif *netif) sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); return ERR_OK; } +#endif /* LWIP_HAVE_SLIPIF */