update lwip to 1.3.1
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@37 bbd45198-f89e-11dd-88c7-29a3b14d5316
This commit is contained in:
parent
1ae9da2752
commit
b9290bcef4
|
@ -19,8 +19,375 @@ HISTORY
|
||||||
|
|
||||||
++ New features:
|
++ 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:
|
++ 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 <lucaceresoli>)
|
||||||
|
* init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when
|
||||||
|
LWIP_TCP==0
|
||||||
|
|
||||||
|
2009-04-09 Kieran Mansley (patch from Roy Lee <roylee17>)
|
||||||
|
* 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 <arasmussen@consultant.datasys.swri.edu>
|
||||||
|
|
||||||
|
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)
|
(STABLE-1.3.0)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
savannah.txt - How to obtain the current development source code.
|
savannah.txt - How to obtain the current development source code.
|
||||||
contrib.txt - How to contribute to lwIP as a developer.
|
contrib.txt - How to contribute to lwIP as a developer.
|
||||||
rawapi.txt - The documentation for the core API of lwIP.
|
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.
|
snmp_agent.txt - The documentation for the lwIP SNMP agent.
|
||||||
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
|
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
|
||||||
|
|
|
@ -2,10 +2,11 @@ Raw TCP/IP interface for lwIP
|
||||||
|
|
||||||
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
|
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:
|
to use for communication with the TCP/IP code:
|
||||||
* low-level "core" / "callback" or "raw" API.
|
* low-level "core" / "callback" or "raw" API.
|
||||||
* higher-level "sequential" API.
|
* higher-level "sequential" API.
|
||||||
|
* BSD-style socket API.
|
||||||
|
|
||||||
The sequential API provides a way for ordinary, sequential, programs
|
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
|
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
|
code and the application program must reside in different execution
|
||||||
contexts (threads).
|
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 remainder of this document discusses the "raw" API. **
|
||||||
|
|
||||||
The raw TCP/IP interface allows the application program to integrate
|
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)
|
function specified as the fourth argument (the "connected" argument)
|
||||||
when the connection is established. If the connection could not be
|
when the connection is established. If the connection could not be
|
||||||
properly established, either because the other host refused the
|
properly established, either because the other host refused the
|
||||||
connection or because the other host didn't answer, the "connected"
|
connection or because the other host didn't answer, the "err"
|
||||||
function will be called with an the "err" argument set accordingly.
|
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
|
The tcp_connect() function can return ERR_MEM if no memory is
|
||||||
available for enqueueing the SYN segment. If the SYN indeed was
|
available for enqueueing the SYN segment. If the SYN indeed was
|
||||||
|
|
|
@ -195,6 +195,8 @@ cc.h - Architecture environment, some compiler specific, some
|
||||||
Platform specific diagnostic output -
|
Platform specific diagnostic output -
|
||||||
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
|
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
|
||||||
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
|
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 -
|
"lightweight" synchronization mechanisms -
|
||||||
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
|
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
|
||||||
|
|
|
@ -119,19 +119,6 @@ netconn_delete(struct netconn *conn)
|
||||||
return ERR_OK;
|
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.
|
* Get the local or remote IP address and port of a netconn.
|
||||||
* For RAW netconns, this returns the protocol instead of a port!
|
* 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_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.function = do_send;
|
||||||
msg.msg.conn = conn;
|
msg.msg.conn = conn;
|
||||||
msg.msg.msg.b = buf;
|
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
|
* @return ERR_OK if data was sent, any other err_t on error
|
||||||
*/
|
*/
|
||||||
err_t
|
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;
|
struct api_msg msg;
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@
|
||||||
#include "lwip/igmp.h"
|
#include "lwip/igmp.h"
|
||||||
#include "lwip/dns.h"
|
#include "lwip/dns.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* forward declarations */
|
/* forward declarations */
|
||||||
#if LWIP_TCP
|
#if LWIP_TCP
|
||||||
static err_t do_writemore(struct netconn *conn);
|
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->addr = &(((struct ip_hdr*)(q->payload))->src);
|
||||||
buf->port = pcb->protocol;
|
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) {
|
if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
|
||||||
netbuf_delete(buf);
|
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;
|
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) {
|
if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
|
||||||
netbuf_delete(buf);
|
netbuf_delete(buf);
|
||||||
return;
|
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 */
|
#endif /* LWIP_UDP */
|
||||||
|
@ -206,10 +211,12 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||||
} else {
|
} else {
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
/* Register event with callback */
|
|
||||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
|
|
||||||
if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
|
if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
|
||||||
return ERR_MEM;
|
return ERR_MEM;
|
||||||
|
} else {
|
||||||
|
/* Register event with callback */
|
||||||
|
API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
|
@ -365,8 +372,6 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||||
newconn->pcb.tcp = newpcb;
|
newconn->pcb.tcp = newpcb;
|
||||||
setup_tcp(newconn);
|
setup_tcp(newconn);
|
||||||
newconn->err = err;
|
newconn->err = err;
|
||||||
/* Register event with callback */
|
|
||||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
|
|
||||||
|
|
||||||
if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
|
if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
|
||||||
/* When returning != ERR_OK, the connection is aborted in tcp_process(),
|
/* 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;
|
newconn->pcb.tcp = NULL;
|
||||||
netconn_free(newconn);
|
netconn_free(newconn);
|
||||||
return ERR_MEM;
|
return ERR_MEM;
|
||||||
|
} else {
|
||||||
|
/* Register event with callback */
|
||||||
|
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
#endif /* LWIP_TCP */
|
#endif /* LWIP_TCP */
|
||||||
|
@ -528,11 +537,18 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
|
||||||
conn->socket = -1;
|
conn->socket = -1;
|
||||||
conn->callback = callback;
|
conn->callback = callback;
|
||||||
conn->recv_avail = 0;
|
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
|
#if LWIP_SO_RCVTIMEO
|
||||||
conn->recv_timeout = 0;
|
conn->recv_timeout = 0;
|
||||||
#endif /* LWIP_SO_RCVTIMEO */
|
#endif /* LWIP_SO_RCVTIMEO */
|
||||||
#if LWIP_SO_RCVBUF
|
#if LWIP_SO_RCVBUF
|
||||||
conn->recv_bufsize = INT_MAX;
|
conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
|
||||||
#endif /* LWIP_SO_RCVBUF */
|
#endif /* LWIP_SO_RCVBUF */
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
@ -598,11 +614,16 @@ do_close_internal(struct netconn *conn)
|
||||||
LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
|
LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
|
||||||
|
|
||||||
/* Set back some callback pointers */
|
/* Set back some callback pointers */
|
||||||
|
tcp_arg(conn->pcb.tcp, NULL);
|
||||||
if (conn->pcb.tcp->state == LISTEN) {
|
if (conn->pcb.tcp->state == LISTEN) {
|
||||||
tcp_arg(conn->pcb.tcp, NULL);
|
|
||||||
tcp_accept(conn->pcb.tcp, NULL);
|
tcp_accept(conn->pcb.tcp, NULL);
|
||||||
} else {
|
} else {
|
||||||
tcp_recv(conn->pcb.tcp, NULL);
|
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 */
|
/* Try to close the connection */
|
||||||
err = tcp_close(conn->pcb.tcp);
|
err = tcp_close(conn->pcb.tcp);
|
||||||
|
@ -610,11 +631,6 @@ do_close_internal(struct netconn *conn)
|
||||||
/* Closing succeeded */
|
/* Closing succeeded */
|
||||||
conn->state = NETCONN_NONE;
|
conn->state = NETCONN_NONE;
|
||||||
/* Set back some callback pointers as conn is going away */
|
/* 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->pcb.tcp = NULL;
|
||||||
conn->err = ERR_OK;
|
conn->err = ERR_OK;
|
||||||
/* Trigger select() in socket layer. This send should something else so the
|
/* 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);
|
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
|
||||||
/* wake up the application task */
|
/* wake up the application task */
|
||||||
sys_sem_signal(conn->op_completed);
|
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
|
/* If closing didn't succeed, we get called again either
|
||||||
from poll_tcp or from sent_tcp */
|
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
|
* Called from netconn_recv
|
||||||
*
|
*
|
||||||
* @param msg the api_msg_msg pointing to the connection
|
* @param msg the api_msg_msg pointing to the connection
|
||||||
|
@ -940,17 +964,19 @@ do_writemore(struct netconn *conn)
|
||||||
void *dataptr;
|
void *dataptr;
|
||||||
u16_t len, available;
|
u16_t len, available;
|
||||||
u8_t write_finished = 0;
|
u8_t write_finished = 0;
|
||||||
|
size_t diff;
|
||||||
|
|
||||||
LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
|
LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
|
||||||
|
|
||||||
dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset;
|
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;
|
len = 0xffff;
|
||||||
#if LWIP_TCPIP_CORE_LOCKING
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
conn->write_delayed = 1;
|
conn->write_delayed = 1;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
len = conn->write_msg->msg.w.len - conn->write_offset;
|
len = (u16_t)diff;
|
||||||
}
|
}
|
||||||
available = tcp_sndbuf(conn->pcb.tcp);
|
available = tcp_sndbuf(conn->pcb.tcp);
|
||||||
if (available < len) {
|
if (available < len) {
|
||||||
|
@ -970,6 +996,8 @@ do_writemore(struct netconn *conn)
|
||||||
write_finished = 1;
|
write_finished = 1;
|
||||||
conn->write_msg = NULL;
|
conn->write_msg = NULL;
|
||||||
conn->write_offset = 0;
|
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);
|
err = tcp_output_nagle(conn->pcb.tcp);
|
||||||
conn->err = err;
|
conn->err = err;
|
||||||
|
@ -1027,6 +1055,8 @@ do_write(struct api_msg_msg *msg)
|
||||||
#if LWIP_TCP
|
#if LWIP_TCP
|
||||||
msg->conn->state = NETCONN_WRITE;
|
msg->conn->state = NETCONN_WRITE;
|
||||||
/* set all the variables used by do_writemore */
|
/* 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_msg = msg;
|
||||||
msg->conn->write_offset = 0;
|
msg->conn->write_offset = 0;
|
||||||
#if LWIP_TCPIP_CORE_LOCKING
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
|
|
|
@ -44,17 +44,17 @@ static const char *err_strerr[] = {
|
||||||
"Ok.", /* ERR_OK 0 */
|
"Ok.", /* ERR_OK 0 */
|
||||||
"Out of memory error.", /* ERR_MEM -1 */
|
"Out of memory error.", /* ERR_MEM -1 */
|
||||||
"Buffer error.", /* ERR_BUF -2 */
|
"Buffer error.", /* ERR_BUF -2 */
|
||||||
"Routing problem.", /* ERR_RTE -3 */
|
"Timeout.", /* ERR_TIMEOUT -3 */
|
||||||
"Connection aborted.", /* ERR_ABRT -4 */
|
"Routing problem.", /* ERR_RTE -4 */
|
||||||
"Connection reset.", /* ERR_RST -5 */
|
"Connection aborted.", /* ERR_ABRT -5 */
|
||||||
"Connection closed.", /* ERR_CLSD -6 */
|
"Connection reset.", /* ERR_RST -6 */
|
||||||
"Not connected.", /* ERR_CONN -7 */
|
"Connection closed.", /* ERR_CLSD -7 */
|
||||||
"Illegal value.", /* ERR_VAL -8 */
|
"Not connected.", /* ERR_CONN -8 */
|
||||||
"Illegal argument.", /* ERR_ARG -9 */
|
"Illegal value.", /* ERR_VAL -9 */
|
||||||
"Address in use.", /* ERR_USE -10 */
|
"Illegal argument.", /* ERR_ARG -10 */
|
||||||
"Low-level netif error.", /* ERR_IF -11 */
|
"Address in use.", /* ERR_USE -11 */
|
||||||
"Already connected.", /* ERR_ISCONN -12 */
|
"Low-level netif error.", /* ERR_IF -12 */
|
||||||
"Timeout.", /* ERR_TIMEOUT -13 */
|
"Already connected.", /* ERR_ISCONN -13 */
|
||||||
"Operation in progress." /* ERR_INPROGRESS -14 */
|
"Operation in progress." /* ERR_INPROGRESS -14 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -158,14 +158,14 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
||||||
* Chain one netbuf to another (@see pbuf_chain)
|
* Chain one netbuf to another (@see pbuf_chain)
|
||||||
*
|
*
|
||||||
* @param head the first netbuf
|
* @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
|
void
|
||||||
netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
||||||
{
|
{
|
||||||
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
|
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
|
||||||
LWIP_ERROR("netbuf_chain: invalid tail", (tail != 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;
|
head->ptr = head->p;
|
||||||
memp_free(MEMP_NETBUF, tail);
|
memp_free(MEMP_NETBUF, tail);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,9 @@
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
#include "lwip/api.h"
|
#include "lwip/api.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
/** helper struct for gethostbyname_r to access the char* buffer */
|
/** helper struct for gethostbyname_r to access the char* buffer */
|
||||||
struct gethostbyname_r_helper {
|
struct gethostbyname_r_helper {
|
||||||
struct ip_addr *addrs;
|
struct ip_addr *addrs;
|
||||||
|
@ -107,23 +110,23 @@ lwip_gethostbyname(const char *name)
|
||||||
|
|
||||||
#if DNS_DEBUG
|
#if DNS_DEBUG
|
||||||
/* dump hostent */
|
/* dump hostent */
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
|
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_aliases == %p\n", s_hostent.h_aliases));
|
||||||
if (s_hostent.h_aliases != NULL) {
|
if (s_hostent.h_aliases != NULL) {
|
||||||
u8_t idx;
|
u8_t idx;
|
||||||
for ( idx=0; s_hostent.h_aliases[idx]; 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_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_addrtype == %d\n", 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_length == %d\n", 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_addr_list == %p\n", s_hostent.h_addr_list));
|
||||||
if (s_hostent.h_addr_list != NULL) {
|
if (s_hostent.h_addr_list != NULL) {
|
||||||
u8_t idx;
|
u8_t idx;
|
||||||
for ( idx=0; s_hostent.h_addr_list[idx]; 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] == %p\n", idx, s_hostent.h_addr_list[idx]));
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* DNS_DEBUG */
|
#endif /* DNS_DEBUG */
|
||||||
|
@ -326,7 +329,8 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||||
if (nodename != NULL) {
|
if (nodename != NULL) {
|
||||||
/* copy nodename to canonname if specified */
|
/* copy nodename to canonname if specified */
|
||||||
size_t namelen = strlen(nodename);
|
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) {
|
if (ai->ai_canonname == NULL) {
|
||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ struct lwip_socket {
|
||||||
u16_t lastoffset;
|
u16_t lastoffset;
|
||||||
/** number of times data was received, set by event_callback(),
|
/** number of times data was received, set by event_callback(),
|
||||||
tested by the receive and select functions */
|
tested by the receive and select functions */
|
||||||
u16_t rcvevent;
|
s16_t rcvevent;
|
||||||
/** number of times data was received, set by event_callback(),
|
/** number of times data was received, set by event_callback(),
|
||||||
tested by select */
|
tested by select */
|
||||||
u16_t sendevent;
|
u16_t sendevent;
|
||||||
|
@ -128,17 +128,17 @@ static const int err_to_errno_table[] = {
|
||||||
0, /* ERR_OK 0 No error, everything OK. */
|
0, /* ERR_OK 0 No error, everything OK. */
|
||||||
ENOMEM, /* ERR_MEM -1 Out of memory error. */
|
ENOMEM, /* ERR_MEM -1 Out of memory error. */
|
||||||
ENOBUFS, /* ERR_BUF -2 Buffer error. */
|
ENOBUFS, /* ERR_BUF -2 Buffer error. */
|
||||||
EHOSTUNREACH, /* ERR_RTE -3 Routing problem. */
|
ETIMEDOUT, /* ERR_TIMEOUT -3 Timeout */
|
||||||
ECONNABORTED, /* ERR_ABRT -4 Connection aborted. */
|
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
|
||||||
ECONNRESET, /* ERR_RST -5 Connection reset. */
|
ECONNABORTED, /* ERR_ABRT -5 Connection aborted. */
|
||||||
ESHUTDOWN, /* ERR_CLSD -6 Connection closed. */
|
ECONNRESET, /* ERR_RST -6 Connection reset. */
|
||||||
ENOTCONN, /* ERR_CONN -7 Not connected. */
|
ESHUTDOWN, /* ERR_CLSD -7 Connection closed. */
|
||||||
EINVAL, /* ERR_VAL -8 Illegal value. */
|
ENOTCONN, /* ERR_CONN -8 Not connected. */
|
||||||
EIO, /* ERR_ARG -9 Illegal argument. */
|
EINVAL, /* ERR_VAL -9 Illegal value. */
|
||||||
EADDRINUSE, /* ERR_USE -10 Address in use. */
|
EIO, /* ERR_ARG -10 Illegal argument. */
|
||||||
-1, /* ERR_IF -11 Low-level netif error */
|
EADDRINUSE, /* ERR_USE -11 Address in use. */
|
||||||
-1, /* ERR_ISCONN -12 Already connected. */
|
-1, /* ERR_IF -12 Low-level netif error */
|
||||||
ETIMEDOUT, /* ERR_TIMEOUT -13 Timeout */
|
-1, /* ERR_ISCONN -13 Already connected. */
|
||||||
EINPROGRESS /* ERR_INPROGRESS -14 Operation in progress */
|
EINPROGRESS /* ERR_INPROGRESS -14 Operation in progress */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,7 +150,9 @@ static const int err_to_errno_table[] = {
|
||||||
err_to_errno_table[-(err)] : EIO)
|
err_to_errno_table[-(err)] : EIO)
|
||||||
|
|
||||||
#ifdef ERRNO
|
#ifdef ERRNO
|
||||||
|
#ifndef set_errno
|
||||||
#define set_errno(err) errno = (err)
|
#define set_errno(err) errno = (err)
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define set_errno(err)
|
#define set_errno(err)
|
||||||
#endif
|
#endif
|
||||||
|
@ -258,6 +260,12 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||||
if (!sock)
|
if (!sock)
|
||||||
return -1;
|
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);
|
newconn = netconn_accept(sock->conn);
|
||||||
if (!newconn) {
|
if (!newconn) {
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err));
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&sin, 0, sizeof(sin));
|
/* Note that POSIX only requires us to check addr is non-NULL. addrlen must
|
||||||
sin.sin_len = sizeof(sin);
|
* not be NULL if addr is valid.
|
||||||
sin.sin_family = AF_INET;
|
*/
|
||||||
sin.sin_port = htons(port);
|
if (NULL != addr) {
|
||||||
sin.sin_addr.s_addr = naddr.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))
|
if (*addrlen > sizeof(sin))
|
||||||
*addrlen = sizeof(sin);
|
*addrlen = sizeof(sin);
|
||||||
|
|
||||||
SMEMCPY(addr, &sin, *addrlen);
|
MEMCPY(addr, &sin, *addrlen);
|
||||||
|
}
|
||||||
|
|
||||||
newsock = alloc_socket(newconn);
|
newsock = alloc_socket(newconn);
|
||||||
if (newsock == -1) {
|
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));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
|
||||||
ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
|
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);
|
sock_set_errno(sock, 0);
|
||||||
return newsock;
|
return newsock;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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 lwip_socket *sock;
|
||||||
struct ip_addr local_addr;
|
struct ip_addr local_addr;
|
||||||
|
@ -326,15 +340,15 @@ lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
|
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;);
|
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
|
||||||
|
|
||||||
local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
|
local_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr;
|
||||||
local_port = ((struct sockaddr_in *)name)->sin_port;
|
local_port = ((const struct sockaddr_in *)name)->sin_port;
|
||||||
|
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
|
||||||
ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
|
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));
|
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;
|
return -1;
|
||||||
|
|
||||||
LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
|
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;);
|
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));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
|
||||||
err = netconn_disconnect(sock->conn);
|
err = netconn_disconnect(sock->conn);
|
||||||
} else {
|
} else {
|
||||||
struct ip_addr remote_addr;
|
struct ip_addr remote_addr;
|
||||||
u16_t remote_port;
|
u16_t remote_port;
|
||||||
|
|
||||||
remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
|
remote_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr;
|
||||||
remote_port = ((struct sockaddr_in *)name)->sin_port;
|
remote_port = ((const struct sockaddr_in *)name)->sin_port;
|
||||||
|
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
|
||||||
ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
|
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));
|
err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
|
||||||
}
|
}
|
||||||
|
@ -458,7 +472,7 @@ lwip_listen(int s, int backlog)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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 sockaddr *from, socklen_t *fromlen)
|
||||||
{
|
{
|
||||||
struct lwip_socket *sock;
|
struct lwip_socket *sock;
|
||||||
|
@ -468,7 +482,7 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||||
u16_t port;
|
u16_t port;
|
||||||
u8_t done = 0;
|
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);
|
sock = get_socket(s);
|
||||||
if (!sock)
|
if (!sock)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -480,7 +494,13 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||||
buf = sock->lastdata;
|
buf = sock->lastdata;
|
||||||
} else {
|
} else {
|
||||||
/* If this is non-blocking call, then check first */
|
/* 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));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
|
||||||
sock_set_errno(sock, EWOULDBLOCK);
|
sock_set_errno(sock, EWOULDBLOCK);
|
||||||
return -1;
|
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));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf));
|
||||||
|
|
||||||
if (!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. */
|
/* We should really do some error checking here. */
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buflen = netbuf_len(buf);
|
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;
|
buflen -= sock->lastoffset;
|
||||||
|
|
||||||
if (len > buflen) {
|
if (len > buflen) {
|
||||||
copylen = buflen;
|
copylen = buflen;
|
||||||
} else {
|
} else {
|
||||||
copylen = len;
|
copylen = (u16_t)len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy the contents of the received buffer into
|
/* 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;
|
off += copylen;
|
||||||
|
|
||||||
if (netconn_type(sock->conn) == NETCONN_TCP) {
|
if (netconn_type(sock->conn) == NETCONN_TCP) {
|
||||||
|
LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
|
||||||
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;
|
done = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
done = 1;
|
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 we don't peek the incoming message... */
|
||||||
if ((flags & MSG_PEEK)==0) {
|
if ((flags & MSG_PEEK)==0) {
|
||||||
/* If this is a TCP socket, check if there is data left in the
|
/* 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
|
buffer. If so, it should be saved in the sock structure for next
|
||||||
time around. */
|
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->lastdata = buf;
|
||||||
sock->lastoffset += copylen;
|
sock->lastoffset += copylen;
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf));
|
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));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf));
|
||||||
netbuf_delete(buf);
|
netbuf_delete(buf);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
done = 1;
|
|
||||||
}
|
}
|
||||||
} while (!done);
|
} 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);
|
sock_set_errno(sock, 0);
|
||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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);
|
return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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);
|
return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
struct lwip_socket *sock;
|
||||||
err_t err;
|
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));
|
s, data, size, flags));
|
||||||
|
|
||||||
sock = get_socket(s);
|
sock = get_socket(s);
|
||||||
if (!sock)
|
if (!sock)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (sock->conn->type!=NETCONN_TCP) {
|
if (sock->conn->type != NETCONN_TCP) {
|
||||||
#if (LWIP_UDP || LWIP_RAW)
|
#if (LWIP_UDP || LWIP_RAW)
|
||||||
return lwip_sendto(s, data, size, flags, NULL, 0);
|
return lwip_sendto(s, data, size, flags, NULL, 0);
|
||||||
#else
|
#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));
|
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));
|
sock_set_errno(sock, err_to_errno(err));
|
||||||
return (err==ERR_OK?size:-1);
|
return (err == ERR_OK ? (int)size : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
lwip_sendto(int s, const void *data, size_t size, int flags,
|
||||||
struct sockaddr *to, socklen_t tolen)
|
const struct sockaddr *to, socklen_t tolen)
|
||||||
{
|
{
|
||||||
struct lwip_socket *sock;
|
struct lwip_socket *sock;
|
||||||
struct ip_addr remote_addr;
|
struct ip_addr remote_addr;
|
||||||
int err;
|
err_t err;
|
||||||
|
u16_t short_size;
|
||||||
#if !LWIP_TCPIP_CORE_LOCKING
|
#if !LWIP_TCPIP_CORE_LOCKING
|
||||||
struct netbuf buf;
|
struct netbuf buf;
|
||||||
u16_t remote_port;
|
u16_t remote_port;
|
||||||
|
@ -650,7 +683,7 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||||
if (!sock)
|
if (!sock)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (sock->conn->type==NETCONN_TCP) {
|
if (sock->conn->type == NETCONN_TCP) {
|
||||||
#if LWIP_TCP
|
#if LWIP_TCP
|
||||||
return lwip_send(s, data, size, flags);
|
return lwip_send(s, data, size, flags);
|
||||||
#else
|
#else
|
||||||
|
@ -659,11 +692,11 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||||
#endif /* LWIP_TCP */
|
#endif /* LWIP_TCP */
|
||||||
}
|
}
|
||||||
|
|
||||||
LWIP_ASSERT("lwip_sendto: size must fit in u16_t",
|
LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
|
||||||
((size >= 0) && (size <= 0xffff)));
|
short_size = (u16_t)size;
|
||||||
LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
|
LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
|
||||||
((tolen == sizeof(struct sockaddr_in)) &&
|
((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;);
|
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
|
||||||
|
|
||||||
#if LWIP_TCPIP_CORE_LOCKING
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
|
@ -675,15 +708,15 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||||
err = ERR_MEM;
|
err = ERR_MEM;
|
||||||
} else {
|
} else {
|
||||||
p->payload = (void*)data;
|
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();
|
LOCK_TCPIP_CORE();
|
||||||
if (sock->conn->type==NETCONN_RAW) {
|
if (sock->conn->type==NETCONN_RAW) {
|
||||||
err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);
|
err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);
|
||||||
} else {
|
} 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();
|
UNLOCK_TCPIP_CORE();
|
||||||
|
|
||||||
|
@ -694,8 +727,8 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||||
/* initialize a buffer */
|
/* initialize a buffer */
|
||||||
buf.p = buf.ptr = NULL;
|
buf.p = buf.ptr = NULL;
|
||||||
if (to) {
|
if (to) {
|
||||||
remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
|
remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr;
|
||||||
remote_port = ntohs(((struct sockaddr_in *)to)->sin_port);
|
remote_port = ntohs(((const struct sockaddr_in *)to)->sin_port);
|
||||||
buf.addr = &remote_addr;
|
buf.addr = &remote_addr;
|
||||||
buf.port = remote_port;
|
buf.port = remote_port;
|
||||||
} else {
|
} else {
|
||||||
|
@ -705,24 +738,32 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||||
buf.port = 0;
|
buf.port = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=",
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=",
|
||||||
s, data, size, flags));
|
s, data, short_size, flags));
|
||||||
ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
|
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 */
|
/* 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 */
|
/* send the data */
|
||||||
err = netconn_send(sock->conn, &buf);
|
err = netconn_send(sock->conn, &buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deallocated the buffer */
|
/* deallocated the buffer */
|
||||||
if (buf.p != NULL) {
|
netbuf_free(&buf);
|
||||||
pbuf_free(buf.p);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||||
sock_set_errno(sock, err_to_errno(err));
|
sock_set_errno(sock, err_to_errno(err));
|
||||||
return (err==ERR_OK?size:-1);
|
return (err == ERR_OK ? short_size : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -778,7 +819,7 @@ lwip_socket(int domain, int type, int protocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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);
|
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)) {
|
if (FD_ISSET(i, readset)) {
|
||||||
/* See if netconn of this socket is ready for read */
|
/* See if netconn of this socket is ready for read */
|
||||||
p_sock = get_socket(i);
|
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);
|
FD_SET(i, &lreadset);
|
||||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
|
||||||
nready++;
|
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",
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n",
|
||||||
maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
|
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.next = 0;
|
||||||
select_cb.readset = readset;
|
select_cb.readset = readset;
|
||||||
|
@ -924,14 +966,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
||||||
msectimeout = 1;
|
msectimeout = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msectimeout > 0 && sys_arch_timeouts() == NULL){
|
i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Take us off the list */
|
/* Take us off the list */
|
||||||
sys_sem_wait(selectsem);
|
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) {
|
if (scb->sem_signalled == 0) {
|
||||||
/* Test this select call for our socket */
|
/* Test this select call for our socket */
|
||||||
if (scb->readset && FD_ISSET(s, scb->readset))
|
if (scb->readset && FD_ISSET(s, scb->readset))
|
||||||
if (sock->rcvevent)
|
if (sock->rcvevent > 0)
|
||||||
break;
|
break;
|
||||||
if (scb->writeset && FD_ISSET(s, scb->writeset))
|
if (scb->writeset && FD_ISSET(s, scb->writeset))
|
||||||
if (sock->sendevent)
|
if (sock->sendevent)
|
||||||
|
@ -1078,8 +1113,8 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
|
||||||
}
|
}
|
||||||
if (scb) {
|
if (scb) {
|
||||||
scb->sem_signalled = 1;
|
scb->sem_signalled = 1;
|
||||||
sys_sem_signal(selectsem);
|
|
||||||
sys_sem_signal(scb->sem);
|
sys_sem_signal(scb->sem);
|
||||||
|
sys_sem_signal(selectsem);
|
||||||
} else {
|
} else {
|
||||||
sys_sem_signal(selectsem);
|
sys_sem_signal(selectsem);
|
||||||
break;
|
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));
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
|
||||||
ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
|
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_port = htons(sin.sin_port);
|
||||||
sin.sin_addr.s_addr = naddr.addr;
|
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))
|
if (*namelen > sizeof(sin))
|
||||||
*namelen = sizeof(sin);
|
*namelen = sizeof(sin);
|
||||||
|
|
||||||
SMEMCPY(name, &sin, *namelen);
|
MEMCPY(name, &sin, *namelen);
|
||||||
sock_set_errno(sock, 0);
|
sock_set_errno(sock, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1444,7 +1479,7 @@ lwip_getsockopt_internal(void *arg)
|
||||||
break;
|
break;
|
||||||
case IP_MULTICAST_IF:
|
case IP_MULTICAST_IF:
|
||||||
((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr;
|
((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));
|
s, *(u32_t *)optval));
|
||||||
break;
|
break;
|
||||||
#endif /* LWIP_IGMP */
|
#endif /* LWIP_IGMP */
|
||||||
|
@ -1777,12 +1812,12 @@ lwip_setsockopt_internal(void *arg)
|
||||||
switch (optname) {
|
switch (optname) {
|
||||||
case IP_TTL:
|
case IP_TTL:
|
||||||
sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
|
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));
|
s, sock->conn->pcb.ip->ttl));
|
||||||
break;
|
break;
|
||||||
case IP_TOS:
|
case IP_TOS:
|
||||||
sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
|
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));
|
s, sock->conn->pcb.ip->tos));
|
||||||
break;
|
break;
|
||||||
#if LWIP_IGMP
|
#if LWIP_IGMP
|
||||||
|
@ -1826,24 +1861,24 @@ lwip_setsockopt_internal(void *arg)
|
||||||
break;
|
break;
|
||||||
case TCP_KEEPALIVE:
|
case TCP_KEEPALIVE:
|
||||||
sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
|
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));
|
s, sock->conn->pcb.tcp->keep_idle));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if LWIP_TCP_KEEPALIVE
|
#if LWIP_TCP_KEEPALIVE
|
||||||
case TCP_KEEPIDLE:
|
case TCP_KEEPIDLE:
|
||||||
sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
|
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));
|
s, sock->conn->pcb.tcp->keep_idle));
|
||||||
break;
|
break;
|
||||||
case TCP_KEEPINTVL:
|
case TCP_KEEPINTVL:
|
||||||
sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
|
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));
|
s, sock->conn->pcb.tcp->keep_intvl));
|
||||||
break;
|
break;
|
||||||
case TCP_KEEPCNT:
|
case TCP_KEEPCNT:
|
||||||
sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
|
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));
|
s, sock->conn->pcb.tcp->keep_cnt));
|
||||||
break;
|
break;
|
||||||
#endif /* LWIP_TCP_KEEPALIVE */
|
#endif /* LWIP_TCP_KEEPALIVE */
|
||||||
|
@ -1887,6 +1922,7 @@ lwip_ioctl(int s, long cmd, void *argp)
|
||||||
{
|
{
|
||||||
struct lwip_socket *sock = get_socket(s);
|
struct lwip_socket *sock = get_socket(s);
|
||||||
u16_t buflen = 0;
|
u16_t buflen = 0;
|
||||||
|
s16_t recv_avail;
|
||||||
|
|
||||||
if (!sock)
|
if (!sock)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1898,7 +1934,10 @@ lwip_ioctl(int s, long cmd, void *argp)
|
||||||
return -1;
|
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 */
|
/* Check if there is data left from the last recv operation. /maq 041215 */
|
||||||
if (sock->lastdata) {
|
if (sock->lastdata) {
|
||||||
|
@ -1908,7 +1947,7 @@ lwip_ioctl(int s, long cmd, void *argp)
|
||||||
*((u16_t*)argp) += buflen;
|
*((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);
|
sock_set_errno(sock, 0);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -297,11 +297,12 @@ tcpip_thread(void *arg)
|
||||||
|
|
||||||
case TCPIP_MSG_TIMEOUT:
|
case TCPIP_MSG_TIMEOUT:
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
||||||
|
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||||
if(msg->msg.tmo.msecs != 0xffffffff)
|
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||||
sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
break;
|
||||||
else
|
case TCPIP_MSG_UNTIMEOUT:
|
||||||
sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg);
|
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);
|
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -379,6 +380,14 @@ tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
|
||||||
return ERR_VAL;
|
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
|
err_t
|
||||||
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
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;
|
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
|
#if LWIP_NETCONN
|
||||||
/**
|
/**
|
||||||
* Call the lower part of a netconn_* function
|
* 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);
|
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 */
|
#endif /* !NO_SYS */
|
||||||
|
|
|
@ -77,8 +77,9 @@ typedef rt_uint32_t mem_ptr_t;
|
||||||
#define PACK_STRUCT_END
|
#define PACK_STRUCT_END
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void sys_arch_assert(const char* file, int line);
|
||||||
#define LWIP_PLATFORM_DIAG(x) do {rt_kprintf x;} while(0)
|
#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_DECL_PROTECT(x)
|
||||||
#define SYS_ARCH_PROTECT(x)
|
#define SYS_ARCH_PROTECT(x)
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include <rtthread.h>
|
|
||||||
|
|
||||||
#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
|
|
|
@ -83,7 +83,10 @@ u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
|
||||||
{
|
{
|
||||||
rt_err_t ret;
|
rt_err_t ret;
|
||||||
s32_t t;
|
s32_t t;
|
||||||
|
u32_t tick;
|
||||||
|
|
||||||
|
/* get the begin tick */
|
||||||
|
tick = rt_tick_get();
|
||||||
#ifdef LWIP_DEBUG
|
#ifdef LWIP_DEBUG
|
||||||
{
|
{
|
||||||
struct rt_thread *thread;
|
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;
|
if (ret == -RT_ETIMEOUT) return SYS_ARCH_TIMEOUT;
|
||||||
else if (ret == RT_EOK) ret = 1;
|
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)
|
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;
|
rt_err_t ret;
|
||||||
s32_t t;
|
s32_t t;
|
||||||
|
u32_t tick;
|
||||||
|
|
||||||
|
/* get the begin tick */
|
||||||
|
tick = rt_tick_get();
|
||||||
|
|
||||||
if(timeout == 0)
|
if(timeout == 0)
|
||||||
t = RT_WAITING_FOREVER;
|
t = RT_WAITING_FOREVER;
|
||||||
|
@ -212,7 +226,14 @@ u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sys_arch_assert(const char* file, int line)
|
||||||
|
{
|
||||||
|
rt_kprintf("Assertion: %d in %s\n", line, file);
|
||||||
|
RT_ASSERT(0);
|
||||||
|
}
|
||||||
|
|
|
@ -86,10 +86,19 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/** global transaction identifier, must be
|
/** Default for DHCP_GLOBAL_XID is 0xABCD0000
|
||||||
* unique for each DHCP request. We simply increment, starting
|
* This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
|
||||||
* with this value (easy to match with a packet analyzer) */
|
* #define DHCP_GLOBAL_XID_HEADER "stdlib.h"
|
||||||
static u32_t xid = 0xABCD0000;
|
* #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 */
|
/* DHCP client state machine functions */
|
||||||
static void dhcp_handle_ack(struct netif *netif);
|
static void dhcp_handle_ack(struct netif *netif);
|
||||||
|
@ -183,6 +192,7 @@ dhcp_check(struct netif *netif)
|
||||||
u16_t msecs;
|
u16_t msecs;
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
|
||||||
(s16_t)netif->name[1]));
|
(s16_t)netif->name[1]));
|
||||||
|
dhcp_set_state(dhcp, DHCP_CHECKING);
|
||||||
/* create an ARP query for the offered IP address, expecting that no host
|
/* create an ARP query for the offered IP address, expecting that no host
|
||||||
responds, as the IP address should not be in use. */
|
responds, as the IP address should not be in use. */
|
||||||
result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
|
result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
|
||||||
|
@ -193,7 +203,6 @@ dhcp_check(struct netif *netif)
|
||||||
msecs = 500;
|
msecs = 500;
|
||||||
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
|
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));
|
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 */
|
#endif /* LWIP_NETIF_HOSTNAME */
|
||||||
|
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 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 */
|
/* create and initialize the DHCP message header */
|
||||||
result = dhcp_create_request(netif);
|
result = dhcp_create_request(netif);
|
||||||
|
@ -247,7 +257,7 @@ dhcp_select(struct netif *netif)
|
||||||
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
||||||
|
|
||||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
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 */
|
/* MUST request the offered IP address */
|
||||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||||
|
@ -264,7 +274,7 @@ dhcp_select(struct netif *netif)
|
||||||
|
|
||||||
#if LWIP_NETIF_HOSTNAME
|
#if LWIP_NETIF_HOSTNAME
|
||||||
p = (const char*)netif->hostname;
|
p = (const char*)netif->hostname;
|
||||||
if (p!=NULL) {
|
if (p != NULL) {
|
||||||
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
|
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
|
||||||
while (*p) {
|
while (*p) {
|
||||||
dhcp_option_byte(dhcp, *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);
|
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||||
dhcp_delete_request(netif);
|
dhcp_delete_request(netif);
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
|
||||||
dhcp_set_state(dhcp, DHCP_REQUESTING);
|
|
||||||
} else {
|
} else {
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
|
||||||
}
|
}
|
||||||
dhcp->tries++;
|
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;
|
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));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
|
||||||
return result;
|
return result;
|
||||||
|
@ -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]));
|
dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));
|
||||||
#if LWIP_DNS
|
#if LWIP_DNS
|
||||||
dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr)));
|
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 */
|
#endif /* LWIP_DNS */
|
||||||
}
|
}
|
||||||
#if LWIP_DNS
|
#if LWIP_DNS
|
||||||
|
@ -570,8 +577,16 @@ dhcp_start(struct netif *netif)
|
||||||
LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
|
LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
|
||||||
dhcp = netif->dhcp;
|
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));
|
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;
|
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? */
|
/* no DHCP client attached yet? */
|
||||||
if (dhcp == NULL) {
|
if (dhcp == NULL) {
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
|
||||||
|
@ -586,6 +601,12 @@ dhcp_start(struct netif *netif)
|
||||||
/* already has DHCP client attached */
|
/* already has DHCP client attached */
|
||||||
} else {
|
} else {
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 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 */
|
/* clear data structure */
|
||||||
|
@ -598,6 +619,9 @@ dhcp_start(struct netif *netif)
|
||||||
netif->dhcp = dhcp = NULL;
|
netif->dhcp = dhcp = NULL;
|
||||||
return ERR_MEM;
|
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 */
|
/* set up local and remote port for the pcb */
|
||||||
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||||
|
@ -611,6 +635,7 @@ dhcp_start(struct netif *netif)
|
||||||
dhcp_stop(netif);
|
dhcp_stop(netif);
|
||||||
return ERR_MEM;
|
return ERR_MEM;
|
||||||
}
|
}
|
||||||
|
/* Set the flag that says this netif is handled by DHCP. */
|
||||||
netif->flags |= NETIF_FLAG_DHCP;
|
netif->flags |= NETIF_FLAG_DHCP;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -653,13 +678,15 @@ dhcp_inform(struct netif *netif)
|
||||||
dhcp_option_byte(dhcp, DHCP_INFORM);
|
dhcp_option_byte(dhcp, DHCP_INFORM);
|
||||||
|
|
||||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||||
/* TODO: use netif->mtu ?! */
|
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
|
||||||
dhcp_option_short(dhcp, 576);
|
|
||||||
|
|
||||||
dhcp_option_trailer(dhcp);
|
dhcp_option_trailer(dhcp);
|
||||||
|
|
||||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
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_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||||
udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_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"));
|
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"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dhcp != NULL) {
|
if (dhcp->pcb != NULL) {
|
||||||
if (dhcp->pcb != NULL) {
|
udp_remove(dhcp->pcb);
|
||||||
udp_remove(dhcp->pcb);
|
|
||||||
}
|
|
||||||
dhcp->pcb = NULL;
|
|
||||||
mem_free((void *)dhcp);
|
|
||||||
netif->dhcp = old_dhcp;
|
|
||||||
}
|
}
|
||||||
|
dhcp->pcb = NULL;
|
||||||
|
mem_free((void *)dhcp);
|
||||||
|
netif->dhcp = old_dhcp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DHCP_DOES_ARP_CHECK
|
#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(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
|
||||||
dhcp_option_byte(dhcp, DHCP_DECLINE);
|
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(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||||
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
|
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
|
||||||
|
|
||||||
|
@ -768,6 +790,7 @@ dhcp_discover(struct netif *netif)
|
||||||
u16_t msecs;
|
u16_t msecs;
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n"));
|
||||||
ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
|
ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
|
||||||
|
dhcp_set_state(dhcp, DHCP_SELECTING);
|
||||||
/* create and initialize the DHCP message header */
|
/* create and initialize the DHCP message header */
|
||||||
result = dhcp_create_request(netif);
|
result = dhcp_create_request(netif);
|
||||||
if (result == ERR_OK) {
|
if (result == ERR_OK) {
|
||||||
|
@ -776,7 +799,7 @@ dhcp_discover(struct netif *netif)
|
||||||
dhcp_option_byte(dhcp, DHCP_DISCOVER);
|
dhcp_option_byte(dhcp, DHCP_DISCOVER);
|
||||||
|
|
||||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
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(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
|
||||||
dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
|
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"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
|
||||||
dhcp_delete_request(netif);
|
dhcp_delete_request(netif);
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
|
||||||
dhcp_set_state(dhcp, DHCP_SELECTING);
|
|
||||||
} else {
|
} else {
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
|
||||||
}
|
}
|
||||||
dhcp->tries++;
|
dhcp->tries++;
|
||||||
#if LWIP_DHCP_AUTOIP_COOP
|
#if LWIP_DHCP_AUTOIP_COOP
|
||||||
/* that means we waited 57 seconds */
|
if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {
|
||||||
if(dhcp->tries >= 9 && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {
|
|
||||||
dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;
|
dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;
|
||||||
autoip_start(netif);
|
autoip_start(netif);
|
||||||
}
|
}
|
||||||
#endif /* LWIP_DHCP_AUTOIP_COOP */
|
#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;
|
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));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));
|
||||||
return result;
|
return result;
|
||||||
|
@ -883,6 +904,13 @@ dhcp_bind(struct netif *netif)
|
||||||
gw_addr.addr |= htonl(0x00000001);
|
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));
|
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);
|
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));
|
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;
|
struct dhcp *dhcp = netif->dhcp;
|
||||||
err_t result;
|
err_t result;
|
||||||
u16_t msecs;
|
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"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n"));
|
||||||
dhcp_set_state(dhcp, DHCP_RENEWING);
|
dhcp_set_state(dhcp, DHCP_RENEWING);
|
||||||
|
|
||||||
|
@ -917,8 +948,17 @@ dhcp_renew(struct netif *netif)
|
||||||
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
||||||
|
|
||||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
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, DHCP_MAX_MSG_LEN(netif));
|
||||||
dhcp_option_short(dhcp, 576);
|
|
||||||
|
#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
|
#if 0
|
||||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||||
|
@ -961,6 +1001,9 @@ dhcp_rebind(struct netif *netif)
|
||||||
struct dhcp *dhcp = netif->dhcp;
|
struct dhcp *dhcp = netif->dhcp;
|
||||||
err_t result;
|
err_t result;
|
||||||
u16_t msecs;
|
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"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));
|
||||||
dhcp_set_state(dhcp, DHCP_REBINDING);
|
dhcp_set_state(dhcp, DHCP_REBINDING);
|
||||||
|
|
||||||
|
@ -972,7 +1015,17 @@ dhcp_rebind(struct netif *netif)
|
||||||
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
||||||
|
|
||||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
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
|
#if 0
|
||||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||||
|
@ -1065,10 +1118,19 @@ dhcp_stop(struct netif *netif)
|
||||||
{
|
{
|
||||||
struct dhcp *dhcp = netif->dhcp;
|
struct dhcp *dhcp = netif->dhcp;
|
||||||
LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
|
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"));
|
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_stop()\n"));
|
||||||
/* netif is DHCP configured? */
|
/* netif is DHCP configured? */
|
||||||
if (dhcp != NULL) {
|
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) {
|
if (dhcp->pcb != NULL) {
|
||||||
udp_remove(dhcp->pcb);
|
udp_remove(dhcp->pcb);
|
||||||
dhcp->pcb = NULL;
|
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);
|
dhcp_handle_offer(netif);
|
||||||
}
|
}
|
||||||
free_pbuf_and_return:
|
free_pbuf_and_return:
|
||||||
|
dhcp_free_reply(dhcp);
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
dhcp->p = NULL;
|
dhcp->p = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1319,6 +1382,20 @@ dhcp_create_request(struct netif *netif)
|
||||||
{
|
{
|
||||||
struct dhcp *dhcp;
|
struct dhcp *dhcp;
|
||||||
u16_t i;
|
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;);
|
LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;);
|
||||||
dhcp = netif->dhcp;
|
dhcp = netif->dhcp;
|
||||||
LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
|
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",
|
LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg",
|
||||||
(dhcp->p_out->len >= sizeof(struct dhcp_msg)));
|
(dhcp->p_out->len >= sizeof(struct dhcp_msg)));
|
||||||
|
|
||||||
/* give unique transaction identifier to this request */
|
/* reuse transaction identifier in retransmissions */
|
||||||
dhcp->xid = xid++;
|
if (dhcp->tries==0)
|
||||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));
|
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;
|
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->xid = htonl(dhcp->xid);
|
||||||
dhcp->msg_out->secs = 0;
|
dhcp->msg_out->secs = 0;
|
||||||
dhcp->msg_out->flags = 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->yiaddr.addr = 0;
|
||||||
dhcp->msg_out->siaddr.addr = 0;
|
dhcp->msg_out->siaddr.addr = 0;
|
||||||
dhcp->msg_out->giaddr.addr = 0;
|
dhcp->msg_out->giaddr.addr = 0;
|
||||||
|
|
|
@ -127,18 +127,19 @@
|
||||||
PACK_STRUCT_BEGIN
|
PACK_STRUCT_BEGIN
|
||||||
/** DNS message header */
|
/** DNS message header */
|
||||||
struct dns_hdr {
|
struct dns_hdr {
|
||||||
u16_t id;
|
PACK_STRUCT_FIELD(u16_t id);
|
||||||
u8_t flags1;
|
PACK_STRUCT_FIELD(u8_t flags1);
|
||||||
u8_t flags2;
|
PACK_STRUCT_FIELD(u8_t flags2);
|
||||||
u16_t numquestions;
|
PACK_STRUCT_FIELD(u16_t numquestions);
|
||||||
u16_t numanswers;
|
PACK_STRUCT_FIELD(u16_t numanswers);
|
||||||
u16_t numauthrr;
|
PACK_STRUCT_FIELD(u16_t numauthrr);
|
||||||
u16_t numextrarr;
|
PACK_STRUCT_FIELD(u16_t numextrarr);
|
||||||
} PACK_STRUCT_STRUCT;
|
} PACK_STRUCT_STRUCT;
|
||||||
PACK_STRUCT_END
|
PACK_STRUCT_END
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
# include "arch/epstruct.h"
|
# include "arch/epstruct.h"
|
||||||
#endif
|
#endif
|
||||||
|
#define SIZEOF_DNS_HDR 12
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
# include "arch/bpstruct.h"
|
# include "arch/bpstruct.h"
|
||||||
|
@ -148,13 +149,14 @@ PACK_STRUCT_BEGIN
|
||||||
struct dns_query {
|
struct dns_query {
|
||||||
/* DNS query record starts with either a domain name or a pointer
|
/* DNS query record starts with either a domain name or a pointer
|
||||||
to a name already present somewhere in the packet. */
|
to a name already present somewhere in the packet. */
|
||||||
u16_t type;
|
PACK_STRUCT_FIELD(u16_t type);
|
||||||
u16_t class;
|
PACK_STRUCT_FIELD(u16_t class);
|
||||||
} PACK_STRUCT_STRUCT;
|
} PACK_STRUCT_STRUCT;
|
||||||
PACK_STRUCT_END
|
PACK_STRUCT_END
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
# include "arch/epstruct.h"
|
# include "arch/epstruct.h"
|
||||||
#endif
|
#endif
|
||||||
|
#define SIZEOF_DNS_QUERY 4
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
# include "arch/bpstruct.h"
|
# include "arch/bpstruct.h"
|
||||||
|
@ -164,15 +166,16 @@ PACK_STRUCT_BEGIN
|
||||||
struct dns_answer {
|
struct dns_answer {
|
||||||
/* DNS answer record starts with either a domain name or a pointer
|
/* DNS answer record starts with either a domain name or a pointer
|
||||||
to a name already present somewhere in the packet. */
|
to a name already present somewhere in the packet. */
|
||||||
u16_t type;
|
PACK_STRUCT_FIELD(u16_t type);
|
||||||
u16_t class;
|
PACK_STRUCT_FIELD(u16_t class);
|
||||||
u32_t ttl;
|
PACK_STRUCT_FIELD(u32_t ttl);
|
||||||
u16_t len;
|
PACK_STRUCT_FIELD(u16_t len);
|
||||||
} PACK_STRUCT_STRUCT;
|
} PACK_STRUCT_STRUCT;
|
||||||
PACK_STRUCT_END
|
PACK_STRUCT_END
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
# include "arch/epstruct.h"
|
# include "arch/epstruct.h"
|
||||||
#endif
|
#endif
|
||||||
|
#define SIZEOF_DNS_ANSWER 10
|
||||||
|
|
||||||
/** DNS table entry */
|
/** DNS table entry */
|
||||||
struct dns_table_entry {
|
struct dns_table_entry {
|
||||||
|
@ -190,6 +193,40 @@ struct dns_table_entry {
|
||||||
void *arg;
|
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 */
|
/* forward declarations */
|
||||||
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
|
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);
|
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.
|
* Look up a hostname in the array of known hostnames.
|
||||||
*
|
*
|
||||||
|
@ -298,13 +451,26 @@ dns_tmr(void)
|
||||||
*
|
*
|
||||||
* @param name the hostname to look up
|
* @param name the hostname to look up
|
||||||
* @return the hostname's IP address, as u32_t (instead of struct ip_addr to
|
* @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
|
* better check for failure: != INADDR_NONE) or INADDR_NONE if the hostname
|
||||||
* in the cached dns_table.
|
* was not found in the cached dns_table.
|
||||||
*/
|
*/
|
||||||
static u32_t
|
static u32_t
|
||||||
dns_lookup(const char *name)
|
dns_lookup(const char *name)
|
||||||
{
|
{
|
||||||
u8_t i;
|
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. */
|
/* Walk through name list, return entry if found. If not, return NULL. */
|
||||||
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
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
|
#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);
|
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 */
|
/* 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 +
|
p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
|
||||||
sizeof(struct dns_query), PBUF_RAM);
|
SIZEOF_DNS_QUERY, PBUF_RAM);
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
|
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
|
||||||
/* fill dns header */
|
/* fill dns header */
|
||||||
hdr = (struct dns_hdr*)p->payload;
|
hdr = (struct dns_hdr*)p->payload;
|
||||||
memset(hdr, 0, sizeof(struct dns_hdr));
|
memset(hdr, 0, SIZEOF_DNS_HDR);
|
||||||
hdr->id = htons(id);
|
hdr->id = htons(id);
|
||||||
hdr->flags1 = DNS_FLAG1_RD;
|
hdr->flags1 = DNS_FLAG1_RD;
|
||||||
hdr->numquestions = htons(1);
|
hdr->numquestions = htons(1);
|
||||||
query = (char*)hdr + sizeof(struct dns_hdr);
|
query = (char*)hdr + SIZEOF_DNS_HDR;
|
||||||
pHostname = name;
|
pHostname = name;
|
||||||
--pHostname;
|
--pHostname;
|
||||||
|
|
||||||
|
@ -446,10 +612,10 @@ dns_send(u8_t numdns, const char* name, u8_t id)
|
||||||
/* fill dns query */
|
/* fill dns query */
|
||||||
qry.type = htons(DNS_RRTYPE_A);
|
qry.type = htons(DNS_RRTYPE_A);
|
||||||
qry.class = htons(DNS_RRCLASS_IN);
|
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 */
|
/* 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 */
|
/* connect to the server for faster receiving */
|
||||||
udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
|
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 ? */
|
/* 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"));
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
|
||||||
/* free pbuf and return */
|
/* free pbuf and return */
|
||||||
goto memerr1;
|
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
|
#if DNS_DOES_NAME_CHECK
|
||||||
/* Check if the name in the "question" part match with the name in the entry. */
|
/* 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));
|
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 */
|
/* call callback to indicate error, clean up memory and return */
|
||||||
goto responseerr;
|
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 */
|
#endif /* DNS_DOES_NAME_CHECK */
|
||||||
|
|
||||||
/* Skip the name in the "question" part */
|
/* 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) {
|
while(nanswers > 0) {
|
||||||
/* skip answer resource record's host name */
|
/* skip answer resource record's host name */
|
||||||
pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
|
pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
|
||||||
|
|
||||||
/* Check for IP address type and Internet class. Others are discarded. */
|
/* 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)) ) {
|
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 */
|
/* read the answer resource record's TTL, and maximize it if needed */
|
||||||
pEntry->ttl = ntohl(ans.ttl);
|
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;
|
pEntry->ttl = DNS_MAX_TTL;
|
||||||
}
|
}
|
||||||
/* read the IP address after answer resource record's header */
|
/* 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));
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
|
||||||
ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
|
ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
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 */
|
/* deallocate memory and return */
|
||||||
goto memerr2;
|
goto memerr2;
|
||||||
} else {
|
} else {
|
||||||
pHostname = pHostname + sizeof(struct dns_answer) + htons(ans.len);
|
pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
|
||||||
}
|
}
|
||||||
--nanswers;
|
--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
|
/* host name already in octet notation? set ip addr and return ERR_OK
|
||||||
* already have this address cached? */
|
* already have this address cached? */
|
||||||
if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||
|
if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||
|
||||||
((addr->addr = dns_lookup(hostname)) != 0)) {
|
((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) {
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "lwip/raw.h"
|
#include "lwip/raw.h"
|
||||||
#include "lwip/udp.h"
|
#include "lwip/udp.h"
|
||||||
#include "lwip/tcp.h"
|
#include "lwip/tcp.h"
|
||||||
|
#include "lwip/snmp_msg.h"
|
||||||
#include "lwip/autoip.h"
|
#include "lwip/autoip.h"
|
||||||
#include "lwip/igmp.h"
|
#include "lwip/igmp.h"
|
||||||
#include "lwip/dns.h"
|
#include "lwip/dns.h"
|
||||||
|
@ -61,6 +62,9 @@
|
||||||
#ifndef BYTE_ORDER
|
#ifndef BYTE_ORDER
|
||||||
#error "BYTE_ORDER is not defined, you have to define it in your cc.h"
|
#error "BYTE_ORDER is not defined, you have to define it in your cc.h"
|
||||||
#endif
|
#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)
|
#if (!LWIP_ARP && ARP_QUEUEING)
|
||||||
#error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
|
#error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -155,6 +159,15 @@
|
||||||
#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
|
#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"
|
#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
|
||||||
#endif
|
#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.
|
/* Compile-time checks for deprecated options.
|
||||||
|
@ -241,6 +254,9 @@ lwip_init(void)
|
||||||
#if LWIP_TCP
|
#if LWIP_TCP
|
||||||
tcp_init();
|
tcp_init();
|
||||||
#endif /* LWIP_TCP */
|
#endif /* LWIP_TCP */
|
||||||
|
#if LWIP_SNMP
|
||||||
|
snmp_init();
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
#if LWIP_AUTOIP
|
#if LWIP_AUTOIP
|
||||||
autoip_init();
|
autoip_init();
|
||||||
#endif /* LWIP_AUTOIP */
|
#endif /* LWIP_AUTOIP */
|
||||||
|
|
|
@ -76,7 +76,15 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/* 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 */
|
* You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
|
||||||
#ifndef LWIP_AUTOIP_RAND
|
#ifndef LWIP_AUTOIP_RAND
|
||||||
#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
|
#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
|
||||||
|
@ -86,11 +94,21 @@
|
||||||
(netif->autoip?netif->autoip->tried_llipaddr:0))
|
(netif->autoip?netif->autoip->tried_llipaddr:0))
|
||||||
#endif /* LWIP_AUTOIP_RAND */
|
#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 functions */
|
||||||
static void autoip_handle_arp_conflict(struct netif *netif);
|
static void autoip_handle_arp_conflict(struct netif *netif);
|
||||||
|
|
||||||
/* creates random LL IP-Address for a network interface */
|
/* creates a pseudo random LL IP-Address for a network interface */
|
||||||
static void autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr);
|
static void autoip_create_addr(struct netif *netif, struct ip_addr *IPAddr);
|
||||||
|
|
||||||
/* sends an ARP announce */
|
/* sends an ARP announce */
|
||||||
static err_t autoip_arp_announce(struct netif *netif);
|
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
|
* 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 netif network interface on which create the IP-Address
|
||||||
* @param RandomIPAddr ip address to initialize
|
* @param IPAddr ip address to initialize
|
||||||
*/
|
*/
|
||||||
static void
|
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
|
/* 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
|
* compliant to RFC 3927 Section 2.1
|
||||||
* We have 254 * 256 possibilities
|
* We have 254 * 256 possibilities */
|
||||||
*/
|
|
||||||
|
|
||||||
RandomIPAddr->addr = (0xA9FE0100 + ((u32_t)(((u8_t)(netif->hwaddr[4])) |
|
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
|
||||||
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)) + netif->autoip->tried_llipaddr);
|
addr += netif->autoip->tried_llipaddr;
|
||||||
|
addr = AUTOIP_NET | (addr & 0xffff);
|
||||||
|
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
|
||||||
|
|
||||||
if (RandomIPAddr->addr>0xA9FEFEFF) {
|
if (addr < AUTOIP_RANGE_START) {
|
||||||
RandomIPAddr->addr = (0xA9FE0100 + (RandomIPAddr->addr-0xA9FEFEFF));
|
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
||||||
}
|
}
|
||||||
if (RandomIPAddr->addr<0xA9FE0100) {
|
if (addr > AUTOIP_RANGE_END) {
|
||||||
RandomIPAddr->addr = (0xA9FEFEFF - (0xA9FE0100-RandomIPAddr->addr));
|
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,
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||||
("autoip_create_rand_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
|
("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
|
||||||
(u16_t)(netif->autoip->tried_llipaddr), (u32_t)(RandomIPAddr->addr)));
|
(u16_t)(netif->autoip->tried_llipaddr), (u32_t)(IPAddr->addr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -258,7 +279,7 @@ autoip_start(struct netif *netif)
|
||||||
autoip->lastconflict = 0;
|
autoip->lastconflict = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
autoip_create_rand_addr(netif, &(autoip->llipaddr));
|
autoip_create_addr(netif, &(autoip->llipaddr));
|
||||||
autoip->tried_llipaddr++;
|
autoip->tried_llipaddr++;
|
||||||
autoip->state = AUTOIP_STATE_PROBING;
|
autoip->state = AUTOIP_STATE_PROBING;
|
||||||
autoip->sent_num = 0;
|
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
|
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
|
||||||
* structure packing (not using structure copy which breaks strict-aliasing rules).
|
* structure packing (not using structure copy which breaks strict-aliasing rules).
|
||||||
*/
|
*/
|
||||||
MEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
|
SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
|
||||||
MEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
|
SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
|
||||||
|
|
||||||
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
|
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
|
||||||
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
|
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
|
||||||
|
|
|
@ -53,9 +53,18 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/** 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 */
|
/* The amount of data from the original packet to return in a dest-unreachable */
|
||||||
#define ICMP_DEST_UNREACH_DATASIZE 8
|
#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().
|
* Processes ICMP input packets, called from ip_input().
|
||||||
*
|
*
|
||||||
|
@ -94,13 +103,30 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||||
#endif /* LWIP_DEBUG */
|
#endif /* LWIP_DEBUG */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ICMP_ECHO:
|
case ICMP_ECHO:
|
||||||
/* broadcast or multicast destination address? */
|
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
|
||||||
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"));
|
int accepted = 1;
|
||||||
ICMP_STATS_INC(icmp.err);
|
#if !LWIP_MULTICAST_PING
|
||||||
pbuf_free(p);
|
/* multicast destination address? */
|
||||||
return;
|
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"));
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
|
||||||
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
|
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();
|
snmp_inc_icmpinerrors();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||||
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
||||||
/* p is not big enough to contain link headers
|
/* p is not big enough to contain link headers
|
||||||
* allocate a new one and copy p into it
|
* allocate a new one and copy p into it
|
||||||
|
@ -153,6 +180,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||||
/* At this point, all checks are OK. */
|
/* At this point, all checks are OK. */
|
||||||
/* We generate an answer by switching the dest and src ip addresses,
|
/* We generate an answer by switching the dest and src ip addresses,
|
||||||
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
|
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
|
||||||
|
@ -205,11 +233,13 @@ lenerr:
|
||||||
ICMP_STATS_INC(icmp.lenerr);
|
ICMP_STATS_INC(icmp.lenerr);
|
||||||
snmp_inc_icmpinerrors();
|
snmp_inc_icmpinerrors();
|
||||||
return;
|
return;
|
||||||
|
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||||
memerr:
|
memerr:
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
ICMP_STATS_INC(icmp.err);
|
ICMP_STATS_INC(icmp.err);
|
||||||
snmp_inc_icmpinerrors();
|
snmp_inc_icmpinerrors();
|
||||||
return;
|
return;
|
||||||
|
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -224,40 +254,7 @@ memerr:
|
||||||
void
|
void
|
||||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||||
{
|
{
|
||||||
struct pbuf *q;
|
icmp_send_response(p, ICMP_DUR, t);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IP_FORWARD || IP_REASSEMBLY
|
#if IP_FORWARD || IP_REASSEMBLY
|
||||||
|
@ -270,20 +267,37 @@ icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
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 pbuf *q;
|
||||||
struct ip_hdr *iphdr;
|
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 */
|
/* 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);
|
PBUF_RAM);
|
||||||
if (q == NULL) {
|
if (q == NULL) {
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
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;
|
iphdr = p->payload;
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
|
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));
|
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
|
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
|
||||||
|
|
||||||
tehdr = q->payload;
|
icmphdr = q->payload;
|
||||||
ICMPH_TYPE_SET(tehdr, ICMP_TE);
|
icmphdr->type = type;
|
||||||
ICMPH_CODE_SET(tehdr, t);
|
icmphdr->code = code;
|
||||||
|
icmphdr->id = 0;
|
||||||
|
icmphdr->seqno = 0;
|
||||||
|
|
||||||
/* copy fields from original packet */
|
/* 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);
|
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
||||||
|
|
||||||
/* calculate checksum */
|
/* calculate checksum */
|
||||||
tehdr->chksum = 0;
|
icmphdr->chksum = 0;
|
||||||
tehdr->chksum = inet_chksum(tehdr, q->len);
|
icmphdr->chksum = inet_chksum(icmphdr, q->len);
|
||||||
ICMP_STATS_INC(icmp.xmit);
|
ICMP_STATS_INC(icmp.xmit);
|
||||||
/* increase number of messages attempted to send */
|
/* increase number of messages attempted to send */
|
||||||
snmp_inc_icmpoutmsgs();
|
snmp_inc_icmpoutmsgs();
|
||||||
|
@ -312,6 +328,4 @@ icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||||
pbuf_free(q);
|
pbuf_free(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* IP_FORWARD */
|
|
||||||
|
|
||||||
#endif /* LWIP_ICMP */
|
#endif /* LWIP_ICMP */
|
||||||
|
|
|
@ -128,7 +128,7 @@ igmp_dump_group_list()
|
||||||
while (group != NULL) {
|
while (group != NULL) {
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_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));
|
||||||
group = group->next;
|
group = group->next;
|
||||||
}
|
}
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
||||||
|
@ -147,7 +147,7 @@ igmp_start(struct netif *netif)
|
||||||
{
|
{
|
||||||
struct igmp_group* group;
|
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);
|
group = igmp_lookup_group(netif, &allsystems);
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ igmp_start(struct netif *netif)
|
||||||
if (netif->igmp_mac_filter != NULL) {
|
if (netif->igmp_mac_filter != NULL) {
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
|
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);
|
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) {
|
if (netif->igmp_mac_filter != NULL) {
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
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);
|
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
|
||||||
}
|
}
|
||||||
/* free group */
|
/* free group */
|
||||||
|
@ -223,7 +223,7 @@ igmp_report_groups( struct netif *netif)
|
||||||
{
|
{
|
||||||
struct igmp_group *group = igmp_group_list;
|
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) {
|
while (group != NULL) {
|
||||||
if (group->interface == netif) {
|
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 ")));
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
|
||||||
ip_addr_debug_print(IGMP_DEBUG, addr);
|
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;
|
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));
|
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
|
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
|
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 */
|
/* Now calculate and check the checksum */
|
||||||
igmp = (struct igmp_msg *)p->payload;
|
igmp = (struct igmp_msg *)p->payload;
|
||||||
|
@ -439,7 +439,8 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -488,7 +489,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||||
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
|
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
|
||||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
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);
|
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) {
|
if (netif->igmp_mac_filter != NULL) {
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
|
||||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
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);
|
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) {
|
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &(group->group_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);
|
igmp_send(group, IGMP_V2_MEMB_REPORT);
|
||||||
}
|
}
|
||||||
|
@ -666,7 +667,8 @@ igmp_stop_timer(struct igmp_group *group)
|
||||||
void
|
void
|
||||||
igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
|
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);
|
igmp_start_timer(group, (maxresp)/2);
|
||||||
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
|
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,
|
igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||||
u8_t ttl, u8_t proto, struct netif *netif)
|
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 */
|
/* This is the "router alert" option */
|
||||||
ra = p->payload;
|
u16_t ra[2];
|
||||||
ra[0] = htons (ROUTER_ALERT);
|
ra[0] = htons (ROUTER_ALERT);
|
||||||
ra[1] = 0x0000; /* Router shall examine packet */
|
ra[1] = 0x0000; /* Router shall examine packet */
|
||||||
|
return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN);
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -796,10 +745,10 @@ igmp_send(struct igmp_group *group, u8_t type)
|
||||||
igmp->igmp_checksum = 0;
|
igmp->igmp_checksum = 0;
|
||||||
igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
|
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 {
|
} else {
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,8 @@ int
|
||||||
inet_aton(const char *cp, struct in_addr *addr)
|
inet_aton(const char *cp, struct in_addr *addr)
|
||||||
{
|
{
|
||||||
u32_t val;
|
u32_t val;
|
||||||
int base, n, c;
|
u8_t base;
|
||||||
|
char c;
|
||||||
u32_t parts[4];
|
u32_t parts[4];
|
||||||
u32_t *pp = parts;
|
u32_t *pp = parts;
|
||||||
|
|
||||||
|
@ -133,14 +134,13 @@ inet_aton(const char *cp, struct in_addr *addr)
|
||||||
/*
|
/*
|
||||||
* Check for trailing characters.
|
* Check for trailing characters.
|
||||||
*/
|
*/
|
||||||
if (c != '\0' && (!isprint(c) || !isspace(c)))
|
if (c != '\0' && !isspace(c))
|
||||||
return (0);
|
return (0);
|
||||||
/*
|
/*
|
||||||
* Concoct the address according to
|
* Concoct the address according to
|
||||||
* the number of parts specified.
|
* the number of parts specified.
|
||||||
*/
|
*/
|
||||||
n = pp - parts + 1;
|
switch (pp - parts + 1) {
|
||||||
switch (n) {
|
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
return (0); /* initial nondigit */
|
return (0); /* initial nondigit */
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#include "lwip/inet_chksum.h"
|
#include "lwip/inet_chksum.h"
|
||||||
#include "lwip/inet.h"
|
#include "lwip/inet.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
/* These are some reference implementations of the checksum algorithm, with the
|
/* These are some reference implementations of the checksum algorithm, with the
|
||||||
* aim of being simple, correct and fully portable. Checksumming is the
|
* aim of being simple, correct and fully portable. Checksumming is the
|
||||||
|
@ -65,6 +65,18 @@
|
||||||
# define LWIP_CHKSUM_ALGORITHM 0
|
# define LWIP_CHKSUM_ALGORITHM 0
|
||||||
#endif
|
#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 */
|
#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
|
||||||
/**
|
/**
|
||||||
* lwip checksum
|
* lwip checksum
|
||||||
|
@ -86,8 +98,7 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||||
acc = 0;
|
acc = 0;
|
||||||
/* dataptr may be at odd or even addresses */
|
/* dataptr may be at odd or even addresses */
|
||||||
octetptr = (u8_t*)dataptr;
|
octetptr = (u8_t*)dataptr;
|
||||||
while (len > 1)
|
while (len > 1) {
|
||||||
{
|
|
||||||
/* declare first octet as most significant
|
/* declare first octet as most significant
|
||||||
thus assume network order, ignoring host order */
|
thus assume network order, ignoring host order */
|
||||||
src = (*octetptr) << 8;
|
src = (*octetptr) << 8;
|
||||||
|
@ -98,15 +109,14 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||||
acc += src;
|
acc += src;
|
||||||
len -= 2;
|
len -= 2;
|
||||||
}
|
}
|
||||||
if (len > 0)
|
if (len > 0) {
|
||||||
{
|
|
||||||
/* accumulate remaining octet */
|
/* accumulate remaining octet */
|
||||||
src = (*octetptr) << 8;
|
src = (*octetptr) << 8;
|
||||||
acc += src;
|
acc += src;
|
||||||
}
|
}
|
||||||
/* add deferred carry bits */
|
/* add deferred carry bits */
|
||||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||||
if ((acc & 0xffff0000) != 0) {
|
if ((acc & 0xffff0000UL) != 0) {
|
||||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||||
}
|
}
|
||||||
/* This maybe a little confusing: reorder sum using htons()
|
/* 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 */
|
/* Consume left-over byte, if any */
|
||||||
if (len > 0)
|
if (len > 0) {
|
||||||
((u8_t *)&t)[0] = *(u8_t *)ps;;
|
((u8_t *)&t)[0] = *(u8_t *)ps;;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add end bytes */
|
/* Add end bytes */
|
||||||
sum += t;
|
sum += t;
|
||||||
|
|
||||||
/* Fold 32-bit sum to 16 bits */
|
/* Fold 32-bit sum to 16 bits
|
||||||
while ((sum >> 16) != 0)
|
calling this twice is propably faster than if statements... */
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
sum = FOLD_U32T(sum);
|
||||||
|
sum = FOLD_U32T(sum);
|
||||||
|
|
||||||
/* Swap if alignment was odd */
|
/* Swap if alignment was odd */
|
||||||
if (odd)
|
if (odd) {
|
||||||
sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
|
sum = SWAP_BYTES_IN_WORD(sum);
|
||||||
|
}
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
@ -211,18 +224,20 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||||
|
|
||||||
while (len > 7) {
|
while (len > 7) {
|
||||||
tmp = sum + *pl++; /* ping */
|
tmp = sum + *pl++; /* ping */
|
||||||
if (tmp < sum)
|
if (tmp < sum) {
|
||||||
tmp++; /* add back carry */
|
tmp++; /* add back carry */
|
||||||
|
}
|
||||||
|
|
||||||
sum = tmp + *pl++; /* pong */
|
sum = tmp + *pl++; /* pong */
|
||||||
if (sum < tmp)
|
if (sum < tmp) {
|
||||||
sum++; /* add back carry */
|
sum++; /* add back carry */
|
||||||
|
}
|
||||||
|
|
||||||
len -= 8;
|
len -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make room in upper bits */
|
/* make room in upper bits */
|
||||||
sum = (sum >> 16) + (sum & 0xffff);
|
sum = FOLD_U32T(sum);
|
||||||
|
|
||||||
ps = (u16_t *)pl;
|
ps = (u16_t *)pl;
|
||||||
|
|
||||||
|
@ -233,16 +248,20 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dangling tail byte remaining? */
|
/* dangling tail byte remaining? */
|
||||||
if (len > 0) /* include odd byte */
|
if (len > 0) { /* include odd byte */
|
||||||
((u8_t *)&t)[0] = *(u8_t *)ps;
|
((u8_t *)&t)[0] = *(u8_t *)ps;
|
||||||
|
}
|
||||||
|
|
||||||
sum += t; /* add end bytes */
|
sum += t; /* add end bytes */
|
||||||
|
|
||||||
while ((sum >> 16) != 0) /* combine halves */
|
/* Fold 32-bit sum to 16 bits
|
||||||
sum = (sum >> 16) + (sum & 0xffff);
|
calling this twice is propably faster than if statements... */
|
||||||
|
sum = FOLD_U32T(sum);
|
||||||
|
sum = FOLD_U32T(sum);
|
||||||
|
|
||||||
if (odd)
|
if (odd) {
|
||||||
sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
|
sum = SWAP_BYTES_IN_WORD(sum);
|
||||||
|
}
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
@ -277,18 +296,18 @@ inet_chksum_pseudo(struct pbuf *p,
|
||||||
(void *)q, (void *)q->next));
|
(void *)q, (void *)q->next));
|
||||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||||
while ((acc >> 16) != 0) {
|
/* just executing this next line is probably faster that the if statement needed
|
||||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
to check whether we really need to execute it, and does no harm */
|
||||||
}
|
acc = FOLD_U32T(acc);
|
||||||
if (q->len % 2 != 0) {
|
if (q->len % 2 != 0) {
|
||||||
swapped = 1 - swapped;
|
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));*/
|
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swapped) {
|
if (swapped) {
|
||||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
}
|
}
|
||||||
acc += (src->addr & 0xffffUL);
|
acc += (src->addr & 0xffffUL);
|
||||||
acc += ((src->addr >> 16) & 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((u16_t)proto);
|
||||||
acc += (u32_t)htons(proto_len);
|
acc += (u32_t)htons(proto_len);
|
||||||
|
|
||||||
while ((acc >> 16) != 0) {
|
/* Fold 32-bit sum to 16 bits
|
||||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
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));
|
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||||
return (u16_t)~(acc & 0xffffUL);
|
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)
|
* @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
|
* @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
|
u16_t
|
||||||
inet_chksum_pseudo_partial(struct pbuf *p,
|
inet_chksum_pseudo_partial(struct pbuf *p,
|
||||||
struct ip_addr *src, struct ip_addr *dest,
|
struct ip_addr *src, struct ip_addr *dest,
|
||||||
|
@ -340,18 +362,17 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||||
chksum_len -= chklen;
|
chksum_len -= chklen;
|
||||||
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
|
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
|
||||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||||
while ((acc >> 16) != 0) {
|
/* fold the upper bit down */
|
||||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
acc = FOLD_U32T(acc);
|
||||||
}
|
|
||||||
if (q->len % 2 != 0) {
|
if (q->len % 2 != 0) {
|
||||||
swapped = 1 - swapped;
|
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));*/
|
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swapped) {
|
if (swapped) {
|
||||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
}
|
}
|
||||||
acc += (src->addr & 0xffffUL);
|
acc += (src->addr & 0xffffUL);
|
||||||
acc += ((src->addr >> 16) & 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((u16_t)proto);
|
||||||
acc += (u32_t)htons(proto_len);
|
acc += (u32_t)htons(proto_len);
|
||||||
|
|
||||||
while ((acc >> 16) != 0) {
|
/* Fold 32-bit sum to 16 bits
|
||||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
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));
|
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||||
return (u16_t)~(acc & 0xffffUL);
|
return (u16_t)~(acc & 0xffffUL);
|
||||||
}
|
}
|
||||||
|
#endif /* LWIP_UDPLITE */
|
||||||
|
|
||||||
/* inet_chksum:
|
/* inet_chksum:
|
||||||
*
|
*
|
||||||
|
@ -380,13 +403,7 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||||
u16_t
|
u16_t
|
||||||
inet_chksum(void *dataptr, u16_t len)
|
inet_chksum(void *dataptr, u16_t len)
|
||||||
{
|
{
|
||||||
u32_t acc;
|
return ~LWIP_CHKSUM(dataptr, len);
|
||||||
|
|
||||||
acc = LWIP_CHKSUM(dataptr, len);
|
|
||||||
while ((acc >> 16) != 0) {
|
|
||||||
acc = (acc & 0xffff) + (acc >> 16);
|
|
||||||
}
|
|
||||||
return (u16_t)~(acc & 0xffff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -407,17 +424,15 @@ inet_chksum_pbuf(struct pbuf *p)
|
||||||
swapped = 0;
|
swapped = 0;
|
||||||
for(q = p; q != NULL; q = q->next) {
|
for(q = p; q != NULL; q = q->next) {
|
||||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||||
while ((acc >> 16) != 0) {
|
acc = FOLD_U32T(acc);
|
||||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
|
||||||
}
|
|
||||||
if (q->len % 2 != 0) {
|
if (q->len % 2 != 0) {
|
||||||
swapped = 1 - swapped;
|
swapped = 1 - swapped;
|
||||||
acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swapped) {
|
if (swapped) {
|
||||||
acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
}
|
}
|
||||||
return (u16_t)~(acc & 0xffffUL);
|
return (u16_t)~(acc & 0xffffUL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,47 @@
|
||||||
#include "lwip/stats.h"
|
#include "lwip/stats.h"
|
||||||
#include "arch/perf.h"
|
#include "arch/perf.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Finds the appropriate network interface for a given IP address. It
|
||||||
* searches the list of network interfaces linearly. A match is found
|
* 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);
|
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));
|
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
|
#if LWIP_RAW
|
||||||
/* raw input did not eat the packet? */
|
/* raw input did not eat the packet? */
|
||||||
if (raw_input(p, inp) == 0)
|
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;
|
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 ttl, u8_t tos,
|
||||||
u8_t proto, struct netif *netif)
|
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;
|
struct ip_hdr *iphdr;
|
||||||
static u16_t ip_id = 0;
|
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? */
|
/* Should the IP header be generated or is it already included in p? */
|
||||||
if (dest != IP_HDRINCL) {
|
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 */
|
/* generate IP header */
|
||||||
if (pbuf_header(p, IP_HLEN)) {
|
if (pbuf_header(p, IP_HLEN)) {
|
||||||
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
|
LWIP_DEBUGF(IP_DEBUG | 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);
|
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_LEN_SET(iphdr, htons(p->tot_len));
|
||||||
IPH_OFFSET_SET(iphdr, 0);
|
IPH_OFFSET_SET(iphdr, 0);
|
||||||
IPH_ID_SET(iphdr, htons(ip_id));
|
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);
|
IPH_CHKSUM_SET(iphdr, 0);
|
||||||
#if CHECKSUM_GEN_IP
|
#if CHECKSUM_GEN_IP
|
||||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
/* IP header already included in p */
|
/* 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));
|
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
|
||||||
ip_debug_print(p);
|
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;
|
struct netif *netif;
|
||||||
|
|
||||||
if ((netif = ip_route(dest)) == NULL) {
|
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 ERR_RTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
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
|
#if IP_DEBUG
|
||||||
/* Print an IP header by using LWIP_DEBUGF
|
/* Print an IP header by using LWIP_DEBUGF
|
||||||
* @param p an IP packet, p->payload pointing to the IP header
|
* @param p an IP packet, p->payload pointing to the IP header
|
||||||
|
|
|
@ -81,12 +81,21 @@
|
||||||
/** This is a helper struct which holds the starting
|
/** This is a helper struct which holds the starting
|
||||||
* offset and the ending offset of this fragment to
|
* offset and the ending offset of this fragment to
|
||||||
* easily chain the fragments.
|
* 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 ip_reass_helper {
|
||||||
struct pbuf *next_pbuf;
|
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
|
||||||
u16_t start;
|
PACK_STRUCT_FIELD(u16_t start);
|
||||||
u16_t end;
|
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) \
|
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
|
||||||
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
|
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
|
||||||
|
@ -599,7 +608,7 @@ nullreturn:
|
||||||
|
|
||||||
#if IP_FRAG
|
#if IP_FRAG
|
||||||
#if IP_FRAG_USES_STATIC_BUF
|
#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 */
|
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
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
|
#if IP_DEBUG
|
||||||
void
|
void
|
||||||
ip_debug_print(struct pbuf *p)
|
ip_debug_print(struct pbuf *p)
|
||||||
|
|
|
@ -67,14 +67,6 @@
|
||||||
#if MEM_USE_POOLS
|
#if MEM_USE_POOLS
|
||||||
/* lwIP head implemented with different sized 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
|
* Allocate memory: determine the smallest pool that is big enough
|
||||||
* to contain an element of 'size' and get an element from that pool.
|
* to contain an element of 'size' and get an element from that pool.
|
||||||
|
@ -85,13 +77,17 @@ struct mem_helper
|
||||||
void *
|
void *
|
||||||
mem_malloc(mem_size_t size)
|
mem_malloc(mem_size_t size)
|
||||||
{
|
{
|
||||||
struct mem_helper *element;
|
struct memp_malloc_helper *element;
|
||||||
memp_t poolnr;
|
memp_t poolnr;
|
||||||
|
mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
|
||||||
|
|
||||||
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) {
|
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
|
/* 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? */
|
plus a struct memp_malloc_helper that saves the pool this element came from? */
|
||||||
if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) {
|
if (required_size <= memp_sizes[poolnr]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,17 +95,23 @@ mem_malloc(mem_size_t size)
|
||||||
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
|
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
element = (struct mem_helper*)memp_malloc(poolnr);
|
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
|
||||||
if (element == NULL) {
|
if (element == NULL) {
|
||||||
/* No need to DEBUGF or ASSERT: This error is already
|
/* No need to DEBUGF or ASSERT: This error is already
|
||||||
taken care of in memp.c */
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save the pool number this element came from */
|
/* save the pool number this element came from */
|
||||||
element->poolnr = poolnr;
|
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++;
|
element++;
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
|
@ -125,12 +127,12 @@ mem_malloc(mem_size_t size)
|
||||||
void
|
void
|
||||||
mem_free(void *rmem)
|
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 != NULL", (rmem != NULL));
|
||||||
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
|
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--;
|
hmem--;
|
||||||
|
|
||||||
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
|
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
|
||||||
|
@ -177,9 +179,36 @@ static u8_t *ram;
|
||||||
static struct mem *ram_end;
|
static struct mem *ram_end;
|
||||||
/** pointer to the lowest free block, this is used for faster search */
|
/** pointer to the lowest free block, this is used for faster search */
|
||||||
static struct mem *lfree;
|
static struct mem *lfree;
|
||||||
|
|
||||||
/** concurrent access protection */
|
/** concurrent access protection */
|
||||||
static sys_sem_t mem_sem;
|
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.
|
* "Plug holes" by combining adjacent empty struct mems.
|
||||||
* After this function is through, there should not exist
|
* 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 */
|
/* initialize the lowest-free pointer to the start of the heap */
|
||||||
lfree = (struct mem *)ram;
|
lfree = (struct mem *)ram;
|
||||||
|
|
||||||
#if MEM_STATS
|
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
|
||||||
lwip_stats.mem.avail = MEM_SIZE_ALIGNED;
|
|
||||||
#endif /* MEM_STATS */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -270,6 +297,7 @@ void
|
||||||
mem_free(void *rmem)
|
mem_free(void *rmem)
|
||||||
{
|
{
|
||||||
struct mem *mem;
|
struct mem *mem;
|
||||||
|
LWIP_MEM_FREE_DECL_PROTECT();
|
||||||
|
|
||||||
if (rmem == NULL) {
|
if (rmem == NULL) {
|
||||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
|
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 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);
|
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 &&
|
LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||||
(u8_t *)rmem < (u8_t *)ram_end);
|
(u8_t *)rmem < (u8_t *)ram_end);
|
||||||
|
|
||||||
if ((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"));
|
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
|
||||||
#if MEM_STATS
|
/* protect mem stats from concurrent access */
|
||||||
++lwip_stats.mem.err;
|
SYS_ARCH_PROTECT(lev);
|
||||||
#endif /* MEM_STATS */
|
MEM_STATS_INC(illegal);
|
||||||
sys_sem_signal(mem_sem);
|
SYS_ARCH_UNPROTECT(lev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* protect the heap from concurrent access */
|
||||||
|
LWIP_MEM_FREE_PROTECT();
|
||||||
/* Get the corresponding struct mem ... */
|
/* Get the corresponding struct mem ... */
|
||||||
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||||
/* ... which has to be in a used state ... */
|
/* ... which has to be in a used state ... */
|
||||||
|
@ -303,13 +331,14 @@ mem_free(void *rmem)
|
||||||
lfree = mem;
|
lfree = mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MEM_STATS
|
MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram));
|
||||||
lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);
|
|
||||||
#endif /* MEM_STATS */
|
|
||||||
|
|
||||||
/* finally, see if prev or next are free also */
|
/* finally, see if prev or next are free also */
|
||||||
plug_holes(mem);
|
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
|
* @param newsize required size after shrinking (needs to be smaller than or
|
||||||
* equal to the previous size)
|
* equal to the previous size)
|
||||||
* @return for compatibility reasons: is always == rmem, at the moment
|
* @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 *
|
void *
|
||||||
mem_realloc(void *rmem, mem_size_t newsize)
|
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 size;
|
||||||
mem_size_t ptr, ptr2;
|
mem_size_t ptr, ptr2;
|
||||||
struct mem *mem, *mem2;
|
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
|
/* Expand the size of the allocated memory region so that we can
|
||||||
adjust for alignment. */
|
adjust for alignment. */
|
||||||
|
@ -346,7 +379,12 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||||
(u8_t *)rmem < (u8_t *)ram_end);
|
(u8_t *)rmem < (u8_t *)ram_end);
|
||||||
|
|
||||||
if ((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_realloc: illegal memory\n"));
|
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;
|
return rmem;
|
||||||
}
|
}
|
||||||
/* Get the corresponding struct mem ... */
|
/* Get the corresponding struct mem ... */
|
||||||
|
@ -366,11 +404,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* protect the heap from concurrent access */
|
/* protect the heap from concurrent access */
|
||||||
sys_arch_sem_wait(mem_sem, 0);
|
LWIP_MEM_FREE_PROTECT();
|
||||||
|
|
||||||
#if MEM_STATS
|
MEM_STATS_DEC_USED(used, (size - newsize));
|
||||||
lwip_stats.mem.used -= (size - newsize);
|
|
||||||
#endif /* MEM_STATS */
|
|
||||||
|
|
||||||
mem2 = (struct mem *)&ram[mem->next];
|
mem2 = (struct mem *)&ram[mem->next];
|
||||||
if(mem2->used == 0) {
|
if(mem2->used == 0) {
|
||||||
|
@ -426,7 +462,10 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||||
-> don't do anyhting.
|
-> don't do anyhting.
|
||||||
-> the remaining space stays unused since it is too small
|
-> 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;
|
return rmem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,6 +483,10 @@ mem_malloc(mem_size_t size)
|
||||||
{
|
{
|
||||||
mem_size_t ptr, ptr2;
|
mem_size_t ptr, ptr2;
|
||||||
struct mem *mem, *mem2;
|
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) {
|
if (size == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -464,88 +507,101 @@ mem_malloc(mem_size_t size)
|
||||||
|
|
||||||
/* protect the heap from concurrent access */
|
/* protect the heap from concurrent access */
|
||||||
sys_arch_sem_wait(mem_sem, 0);
|
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,
|
/* Scan through the heap searching for a free block that is big enough,
|
||||||
* beginning with the lowest free block.
|
* beginning with the lowest free block.
|
||||||
*/
|
*/
|
||||||
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
|
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
|
||||||
ptr = ((struct mem *)&ram[ptr])->next) {
|
ptr = ((struct mem *)&ram[ptr])->next) {
|
||||||
mem = (struct mem *)&ram[ptr];
|
mem = (struct mem *)&ram[ptr];
|
||||||
|
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||||
if ((!mem->used) &&
|
mem_free_count = 0;
|
||||||
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
|
LWIP_MEM_ALLOC_UNPROTECT();
|
||||||
/* mem is not used and at least perfect fit is possible:
|
/* allow mem_free to run */
|
||||||
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
|
LWIP_MEM_ALLOC_PROTECT();
|
||||||
|
if (mem_free_count != 0) {
|
||||||
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
|
local_mem_free_count = mem_free_count;
|
||||||
/* (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 */
|
|
||||||
}
|
}
|
||||||
|
mem_free_count = 0;
|
||||||
|
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
|
||||||
if (mem == lfree) {
|
if ((!mem->used) &&
|
||||||
/* Find next free block after mem and update lowest free pointer */
|
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
|
||||||
while (lfree->used && lfree != ram_end) {
|
/* mem is not used and at least perfect fit is possible:
|
||||||
lfree = (struct mem *)&ram[lfree->next];
|
* 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));
|
LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
|
||||||
#if MEM_STATS
|
MEM_STATS_INC(err);
|
||||||
++lwip_stats.mem.err;
|
LWIP_MEM_ALLOC_UNPROTECT();
|
||||||
#endif /* MEM_STATS */
|
|
||||||
sys_sem_signal(mem_sem);
|
sys_sem_signal(mem_sem);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
struct memp {
|
struct memp {
|
||||||
struct memp *next;
|
struct memp *next;
|
||||||
#if MEMP_OVERFLOW_CHECK
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
@ -109,15 +111,23 @@ struct memp {
|
||||||
* Elements form a linked list. */
|
* Elements form a linked list. */
|
||||||
static struct memp *memp_tab[MEMP_MAX];
|
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. */
|
/** This array holds the element sizes of each pool. */
|
||||||
#if !MEM_USE_POOLS
|
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
|
||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
const u16_t memp_sizes[MEMP_MAX] = {
|
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"
|
#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. */
|
/** This array holds the number of elements in each pool. */
|
||||||
static const u16_t memp_num[MEMP_MAX] = {
|
static const u16_t memp_num[MEMP_MAX] = {
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc) (num),
|
#define LWIP_MEMPOOL(name,num,size,desc) (num),
|
||||||
|
@ -183,7 +193,7 @@ memp_overflow_check_element(struct memp *p, u16_t memp_size)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
#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++) {
|
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
|
||||||
if (m[k] != 0xcd) {
|
if (m[k] != 0xcd) {
|
||||||
LWIP_ASSERT("detected memp overflow!", 0);
|
LWIP_ASSERT("detected memp overflow!", 0);
|
||||||
|
@ -208,7 +218,7 @@ memp_overflow_check_all(void)
|
||||||
p = p;
|
p = p;
|
||||||
for (j = 0; j < memp_num[i]; ++j) {
|
for (j = 0; j < memp_num[i]; ++j) {
|
||||||
memp_overflow_check_element(p, memp_sizes[i]);
|
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);
|
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
|
||||||
#endif
|
#endif
|
||||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
#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);
|
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||||
#endif
|
#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;
|
struct memp *memp;
|
||||||
u16_t i, j;
|
u16_t i, j;
|
||||||
|
|
||||||
#if MEMP_STATS
|
|
||||||
for (i = 0; i < MEMP_MAX; ++i) {
|
for (i = 0; i < MEMP_MAX; ++i) {
|
||||||
lwip_stats.memp[i].used = lwip_stats.memp[i].max =
|
MEMP_STATS_AVAIL(used, i, 0);
|
||||||
lwip_stats.memp[i].err = 0;
|
MEMP_STATS_AVAIL(max, i, 0);
|
||||||
lwip_stats.memp[i].avail = memp_num[i];
|
MEMP_STATS_AVAIL(err, i, 0);
|
||||||
|
MEMP_STATS_AVAIL(avail, i, memp_num[i]);
|
||||||
}
|
}
|
||||||
#endif /* MEMP_STATS */
|
|
||||||
|
|
||||||
memp = LWIP_MEM_ALIGN(memp_memory);
|
memp = LWIP_MEM_ALIGN(memp_memory);
|
||||||
/* for every pool: */
|
/* for every pool: */
|
||||||
|
@ -268,7 +277,11 @@ memp_init(void)
|
||||||
for (j = 0; j < memp_num[i]; ++j) {
|
for (j = 0; j < memp_num[i]; ++j) {
|
||||||
memp->next = memp_tab[i];
|
memp->next = memp_tab[i];
|
||||||
memp_tab[i] = memp;
|
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
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
@ -315,20 +328,13 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
|
||||||
memp->file = file;
|
memp->file = file;
|
||||||
memp->line = line;
|
memp->line = line;
|
||||||
#endif /* MEMP_OVERFLOW_CHECK */
|
#endif /* MEMP_OVERFLOW_CHECK */
|
||||||
#if MEMP_STATS
|
MEMP_STATS_INC_USED(used, type);
|
||||||
++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 */
|
|
||||||
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
||||||
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
|
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
|
||||||
memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);
|
memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);
|
||||||
} else {
|
} else {
|
||||||
LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
|
LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
|
||||||
#if MEMP_STATS
|
MEMP_STATS_INC(err, type);
|
||||||
++lwip_stats.memp[type].err;
|
|
||||||
#endif /* MEMP_STATS */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
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 >= 2 */
|
||||||
#endif /* MEMP_OVERFLOW_CHECK */
|
#endif /* MEMP_OVERFLOW_CHECK */
|
||||||
|
|
||||||
#if MEMP_STATS
|
MEMP_STATS_DEC(used, type);
|
||||||
lwip_stats.memp[type].used--;
|
|
||||||
#endif /* MEMP_STATS */
|
|
||||||
|
|
||||||
memp->next = memp_tab[type];
|
memp->next = memp_tab[type];
|
||||||
memp_tab[type] = memp;
|
memp_tab[type] = memp;
|
||||||
|
@ -378,3 +382,5 @@ memp_free(memp_t type, void *mem)
|
||||||
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* MEMP_MEM_MALLOC */
|
||||||
|
|
|
@ -45,6 +45,12 @@
|
||||||
#include "lwip/snmp.h"
|
#include "lwip/snmp.h"
|
||||||
#include "lwip/igmp.h"
|
#include "lwip/igmp.h"
|
||||||
#include "netif/etharp.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
|
#if LWIP_NETIF_STATUS_CALLBACK
|
||||||
#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }
|
#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
|
#if LWIP_IGMP
|
||||||
netif->igmp_mac_filter = NULL;
|
netif->igmp_mac_filter = NULL;
|
||||||
#endif /* LWIP_IGMP */
|
#endif /* LWIP_IGMP */
|
||||||
|
#if ENABLE_LOOPBACK
|
||||||
|
netif->loop_first = NULL;
|
||||||
|
netif->loop_last = NULL;
|
||||||
|
#endif /* ENABLE_LOOPBACK */
|
||||||
|
|
||||||
/* remember netif specific state information data */
|
/* remember netif specific state information data */
|
||||||
netif->state = state;
|
netif->state = state;
|
||||||
|
@ -114,6 +124,9 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
netif->addr_hint = NULL;
|
netif->addr_hint = NULL;
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
#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);
|
netif_set_addr(netif, ipaddr, netmask, gw);
|
||||||
|
|
||||||
|
@ -388,13 +401,9 @@ void netif_set_up(struct netif *netif)
|
||||||
NETIF_STATUS_CALLBACK(netif);
|
NETIF_STATUS_CALLBACK(netif);
|
||||||
|
|
||||||
#if LWIP_ARP
|
#if LWIP_ARP
|
||||||
/** For Ethernet network interfaces, we would like to send a
|
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
||||||
* "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.
|
|
||||||
*/
|
|
||||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||||
etharp_query(netif, &(netif->ip_addr), NULL);
|
etharp_gratuitous(netif);
|
||||||
}
|
}
|
||||||
#endif /* LWIP_ARP */
|
#endif /* LWIP_ARP */
|
||||||
|
|
||||||
|
@ -451,13 +460,9 @@ void netif_set_link_up(struct netif *netif )
|
||||||
netif->flags |= NETIF_FLAG_LINK_UP;
|
netif->flags |= NETIF_FLAG_LINK_UP;
|
||||||
|
|
||||||
#if LWIP_ARP
|
#if LWIP_ARP
|
||||||
/** For Ethernet network interfaces, we would like to send a
|
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
||||||
* "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.
|
|
||||||
*/
|
|
||||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||||
etharp_query(netif, &(netif->ip_addr), NULL);
|
etharp_gratuitous(netif);
|
||||||
}
|
}
|
||||||
#endif /* LWIP_ARP */
|
#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 ))
|
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif ))
|
||||||
{
|
{
|
||||||
if ( netif )
|
if (netif) {
|
||||||
netif->link_callback = link_callback;
|
netif->link_callback = link_callback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* LWIP_NETIF_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 */
|
||||||
|
|
|
@ -70,6 +70,9 @@
|
||||||
#include "lwip/pbuf.h"
|
#include "lwip/pbuf.h"
|
||||||
#include "lwip/sys.h"
|
#include "lwip/sys.h"
|
||||||
#include "arch/perf.h"
|
#include "arch/perf.h"
|
||||||
|
#if TCP_QUEUE_OOSEQ
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -78,6 +81,42 @@
|
||||||
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
|
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
|
||||||
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
|
#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).
|
* 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) {
|
switch (type) {
|
||||||
case PBUF_POOL:
|
case PBUF_POOL:
|
||||||
/* allocate head of pbuf chain into p */
|
/* 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));
|
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return 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",
|
LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
|
||||||
((u8_t*)p->payload + p->len <=
|
((u8_t*)p->payload + p->len <=
|
||||||
(u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
|
(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) */
|
/* set reference count (needed here in case we fail) */
|
||||||
p->ref = 1;
|
p->ref = 1;
|
||||||
|
|
||||||
|
@ -172,7 +213,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||||
rem_len = length - p->len;
|
rem_len = length - p->len;
|
||||||
/* any remaining pbufs to be allocated? */
|
/* any remaining pbufs to be allocated? */
|
||||||
while (rem_len > 0) {
|
while (rem_len > 0) {
|
||||||
q = memp_malloc(MEMP_PBUF_POOL);
|
ALLOC_POOL_PBUF(q);
|
||||||
if (q == NULL) {
|
if (q == NULL) {
|
||||||
/* free chain so far allocated */
|
/* free chain so far allocated */
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
|
@ -272,6 +313,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
|
||||||
u16_t rem_len; /* remaining length */
|
u16_t rem_len; /* remaining length */
|
||||||
s32_t grow;
|
s32_t grow;
|
||||||
|
|
||||||
|
LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
|
||||||
LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
|
LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
|
||||||
p->type == PBUF_ROM ||
|
p->type == PBUF_ROM ||
|
||||||
p->type == PBUF_RAM ||
|
p->type == PBUF_RAM ||
|
||||||
|
@ -299,6 +341,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
|
||||||
q->tot_len += (u16_t)grow;
|
q->tot_len += (u16_t)grow;
|
||||||
/* proceed to next pbuf in chain */
|
/* proceed to next pbuf in chain */
|
||||||
q = q->next;
|
q = q->next;
|
||||||
|
LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
|
||||||
}
|
}
|
||||||
/* we have now reached the new last pbuf (in q) */
|
/* we have now reached the new last pbuf (in q) */
|
||||||
/* rem_len == desired length for pbuf 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!
|
* @note Only one packet is copied, no packet queue!
|
||||||
*
|
*
|
||||||
* @param p_to pbuf source of the copy
|
* @param p_to pbuf destination of the copy
|
||||||
* @param p_from pbuf destination of the copy
|
* @param p_from pbuf source of the copy
|
||||||
*
|
*
|
||||||
* @return ERR_OK if pbuf was copied
|
* @return ERR_OK if pbuf was copied
|
||||||
* ERR_ARG if one of the pbufs is NULL or p_to is not big
|
* 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 buf the pbuf from which to copy data
|
||||||
* @param dataptr the application supplied buffer
|
* @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
|
* @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
|
u16_t
|
||||||
pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
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 buf_copy_len;
|
||||||
u16_t copied_total = 0;
|
u16_t copied_total = 0;
|
||||||
|
|
||||||
LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
|
LWIP_ERROR("pbuf_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 dataptr", (dataptr != NULL), return 0;);
|
||||||
|
|
||||||
left = 0;
|
left = 0;
|
||||||
|
|
||||||
|
@ -775,3 +820,76 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||||
}
|
}
|
||||||
return copied_total;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -93,24 +93,29 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||||
/* this allows multiple pcbs to match against the packet by design */
|
/* this allows multiple pcbs to match against the packet by design */
|
||||||
while ((eaten == 0) && (pcb != NULL)) {
|
while ((eaten == 0) && (pcb != NULL)) {
|
||||||
if (pcb->protocol == proto) {
|
if (pcb->protocol == proto) {
|
||||||
/* receive callback function available? */
|
#if IP_SOF_BROADCAST_RECV
|
||||||
if (pcb->recv != NULL) {
|
/* broadcast filter? */
|
||||||
/* the receive callback function did not eat the packet? */
|
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp))
|
||||||
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)
|
#endif /* IP_SOF_BROADCAST_RECV */
|
||||||
{
|
{
|
||||||
/* receive function ate the packet */
|
/* receive callback function available? */
|
||||||
p = NULL;
|
if (pcb->recv != NULL) {
|
||||||
eaten = 1;
|
/* the receive callback function did not eat the packet? */
|
||||||
if (prev != NULL) {
|
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) {
|
||||||
/* move the pcb to the front of raw_pcbs so that is
|
/* receive function ate the packet */
|
||||||
found faster next time */
|
p = NULL;
|
||||||
prev->next = pcb->next;
|
eaten = 1;
|
||||||
pcb->next = raw_pcbs;
|
if (prev != NULL) {
|
||||||
raw_pcbs = pcb;
|
/* 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 */
|
/* drop the packet */
|
||||||
}
|
}
|
||||||
prev = pcb;
|
prev = pcb;
|
||||||
|
@ -238,6 +243,18 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||||
return ERR_RTE;
|
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)) {
|
if (ip_addr_isany(&pcb->local_ip)) {
|
||||||
/* use outgoing network interface IP address as source address */
|
/* use outgoing network interface IP address as source address */
|
||||||
src_ip = &(netif->ip_addr);
|
src_ip = &(netif->ip_addr);
|
||||||
|
|
|
@ -2205,10 +2205,10 @@ system_get_value(struct obj_def *od, u16_t len, void *value)
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case 1: /* sysDescr */
|
case 1: /* sysDescr */
|
||||||
ocstrncpy(value,sysdescr_ptr,len);
|
ocstrncpy(value,sysdescr_ptr, len);
|
||||||
break;
|
break;
|
||||||
case 2: /* sysObjectID */
|
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;
|
break;
|
||||||
case 3: /* sysUpTime */
|
case 3: /* sysUpTime */
|
||||||
{
|
{
|
||||||
|
@ -2606,7 +2606,7 @@ ifentry_get_value(struct obj_def *od, u16_t len, void *value)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 22: /* ifSpecific */
|
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;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3342,7 +3342,7 @@ ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 13: /* ipRouteInfo */
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -589,9 +589,10 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||||
{
|
{
|
||||||
struct mib_external_node *en;
|
struct mib_external_node *en;
|
||||||
|
|
||||||
/** set_value_a() @todo: use reply value?? */
|
/** set_value_a() */
|
||||||
en = msg_ps->ext_mib_node;
|
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 */
|
/** @todo use set_value_pc() if toobig */
|
||||||
msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
|
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);
|
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
||||||
if ((derr != ERR_OK) ||
|
if ((derr != ERR_OK) ||
|
||||||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
|
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
|
||||||
(len <= 0) || (len > vb_len))
|
(len == 0) || (len > vb_len))
|
||||||
{
|
{
|
||||||
snmp_inc_snmpinasnparseerrs();
|
snmp_inc_snmpinasnparseerrs();
|
||||||
/* free varbinds (if available) */
|
/* free varbinds (if available) */
|
||||||
|
|
|
@ -54,7 +54,6 @@ stats_display_proto(struct stats_proto *proto, char *name)
|
||||||
{
|
{
|
||||||
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
|
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
|
||||||
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
|
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(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));
|
||||||
LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
|
LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
|
||||||
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));
|
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));
|
LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IGMP_STATS
|
||||||
void
|
void
|
||||||
stats_display_igmp(struct stats_igmp *igmp)
|
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(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed));
|
||||||
LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed));
|
LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed));
|
||||||
}
|
}
|
||||||
|
#endif /* IGMP_STATS */
|
||||||
|
|
||||||
|
#if MEM_STATS || MEMP_STATS
|
||||||
void
|
void
|
||||||
stats_display_mem(struct stats_mem *mem, char *name)
|
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));
|
LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
stats_display(void)
|
|
||||||
{
|
|
||||||
#if MEMP_STATS
|
#if MEMP_STATS
|
||||||
s16_t i;
|
void
|
||||||
|
stats_display_memp(struct stats_mem *mem, int index)
|
||||||
|
{
|
||||||
char * memp_names[] = {
|
char * memp_names[] = {
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc) desc,
|
#define LWIP_MEMPOOL(name,num,size,desc) desc,
|
||||||
#include "lwip/memp_std.h"
|
#include "lwip/memp_std.h"
|
||||||
};
|
};
|
||||||
#endif
|
if(index < MEMP_MAX) {
|
||||||
#if LINK_STATS
|
stats_display_mem(mem, memp_names[index]);
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
#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 */
|
#endif /* LWIP_STATS_DISPLAY */
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ struct sswt_cb
|
||||||
void
|
void
|
||||||
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||||
{
|
{
|
||||||
u32_t time;
|
u32_t time_needed;
|
||||||
struct sys_timeouts *timeouts;
|
struct sys_timeouts *timeouts;
|
||||||
struct sys_timeo *tmptimeout;
|
struct sys_timeo *tmptimeout;
|
||||||
sys_timeout_handler h;
|
sys_timeout_handler h;
|
||||||
|
@ -76,18 +76,18 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||||
|
|
||||||
if (!timeouts || !timeouts->next) {
|
if (!timeouts || !timeouts->next) {
|
||||||
UNLOCK_TCPIP_CORE();
|
UNLOCK_TCPIP_CORE();
|
||||||
time = sys_arch_mbox_fetch(mbox, msg, 0);
|
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
|
||||||
LOCK_TCPIP_CORE();
|
LOCK_TCPIP_CORE();
|
||||||
} else {
|
} else {
|
||||||
if (timeouts->next->time > 0) {
|
if (timeouts->next->time > 0) {
|
||||||
UNLOCK_TCPIP_CORE();
|
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();
|
LOCK_TCPIP_CORE();
|
||||||
} else {
|
} 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
|
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
||||||
could be fetched. We should now call the timeout handler and
|
could be fetched. We should now call the timeout handler and
|
||||||
deallocate the memory allocated for the timeout. */
|
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
|
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
||||||
occured. The time variable is set to the number of
|
occured. The time variable is set to the number of
|
||||||
milliseconds we waited for the message. */
|
milliseconds we waited for the message. */
|
||||||
if (time < timeouts->next->time) {
|
if (time_needed < timeouts->next->time) {
|
||||||
timeouts->next->time -= time;
|
timeouts->next->time -= time_needed;
|
||||||
} else {
|
} else {
|
||||||
timeouts->next->time = 0;
|
timeouts->next->time = 0;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||||
void
|
void
|
||||||
sys_sem_wait(sys_sem_t sem)
|
sys_sem_wait(sys_sem_t sem)
|
||||||
{
|
{
|
||||||
u32_t time;
|
u32_t time_needed;
|
||||||
struct sys_timeouts *timeouts;
|
struct sys_timeouts *timeouts;
|
||||||
struct sys_timeo *tmptimeout;
|
struct sys_timeo *tmptimeout;
|
||||||
sys_timeout_handler h;
|
sys_timeout_handler h;
|
||||||
|
@ -139,12 +139,12 @@ sys_sem_wait(sys_sem_t sem)
|
||||||
sys_arch_sem_wait(sem, 0);
|
sys_arch_sem_wait(sem, 0);
|
||||||
} else {
|
} else {
|
||||||
if (timeouts->next->time > 0) {
|
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 {
|
} 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
|
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
||||||
could be fetched. We should now call the timeout handler and
|
could be fetched. We should now call the timeout handler and
|
||||||
deallocate the memory allocated for the timeout. */
|
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
|
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
||||||
occured. The time variable is set to the number of
|
occured. The time variable is set to the number of
|
||||||
milliseconds we waited for the message. */
|
milliseconds we waited for the message. */
|
||||||
if (time < timeouts->next->time) {
|
if (time_needed < timeouts->next->time) {
|
||||||
timeouts->next->time -= time;
|
timeouts->next->time -= time_needed;
|
||||||
} else {
|
} else {
|
||||||
timeouts->next->time = 0;
|
timeouts->next->time = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "lwip/memp.h"
|
#include "lwip/memp.h"
|
||||||
#include "lwip/snmp.h"
|
#include "lwip/snmp.h"
|
||||||
#include "lwip/tcp.h"
|
#include "lwip/tcp.h"
|
||||||
|
#include "lwip/debug.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -186,14 +187,15 @@ tcp_close(struct tcp_pcb *pcb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts a connection by sending a RST to the remote host and deletes
|
* Abandons a connection and optionally sends a RST to the remote
|
||||||
* the local protocol control block. This is done when a connection is
|
* host. Deletes the local protocol control block. This is done when
|
||||||
* killed because of shortage of memory.
|
* a connection is killed because of shortage of memory.
|
||||||
*
|
*
|
||||||
* @param pcb the tcp_pcb to abort
|
* @param pcb the tcp_pcb to abort
|
||||||
|
* @param reset boolean to indicate whether a reset should be sent
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
tcp_abort(struct tcp_pcb *pcb)
|
tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||||
{
|
{
|
||||||
u32_t seqno, ackno;
|
u32_t seqno, ackno;
|
||||||
u16_t remote_port, local_port;
|
u16_t remote_port, local_port;
|
||||||
|
@ -235,8 +237,10 @@ tcp_abort(struct tcp_pcb *pcb)
|
||||||
#endif /* TCP_QUEUE_OOSEQ */
|
#endif /* TCP_QUEUE_OOSEQ */
|
||||||
memp_free(MEMP_TCP_PCB, pcb);
|
memp_free(MEMP_TCP_PCB, pcb);
|
||||||
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
|
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
|
||||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));
|
if (reset) {
|
||||||
tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
|
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;
|
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) {
|
if (port == 0) {
|
||||||
port = tcp_new_port();
|
port = tcp_new_port();
|
||||||
|
@ -380,6 +384,33 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||||
return (struct tcp_pcb *)lpcb;
|
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
|
* This function should be called by the application when it has
|
||||||
* processed the data. The purpose is to advertise a larger window
|
* 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
|
void
|
||||||
tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||||
{
|
{
|
||||||
if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {
|
int wnd_inflation;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pcb->flags & TF_ACK_DELAY) &&
|
LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
|
||||||
!(pcb->flags & TF_ACK_NOW)) {
|
len <= 0xffff - pcb->rcv_wnd );
|
||||||
/*
|
|
||||||
* We send an ACK here (if one is not already pending, hence
|
pcb->rcv_wnd += len;
|
||||||
* the above tests) as tcp_recved() implies that the application
|
if (pcb->rcv_wnd > TCP_WND)
|
||||||
* has processed some data, and so we can open the receiver's
|
pcb->rcv_wnd = TCP_WND;
|
||||||
* window to allow more to be transmitted. This could result in
|
|
||||||
* two ACKs being sent for each received packet in some limited cases
|
wnd_inflation = tcp_update_rcv_ann_wnd(pcb);
|
||||||
* (where the application is only receiving data, and is slow to
|
|
||||||
* process it) but it is necessary to guarantee that the sender can
|
/* If the change in the right edge of window is significant (default
|
||||||
* continue to transmit.
|
* watermark is TCP_WND/2), then send an explicit update now.
|
||||||
*/
|
* Otherwise wait for a packet to be sent in the normal course of
|
||||||
tcp_ack(pcb);
|
* events (or more window to be available later) */
|
||||||
}
|
if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD)
|
||||||
else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {
|
|
||||||
/* If we can send a window update such that there is a full
|
|
||||||
* segment available in the window, do so now. This is sort of
|
|
||||||
* nagle-like in its goals, and tries to hit a compromise between
|
|
||||||
* sending acks each time the window is updated, and only sending
|
|
||||||
* window updates when a timer expires. The "threshold" used
|
|
||||||
* above (currently TCP_WND/2) can be tuned to be more or less
|
|
||||||
* aggressive */
|
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
|
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));
|
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,
|
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))
|
err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
|
||||||
{
|
{
|
||||||
u32_t optdata;
|
|
||||||
err_t ret;
|
err_t ret;
|
||||||
u32_t iss;
|
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->snd_lbb = iss - 1;
|
||||||
pcb->rcv_wnd = TCP_WND;
|
pcb->rcv_wnd = TCP_WND;
|
||||||
pcb->rcv_ann_wnd = TCP_WND;
|
pcb->rcv_ann_wnd = TCP_WND;
|
||||||
|
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
|
||||||
pcb->snd_wnd = TCP_WND;
|
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;
|
pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
|
||||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||||
pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
|
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();
|
snmp_inc_tcpactiveopens();
|
||||||
|
|
||||||
/* Build an MSS option */
|
ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS
|
||||||
optdata = TCP_BUILD_MSS_OPTION();
|
#if LWIP_TCP_TIMESTAMPS
|
||||||
|
| TF_SEG_OPTS_TS
|
||||||
ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);
|
#endif
|
||||||
|
);
|
||||||
if (ret == ERR_OK) {
|
if (ret == ERR_OK) {
|
||||||
tcp_output(pcb);
|
tcp_output(pcb);
|
||||||
}
|
}
|
||||||
|
@ -991,7 +1007,8 @@ tcp_alloc(u8_t prio)
|
||||||
pcb->rcv_ann_wnd = TCP_WND;
|
pcb->rcv_ann_wnd = TCP_WND;
|
||||||
pcb->tos = 0;
|
pcb->tos = 0;
|
||||||
pcb->ttl = TCP_TTL;
|
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->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
|
||||||
pcb->rto = 3000 / TCP_SLOW_INTERVAL;
|
pcb->rto = 3000 / TCP_SLOW_INTERVAL;
|
||||||
pcb->sa = 0;
|
pcb->sa = 0;
|
||||||
|
@ -1001,7 +1018,6 @@ tcp_alloc(u8_t prio)
|
||||||
iss = tcp_next_iss();
|
iss = tcp_next_iss();
|
||||||
pcb->snd_wl2 = iss;
|
pcb->snd_wl2 = iss;
|
||||||
pcb->snd_nxt = iss;
|
pcb->snd_nxt = iss;
|
||||||
pcb->snd_max = iss;
|
|
||||||
pcb->lastack = iss;
|
pcb->lastack = iss;
|
||||||
pcb->snd_lbb = iss;
|
pcb->snd_lbb = iss;
|
||||||
pcb->tmr = tcp_ticks;
|
pcb->tmr = tcp_ticks;
|
||||||
|
@ -1112,7 +1128,7 @@ void
|
||||||
tcp_accept(struct tcp_pcb *pcb,
|
tcp_accept(struct tcp_pcb *pcb,
|
||||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
|
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 */
|
#endif /* LWIP_CALLBACK_API */
|
||||||
|
|
||||||
|
@ -1148,6 +1164,27 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
|
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) {
|
if (pcb->refused_data != NULL) {
|
||||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
|
||||||
pbuf_free(pcb->refused_data);
|
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;
|
mss_s = outif->mtu - IP_HLEN - TCP_HLEN;
|
||||||
/* RFC 1122, chap 4.2.2.6:
|
/* RFC 1122, chap 4.2.2.6:
|
||||||
* Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
|
* 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);
|
sendmss = LWIP_MIN(sendmss, mss_s);
|
||||||
}
|
}
|
||||||
return sendmss;
|
return sendmss;
|
||||||
|
@ -1364,6 +1403,7 @@ tcp_debug_print_flags(u8_t flags)
|
||||||
if (flags & TCP_CWR) {
|
if (flags & TCP_CWR) {
|
||||||
LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
|
LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
|
||||||
}
|
}
|
||||||
|
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -169,8 +169,8 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||||
ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
|
ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
|
||||||
tcphdr->wnd = ntohs(tcphdr->wnd);
|
tcphdr->wnd = ntohs(tcphdr->wnd);
|
||||||
|
|
||||||
flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;
|
flags = TCPH_FLAGS(tcphdr);
|
||||||
tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);
|
tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
|
||||||
|
|
||||||
/* Demultiplex an incoming segment. First, we check if it is destined
|
/* Demultiplex an incoming segment. First, we check if it is destined
|
||||||
for an active connection. */
|
for an active connection. */
|
||||||
|
@ -393,7 +393,7 @@ static err_t
|
||||||
tcp_listen_input(struct tcp_pcb_listen *pcb)
|
tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||||
{
|
{
|
||||||
struct tcp_pcb *npcb;
|
struct tcp_pcb *npcb;
|
||||||
u32_t optdata;
|
err_t rc;
|
||||||
|
|
||||||
/* In the LISTEN state, we check for incoming SYN segments,
|
/* In the LISTEN state, we check for incoming SYN segments,
|
||||||
creates a new PCB, and responds with a SYN|ACK. */
|
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));
|
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
|
||||||
#if TCP_LISTEN_BACKLOG
|
#if TCP_LISTEN_BACKLOG
|
||||||
if (pcb->accepts_pending >= pcb->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;
|
return ERR_ABRT;
|
||||||
}
|
}
|
||||||
#endif /* TCP_LISTEN_BACKLOG */
|
#endif /* TCP_LISTEN_BACKLOG */
|
||||||
|
@ -430,6 +431,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||||
npcb->remote_port = tcphdr->src;
|
npcb->remote_port = tcphdr->src;
|
||||||
npcb->state = SYN_RCVD;
|
npcb->state = SYN_RCVD;
|
||||||
npcb->rcv_nxt = seqno + 1;
|
npcb->rcv_nxt = seqno + 1;
|
||||||
|
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
|
||||||
npcb->snd_wnd = tcphdr->wnd;
|
npcb->snd_wnd = tcphdr->wnd;
|
||||||
npcb->ssthresh = npcb->snd_wnd;
|
npcb->ssthresh = npcb->snd_wnd;
|
||||||
npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
|
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();
|
snmp_inc_tcppassiveopens();
|
||||||
|
|
||||||
/* Build an MSS option. */
|
|
||||||
optdata = TCP_BUILD_MSS_OPTION();
|
|
||||||
/* Send a SYN|ACK together with the 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 tcp_output(npcb);
|
||||||
}
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
|
@ -498,7 +507,6 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
struct tcp_seg *rseg;
|
struct tcp_seg *rseg;
|
||||||
u8_t acceptable = 0;
|
u8_t acceptable = 0;
|
||||||
err_t err;
|
err_t err;
|
||||||
u8_t accepted_inseq;
|
|
||||||
|
|
||||||
err = ERR_OK;
|
err = ERR_OK;
|
||||||
|
|
||||||
|
@ -511,7 +519,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
|
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
|
||||||
pcb->rcv_nxt+pcb->rcv_ann_wnd)) {
|
pcb->rcv_nxt+pcb->rcv_wnd)) {
|
||||||
acceptable = 1;
|
acceptable = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,7 +527,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
if (acceptable) {
|
if (acceptable) {
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
|
||||||
LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
|
LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
|
||||||
recv_flags = TF_RESET;
|
recv_flags |= TF_RESET;
|
||||||
pcb->flags &= ~TF_ACK_DELAY;
|
pcb->flags &= ~TF_ACK_DELAY;
|
||||||
return ERR_RST;
|
return ERR_RST;
|
||||||
} else {
|
} 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. */
|
/* Update the PCB (in)activity timer. */
|
||||||
pcb->tmr = tcp_ticks;
|
pcb->tmr = tcp_ticks;
|
||||||
pcb->keep_cnt_sent = 0;
|
pcb->keep_cnt_sent = 0;
|
||||||
|
|
||||||
|
tcp_parseopt(pcb);
|
||||||
|
|
||||||
/* Do different things depending on the TCP state. */
|
/* Do different things depending on the TCP state. */
|
||||||
switch (pcb->state) {
|
switch (pcb->state) {
|
||||||
case SYN_SENT:
|
case SYN_SENT:
|
||||||
|
@ -545,14 +561,12 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
&& ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
|
&& ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
|
||||||
pcb->snd_buf++;
|
pcb->snd_buf++;
|
||||||
pcb->rcv_nxt = seqno + 1;
|
pcb->rcv_nxt = seqno + 1;
|
||||||
|
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
|
||||||
pcb->lastack = ackno;
|
pcb->lastack = ackno;
|
||||||
pcb->snd_wnd = tcphdr->wnd;
|
pcb->snd_wnd = tcphdr->wnd;
|
||||||
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
|
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
|
||||||
pcb->state = ESTABLISHED;
|
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
|
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
|
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
|
||||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||||
|
@ -592,8 +606,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SYN_RCVD:
|
case SYN_RCVD:
|
||||||
if (flags & TCP_ACK &&
|
if (flags & TCP_ACK) {
|
||||||
!(flags & TCP_RST)) {
|
|
||||||
/* expected ACK number? */
|
/* expected ACK number? */
|
||||||
if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
|
if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
|
||||||
u16_t old_cwnd;
|
u16_t old_cwnd;
|
||||||
|
@ -613,11 +626,11 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
old_cwnd = pcb->cwnd;
|
old_cwnd = pcb->cwnd;
|
||||||
/* If there was any data contained within this ACK,
|
/* If there was any data contained within this ACK,
|
||||||
* we'd better pass it on to the application as well. */
|
* 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);
|
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);
|
tcp_ack_now(pcb);
|
||||||
pcb->state = CLOSE_WAIT;
|
pcb->state = CLOSE_WAIT;
|
||||||
}
|
}
|
||||||
|
@ -628,21 +641,24 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
|
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
|
||||||
tcphdr->dest, tcphdr->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;
|
break;
|
||||||
case CLOSE_WAIT:
|
case CLOSE_WAIT:
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case ESTABLISHED:
|
case ESTABLISHED:
|
||||||
accepted_inseq = tcp_receive(pcb);
|
tcp_receive(pcb);
|
||||||
if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */
|
if (recv_flags & TF_GOT_FIN) { /* passive close */
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
pcb->state = CLOSE_WAIT;
|
pcb->state = CLOSE_WAIT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FIN_WAIT_1:
|
case FIN_WAIT_1:
|
||||||
tcp_receive(pcb);
|
tcp_receive(pcb);
|
||||||
if (flags & TCP_FIN) {
|
if (recv_flags & TF_GOT_FIN) {
|
||||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
|
||||||
LWIP_DEBUGF(TCP_DEBUG,
|
LWIP_DEBUGF(TCP_DEBUG,
|
||||||
("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
|
@ -654,13 +670,13 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
pcb->state = CLOSING;
|
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;
|
pcb->state = FIN_WAIT_2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FIN_WAIT_2:
|
case FIN_WAIT_2:
|
||||||
tcp_receive(pcb);
|
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));
|
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
tcp_pcb_purge(pcb);
|
tcp_pcb_purge(pcb);
|
||||||
|
@ -673,7 +689,6 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
tcp_receive(pcb);
|
tcp_receive(pcb);
|
||||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
||||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||||
tcp_ack_now(pcb);
|
|
||||||
tcp_pcb_purge(pcb);
|
tcp_pcb_purge(pcb);
|
||||||
TCP_RMV(&tcp_active_pcbs, pcb);
|
TCP_RMV(&tcp_active_pcbs, pcb);
|
||||||
pcb->state = TIME_WAIT;
|
pcb->state = TIME_WAIT;
|
||||||
|
@ -685,7 +700,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
||||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"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 */
|
/* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
|
||||||
recv_flags = TF_CLOSED;
|
recv_flags |= TF_CLOSED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -723,7 +738,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
u8_t accepted_inseq = 0;
|
u8_t accepted_inseq = 0;
|
||||||
|
|
||||||
if (flags & TCP_ACK) {
|
if (flags & TCP_ACK) {
|
||||||
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;
|
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
|
||||||
|
|
||||||
/* Update window. */
|
/* Update window. */
|
||||||
if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
|
if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
|
||||||
|
@ -739,8 +754,10 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
#if TCP_WND_DEBUG
|
#if TCP_WND_DEBUG
|
||||||
} else {
|
} else {
|
||||||
if (pcb->snd_wnd != tcphdr->wnd) {
|
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",
|
LWIP_DEBUGF(TCP_WND_DEBUG,
|
||||||
pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
|
("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 */
|
#endif /* TCP_WND_DEBUG */
|
||||||
}
|
}
|
||||||
|
@ -748,7 +765,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
if (pcb->lastack == ackno) {
|
if (pcb->lastack == ackno) {
|
||||||
pcb->acked = 0;
|
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;
|
++pcb->dupacks;
|
||||||
if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
|
if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
|
||||||
if (!(pcb->flags & TF_INFR)) {
|
if (!(pcb->flags & TF_INFR)) {
|
||||||
|
@ -785,9 +802,9 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",
|
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. */
|
/* We come here when the ACK acknowledges new data. */
|
||||||
|
|
||||||
/* Reset the "IN Fast Retransmit" flag, since we are no longer
|
/* 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
|
->unsent list after a retransmission, so these segments may
|
||||||
in fact have been sent once. */
|
in fact have been sent once. */
|
||||||
while (pcb->unsent != NULL &&
|
while (pcb->unsent != NULL &&
|
||||||
/*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&
|
TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
|
||||||
TCP_SEQ_LEQ(ackno, pcb->snd_max)*/
|
TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
|
||||||
TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)
|
|
||||||
) {
|
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
|
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) +
|
ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
|
||||||
TCP_TCPLEN(pcb->unsent)));
|
TCP_TCPLEN(pcb->unsent)));
|
||||||
|
@ -900,10 +915,6 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
LWIP_ASSERT("tcp_receive: valid queue length",
|
LWIP_ASSERT("tcp_receive: valid queue length",
|
||||||
pcb->unacked != NULL || pcb->unsent != NULL);
|
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. */
|
/* 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
|
and below rcv_nxt + rcv_wnd) in order to be further
|
||||||
processed. */
|
processed. */
|
||||||
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
|
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) {
|
if (pcb->rcv_nxt == seqno) {
|
||||||
accepted_inseq = 1;
|
accepted_inseq = 1;
|
||||||
/* The incoming segment is the next in sequence. We check if
|
/* The incoming segment is the next in sequence. We check if
|
||||||
we have to trim the end of the segment and update rcv_nxt
|
we have to trim the end of the segment and update rcv_nxt
|
||||||
and pass the data to the application. */
|
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 TCP_QUEUE_OOSEQ
|
||||||
if (pcb->ooseq != NULL &&
|
if (pcb->ooseq != NULL) {
|
||||||
TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
|
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
||||||
if (pcb->ooseq->len > 0) {
|
LWIP_DEBUGF(TCP_INPUT_DEBUG,
|
||||||
/* We have to trim the second edge of the incoming
|
("tcp_receive: received in-order FIN, binning ooseq queue\n"));
|
||||||
segment. */
|
/* Received in-order FIN means anything that was received
|
||||||
inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);
|
* out of order must now have been received in-order, so
|
||||||
pbuf_realloc(inseg.p, inseg.len);
|
* bin the ooseq queue */
|
||||||
} else {
|
while (pcb->ooseq != NULL) {
|
||||||
/* 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;
|
struct tcp_seg *old_ooseq = pcb->ooseq;
|
||||||
pcb->ooseq = pcb->ooseq->next;
|
pcb->ooseq = pcb->ooseq->next;
|
||||||
memp_free(MEMP_TCP_SEG, old_ooseq);
|
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 */
|
#endif /* TCP_QUEUE_OOSEQ */
|
||||||
|
|
||||||
tcplen = TCP_TCPLEN(&inseg);
|
pcb->rcv_nxt = seqno + tcplen;
|
||||||
|
|
||||||
/* First received FIN will be ACKed +1, on any successive (duplicate)
|
|
||||||
* FINs we are already in CLOSE_WAIT and have already done +1.
|
|
||||||
*/
|
|
||||||
if (pcb->state != CLOSE_WAIT) {
|
|
||||||
pcb->rcv_nxt += tcplen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the receiver's (our) window. */
|
/* Update the receiver's (our) window. */
|
||||||
if (pcb->rcv_wnd < tcplen) {
|
LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
|
||||||
pcb->rcv_wnd = 0;
|
pcb->rcv_wnd -= tcplen;
|
||||||
} else {
|
|
||||||
pcb->rcv_wnd -= tcplen;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pcb->rcv_ann_wnd < tcplen) {
|
tcp_update_rcv_ann_wnd(pcb);
|
||||||
pcb->rcv_ann_wnd = 0;
|
|
||||||
} else {
|
|
||||||
pcb->rcv_ann_wnd -= tcplen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there is data in the segment, we make preparations to
|
/* If there is data in the segment, we make preparations to
|
||||||
pass this up to the application. The ->recv_data variable
|
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) {
|
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
|
||||||
recv_flags = TF_GOT_FIN;
|
recv_flags |= TF_GOT_FIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TCP_QUEUE_OOSEQ
|
#if TCP_QUEUE_OOSEQ
|
||||||
|
@ -1117,16 +1156,11 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
seqno = pcb->ooseq->tcphdr->seqno;
|
seqno = pcb->ooseq->tcphdr->seqno;
|
||||||
|
|
||||||
pcb->rcv_nxt += TCP_TCPLEN(cseg);
|
pcb->rcv_nxt += TCP_TCPLEN(cseg);
|
||||||
if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
|
LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
|
||||||
pcb->rcv_wnd = 0;
|
pcb->rcv_wnd >= TCP_TCPLEN(cseg));
|
||||||
} else {
|
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
|
||||||
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
|
|
||||||
}
|
tcp_update_rcv_ann_wnd(pcb);
|
||||||
if (pcb->rcv_ann_wnd < TCP_TCPLEN(cseg)) {
|
|
||||||
pcb->rcv_ann_wnd = 0;
|
|
||||||
} else {
|
|
||||||
pcb->rcv_ann_wnd -= TCP_TCPLEN(cseg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cseg->p->tot_len > 0) {
|
if (cseg->p->tot_len > 0) {
|
||||||
/* Chain this pbuf onto the pbuf that we will pass to
|
/* 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) {
|
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
|
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 */
|
if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
|
||||||
pcb->state = CLOSE_WAIT;
|
pcb->state = CLOSE_WAIT;
|
||||||
}
|
}
|
||||||
|
@ -1195,14 +1229,14 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
} else {
|
} else {
|
||||||
pcb->ooseq = cseg;
|
pcb->ooseq = cseg;
|
||||||
}
|
}
|
||||||
}
|
tcp_seg_free(next);
|
||||||
tcp_seg_free(next);
|
if (cseg->next != NULL) {
|
||||||
if (cseg->next != NULL) {
|
next = cseg->next;
|
||||||
next = cseg->next;
|
if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
|
||||||
if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
|
/* We need to trim the incoming segment. */
|
||||||
/* We need to trim the incoming segment. */
|
cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||||
cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
|
pbuf_realloc(cseg->p, cseg->len);
|
||||||
pbuf_realloc(cseg->p, cseg->len);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1282,10 +1316,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
|
tcp_ack_now(pcb);
|
||||||
pcb->rcv_nxt + pcb->rcv_ann_wnd-1)){
|
|
||||||
tcp_ack_now(pcb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Segments with length 0 is taken care of here. Segments that
|
/* 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
|
* Parses the options contained in the incoming segment.
|
||||||
* from uIP with only small changes.)
|
|
||||||
*
|
*
|
||||||
* Called from tcp_listen_input() and tcp_process().
|
* Called from tcp_listen_input() and tcp_process().
|
||||||
* Currently, only the MSS option is supported!
|
* Currently, only the MSS option is supported!
|
||||||
|
@ -1311,35 +1341,72 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||||
static void
|
static void
|
||||||
tcp_parseopt(struct tcp_pcb *pcb)
|
tcp_parseopt(struct tcp_pcb *pcb)
|
||||||
{
|
{
|
||||||
u8_t c;
|
u16_t c, max_c;
|
||||||
u8_t *opts, opt;
|
|
||||||
u16_t mss;
|
u16_t mss;
|
||||||
|
u8_t *opts, opt;
|
||||||
|
#if LWIP_TCP_TIMESTAMPS
|
||||||
|
u32_t tsval;
|
||||||
|
#endif
|
||||||
|
|
||||||
opts = (u8_t *)tcphdr + TCP_HLEN;
|
opts = (u8_t *)tcphdr + TCP_HLEN;
|
||||||
|
|
||||||
/* Parse the TCP MSS option, if present. */
|
/* Parse the TCP MSS option, if present. */
|
||||||
if(TCPH_HDRLEN(tcphdr) > 0x5) {
|
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];
|
opt = opts[c];
|
||||||
if (opt == 0x00) {
|
switch (opt) {
|
||||||
|
case 0x00:
|
||||||
/* End of options. */
|
/* End of options. */
|
||||||
break;
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
|
||||||
} else if (opt == 0x01) {
|
return;
|
||||||
++c;
|
case 0x01:
|
||||||
/* NOP option. */
|
/* NOP option. */
|
||||||
} else if (opt == 0x02 &&
|
++c;
|
||||||
opts[c + 1] == 0x04) {
|
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. */
|
/* An MSS option with the right option length. */
|
||||||
mss = (opts[c + 2] << 8) | opts[c + 3];
|
mss = (opts[c + 2] << 8) | opts[c + 3];
|
||||||
pcb->mss = mss > TCP_MSS? TCP_MSS: mss;
|
/* Limit the mss to the configured TCP_MSS and prevent division by zero */
|
||||||
|
pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
|
||||||
/* And we are done processing options. */
|
/* Advance to next option */
|
||||||
|
c += 0x04;
|
||||||
break;
|
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) {
|
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
|
/* If the length field is zero, the options are malformed
|
||||||
and we don't process them further. */
|
and we don't process them further. */
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
/* All other options have a length field, so that we easily
|
/* All other options have a length field, so that we easily
|
||||||
can skip past them. */
|
can skip past them. */
|
||||||
|
|
|
@ -59,6 +59,27 @@
|
||||||
/* Forward declarations.*/
|
/* Forward declarations.*/
|
||||||
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
|
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.
|
* 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
|
err_t
|
||||||
tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
|
tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
|
||||||
{
|
{
|
||||||
/* no data, no length, flags, copy=1, no optdata, no optdatalen */
|
/* no data, no length, flags, copy=1, no optdata */
|
||||||
return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, NULL, 0);
|
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_SENT ||
|
||||||
pcb->state == SYN_RCVD) {
|
pcb->state == SYN_RCVD) {
|
||||||
if (len > 0) {
|
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;
|
return ERR_OK;
|
||||||
} else {
|
} 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().
|
* 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 :
|
* @param apiflags combination of following flags :
|
||||||
* - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
|
* - 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,
|
* - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,
|
||||||
* @param optdata
|
* @param optflags options to include in segment later on (see definition of struct tcp_seg)
|
||||||
* @param optlen
|
|
||||||
*/
|
*/
|
||||||
err_t
|
err_t
|
||||||
tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||||
u8_t flags, u8_t apiflags,
|
u8_t flags, u8_t apiflags, u8_t optflags)
|
||||||
u8_t *optdata, u8_t optlen)
|
|
||||||
{
|
{
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
struct tcp_seg *seg, *useg, *queue;
|
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;
|
u16_t left, seglen;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
u16_t queuelen;
|
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 */
|
/* fail on too much data */
|
||||||
if (len > pcb->snd_buf) {
|
if (len > pcb->snd_buf) {
|
||||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));
|
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 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;
|
left = len;
|
||||||
ptr = arg;
|
ptr = arg;
|
||||||
|
|
||||||
|
optlen = LWIP_TCP_OPT_LENGTH(optflags);
|
||||||
|
|
||||||
/* seqno will be the sequence number of the first segment enqueued
|
/* seqno will be the sequence number of the first segment enqueued
|
||||||
* by the call to this function. */
|
* by the call to this function. */
|
||||||
seqno = pcb->snd_lbb;
|
seqno = pcb->snd_lbb;
|
||||||
|
@ -182,15 +212,14 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||||
useg = queue = seg = NULL;
|
useg = queue = seg = NULL;
|
||||||
seglen = 0;
|
seglen = 0;
|
||||||
while (queue == NULL || left > 0) {
|
while (queue == NULL || left > 0) {
|
||||||
|
/* The segment length (including options) should be at most the MSS */
|
||||||
/* The segment length should be the MSS if the data to be enqueued
|
seglen = left > (pcb->mss - optlen) ? (pcb->mss - optlen) : left;
|
||||||
* is larger than the MSS. */
|
|
||||||
seglen = left > pcb->mss? pcb->mss: left;
|
|
||||||
|
|
||||||
/* Allocate memory for tcp_seg, and fill in fields. */
|
/* Allocate memory for tcp_seg, and fill in fields. */
|
||||||
seg = memp_malloc(MEMP_TCP_SEG);
|
seg = memp_malloc(MEMP_TCP_SEG);
|
||||||
if (seg == NULL) {
|
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;
|
goto memerr;
|
||||||
}
|
}
|
||||||
seg->next = NULL;
|
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
|
/* If copy is set, memory should be allocated
|
||||||
* and data copied into pbuf, otherwise data comes from
|
* and data copied into pbuf, otherwise data comes from
|
||||||
* ROM or other static memory, and need not be copied. If
|
* ROM or other static memory, and need not be copied. */
|
||||||
* optdata is != NULL, we have options instead of data. */
|
if (apiflags & TCP_WRITE_FLAG_COPY) {
|
||||||
|
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen + optlen, PBUF_RAM)) == NULL) {
|
||||||
/* options? */
|
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
|
||||||
if (optdata != NULL) {
|
("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
|
||||||
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));
|
|
||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
LWIP_ASSERT("check that first pbuf can hold the complete seglen",
|
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);
|
queuelen += pbuf_clen(seg->p);
|
||||||
if (arg != NULL) {
|
if (arg != NULL) {
|
||||||
MEMCPY(seg->p->payload, ptr, seglen);
|
MEMCPY((char *)seg->p->payload + optlen, ptr, seglen);
|
||||||
}
|
}
|
||||||
seg->dataptr = seg->p->payload;
|
seg->dataptr = seg->p->payload;
|
||||||
}
|
}
|
||||||
/* do not copy data */
|
/* do not copy data */
|
||||||
else {
|
else {
|
||||||
/* First, allocate a pbuf for holding the data.
|
/* First, allocate a pbuf for the headers. */
|
||||||
* since the referenced data is available at least until it is sent out on the
|
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
|
||||||
* link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
|
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
|
||||||
* instead of PBUF_REF here.
|
("tcp_enqueue: could not allocate memory for header pbuf\n"));
|
||||||
*/
|
|
||||||
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"));
|
|
||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
queuelen += pbuf_clen(seg->p);
|
queuelen += pbuf_clen(seg->p);
|
||||||
|
|
||||||
/* Concatenate the headers and data pbufs together. */
|
/* Second, allocate a pbuf for holding the data.
|
||||||
pbuf_cat(seg->p/*header*/, p/*data*/);
|
* since the referenced data is available at least until it is sent out on the
|
||||||
p = NULL;
|
* 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
|
/* 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);
|
TCPH_FLAGS_SET(seg->tcphdr, flags);
|
||||||
/* don't fill in tcphdr->ackno and tcphdr->wnd until later */
|
/* don't fill in tcphdr->ackno and tcphdr->wnd until later */
|
||||||
|
|
||||||
/* Copy the options into the header, if they are present. */
|
seg->flags = optflags;
|
||||||
if (optdata == NULL) {
|
|
||||||
TCPH_HDRLEN_SET(seg->tcphdr, 5);
|
/* Set the length of the header */
|
||||||
}
|
TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));
|
||||||
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);
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
|
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),
|
||||||
ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
|
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)) &&
|
!(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
|
||||||
!(flags & (TCP_SYN | TCP_FIN)) &&
|
!(flags & (TCP_SYN | TCP_FIN)) &&
|
||||||
/* fit within max seg size */
|
/* 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 */
|
/* 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 */
|
/* Can we cope with this failing? Just assert for now */
|
||||||
LWIP_ASSERT("pbuf_header failed\n", 0);
|
LWIP_ASSERT("pbuf_header failed\n", 0);
|
||||||
TCP_STATS_INC(tcp.err);
|
TCP_STATS_INC(tcp.err);
|
||||||
goto memerr;
|
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);
|
pbuf_cat(useg->p, queue->p);
|
||||||
useg->len += queue->len;
|
useg->len += queue->len;
|
||||||
useg->next = queue->next;
|
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));
|
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) {
|
if (seg == queue) {
|
||||||
seg = NULL;
|
seg = useg;
|
||||||
|
seglen = useg->len;
|
||||||
}
|
}
|
||||||
memp_free(MEMP_TCP_SEG, queue);
|
memp_free(MEMP_TCP_SEG, queue);
|
||||||
}
|
}
|
||||||
|
@ -400,6 +426,24 @@ memerr:
|
||||||
return ERR_MEM;
|
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
|
* Find out what we can send and send it
|
||||||
*
|
*
|
||||||
|
@ -413,10 +457,11 @@ tcp_output(struct tcp_pcb *pcb)
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
struct tcp_hdr *tcphdr;
|
struct tcp_hdr *tcphdr;
|
||||||
struct tcp_seg *seg, *useg;
|
struct tcp_seg *seg, *useg;
|
||||||
u32_t wnd;
|
u32_t wnd, snd_nxt;
|
||||||
#if TCP_CWND_DEBUG
|
#if TCP_CWND_DEBUG
|
||||||
s16_t i = 0;
|
s16_t i = 0;
|
||||||
#endif /* TCP_CWND_DEBUG */
|
#endif /* TCP_CWND_DEBUG */
|
||||||
|
u8_t optlen = 0;
|
||||||
|
|
||||||
/* First, check if we are invoked by the TCP input processing
|
/* First, check if we are invoked by the TCP input processing
|
||||||
code. If so, we do not output anything. Instead, we rely on the
|
code. If so, we do not output anything. Instead, we rely on the
|
||||||
|
@ -445,41 +490,37 @@ tcp_output(struct tcp_pcb *pcb)
|
||||||
if (pcb->flags & TF_ACK_NOW &&
|
if (pcb->flags & TF_ACK_NOW &&
|
||||||
(seg == NULL ||
|
(seg == NULL ||
|
||||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
|
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) {
|
if (p == NULL) {
|
||||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
|
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
|
||||||
return ERR_BUF;
|
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 */
|
/* remove ACK flags from the PCB, as we send an empty ACK now */
|
||||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||||
|
|
||||||
tcphdr = p->payload;
|
tcphdr = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt));
|
||||||
tcphdr->src = htons(pcb->local_port);
|
|
||||||
tcphdr->dest = htons(pcb->remote_port);
|
/* NB. MSS option is only sent on SYNs, so ignore it here */
|
||||||
tcphdr->seqno = htonl(pcb->snd_nxt);
|
#if LWIP_TCP_TIMESTAMPS
|
||||||
tcphdr->ackno = htonl(pcb->rcv_nxt);
|
pcb->ts_lastacksent = pcb->rcv_nxt;
|
||||||
TCPH_FLAGS_SET(tcphdr, TCP_ACK);
|
|
||||||
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
if (pcb->flags & TF_TIMESTAMP)
|
||||||
tcphdr->urgp = 0;
|
tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
|
||||||
TCPH_HDRLEN_SET(tcphdr, 5);
|
#endif
|
||||||
|
|
||||||
tcphdr->chksum = 0;
|
|
||||||
#if CHECKSUM_GEN_TCP
|
#if CHECKSUM_GEN_TCP
|
||||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||||
IP_PROTO_TCP, p->tot_len);
|
IP_PROTO_TCP, p->tot_len);
|
||||||
#endif
|
#endif
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
{
|
ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||||
struct netif *netif;
|
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||||
IP_PROTO_TCP);
|
IP_PROTO_TCP);
|
||||||
|
@ -543,9 +584,9 @@ tcp_output(struct tcp_pcb *pcb)
|
||||||
}
|
}
|
||||||
|
|
||||||
tcp_output_segment(seg, pcb);
|
tcp_output_segment(seg, pcb);
|
||||||
pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
|
snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
|
||||||
if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
|
if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
|
||||||
pcb->snd_max = pcb->snd_nxt;
|
pcb->snd_nxt = snd_nxt;
|
||||||
}
|
}
|
||||||
/* put segment on unacknowledged list if length > 0 */
|
/* put segment on unacknowledged list if length > 0 */
|
||||||
if (TCP_TCPLEN(seg) > 0) {
|
if (TCP_TCPLEN(seg) > 0) {
|
||||||
|
@ -557,12 +598,17 @@ tcp_output(struct tcp_pcb *pcb)
|
||||||
/* unacked list is not empty? */
|
/* unacked list is not empty? */
|
||||||
} else {
|
} else {
|
||||||
/* In the case of fast retransmit, the packet should not go to the tail
|
/* 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 */
|
* this case. -STJ Jul 27, 2004 */
|
||||||
if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
|
if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
|
||||||
/* add segment to head of unacked list */
|
/* add segment to before tail of unacked list, keeping the list sorted */
|
||||||
seg->next = pcb->unacked;
|
struct tcp_seg **cur_seg = &(pcb->unacked);
|
||||||
pcb->unacked = seg;
|
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 {
|
} else {
|
||||||
/* add segment to tail of unacked list */
|
/* add segment to tail of unacked list */
|
||||||
useg->next = seg;
|
useg->next = seg;
|
||||||
|
@ -598,6 +644,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||||
{
|
{
|
||||||
u16_t len;
|
u16_t len;
|
||||||
struct netif *netif;
|
struct netif *netif;
|
||||||
|
u32_t *opts;
|
||||||
|
|
||||||
/** @bug Exclude retransmitted segments from this count. */
|
/** @bug Exclude retransmitted segments from this count. */
|
||||||
snmp_inc_tcpoutsegs();
|
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 */
|
/* advertise our receive window size in this TCP segment */
|
||||||
seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
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
|
/* If we don't have a local IP address, we get one by
|
||||||
calling ip_route(). */
|
calling ip_route(). */
|
||||||
if (ip_addr_isany(&(pcb->local_ip))) {
|
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);
|
TCP_STATS_INC(tcp.xmit);
|
||||||
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
{
|
ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||||
struct netif *netif;
|
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||||
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||||
IP_PROTO_TCP);
|
IP_PROTO_TCP);
|
||||||
|
@ -749,7 +806,6 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
|
||||||
/* unacked queue is now empty */
|
/* unacked queue is now empty */
|
||||||
pcb->unacked = NULL;
|
pcb->unacked = NULL;
|
||||||
|
|
||||||
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
|
|
||||||
/* increment number of retransmissions */
|
/* increment number of retransmissions */
|
||||||
++pcb->nrtx;
|
++pcb->nrtx;
|
||||||
|
|
||||||
|
@ -771,18 +827,24 @@ void
|
||||||
tcp_rexmit(struct tcp_pcb *pcb)
|
tcp_rexmit(struct tcp_pcb *pcb)
|
||||||
{
|
{
|
||||||
struct tcp_seg *seg;
|
struct tcp_seg *seg;
|
||||||
|
struct tcp_seg **cur_seg;
|
||||||
|
|
||||||
if (pcb->unacked == NULL) {
|
if (pcb->unacked == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move the first unacked segment to the unsent queue */
|
/* Move the first unacked segment to the unsent queue */
|
||||||
seg = pcb->unacked->next;
|
/* Keep the unsent queue sorted. */
|
||||||
pcb->unacked->next = pcb->unsent;
|
seg = pcb->unacked;
|
||||||
pcb->unsent = pcb->unacked;
|
pcb->unacked = seg->next;
|
||||||
pcb->unacked = seg;
|
|
||||||
|
|
||||||
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;
|
++pcb->nrtx;
|
||||||
|
|
||||||
|
@ -825,17 +887,8 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
||||||
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
|
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
|
||||||
(p->len >= sizeof(struct tcp_hdr)));
|
(p->len >= sizeof(struct tcp_hdr)));
|
||||||
|
|
||||||
tcphdr = p->payload;
|
tcphdr = tcp_output_set_header(pcb, p, 0, htonl(pcb->snd_nxt - 1));
|
||||||
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->chksum = 0;
|
|
||||||
#if CHECKSUM_GEN_TCP
|
#if CHECKSUM_GEN_TCP
|
||||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
||||||
IP_PROTO_TCP, p->tot_len);
|
IP_PROTO_TCP, p->tot_len);
|
||||||
|
@ -844,16 +897,8 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
||||||
|
|
||||||
/* Send output to IP */
|
/* Send output to IP */
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
{
|
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
|
||||||
struct netif *netif;
|
&(pcb->addr_hint));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||||
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
#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",
|
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
|
||||||
(p->len >= sizeof(struct tcp_hdr)));
|
(p->len >= sizeof(struct tcp_hdr)));
|
||||||
|
|
||||||
tcphdr = p->payload;
|
tcphdr = tcp_output_set_header(pcb, p, 0, seg->tcphdr->seqno);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Copy in one byte from the head of the unacked queue */
|
/* Copy in one byte from the head of the unacked queue */
|
||||||
*((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;
|
*((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;
|
||||||
|
|
||||||
tcphdr->chksum = 0;
|
|
||||||
#if CHECKSUM_GEN_TCP
|
#if CHECKSUM_GEN_TCP
|
||||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
||||||
IP_PROTO_TCP, p->tot_len);
|
IP_PROTO_TCP, p->tot_len);
|
||||||
|
@ -930,16 +966,8 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||||
|
|
||||||
/* Send output to IP */
|
/* Send output to IP */
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
{
|
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
|
||||||
struct netif *netif;
|
&(pcb->addr_hint));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||||
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||||
|
|
|
@ -90,6 +90,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||||
struct ip_hdr *iphdr;
|
struct ip_hdr *iphdr;
|
||||||
u16_t src, dest;
|
u16_t src, dest;
|
||||||
u8_t local_match;
|
u8_t local_match;
|
||||||
|
u8_t broadcast;
|
||||||
|
|
||||||
PERF_START;
|
PERF_START;
|
||||||
|
|
||||||
|
@ -112,6 +113,9 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||||
|
|
||||||
udphdr = (struct udp_hdr *)p->payload;
|
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));
|
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 */
|
/* convert src and dest ports to host byte order */
|
||||||
|
@ -169,12 +173,16 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||||
|
|
||||||
/* compare PCB local addr+port to UDP destination addr+port */
|
/* compare PCB local addr+port to UDP destination addr+port */
|
||||||
if ((pcb->local_port == dest) &&
|
if ((pcb->local_port == dest) &&
|
||||||
(ip_addr_isany(&pcb->local_ip) ||
|
((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
|
||||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
|
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
|
||||||
#if LWIP_IGMP
|
#if LWIP_IGMP
|
||||||
ip_addr_ismulticast(&(iphdr->dest)) ||
|
ip_addr_ismulticast(&(iphdr->dest)) ||
|
||||||
#endif /* LWIP_IGMP */
|
#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;
|
local_match = 1;
|
||||||
if ((uncon_pcb == NULL) &&
|
if ((uncon_pcb == NULL) &&
|
||||||
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
|
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
|
||||||
|
@ -286,7 +294,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||||
#if LWIP_ICMP
|
#if LWIP_ICMP
|
||||||
/* No match was found, send ICMP destination port unreachable unless
|
/* No match was found, send ICMP destination port unreachable unless
|
||||||
destination address was broadcast/multicast. */
|
destination address was broadcast/multicast. */
|
||||||
if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&
|
if (!broadcast &&
|
||||||
!ip_addr_ismulticast(&iphdr->dest)) {
|
!ip_addr_ismulticast(&iphdr->dest)) {
|
||||||
/* move payload pointer back to ip header */
|
/* move payload pointer back to ip header */
|
||||||
pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
|
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;
|
err_t err;
|
||||||
struct pbuf *q; /* q will be sent down the stack */
|
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 the PCB is not yet bound to a port, bind it here */
|
||||||
if (pcb->local_port == 0) {
|
if (pcb->local_port == 0) {
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
|
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
|
||||||
|
@ -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,
|
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",
|
("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) >> 24) & 0xff),
|
||||||
(u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 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) >> 8) & 0xff),
|
||||||
(u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
|
(u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
@ -693,9 +709,9 @@ udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||||
#endif
|
#endif
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
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",
|
("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) >> 24) & 0xff),
|
||||||
(u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 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) >> 8) & 0xff),
|
||||||
(u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
|
(u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
|
||||||
|
|
||||||
/* Insert UDP PCB into the list of active UDP PCBs. */
|
/* Insert UDP PCB into the list of active UDP PCBs. */
|
||||||
|
|
|
@ -78,39 +78,30 @@ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
# include "arch/bpstruct.h"
|
# include "arch/bpstruct.h"
|
||||||
#endif
|
#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
|
PACK_STRUCT_BEGIN
|
||||||
struct icmp_echo_hdr {
|
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 chksum);
|
||||||
PACK_STRUCT_FIELD(u16_t id);
|
PACK_STRUCT_FIELD(u16_t id);
|
||||||
PACK_STRUCT_FIELD(u16_t seqno);
|
PACK_STRUCT_FIELD(u16_t seqno);
|
||||||
} PACK_STRUCT_STRUCT;
|
} PACK_STRUCT_STRUCT;
|
||||||
PACK_STRUCT_END
|
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
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
# include "arch/epstruct.h"
|
# include "arch/epstruct.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)
|
#define ICMPH_TYPE(hdr) ((hdr)->type)
|
||||||
#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)
|
#define ICMPH_CODE(hdr) ((hdr)->code)
|
||||||
|
|
||||||
#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))
|
/** Combines type and code to an u16_t */
|
||||||
#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))
|
#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
|
||||||
|
#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,20 @@
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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);
|
u32_t inet_addr(const char *cp);
|
||||||
int inet_aton(const char *cp, struct in_addr *addr);
|
int inet_aton(const char *cp, struct in_addr *addr);
|
||||||
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
|
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
|
||||||
|
|
|
@ -46,9 +46,11 @@ u16_t inet_chksum_pbuf(struct pbuf *p);
|
||||||
u16_t inet_chksum_pseudo(struct pbuf *p,
|
u16_t inet_chksum_pseudo(struct pbuf *p,
|
||||||
struct ip_addr *src, struct ip_addr *dest,
|
struct ip_addr *src, struct ip_addr *dest,
|
||||||
u8_t proto, u16_t proto_len);
|
u8_t proto, u16_t proto_len);
|
||||||
|
#if LWIP_UDPLITE
|
||||||
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
|
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
|
||||||
struct ip_addr *src, struct ip_addr *dest,
|
struct ip_addr *src, struct ip_addr *dest,
|
||||||
u8_t proto, u16_t proto_len, u16_t chksum_len);
|
u8_t proto, u16_t proto_len, u16_t chksum_len);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,19 +38,14 @@
|
||||||
#include "lwip/pbuf.h"
|
#include "lwip/pbuf.h"
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ip_init() /* Compatibility define, not init needed. */
|
/** Currently, the function ip_output_if_opt() is only used with IGMP */
|
||||||
struct netif *ip_route(struct ip_addr *dest);
|
#define IP_OPTIONS_SEND LWIP_IGMP
|
||||||
err_t ip_input(struct pbuf *p, struct netif *inp);
|
|
||||||
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto);
|
|
||||||
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto,
|
|
||||||
struct netif *netif);
|
|
||||||
|
|
||||||
#define IP_HLEN 20
|
#define IP_HLEN 20
|
||||||
|
|
||||||
|
@ -103,7 +98,7 @@ struct ip_pcb {
|
||||||
#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */
|
#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */
|
||||||
#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */
|
#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */
|
||||||
#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */
|
#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_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */
|
||||||
#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */
|
#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */
|
||||||
#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */
|
#define SOF_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_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
|
||||||
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
|
#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
|
#if IP_DEBUG
|
||||||
void ip_debug_print(struct pbuf *p);
|
void ip_debug_print(struct pbuf *p);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -66,11 +68,6 @@ PACK_STRUCT_END
|
||||||
# include "arch/epstruct.h"
|
# include "arch/epstruct.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* For compatibility with BSD code */
|
|
||||||
struct in_addr {
|
|
||||||
u32_t s_addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct netif;
|
struct netif;
|
||||||
|
|
||||||
extern const struct ip_addr ip_addr_any;
|
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_ANY ((struct ip_addr *)&ip_addr_any)
|
||||||
#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast)
|
#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.
|
/* Definitions of the bits in an Internet address integer.
|
||||||
|
|
||||||
On subnets, host and network parts are found according to
|
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_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))
|
||||||
|
|
||||||
#define ip_addr_debug_print(debug, ipaddr) \
|
#define ip_addr_debug_print(debug, ipaddr) \
|
||||||
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
|
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
|
||||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
|
ipaddr != NULL ? \
|
||||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \
|
(u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
|
||||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \
|
ipaddr != NULL ? \
|
||||||
ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0))
|
(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
|
/* These are cast to u16_t, with the intent that they are often arguments
|
||||||
* to printf using the U16_F format from cc.h. */
|
* to printf using the U16_F format from cc.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,
|
u8_t ttl, u8_t proto,
|
||||||
struct netif *netif);
|
struct netif *netif);
|
||||||
|
|
||||||
|
#define ip_current_netif() NULL
|
||||||
|
#define ip_current_header() NULL
|
||||||
|
|
||||||
#if IP_DEBUG
|
#if IP_DEBUG
|
||||||
void ip_debug_print(struct pbuf *p);
|
void ip_debug_print(struct pbuf *p);
|
||||||
#endif /* IP_DEBUG */
|
#endif /* IP_DEBUG */
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
|
|
||||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include <stddef.h> /* for size_t */
|
||||||
|
|
||||||
#include "lwip/netbuf.h"
|
#include "lwip/netbuf.h"
|
||||||
#include "lwip/sys.h"
|
#include "lwip/sys.h"
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
|
@ -137,19 +139,21 @@ struct netconn {
|
||||||
/** maximum amount of bytes queued in recvmbox */
|
/** maximum amount of bytes queued in recvmbox */
|
||||||
int recv_bufsize;
|
int recv_bufsize;
|
||||||
#endif /* LWIP_SO_RCVBUF */
|
#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,
|
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||||
this temporarily stores the message. */
|
this temporarily stores the message. */
|
||||||
struct api_msg_msg *write_msg;
|
struct api_msg_msg *write_msg;
|
||||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||||
this temporarily stores how much is already sent. */
|
this temporarily stores how much is already sent. */
|
||||||
int write_offset;
|
size_t write_offset;
|
||||||
#if LWIP_TCPIP_CORE_LOCKING
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
/** 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
|
this temporarily stores whether to wake up the original application task
|
||||||
if data couldn't be sent in the first try. */
|
if data couldn't be sent in the first try. */
|
||||||
u8_t write_delayed;
|
u8_t write_delayed;
|
||||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
/** A callback function that is informed about events for this netconn */
|
/** A callback function that is informed about events for this netconn */
|
||||||
netconn_callback callback;
|
netconn_callback callback;
|
||||||
};
|
};
|
||||||
|
@ -166,7 +170,8 @@ struct
|
||||||
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
|
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
|
||||||
netconn_callback callback);
|
netconn_callback callback);
|
||||||
err_t netconn_delete (struct netconn *conn);
|
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,
|
err_t netconn_getaddr (struct netconn *conn,
|
||||||
struct ip_addr *addr,
|
struct ip_addr *addr,
|
||||||
|
@ -191,7 +196,7 @@ err_t netconn_sendto (struct netconn *conn,
|
||||||
err_t netconn_send (struct netconn *conn,
|
err_t netconn_send (struct netconn *conn,
|
||||||
struct netbuf *buf);
|
struct netbuf *buf);
|
||||||
err_t netconn_write (struct netconn *conn,
|
err_t netconn_write (struct netconn *conn,
|
||||||
const void *dataptr, int size,
|
const void *dataptr, size_t size,
|
||||||
u8_t apiflags);
|
u8_t apiflags);
|
||||||
err_t netconn_close (struct netconn *conn);
|
err_t netconn_close (struct netconn *conn);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
|
|
||||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include <stddef.h> /* for size_t */
|
||||||
|
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
#include "lwip/sys.h"
|
#include "lwip/sys.h"
|
||||||
|
@ -78,7 +80,7 @@ struct api_msg_msg {
|
||||||
/** used for do_write */
|
/** used for do_write */
|
||||||
struct {
|
struct {
|
||||||
const void *dataptr;
|
const void *dataptr;
|
||||||
int len;
|
size_t len;
|
||||||
u8_t apiflags;
|
u8_t apiflags;
|
||||||
} w;
|
} w;
|
||||||
/** used ofr do_recv */
|
/** used ofr do_recv */
|
||||||
|
|
|
@ -42,6 +42,11 @@
|
||||||
|
|
||||||
#include "arch/cc.h"
|
#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
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -194,13 +199,7 @@ extern "C" {
|
||||||
#define ENOMEDIUM 123 /* No medium found */
|
#define ENOMEDIUM 123 /* No medium found */
|
||||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
#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 ENSROK 0 /* DNS server returned answer with no data */
|
||||||
#define ENSRNODATA 160 /* DNS server returned answer with no data */
|
#define ENSRNODATA 160 /* DNS server returned answer with no data */
|
||||||
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
|
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
|
||||||
|
@ -221,6 +220,12 @@ extern int errno;
|
||||||
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
|
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
|
||||||
#define ENSRCNAMELOOP 177 /* 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -61,26 +61,28 @@
|
||||||
#define LWIP_DBG_HALT 0x08U
|
#define LWIP_DBG_HALT 0x08U
|
||||||
|
|
||||||
#ifndef LWIP_NOASSERT
|
#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 */
|
#else /* LWIP_NOASSERT */
|
||||||
#define LWIP_ASSERT(x,y)
|
#define LWIP_ASSERT(message, assertion)
|
||||||
#endif /* LWIP_NOASSERT */
|
#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
|
#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 */
|
#endif /* LWIP_ERROR */
|
||||||
|
|
||||||
#ifdef LWIP_DEBUG
|
#ifdef LWIP_DEBUG
|
||||||
/** print debug message only if debug message type is enabled...
|
/** print debug message only if debug message type is enabled...
|
||||||
* AND is of correct type AND is at least LWIP_DBG_LEVEL
|
* 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 ( \
|
if ( \
|
||||||
((debug) & LWIP_DBG_ON) && \
|
((debug) & LWIP_DBG_ON) && \
|
||||||
((debug) & LWIP_DBG_TYPES_ON) && \
|
((debug) & LWIP_DBG_TYPES_ON) && \
|
||||||
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
|
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
|
||||||
LWIP_PLATFORM_DIAG(x); \
|
LWIP_PLATFORM_DIAG(message); \
|
||||||
if ((debug) & LWIP_DBG_HALT) { \
|
if ((debug) & LWIP_DBG_HALT) { \
|
||||||
while(1); \
|
while(1); \
|
||||||
} \
|
} \
|
||||||
|
@ -88,7 +90,7 @@
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#else /* LWIP_DEBUG */
|
#else /* LWIP_DEBUG */
|
||||||
#define LWIP_DEBUGF(debug,x)
|
#define LWIP_DEBUGF(debug, message)
|
||||||
#endif /* LWIP_DEBUG */
|
#endif /* LWIP_DEBUG */
|
||||||
|
|
||||||
#endif /* __LWIP_DEBUG_H__ */
|
#endif /* __LWIP_DEBUG_H__ */
|
||||||
|
|
|
@ -18,7 +18,7 @@ extern "C" {
|
||||||
/** period (in seconds) of the application calling dhcp_coarse_tmr() */
|
/** period (in seconds) of the application calling dhcp_coarse_tmr() */
|
||||||
#define DHCP_COARSE_TIMER_SECS 60
|
#define DHCP_COARSE_TIMER_SECS 60
|
||||||
/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */
|
/** 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() */
|
/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
|
||||||
#define DHCP_FINE_TIMER_MSECS 500
|
#define DHCP_FINE_TIMER_MSECS 500
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,11 @@ struct ip_addr dns_getserver(u8_t numdns);
|
||||||
err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr,
|
err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr,
|
||||||
dns_found_callback found, void *callback_arg);
|
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 */
|
||||||
|
|
||||||
#endif /* __LWIP_DNS_H__ */
|
#endif /* __LWIP_DNS_H__ */
|
||||||
|
|
|
@ -33,37 +33,43 @@
|
||||||
#define __LWIP_ERR_H__
|
#define __LWIP_ERR_H__
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/arch.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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. */
|
/* Definitions for error constants. */
|
||||||
|
|
||||||
#define ERR_OK 0 /* No error, everything OK. */
|
#define ERR_OK 0 /* No error, everything OK. */
|
||||||
#define ERR_MEM -1 /* Out of memory error. */
|
#define ERR_MEM -1 /* Out of memory error. */
|
||||||
#define ERR_BUF -2 /* Buffer 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_IS_FATAL(e) ((e) < ERR_RTE)
|
||||||
|
|
||||||
#define ERR_ABRT -4 /* Connection aborted. */
|
#define ERR_ABRT -5 /* Connection aborted. */
|
||||||
#define ERR_RST -5 /* Connection reset. */
|
#define ERR_RST -6 /* Connection reset. */
|
||||||
#define ERR_CLSD -6 /* Connection closed. */
|
#define ERR_CLSD -7 /* Connection closed. */
|
||||||
#define ERR_CONN -7 /* Not connected. */
|
#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_IF -12 /* Low-level netif error */
|
||||||
#define ERR_ISCONN -12 /* Already connected. */
|
#define ERR_ISCONN -13 /* Already connected. */
|
||||||
|
|
||||||
#define ERR_TIMEOUT -13 /* Timeout. */
|
|
||||||
|
|
||||||
#define ERR_INPROGRESS -14 /* Operation in progress */
|
#define ERR_INPROGRESS -14 /* Operation in progress */
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,30 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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 */
|
/* Modules initialization */
|
||||||
void lwip_init(void);
|
void lwip_init(void);
|
||||||
|
|
||||||
|
|
|
@ -50,16 +50,20 @@ typedef size_t mem_size_t;
|
||||||
* allow these defines to be overridden.
|
* allow these defines to be overridden.
|
||||||
*/
|
*/
|
||||||
#ifndef mem_free
|
#ifndef mem_free
|
||||||
#define mem_free(x) free(x)
|
#define mem_free free
|
||||||
#endif
|
#endif
|
||||||
#ifndef mem_malloc
|
#ifndef mem_malloc
|
||||||
#define mem_malloc(x) malloc(x)
|
#define mem_malloc malloc
|
||||||
#endif
|
#endif
|
||||||
#ifndef mem_calloc
|
#ifndef mem_calloc
|
||||||
#define mem_calloc(x, y) calloc(x, y)
|
#define mem_calloc calloc
|
||||||
#endif
|
#endif
|
||||||
#ifndef mem_realloc
|
#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
|
#endif
|
||||||
#else /* MEM_LIBC_MALLOC */
|
#else /* MEM_LIBC_MALLOC */
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,28 @@ typedef enum {
|
||||||
We use this helper type and these defines so we can avoid using const memp_t values */
|
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_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)
|
||||||
#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST)
|
#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];
|
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 */
|
#endif /* MEM_USE_POOLS */
|
||||||
|
|
||||||
void memp_init(void);
|
void memp_init(void);
|
||||||
|
@ -87,6 +107,8 @@ void *memp_malloc(memp_t type);
|
||||||
#endif
|
#endif
|
||||||
void memp_free(memp_t type, void *mem);
|
void memp_free(memp_t type, void *mem);
|
||||||
|
|
||||||
|
#endif /* MEMP_MEM_MALLOC */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,8 +10,9 @@
|
||||||
* above, then will declare #2 & #3 to be just standard mempools.
|
* above, then will declare #2 & #3 to be just standard mempools.
|
||||||
*/
|
*/
|
||||||
#ifndef LWIP_MALLOC_MEMPOOL
|
#ifndef LWIP_MALLOC_MEMPOOL
|
||||||
/* This treats "malloc pools" just like any other pool */
|
/* This treats "malloc pools" just like any other pool.
|
||||||
#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, size, "MALLOC_"#size)
|
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_START
|
||||||
#define LWIP_MALLOC_MEMPOOL_END
|
#define LWIP_MALLOC_MEMPOOL_END
|
||||||
#endif /* LWIP_MALLOC_MEMPOOL */
|
#endif /* LWIP_MALLOC_MEMPOOL */
|
||||||
|
|
|
@ -65,6 +65,7 @@ void netbuf_first (struct netbuf *buf);
|
||||||
#define netbuf_copy_partial(buf, dataptr, len, offset) \
|
#define netbuf_copy_partial(buf, dataptr, len, offset) \
|
||||||
pbuf_copy_partial((buf)->p, (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_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_len(buf) ((buf)->p->tot_len)
|
||||||
#define netbuf_fromaddr(buf) ((buf)->addr)
|
#define netbuf_fromaddr(buf) ((buf)->addr)
|
||||||
#define netbuf_fromport(buf) ((buf)->port)
|
#define netbuf_fromport(buf) ((buf)->port)
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
#if LWIP_DNS && LWIP_SOCKET
|
#if LWIP_DNS && LWIP_SOCKET
|
||||||
|
|
||||||
|
#include <stddef.h> /* for size_t */
|
||||||
|
|
||||||
#include "lwip/sockets.h"
|
#include "lwip/sockets.h"
|
||||||
|
|
||||||
/* some rarely used options */
|
/* some rarely used options */
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
|
||||||
|
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
|
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
|
@ -165,6 +167,14 @@ struct netif {
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
u8_t *addr_hint;
|
u8_t *addr_hint;
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
#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
|
#if LWIP_SNMP
|
||||||
|
@ -242,4 +252,12 @@ void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct
|
||||||
}
|
}
|
||||||
#endif
|
#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__ */
|
#endif /* __LWIP_NETIF_H__ */
|
||||||
|
|
|
@ -98,6 +98,15 @@
|
||||||
#define MEM_LIBC_MALLOC 0
|
#define MEM_LIBC_MALLOC 0
|
||||||
#endif
|
#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
|
* MEM_ALIGNMENT: should be set to the alignment of the CPU
|
||||||
* 4 byte alignment -> #define MEM_ALIGNMENT 4
|
* 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
|
* 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
|
* 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
|
#ifndef MEM_USE_POOLS
|
||||||
#define MEM_USE_POOLS 0
|
#define MEM_USE_POOLS 0
|
||||||
#endif
|
#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
|
* MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h
|
||||||
* that defines additional pools beyond the "standard" ones required
|
* that defines additional pools beyond the "standard" ones required
|
||||||
|
@ -155,6 +173,27 @@
|
||||||
#define MEMP_USE_CUSTOM_POOLS 0
|
#define MEMP_USE_CUSTOM_POOLS 0
|
||||||
#endif
|
#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
|
#define IP_DEFAULT_TTL 255
|
||||||
#endif
|
#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 ----------
|
---------- ICMP options ----------
|
||||||
|
@ -431,6 +487,20 @@
|
||||||
#define ICMP_TTL (IP_DEFAULT_TTL)
|
#define ICMP_TTL (IP_DEFAULT_TTL)
|
||||||
#endif
|
#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 ----------
|
---------- RAW options ----------
|
||||||
|
@ -489,6 +559,17 @@
|
||||||
#define LWIP_DHCP_AUTOIP_COOP 0
|
#define LWIP_DHCP_AUTOIP_COOP 0
|
||||||
#endif
|
#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 ----------
|
---------- SNMP options ----------
|
||||||
|
@ -591,6 +672,26 @@
|
||||||
#define DNS_MSG_SIZE 512
|
#define DNS_MSG_SIZE 512
|
||||||
#endif
|
#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 ----------
|
---------- UDP options ----------
|
||||||
|
@ -637,7 +738,8 @@
|
||||||
#endif
|
#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
|
#ifndef TCP_WND
|
||||||
#define TCP_WND 2048
|
#define TCP_WND 2048
|
||||||
|
@ -662,7 +764,7 @@
|
||||||
* Define to 0 if your device is low on memory.
|
* Define to 0 if your device is low on memory.
|
||||||
*/
|
*/
|
||||||
#ifndef TCP_QUEUE_OOSEQ
|
#ifndef TCP_QUEUE_OOSEQ
|
||||||
#define TCP_QUEUE_OOSEQ 1
|
#define TCP_QUEUE_OOSEQ (LWIP_TCP)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -729,6 +831,21 @@
|
||||||
#define TCP_DEFAULT_LISTEN_BACKLOG 0xff
|
#define TCP_DEFAULT_LISTEN_BACKLOG 0xff
|
||||||
#endif
|
#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 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
|
* LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all
|
||||||
|
@ -815,6 +932,52 @@
|
||||||
#define LWIP_NETIF_HWADDRHINT 0
|
#define LWIP_NETIF_HWADDRHINT 0
|
||||||
#endif
|
#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 ----------
|
---------- LOOPIF options ----------
|
||||||
|
@ -827,20 +990,16 @@
|
||||||
#define LWIP_HAVE_LOOPIF 0
|
#define LWIP_HAVE_LOOPIF 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------
|
||||||
|
---------- SLIPIF options ----------
|
||||||
|
------------------------------------
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* LWIP_LOOPIF_MULTITHREADING: Indicates whether threading is enabled in
|
* LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
#ifndef LWIP_LOOPIF_MULTITHREADING
|
#ifndef LWIP_HAVE_SLIPIF
|
||||||
#define LWIP_LOOPIF_MULTITHREADING 1
|
#define LWIP_HAVE_SLIPIF 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1039,7 +1198,7 @@
|
||||||
* names (read, write & close). (only used if you use sockets.c)
|
* names (read, write & close). (only used if you use sockets.c)
|
||||||
*/
|
*/
|
||||||
#ifndef LWIP_POSIX_SOCKETS_IO_NAMES
|
#ifndef LWIP_POSIX_SOCKETS_IO_NAMES
|
||||||
#define LWIP_POSIX_SOCKETS_IO_NAMES 0
|
#define LWIP_POSIX_SOCKETS_IO_NAMES 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1065,6 +1224,13 @@
|
||||||
#define LWIP_SO_RCVBUF 0
|
#define LWIP_SO_RCVBUF 0
|
||||||
#endif
|
#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!
|
* SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE!
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -110,6 +110,8 @@ void pbuf_chain(struct pbuf *head, struct pbuf *tail);
|
||||||
struct pbuf *pbuf_dechain(struct pbuf *p);
|
struct pbuf *pbuf_dechain(struct pbuf *p);
|
||||||
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,16 +32,24 @@
|
||||||
* It needs to be implemented by those platforms which need SLIP or PPP
|
* It needs to be implemented by those platforms which need SLIP or PPP
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef __SIO_H__
|
||||||
|
#define __SIO_H__
|
||||||
|
|
||||||
#include "lwip/arch.h"
|
#include "lwip/arch.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* If you want to define sio_fd_t elsewhere or differently,
|
||||||
|
define this in your cc.h file. */
|
||||||
#ifndef __sio_fd_t_defined
|
#ifndef __sio_fd_t_defined
|
||||||
typedef void * sio_fd_t;
|
typedef void * sio_fd_t;
|
||||||
#endif
|
#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
|
#ifndef sio_open
|
||||||
sio_fd_t sio_open(u8_t);
|
sio_fd_t sio_open(u8_t);
|
||||||
#endif
|
#endif
|
||||||
|
@ -69,3 +77,5 @@ void sio_read_abort(sio_fd_t);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* __SIO_H__ */
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
#include "lwip/pbuf.h"
|
#include "lwip/pbuf.h"
|
||||||
#include "lwip/snmp.h"
|
#include "lwip/snmp.h"
|
||||||
|
|
||||||
|
#if LWIP_SNMP
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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
|
||||||
|
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
|
|
||||||
#endif /* __LWIP_SNMP_ASN1_H__ */
|
#endif /* __LWIP_SNMP_ASN1_H__ */
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#include "lwip/snmp.h"
|
#include "lwip/snmp.h"
|
||||||
#include "lwip/snmp_structs.h"
|
#include "lwip/snmp_structs.h"
|
||||||
|
|
||||||
|
#if LWIP_SNMP
|
||||||
|
|
||||||
#if SNMP_PRIVATE_MIB
|
#if SNMP_PRIVATE_MIB
|
||||||
#include "private_mib.h"
|
#include "private_mib.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -304,4 +306,6 @@ void snmp_authfail_trap(void);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
|
|
||||||
#endif /* __LWIP_SNMP_MSG_H__ */
|
#endif /* __LWIP_SNMP_MSG_H__ */
|
||||||
|
|
|
@ -38,6 +38,8 @@
|
||||||
|
|
||||||
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
|
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include <stddef.h> /* for size_t */
|
||||||
|
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
#include "lwip/inet.h"
|
#include "lwip/inet.h"
|
||||||
|
|
||||||
|
@ -69,13 +71,6 @@ struct sockaddr {
|
||||||
#define SOCK_DGRAM 2
|
#define SOCK_DGRAM 2
|
||||||
#define SOCK_RAW 3
|
#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!
|
* 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_REUSEADDR 0x0004 /* Unimplemented: allow local address reuse */
|
||||||
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
|
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
|
||||||
#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */
|
#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_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */
|
||||||
#define SO_LINGER 0x0080 /* linger on close if data present */
|
#define SO_LINGER 0x0080 /* linger on close if data present */
|
||||||
#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */
|
#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */
|
||||||
|
@ -131,9 +126,6 @@ struct linger {
|
||||||
#define IPPROTO_UDP 17
|
#define IPPROTO_UDP 17
|
||||||
#define IPPROTO_UDPLITE 136
|
#define IPPROTO_UDPLITE 136
|
||||||
|
|
||||||
#define INADDR_ANY 0
|
|
||||||
#define INADDR_BROADCAST 0xffffffff
|
|
||||||
|
|
||||||
/* Flags we can use with send and recv. */
|
/* Flags we can use with send and recv. */
|
||||||
#define MSG_PEEK 0x01 /* Peeks at an incoming message */
|
#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 */
|
#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;
|
} ip_mreq;
|
||||||
#endif /* LWIP_IGMP */
|
#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_MASK 0x1E
|
||||||
#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
|
#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
|
||||||
#define IPTOS_LOWDELAY 0x10
|
#define IPTOS_LOWDELAY 0x10
|
||||||
|
@ -194,7 +201,13 @@ typedef struct ip_mreq {
|
||||||
#define IPTOS_MINCOST IPTOS_LOWCOST
|
#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_MASK 0xe0
|
||||||
#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK)
|
#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK)
|
||||||
|
@ -286,7 +299,7 @@ struct timeval {
|
||||||
void lwip_socket_init(void);
|
void lwip_socket_init(void);
|
||||||
|
|
||||||
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
|
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_shutdown(int s, int how);
|
||||||
int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);
|
int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);
|
||||||
int lwip_getsockname (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_close(int s);
|
||||||
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen);
|
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen);
|
||||||
int lwip_listen(int s, int backlog);
|
int lwip_listen(int s, int backlog);
|
||||||
int lwip_recv(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, int len);
|
int lwip_read(int s, void *mem, size_t len);
|
||||||
int lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
int lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
||||||
struct sockaddr *from, socklen_t *fromlen);
|
struct sockaddr *from, socklen_t *fromlen);
|
||||||
int lwip_send(int s, const void *dataptr, int size, unsigned int flags);
|
int lwip_send(int s, const void *dataptr, size_t size, int flags);
|
||||||
int lwip_sendto(int s, const void *dataptr, int size, unsigned int flags,
|
int lwip_sendto(int s, const void *dataptr, size_t size, int flags,
|
||||||
struct sockaddr *to, socklen_t tolen);
|
const struct sockaddr *to, socklen_t tolen);
|
||||||
int lwip_socket(int domain, int type, int protocol);
|
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,
|
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
||||||
struct timeval *timeout);
|
struct timeval *timeout);
|
||||||
int lwip_ioctl(int s, long cmd, void *argp);
|
int lwip_ioctl(int s, long cmd, void *argp);
|
||||||
|
|
|
@ -57,7 +57,6 @@ extern "C" {
|
||||||
|
|
||||||
struct stats_proto {
|
struct stats_proto {
|
||||||
STAT_COUNTER xmit; /* Transmitted packets. */
|
STAT_COUNTER xmit; /* Transmitted packets. */
|
||||||
STAT_COUNTER rexmit; /* Retransmitted packets. */
|
|
||||||
STAT_COUNTER recv; /* Received packets. */
|
STAT_COUNTER recv; /* Received packets. */
|
||||||
STAT_COUNTER fw; /* Forwarded packets. */
|
STAT_COUNTER fw; /* Forwarded packets. */
|
||||||
STAT_COUNTER drop; /* Dropped packets. */
|
STAT_COUNTER drop; /* Dropped packets. */
|
||||||
|
@ -87,7 +86,8 @@ struct stats_mem {
|
||||||
mem_size_t avail;
|
mem_size_t avail;
|
||||||
mem_size_t used;
|
mem_size_t used;
|
||||||
mem_size_t max;
|
mem_size_t max;
|
||||||
mem_size_t err;
|
STAT_COUNTER err;
|
||||||
|
STAT_COUNTER illegal;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct stats_syselem {
|
struct stats_syselem {
|
||||||
|
@ -142,64 +142,138 @@ extern struct stats_ lwip_stats;
|
||||||
#define stats_init() /* Compatibility define, not init needed. */
|
#define stats_init() /* Compatibility define, not init needed. */
|
||||||
|
|
||||||
#define STATS_INC(x) ++lwip_stats.x
|
#define STATS_INC(x) ++lwip_stats.x
|
||||||
|
#define STATS_DEC(x) --lwip_stats.x
|
||||||
#else
|
#else
|
||||||
#define stats_init()
|
#define stats_init()
|
||||||
#define STATS_INC(x)
|
#define STATS_INC(x)
|
||||||
|
#define STATS_DEC(x)
|
||||||
#endif /* LWIP_STATS */
|
#endif /* LWIP_STATS */
|
||||||
|
|
||||||
#if TCP_STATS
|
#if TCP_STATS
|
||||||
#define TCP_STATS_INC(x) STATS_INC(x)
|
#define TCP_STATS_INC(x) STATS_INC(x)
|
||||||
|
#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP")
|
||||||
#else
|
#else
|
||||||
#define TCP_STATS_INC(x)
|
#define TCP_STATS_INC(x)
|
||||||
|
#define TCP_STATS_DISPLAY()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UDP_STATS
|
#if UDP_STATS
|
||||||
#define UDP_STATS_INC(x) STATS_INC(x)
|
#define UDP_STATS_INC(x) STATS_INC(x)
|
||||||
|
#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP")
|
||||||
#else
|
#else
|
||||||
#define UDP_STATS_INC(x)
|
#define UDP_STATS_INC(x)
|
||||||
|
#define UDP_STATS_DISPLAY()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ICMP_STATS
|
#if ICMP_STATS
|
||||||
#define ICMP_STATS_INC(x) STATS_INC(x)
|
#define ICMP_STATS_INC(x) STATS_INC(x)
|
||||||
|
#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP")
|
||||||
#else
|
#else
|
||||||
#define ICMP_STATS_INC(x)
|
#define ICMP_STATS_INC(x)
|
||||||
|
#define ICMP_STATS_DISPLAY()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IGMP_STATS
|
#if IGMP_STATS
|
||||||
#define IGMP_STATS_INC(x) STATS_INC(x)
|
#define IGMP_STATS_INC(x) STATS_INC(x)
|
||||||
|
#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp)
|
||||||
#else
|
#else
|
||||||
#define IGMP_STATS_INC(x)
|
#define IGMP_STATS_INC(x)
|
||||||
|
#define IGMP_STATS_DISPLAY()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IP_STATS
|
#if IP_STATS
|
||||||
#define IP_STATS_INC(x) STATS_INC(x)
|
#define IP_STATS_INC(x) STATS_INC(x)
|
||||||
|
#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP")
|
||||||
#else
|
#else
|
||||||
#define IP_STATS_INC(x)
|
#define IP_STATS_INC(x)
|
||||||
|
#define IP_STATS_DISPLAY()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IPFRAG_STATS
|
#if IPFRAG_STATS
|
||||||
#define IPFRAG_STATS_INC(x) STATS_INC(x)
|
#define IPFRAG_STATS_INC(x) STATS_INC(x)
|
||||||
|
#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG")
|
||||||
#else
|
#else
|
||||||
#define IPFRAG_STATS_INC(x)
|
#define IPFRAG_STATS_INC(x)
|
||||||
|
#define IPFRAG_STATS_DISPLAY()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ETHARP_STATS
|
#if ETHARP_STATS
|
||||||
#define ETHARP_STATS_INC(x) STATS_INC(x)
|
#define ETHARP_STATS_INC(x) STATS_INC(x)
|
||||||
|
#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP")
|
||||||
#else
|
#else
|
||||||
#define ETHARP_STATS_INC(x)
|
#define ETHARP_STATS_INC(x)
|
||||||
|
#define ETHARP_STATS_DISPLAY()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LINK_STATS
|
#if LINK_STATS
|
||||||
#define LINK_STATS_INC(x) STATS_INC(x)
|
#define LINK_STATS_INC(x) STATS_INC(x)
|
||||||
|
#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK")
|
||||||
#else
|
#else
|
||||||
#define LINK_STATS_INC(x)
|
#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
|
#endif
|
||||||
|
|
||||||
/* Display of statistics */
|
/* Display of statistics */
|
||||||
#if LWIP_STATS_DISPLAY
|
#if LWIP_STATS_DISPLAY
|
||||||
void stats_display(void);
|
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
|
#else
|
||||||
#define stats_display()
|
#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 */
|
#endif /* LWIP_STATS_DISPLAY */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -44,7 +44,6 @@ extern "C" {
|
||||||
definitions of the sys_ functions. */
|
definitions of the sys_ functions. */
|
||||||
typedef u8_t sys_sem_t;
|
typedef u8_t sys_sem_t;
|
||||||
typedef u8_t sys_mbox_t;
|
typedef u8_t sys_mbox_t;
|
||||||
typedef u8_t sys_prot_t;
|
|
||||||
struct sys_timeo {u8_t dummy;};
|
struct sys_timeo {u8_t dummy;};
|
||||||
|
|
||||||
#define sys_init()
|
#define sys_init()
|
||||||
|
@ -139,13 +138,11 @@ void sys_mbox_fetch(sys_mbox_t mbox, void **msg);
|
||||||
/* Thread functions. */
|
/* Thread functions. */
|
||||||
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio);
|
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 */
|
#endif /* NO_SYS */
|
||||||
|
|
||||||
|
/** Returns the current time in milliseconds. */
|
||||||
|
u32_t sys_now(void);
|
||||||
|
|
||||||
/* Critical Region Protection */
|
/* Critical Region Protection */
|
||||||
/* These functions must be implemented in the sys_arch.c file.
|
/* These functions must be implemented in the sys_arch.c file.
|
||||||
In some implementations they can provide a more light-weight protection
|
In some implementations they can provide a more light-weight protection
|
||||||
|
|
|
@ -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);
|
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)
|
#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);
|
err_t tcp_close (struct tcp_pcb *pcb);
|
||||||
|
|
||||||
/* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */
|
/* 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);
|
err_t tcp_output (struct tcp_pcb *pcb);
|
||||||
void tcp_rexmit (struct tcp_pcb *pcb);
|
void tcp_rexmit (struct tcp_pcb *pcb);
|
||||||
void tcp_rexmit_rto (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
|
* This is the Nagle algorithm: try to combine user data to send as few TCP
|
||||||
* segments when new outgoing data arrives from the user if any
|
* segments as possible. Only send if
|
||||||
* previously transmitted data on the connection remains
|
* - no previously transmitted data on the connection remains unacknowledged or
|
||||||
* unacknowledged.
|
* - 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) || \
|
#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
|
||||||
((tpcb)->flags & TF_NODELAY) || \
|
((tpcb)->flags & TF_NODELAY) || \
|
||||||
(((tpcb)->unsent != NULL) && ((tpcb)->unsent->next != NULL))) ? \
|
(((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
|
||||||
1 : 0)
|
((tpcb)->unsent->len >= (tpcb)->mss))) \
|
||||||
|
) ? 1 : 0)
|
||||||
#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)
|
#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_LT(a,b) ((s32_t)((a)-(b)) < 0)
|
||||||
#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
|
#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
|
||||||
#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
|
#define TCP_SEQ_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 */
|
#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */
|
||||||
|
|
||||||
#ifndef TCP_MSL
|
#ifndef TCP_MSL
|
||||||
#define TCP_MSL 60000U /* The maximum segment lifetime in milliseconds */
|
#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */
|
/* 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_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */
|
||||||
#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
|
#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
|
* members common to struct tcp_pcb and struct tcp_listen_pcb
|
||||||
*/
|
*/
|
||||||
|
@ -267,7 +280,10 @@ enum tcp_state {
|
||||||
u8_t prio; \
|
u8_t prio; \
|
||||||
void *callback_arg; \
|
void *callback_arg; \
|
||||||
/* ports are in host byte order */ \
|
/* 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 */
|
/* the TCP protocol control block */
|
||||||
struct tcp_pcb {
|
struct tcp_pcb {
|
||||||
|
@ -280,19 +296,21 @@ struct tcp_pcb {
|
||||||
u16_t remote_port;
|
u16_t remote_port;
|
||||||
|
|
||||||
u8_t flags;
|
u8_t flags;
|
||||||
#define TF_ACK_DELAY (u8_t)0x01U /* Delayed ACK. */
|
#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */
|
||||||
#define TF_ACK_NOW (u8_t)0x02U /* Immediate ACK. */
|
#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */
|
||||||
#define TF_INFR (u8_t)0x04U /* In fast recovery. */
|
#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */
|
||||||
#define TF_FIN (u8_t)0x20U /* Connection was closed locally (FIN segment enqueued). */
|
#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */
|
||||||
#define TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */
|
#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */
|
||||||
#define TF_NAGLEMEMERR (u8_t)0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
|
#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
|
/* the rest of the fields are in host byte order
|
||||||
as we have to do some math with them */
|
as we have to do some math with them */
|
||||||
/* receiver variables */
|
/* receiver variables */
|
||||||
u32_t rcv_nxt; /* next seqno expected */
|
u32_t rcv_nxt; /* next seqno expected */
|
||||||
u16_t rcv_wnd; /* receiver window */
|
u16_t rcv_wnd; /* receiver window available */
|
||||||
u16_t rcv_ann_wnd; /* announced receive window */
|
u16_t rcv_ann_wnd; /* receiver window to announce */
|
||||||
|
u32_t rcv_ann_right_edge; /* announced right edge of window */
|
||||||
|
|
||||||
/* Timers */
|
/* Timers */
|
||||||
u32_t tmr;
|
u32_t tmr;
|
||||||
|
@ -320,12 +338,11 @@ struct tcp_pcb {
|
||||||
u16_t ssthresh;
|
u16_t ssthresh;
|
||||||
|
|
||||||
/* sender variables */
|
/* sender variables */
|
||||||
u32_t snd_nxt, /* next seqno to be sent */
|
u32_t snd_nxt; /* next new seqno to be sent */
|
||||||
snd_max; /* Highest seqno sent. */
|
|
||||||
u16_t snd_wnd; /* sender window */
|
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. */
|
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;
|
u16_t acked;
|
||||||
|
|
||||||
|
@ -369,15 +386,6 @@ struct tcp_pcb {
|
||||||
*/
|
*/
|
||||||
err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);
|
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.
|
/* Function which is called periodically.
|
||||||
* The period can be adjusted in multiples of the TCP slow timer interval
|
* The period can be adjusted in multiples of the TCP slow timer interval
|
||||||
* by changing tcp_pcb.polltmr.
|
* by changing tcp_pcb.polltmr.
|
||||||
|
@ -398,6 +406,11 @@ struct tcp_pcb {
|
||||||
void (* errf)(void *arg, err_t err);
|
void (* errf)(void *arg, err_t err);
|
||||||
#endif /* LWIP_CALLBACK_API */
|
#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 */
|
/* idle time before KEEPALIVE is sent */
|
||||||
u32_t keep_idle;
|
u32_t keep_idle;
|
||||||
#if LWIP_TCP_KEEPALIVE
|
#if LWIP_TCP_KEEPALIVE
|
||||||
|
@ -420,16 +433,6 @@ struct tcp_pcb_listen {
|
||||||
/* Protocol specific PCB members */
|
/* Protocol specific PCB members */
|
||||||
TCP_PCB_COMMON(struct tcp_pcb_listen);
|
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
|
#if TCP_LISTEN_BACKLOG
|
||||||
u8_t backlog;
|
u8_t backlog;
|
||||||
u8_t accepts_pending;
|
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, \
|
#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \
|
||||||
LWIP_EVENT_ERR, NULL, 0, (err))
|
LWIP_EVENT_ERR, NULL, 0, (err))
|
||||||
#else /* LWIP_EVENT_API */
|
#else /* LWIP_EVENT_API */
|
||||||
#define TCP_EVENT_ACCEPT(pcb,err,ret) \
|
|
||||||
if((pcb)->accept != NULL) \
|
#define TCP_EVENT_ACCEPT(pcb,err,ret) \
|
||||||
(ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err)))
|
do { \
|
||||||
#define TCP_EVENT_SENT(pcb,space,ret) \
|
if((pcb)->accept != NULL) \
|
||||||
if((pcb)->sent != NULL) \
|
(ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \
|
||||||
(ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space)))
|
else (ret) = ERR_OK; \
|
||||||
#define TCP_EVENT_RECV(pcb,p,err,ret) \
|
} while (0)
|
||||||
if((pcb)->recv != NULL) \
|
|
||||||
{ ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \
|
#define TCP_EVENT_SENT(pcb,space,ret) \
|
||||||
ret = ERR_OK; \
|
do { \
|
||||||
if (p) pbuf_free(p); }
|
if((pcb)->sent != NULL) \
|
||||||
#define TCP_EVENT_CONNECTED(pcb,err,ret) \
|
(ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \
|
||||||
if((pcb)->connected != NULL) \
|
else (ret) = ERR_OK; \
|
||||||
(ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))
|
} while (0)
|
||||||
#define TCP_EVENT_POLL(pcb,ret) \
|
|
||||||
if((pcb)->poll != NULL) \
|
#define TCP_EVENT_RECV(pcb,p,err,ret) \
|
||||||
(ret = (pcb)->poll((pcb)->callback_arg,(pcb)))
|
do { \
|
||||||
#define TCP_EVENT_ERR(errf,arg,err) \
|
if((pcb)->recv != NULL) { \
|
||||||
if((errf) != NULL) \
|
(ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \
|
||||||
(errf)((arg),(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 */
|
#endif /* LWIP_EVENT_API */
|
||||||
|
|
||||||
/* This structure represents a TCP segment on the unsent and unacked queues */
|
/* 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 */
|
struct pbuf *p; /* buffer containing data + TCP header */
|
||||||
void *dataptr; /* pointer to the TCP data in the pbuf */
|
void *dataptr; /* pointer to the TCP data in the pbuf */
|
||||||
u16_t len; /* the TCP length of this segment */
|
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 */
|
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: */
|
/* Internal functions and global variables: */
|
||||||
struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
|
struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
|
||||||
void tcp_pcb_purge(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);
|
u8_t tcp_seg_free(struct tcp_seg *seg);
|
||||||
struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
|
struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
|
||||||
|
|
||||||
#define tcp_ack(pcb) if((pcb)->flags & TF_ACK_DELAY) { \
|
#define tcp_ack(pcb) \
|
||||||
(pcb)->flags &= ~TF_ACK_DELAY; \
|
do { \
|
||||||
(pcb)->flags |= TF_ACK_NOW; \
|
if((pcb)->flags & TF_ACK_DELAY) { \
|
||||||
tcp_output(pcb); \
|
(pcb)->flags &= ~TF_ACK_DELAY; \
|
||||||
} else { \
|
(pcb)->flags |= TF_ACK_NOW; \
|
||||||
(pcb)->flags |= TF_ACK_DELAY; \
|
tcp_output(pcb); \
|
||||||
}
|
} \
|
||||||
|
else { \
|
||||||
|
(pcb)->flags |= TF_ACK_DELAY; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \
|
#define tcp_ack_now(pcb) \
|
||||||
tcp_output(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_send_ctrl(struct tcp_pcb *pcb, u8_t flags);
|
||||||
err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,
|
err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,
|
||||||
u8_t flags, u8_t apiflags,
|
u8_t flags, u8_t apiflags, u8_t optflags);
|
||||||
u8_t *optdata, u8_t optlen);
|
|
||||||
|
|
||||||
void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
|
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)
|
} while(0)
|
||||||
|
|
||||||
#else /* LWIP_DEBUG */
|
#else /* LWIP_DEBUG */
|
||||||
#define TCP_REG(pcbs, npcb) do { \
|
|
||||||
npcb->next = *pcbs; \
|
#define TCP_REG(pcbs, npcb) \
|
||||||
*(pcbs) = npcb; \
|
do { \
|
||||||
tcp_timer_needed(); \
|
npcb->next = *pcbs; \
|
||||||
} while(0)
|
*(pcbs) = npcb; \
|
||||||
#define TCP_RMV(pcbs, npcb) do { \
|
tcp_timer_needed(); \
|
||||||
if(*(pcbs) == npcb) { \
|
} while (0)
|
||||||
(*(pcbs)) = (*pcbs)->next; \
|
|
||||||
} else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
|
#define TCP_RMV(pcbs, npcb) \
|
||||||
if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \
|
do { \
|
||||||
tcp_tmp_pcb->next = npcb->next; \
|
if(*(pcbs) == npcb) { \
|
||||||
break; \
|
(*(pcbs)) = (*pcbs)->next; \
|
||||||
} \
|
} \
|
||||||
} \
|
else { \
|
||||||
npcb->next = NULL; \
|
for(tcp_tmp_pcb = *pcbs; \
|
||||||
} while(0)
|
tcp_tmp_pcb != NULL; \
|
||||||
|
tcp_tmp_pcb = tcp_tmp_pcb->next) { \
|
||||||
|
if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \
|
||||||
|
tcp_tmp_pcb->next = npcb->next; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
npcb->next = NULL; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#endif /* LWIP_DEBUG */
|
#endif /* LWIP_DEBUG */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "lwip/pbuf.h"
|
#include "lwip/pbuf.h"
|
||||||
#include "lwip/api.h"
|
#include "lwip/api.h"
|
||||||
#include "lwip/sys.h"
|
#include "lwip/sys.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -83,10 +84,14 @@ err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
|
||||||
#endif /* LWIP_NETIF_API */
|
#endif /* LWIP_NETIF_API */
|
||||||
|
|
||||||
err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block);
|
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);
|
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 {
|
enum tcpip_msg_type {
|
||||||
#if LWIP_NETCONN
|
#if LWIP_NETCONN
|
||||||
|
@ -97,7 +102,8 @@ enum tcpip_msg_type {
|
||||||
TCPIP_MSG_NETIFAPI,
|
TCPIP_MSG_NETIFAPI,
|
||||||
#endif /* LWIP_NETIF_API */
|
#endif /* LWIP_NETIF_API */
|
||||||
TCPIP_MSG_CALLBACK,
|
TCPIP_MSG_CALLBACK,
|
||||||
TCPIP_MSG_TIMEOUT
|
TCPIP_MSG_TIMEOUT,
|
||||||
|
TCPIP_MSG_UNTIMEOUT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tcpip_msg {
|
struct tcpip_msg {
|
||||||
|
|
|
@ -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_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_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);
|
||||||
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);
|
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);
|
err_t ethernet_input(struct pbuf *p, struct netif *netif);
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#ifndef __NETIF_LOOPIF_H__
|
#ifndef __NETIF_LOOPIF_H__
|
||||||
#define __NETIF_LOOPIF_H__
|
#define __NETIF_LOOPIF_H__
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
|
|
||||||
|
@ -39,9 +40,9 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !LWIP_LOOPIF_MULTITHREADING
|
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||||
void loopif_poll(struct netif *netif);
|
#define loopif_poll netif_poll
|
||||||
#endif
|
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||||
|
|
||||||
err_t loopif_init(struct netif *netif);
|
err_t loopif_init(struct netif *netif);
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
*
|
*
|
||||||
* This implementation complies with RFC 826 (Ethernet ARP). It supports
|
* This implementation complies with RFC 826 (Ethernet ARP). It supports
|
||||||
* Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
|
* 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
|
* if an interface calls etharp_gratuitous(our_netif) upon address change.
|
||||||
* address change.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -353,7 +352,7 @@ find_entry(struct ip_addr *ipaddr, u8_t flags)
|
||||||
* 1) empty entry
|
* 1) empty entry
|
||||||
* 2) oldest stable entry
|
* 2) oldest stable entry
|
||||||
* 3) oldest pending entry without queued packets
|
* 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 }
|
* { 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->opcode = htons(ARP_REPLY);
|
||||||
|
|
||||||
hdr->dipaddr = hdr->sipaddr;
|
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!",
|
LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
|
||||||
(netif->hwaddr_len == ETHARP_HWADDR_LEN));
|
(netif->hwaddr_len == ETHARP_HWADDR_LEN));
|
||||||
|
@ -1041,7 +1040,7 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
||||||
#endif /* LWIP_AUTOIP */
|
#endif /* LWIP_AUTOIP */
|
||||||
|
|
||||||
/* allocate a pbuf for the outgoing ARP request packet */
|
/* 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? */
|
/* could allocate a pbuf for an ARP request? */
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n"));
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n"));
|
||||||
|
@ -1130,6 +1129,13 @@ ethernet_input(struct pbuf *p, struct netif *netif)
|
||||||
|
|
||||||
/* points to packet payload, which starts with an Ethernet header */
|
/* points to packet payload, which starts with an Ethernet header */
|
||||||
ethhdr = p->payload;
|
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)) {
|
switch (htons(ethhdr->type)) {
|
||||||
/* IP packet? */
|
/* IP packet? */
|
||||||
|
@ -1165,6 +1171,8 @@ ethernet_input(struct pbuf *p, struct netif *netif)
|
||||||
#endif /* PPPOE_SUPPORT */
|
#endif /* PPPOE_SUPPORT */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
ETHARP_STATS_INC(etharp.proterr);
|
||||||
|
ETHARP_STATS_INC(etharp.drop);
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -40,149 +40,8 @@
|
||||||
#if LWIP_HAVE_LOOPIF
|
#if LWIP_HAVE_LOOPIF
|
||||||
|
|
||||||
#include "netif/loopif.h"
|
#include "netif/loopif.h"
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/snmp.h"
|
#include "lwip/snmp.h"
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#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
|
* Initialize a lwip network interface structure for a loopback interface
|
||||||
*
|
*
|
||||||
|
@ -193,16 +52,6 @@ loopif_output(struct netif *netif, struct pbuf *p,
|
||||||
err_t
|
err_t
|
||||||
loopif_init(struct netif *netif)
|
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
|
/* initialize the snmp variables and counters inside the struct netif
|
||||||
* ifSpeed: no assumption can be made!
|
* ifSpeed: no assumption can be made!
|
||||||
*/
|
*/
|
||||||
|
@ -210,7 +59,7 @@ loopif_init(struct netif *netif)
|
||||||
|
|
||||||
netif->name[0] = 'l';
|
netif->name[0] = 'l';
|
||||||
netif->name[1] = 'o';
|
netif->name[1] = 'o';
|
||||||
netif->output = loopif_output;
|
netif->output = netif_loop_output;
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -518,16 +518,18 @@ upap_rauthnak(upap_state *u, u_char *inp, int id, int len)
|
||||||
*/
|
*/
|
||||||
if (len < sizeof (u_char)) {
|
if (len < sizeof (u_char)) {
|
||||||
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
|
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;
|
u->us_clientstate = UPAPCS_BADAUTH;
|
||||||
|
|
||||||
|
|
|
@ -1056,7 +1056,7 @@ pppWriteOverEthernet(int pd, const u_char *s, int n)
|
||||||
|
|
||||||
pc->lastXMit = sys_jiffies();
|
pc->lastXMit = sys_jiffies();
|
||||||
|
|
||||||
SMEMCPY(pb->payload, s, n);
|
MEMCPY(pb->payload, s, n);
|
||||||
|
|
||||||
if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
|
if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
|
||||||
LINK_STATS_INC(link.err);
|
LINK_STATS_INC(link.err);
|
||||||
|
@ -1339,10 +1339,6 @@ sifup(int pd)
|
||||||
netif_remove(&pc->netif);
|
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)) {
|
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);
|
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->if_up = 1;
|
||||||
pc->errCode = PPPERR_NONE;
|
pc->errCode = PPPERR_NONE;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,9 @@
|
||||||
|
|
||||||
#include "netif/slipif.h"
|
#include "netif/slipif.h"
|
||||||
#include "lwip/opt.h"
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_HAVE_SLIPIF
|
||||||
|
|
||||||
#include "lwip/def.h"
|
#include "lwip/def.h"
|
||||||
#include "lwip/pbuf.h"
|
#include "lwip/pbuf.h"
|
||||||
#include "lwip/sys.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);
|
sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
#endif /* LWIP_HAVE_SLIPIF */
|
||||||
|
|
Loading…
Reference in New Issue