Compare commits
271 Commits
STABLE-1_3
...
STABLE-1_3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
125efd8396 | ||
|
|
4a9557fa84 | ||
|
|
6b6c82aaee | ||
|
|
feca27d69e | ||
|
|
fbef894674 | ||
|
|
2e4bb8b3b7 | ||
|
|
e9940acb54 | ||
|
|
957331fff4 | ||
|
|
faba395cae | ||
|
|
1d5809679b | ||
|
|
b5014b0966 | ||
|
|
b1ad36eece | ||
|
|
1b42286bda | ||
|
|
5da0620c6b | ||
|
|
96e8f16c05 | ||
|
|
b5d28e0a9c | ||
|
|
73251bc9c1 | ||
|
|
3fa63b35b3 | ||
|
|
65f006e52e | ||
|
|
7d46e06824 | ||
|
|
32acb82bc0 | ||
|
|
3a1c5944e7 | ||
|
|
04c5246e02 | ||
|
|
46dc1c9bfb | ||
|
|
b900253c09 | ||
|
|
59a5fb7ce8 | ||
|
|
c5d2e536cf | ||
|
|
aeef0a21f3 | ||
|
|
902ad897b8 | ||
|
|
478ccee5fc | ||
|
|
43fd5c28b5 | ||
|
|
4391463832 | ||
|
|
c8d2d2a8ea | ||
|
|
6795aabecf | ||
|
|
a939c09a6b | ||
|
|
35d1c33e0a | ||
|
|
10edf64873 | ||
|
|
6d22c38e59 | ||
|
|
8a81cb4ba0 | ||
|
|
6bb7f987f2 | ||
|
|
1c018caefe | ||
|
|
0c136893e5 | ||
|
|
f4c0655190 | ||
|
|
49bdf32765 | ||
|
|
88d02a624a | ||
|
|
98a58f9e67 | ||
|
|
b30c6f8b9e | ||
|
|
94a7fee8c8 | ||
|
|
6f38b63a47 | ||
|
|
70b05c8096 | ||
|
|
28ac4347d4 | ||
|
|
dee1d82c11 | ||
|
|
6d73f82f41 | ||
|
|
71ddff4964 | ||
|
|
af3b796488 | ||
|
|
e2de2c6bb2 | ||
|
|
2ff0ce2d0a | ||
|
|
b09b8a0ccc | ||
|
|
db259c3557 | ||
|
|
bcc87ef851 | ||
|
|
650f16b6d9 | ||
|
|
ae2dd38e0d | ||
|
|
0319c1cf90 | ||
|
|
81f9442ac7 | ||
|
|
18ab274af3 | ||
|
|
65d1f52423 | ||
|
|
f1b82e0e9a | ||
|
|
67411c4299 | ||
|
|
a37e62b7d0 | ||
|
|
e2c1f7d5b5 | ||
|
|
ec97fbd101 | ||
|
|
b7d7559cc9 | ||
|
|
b4404ff0c8 | ||
|
|
502e89f4ad | ||
|
|
d8d8cf7e98 | ||
|
|
d9a5094068 | ||
|
|
a9740c6a44 | ||
|
|
2dc027401f | ||
|
|
ac638c85f3 | ||
|
|
c0e22c255c | ||
|
|
1309e5e86f | ||
|
|
c34c024dd5 | ||
|
|
6ef69ece95 | ||
|
|
a9cbdc141b | ||
|
|
9e5cf1cf8e | ||
|
|
ddc783bee7 | ||
|
|
68f92050e9 | ||
|
|
bd2bc2ee14 | ||
|
|
8a7c1c4926 | ||
|
|
cff3e0cad2 | ||
|
|
b55cfbc342 | ||
|
|
3115087d26 | ||
|
|
057c51ff6d | ||
|
|
f2f20cf133 | ||
|
|
2c618705f0 | ||
|
|
bc10ad2356 | ||
|
|
857fac1168 | ||
|
|
103ba9b0fc | ||
|
|
d83fc6893b | ||
|
|
e7d5739ce7 | ||
|
|
8bf57c0e14 | ||
|
|
dea7255fc5 | ||
|
|
ce3082976c | ||
|
|
362a295e06 | ||
|
|
0e91e2adf2 | ||
|
|
4d49d952b6 | ||
|
|
ae7a7a0abf | ||
|
|
4f265dce60 | ||
|
|
bd96db8c9f | ||
|
|
0b75917121 | ||
|
|
fa2dbc2b1b | ||
|
|
3a6165f0b9 | ||
|
|
62c27f7fce | ||
|
|
7feb116bae | ||
|
|
730a938912 | ||
|
|
3553efb75e | ||
|
|
6111230fe9 | ||
|
|
6bce84e070 | ||
|
|
a6e316a92d | ||
|
|
22bcf5892a | ||
|
|
cc4b968f0a | ||
|
|
893ddcf61b | ||
|
|
cf81dbcca4 | ||
|
|
5830200029 | ||
|
|
972592cf8a | ||
|
|
ce5699f41b | ||
|
|
1eee0be951 | ||
|
|
fb555a0633 | ||
|
|
2b87f899ab | ||
|
|
776e1926a3 | ||
|
|
c232edb83a | ||
|
|
aefeba3fc0 | ||
|
|
6d4064799a | ||
|
|
e0e9a63e63 | ||
|
|
bcdffce6ce | ||
|
|
ff97c8a1a9 | ||
|
|
30acd1662d | ||
|
|
078e2f60d6 | ||
|
|
c7ce2792c8 | ||
|
|
22d6558f13 | ||
|
|
105d72a3c2 | ||
|
|
c752e5731c | ||
|
|
72e9cf53e7 | ||
|
|
e66d315c9b | ||
|
|
95f6dc7011 | ||
|
|
ac9e758f41 | ||
|
|
518b18dad0 | ||
|
|
bdd5586cee | ||
|
|
14dba4ae2b | ||
|
|
99d82c4980 | ||
|
|
fb46e0f192 | ||
|
|
b055128ec4 | ||
|
|
e29f94a980 | ||
|
|
24342eaab0 | ||
|
|
152d22d4f9 | ||
|
|
41eecb67d2 | ||
|
|
9317105c37 | ||
|
|
23d7f5425d | ||
|
|
217f279fdb | ||
|
|
d4ecb23015 | ||
|
|
42c59e1079 | ||
|
|
3b5993e6ee | ||
|
|
4b8255a588 | ||
|
|
36e3d24331 | ||
|
|
261dfdf010 | ||
|
|
cbfacb7ed9 | ||
|
|
4eda29abf9 | ||
|
|
c3f7107e2b | ||
|
|
67a3976a24 | ||
|
|
4fba1b1430 | ||
|
|
029b786c77 | ||
|
|
51e02176da | ||
|
|
ed65d9cd75 | ||
|
|
542b8fffb1 | ||
|
|
12c50ed87b | ||
|
|
9d5bf57dd9 | ||
|
|
04df18bcd3 | ||
|
|
422ba5bcec | ||
|
|
27b28a9306 | ||
|
|
620b3e6739 | ||
|
|
580f334274 | ||
|
|
4f52183a39 | ||
|
|
a55f354687 | ||
|
|
9630c9136b | ||
|
|
dbd6d7ec8d | ||
|
|
b3a5d6df0d | ||
|
|
3587e8481d | ||
|
|
4f8f6ba205 | ||
|
|
f81ed216db | ||
|
|
f1a9f7ea70 | ||
|
|
4b14621208 | ||
|
|
baf30f5eae | ||
|
|
e7a2ab5de9 | ||
|
|
fd41c5de2d | ||
|
|
efac109803 | ||
|
|
84505d4cc8 | ||
|
|
7d8fac62ec | ||
|
|
b6e18d9c6f | ||
|
|
c05e968278 | ||
|
|
103fe60362 | ||
|
|
638020ec70 | ||
|
|
56038b6457 | ||
|
|
96b788bea7 | ||
|
|
7b6c11360f | ||
|
|
ea1eb45e3f | ||
|
|
e001a021d5 | ||
|
|
14cb4eb735 | ||
|
|
d976c8e85f | ||
|
|
d2d33cb984 | ||
|
|
eeae59ecb7 | ||
|
|
466f4e699c | ||
|
|
bf09400c4c | ||
|
|
c4509e700d | ||
|
|
6472e3b35e | ||
|
|
f9bd5019fa | ||
|
|
8c7705bbf9 | ||
|
|
243e3d0d91 | ||
|
|
19884f40b8 | ||
|
|
10c3ce08af | ||
|
|
878532a30d | ||
|
|
102d69004a | ||
|
|
b0c61ffbb1 | ||
|
|
9f96f09652 | ||
|
|
aa568727d1 | ||
|
|
411cb39eb4 | ||
|
|
6777ae2ada | ||
|
|
2cf3e6e9bc | ||
|
|
491b73d5f2 | ||
|
|
1f3fe200df | ||
|
|
299e2a7077 | ||
|
|
13a139eef7 | ||
|
|
06df1647e1 | ||
|
|
1d2804d6a2 | ||
|
|
ba98bcdc60 | ||
|
|
0d7dccba5e | ||
|
|
c231e95cce | ||
|
|
6f6c8c5434 | ||
|
|
edf72a7dfb | ||
|
|
ba636e19a2 | ||
|
|
6374766a55 | ||
|
|
c779a9f29f | ||
|
|
ae2d5266c5 | ||
|
|
99db244124 | ||
|
|
8367feafa9 | ||
|
|
f6a28808e3 | ||
|
|
13d8ae859d | ||
|
|
95b15fe463 | ||
|
|
779938ea68 | ||
|
|
139944a3ac | ||
|
|
b94e3a874d | ||
|
|
3d8e5003af | ||
|
|
94cd14e90d | ||
|
|
c93cfb2c74 | ||
|
|
521d439a07 | ||
|
|
460b18e82c | ||
|
|
ef3666ef26 | ||
|
|
e0aaa87b1f | ||
|
|
eba83ab740 | ||
|
|
a8141c53a8 | ||
|
|
88ff8c83e9 | ||
|
|
24e0b25215 | ||
|
|
7bc881ccc5 | ||
|
|
a3bc6cd666 | ||
|
|
40d4a8fc2f | ||
|
|
7be9e292dc | ||
|
|
9ccd31a12e | ||
|
|
a9aefcc1be | ||
|
|
05587f5da9 | ||
|
|
43dd38df0a | ||
|
|
64fa8d78bc | ||
|
|
aee9c4c8e6 |
538
CHANGELOG
538
CHANGELOG
@@ -23,6 +23,544 @@ HISTORY
|
||||
++ Bugfixes:
|
||||
|
||||
|
||||
(STABLE-1.3.2)
|
||||
|
||||
++ New features:
|
||||
|
||||
2009-10-27 Simon Goldschmidt/Stephan Lesage
|
||||
* netifapi.c/.h: Added netifapi_netif_set_addr()
|
||||
|
||||
2009-10-07 Simon Goldschmidt/Fabian Koch
|
||||
* api_msg.c, netbuf.c/.h, opt.h: patch #6888: Patch for UDP Netbufs to
|
||||
support dest-addr and dest-port (optional: LWIP_NETBUF_RECVINFO)
|
||||
|
||||
2009-08-26 Simon Goldschmidt/Simon Kallweit
|
||||
* slipif.c/.h: bug #26397: SLIP polling support
|
||||
|
||||
2009-08-25 Simon Goldschmidt
|
||||
* opt.h, etharp.h/.c: task #9033: Support IEEE 802.1q tagged frame (VLAN),
|
||||
New configuration options ETHARP_SUPPORT_VLAN and ETHARP_VLAN_CHECK.
|
||||
|
||||
2009-08-25 Simon Goldschmidt
|
||||
* ip_addr.h, netdb.c: patch #6900: added define ip_ntoa(struct ip_addr*)
|
||||
|
||||
2009-08-24 Jakob Stoklund Olesen
|
||||
* autoip.c, dhcp.c, netif.c: patch #6725: Teach AutoIP and DHCP to respond
|
||||
to netif_set_link_up().
|
||||
|
||||
2009-08-23 Simon Goldschmidt
|
||||
* tcp.h/.c: Added function tcp_debug_state_str() to convert a tcp state
|
||||
to a human-readable string.
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2009-12-24: Kieran Mansley
|
||||
* tcp_in.c Apply patches from Oleg Tyshev to improve OOS processing
|
||||
(BUG#28241)
|
||||
|
||||
2009-12-06: Simon Goldschmidt
|
||||
* ppp.h/.c: Fixed bug #27079 (Yet another leak in PPP): outpacket_buf can
|
||||
be statically allocated (like in ucip)
|
||||
|
||||
2009-12-04: Simon Goldschmidt (patch by Ioardan Neshev)
|
||||
* pap.c: patch #6969: PPP: missing PAP authentication UNTIMEOUT
|
||||
|
||||
2009-12-03: Simon Goldschmidt
|
||||
* tcp.h, tcp_in.c, tcp_out.c: Fixed bug #28106: dup ack for fast retransmit
|
||||
could have non-zero length
|
||||
|
||||
2009-12-02: Simon Goldschmidt
|
||||
* tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting
|
||||
tcp_input_pcb until after calling the pcb's callbacks
|
||||
|
||||
2009-11-29: Simon Goldschmidt
|
||||
* tcp_in.c: Fixed bug #28054: Two segments with FIN flag on the out-of-
|
||||
sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code
|
||||
|
||||
2009-11-29: Simon Goldschmidt
|
||||
* pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by
|
||||
queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty
|
||||
|
||||
2009-11-26: Simon Goldschmidt
|
||||
* tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending
|
||||
segment
|
||||
|
||||
2009-11-26: Simon Goldschmidt
|
||||
* tcp.h, sockets.c: Fixed bug #28099: API required to disable Nagle
|
||||
algorithm at PCB level
|
||||
|
||||
2009-11-22: Simon Goldschmidt
|
||||
* tcp_out.c: Fixed bug #27905: FIN isn't combined with data on unsent
|
||||
|
||||
2009-11-22: Simon Goldschmidt (suggested by Bill Auerbach)
|
||||
* tcp.c: tcp_alloc: prevent increasing stats.err for MEMP_TCP_PCB when
|
||||
reusing time-wait pcb
|
||||
|
||||
2009-11-20: Simon Goldschmidt (patch by Albert Bartel)
|
||||
* sockets.c: Fixed bug #28062: Data received directly after accepting
|
||||
does not wake up select
|
||||
|
||||
2009-11-11: Simon Goldschmidt
|
||||
* netdb.h: Fixed bug #27994: incorrect define for freeaddrinfo(addrinfo)
|
||||
|
||||
2009-10-30: Simon Goldschmidt
|
||||
* opt.h: Increased default value for TCP_MSS to 536, updated default
|
||||
value for TCP_WND to 4*TCP_MSS to keep delayed ACK working.
|
||||
|
||||
2009-10-28: Kieran Mansley
|
||||
* tcp_in.c, tcp_out.c, tcp.h: re-work the fast retransmission code
|
||||
to follow algorithm from TCP/IP Illustrated
|
||||
|
||||
2009-10-27: Kieran Mansley
|
||||
* tcp_in.c: fix BUG#27445: grow cwnd with every duplicate ACK
|
||||
|
||||
2009-10-25: Simon Goldschmidt
|
||||
* tcp.h: bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if
|
||||
pcb->recv is NULL to keep rcv_wnd correct)
|
||||
|
||||
2009-10-25: Simon Goldschmidt
|
||||
* tcp_in.c: Fixed bug #26251: RST process in TIME_WAIT TCP state
|
||||
|
||||
2009-10-23: Simon Goldschmidt (David Empson)
|
||||
* tcp.c: Fixed bug #27783: Silly window avoidance for small window sizes
|
||||
|
||||
2009-10-21: Simon Goldschmidt
|
||||
* tcp_in.c: Fixed bug #27215: TCP sent() callback gives leading and
|
||||
trailing 1 byte len (SYN/FIN)
|
||||
|
||||
2009-10-21: Simon Goldschmidt
|
||||
* tcp_out.c: Fixed bug #27315: zero window probe and FIN
|
||||
|
||||
2009-10-19: Simon Goldschmidt
|
||||
* dhcp.c/.h: Minor code simplification (don't store received pbuf, change
|
||||
conditional code to assert where applicable), check pbuf length before
|
||||
testing for valid reply
|
||||
|
||||
2009-10-19: Simon Goldschmidt
|
||||
* dhcp.c: Removed most calls to udp_connect since they aren't necessary
|
||||
when using udp_sendto_if() - always stay connected to IP_ADDR_ANY.
|
||||
|
||||
2009-10-16: Simon Goldschmidt
|
||||
* ip.c: Fixed bug #27390: Source IP check in ip_input() causes it to drop
|
||||
valid DHCP packets -> allow 0.0.0.0 as source address when LWIP_DHCP is
|
||||
enabled
|
||||
|
||||
2009-10-15: Simon Goldschmidt (Oleg Tyshev)
|
||||
* tcp_in.c: Fixed bug #27329: dupacks by unidirectional data transmit
|
||||
|
||||
2009-10-15: Simon Goldschmidt
|
||||
* api_lib.c: Fixed bug #27709: conn->err race condition on netconn_recv()
|
||||
timeout
|
||||
|
||||
2009-10-15: Simon Goldschmidt
|
||||
* autoip.c: Fixed bug #27704: autoip starts with wrong address
|
||||
LWIP_AUTOIP_CREATE_SEED_ADDR() returned address in host byte order instead
|
||||
of network byte order
|
||||
|
||||
2009-10-11 Simon Goldschmidt (J<>rg Kesten)
|
||||
* tcp_out.c: Fixed bug #27504: tcp_enqueue wrongly concatenates segments
|
||||
which are not consecutive when retransmitting unacked segments
|
||||
|
||||
2009-10-09 Simon Goldschmidt
|
||||
* opt.h: Fixed default values of some stats to only be enabled if used
|
||||
Fixes bug #27338: sys_stats is defined when NO_SYS = 1
|
||||
|
||||
2009-08-30 Simon Goldschmidt
|
||||
* ip.c: Fixed bug bug #27345: "ip_frag() does not use the LWIP_NETIF_LOOPBACK
|
||||
function" by checking for loopback before calling ip_frag
|
||||
|
||||
2009-08-25 Simon Goldschmidt
|
||||
* dhcp.c: fixed invalid dependency to etharp_query if DHCP_DOES_ARP_CHECK==0
|
||||
|
||||
2009-08-23 Simon Goldschmidt
|
||||
* ppp.c: bug #27078: Possible memory leak in pppInit()
|
||||
|
||||
2009-08-23 Simon Goldschmidt
|
||||
* netdb.c, dns.c: bug #26657: DNS, if host name is "localhost", result
|
||||
is error.
|
||||
|
||||
2009-08-23 Simon Goldschmidt
|
||||
* opt.h, init.c: bug #26649: TCP fails when TCP_MSS > TCP_SND_BUF
|
||||
Fixed wrong parenthesis, added check in init.c
|
||||
|
||||
2009-08-23 Simon Goldschmidt
|
||||
* ppp.c: bug #27266: wait-state debug message in pppMain occurs every ms
|
||||
|
||||
2009-08-23 Simon Goldschmidt
|
||||
* many ppp files: bug #27267: Added include to string.h where needed
|
||||
|
||||
2009-08-23 Simon Goldschmidt
|
||||
* tcp.h: patch #6843: tcp.h macro optimization patch (for little endian)
|
||||
|
||||
|
||||
(STABLE-1.3.1)
|
||||
|
||||
++ New features:
|
||||
|
||||
2009-05-10 Simon Goldschmidt
|
||||
* opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option
|
||||
LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only
|
||||
one pbuf to help MACs that don't support scatter-gather DMA.
|
||||
|
||||
2009-05-09 Simon Goldschmidt
|
||||
* icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming
|
||||
ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||
|
||||
2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen
|
||||
* ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive
|
||||
extended info about the currently received packet.
|
||||
|
||||
2009-04-27 Simon Goldschmidt
|
||||
* sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1
|
||||
|
||||
2009-04-25 Simon Goldschmidt
|
||||
* mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next
|
||||
bigger malloc pool if one is empty (only usable with MEM_USE_POOLS).
|
||||
|
||||
2009-04-21 Simon Goldschmidt
|
||||
* dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static
|
||||
hosts table. New configuration options DNS_LOCAL_HOSTLIST and
|
||||
DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined
|
||||
as an external function for lookup.
|
||||
|
||||
2009-04-15 Simon Goldschmidt
|
||||
* dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique
|
||||
|
||||
2009-03-31 Kieran Mansley
|
||||
* tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for
|
||||
TCP timestamp options, off by default. Rework tcp_enqueue() to
|
||||
take option flags rather than specified option data
|
||||
|
||||
2009-02-18 Simon Goldschmidt
|
||||
* cc.h: Added printf formatter for size_t: SZT_F
|
||||
|
||||
2009-02-16 Simon Goldschmidt (patch by Rishi Khan)
|
||||
* icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast
|
||||
pings
|
||||
|
||||
2009-02-12 Simon Goldschmidt
|
||||
* init.h: Added LWIP_VERSION to get the current version of the stack
|
||||
|
||||
2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler)
|
||||
* opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead
|
||||
of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc
|
||||
is otherwise used)
|
||||
|
||||
2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach)
|
||||
* ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial()
|
||||
is only used by UDPLITE at present, so conditionalise it.
|
||||
|
||||
2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli)
|
||||
* autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP
|
||||
"seed" address. This should reduce AUTOIP conflicts if
|
||||
LWIP_AUTOIP_CREATE_SEED_ADDR is overridden.
|
||||
|
||||
2008-10-02 Jonathan Larmour and Rishi Khan
|
||||
* sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking
|
||||
socket.
|
||||
|
||||
2008-06-30 Simon Goldschmidt
|
||||
* mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from
|
||||
interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows
|
||||
mem_free to run between mem_malloc iterations. Added illegal counter for
|
||||
mem stats.
|
||||
|
||||
2008-06-27 Simon Goldschmidt
|
||||
* stats.h/.c, some other files: patch #6483: stats module improvement:
|
||||
Added defines to display each module's statistic individually, added stats
|
||||
defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter.
|
||||
|
||||
2008-06-17 Simon Goldschmidt
|
||||
* err.h: patch #6459: Made err_t overridable to use a more efficient type
|
||||
(define LWIP_ERR_T in cc.h)
|
||||
|
||||
2008-06-17 Simon Goldschmidt
|
||||
* slipif.c: patch #6480: Added a configuration option for slipif for symmetry
|
||||
to loopif
|
||||
|
||||
2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli)
|
||||
* netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly
|
||||
modified version of patch # 6370: Moved loopif code to netif.c so that
|
||||
loopback traffic is supported on all netifs (all local IPs).
|
||||
Added option to limit loopback packets for each netifs.
|
||||
|
||||
|
||||
++ Bugfixes:
|
||||
2009-08-12 Kieran Mansley
|
||||
* tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when
|
||||
out of window or out of order properly
|
||||
|
||||
2009-08-12 Kieran Mansley
|
||||
* tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1
|
||||
|
||||
2009-07-28 Simon Goldschmidt
|
||||
* mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s
|
||||
|
||||
2009-07-27 Kieran Mansley
|
||||
* api.h api_msg.h netdb.h sockets.h: add missing #include directives
|
||||
|
||||
2009-07-09 Kieran Mansley
|
||||
* api_msg.c, sockets.c, api.h: BUG23240 use signed counters for
|
||||
recv_avail and don't increment counters until message successfully
|
||||
sent to mbox
|
||||
|
||||
2009-06-25 Kieran Mansley
|
||||
* api_msg.c api.h: BUG26722: initialise netconn write variables
|
||||
in netconn_alloc
|
||||
|
||||
2009-06-25 Kieran Mansley
|
||||
* tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set
|
||||
|
||||
2009-06-25 Kieran Mansley
|
||||
* tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct
|
||||
simultaneous close behaviour, and make snd_nxt have the same meaning
|
||||
as in the RFCs.
|
||||
|
||||
2009-05-12 Simon Goldschmidt
|
||||
* etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on
|
||||
arp_table / uses etharp_query" by adding etharp_gratuitous()
|
||||
|
||||
2009-05-12 Simon Goldschmidt
|
||||
* ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options
|
||||
to the IP header (used by igmp_ip_output_if)
|
||||
|
||||
2009-05-06 Simon Goldschmidt
|
||||
* inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if
|
||||
defined) for SWAP_BYTES_IN_WORD to speed up checksumming.
|
||||
|
||||
2009-05-05 Simon Goldschmidt
|
||||
* sockets.c: bug #26405: Prematurely released semaphore causes lwip_select()
|
||||
to crash
|
||||
|
||||
2009-05-04 Simon Goldschmidt
|
||||
* init.c: snmp was not initialized in lwip_init()
|
||||
|
||||
2009-05-04 Fr<46>d<EFBFBD>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<46>d<EFBFBD>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<46>d<EFBFBD>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<46>d<EFBFBD>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<46>d<EFBFBD>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)
|
||||
|
||||
++ New features:
|
||||
|
||||
2
README
2
README
@@ -72,7 +72,7 @@ current CVS sources and is available from this web page:
|
||||
http://www.nongnu.org/lwip/
|
||||
|
||||
There is now a constantly growin wiki about lwIP at
|
||||
http://lwip.scribblewiki.com/
|
||||
http://lwip.wikia.com/wiki/LwIP_Wiki
|
||||
|
||||
Also, there are mailing lists you can subscribe at
|
||||
http://savannah.nongnu.org/mail/?group=lwip
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
savannah.txt - How to obtain the current development source code.
|
||||
contrib.txt - How to contribute to lwIP as a developer.
|
||||
rawapi.txt - The documentation for the core API of lwIP.
|
||||
Also provides an overview about the other APIs and multithreading.
|
||||
snmp_agent.txt - The documentation for the lwIP SNMP agent.
|
||||
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
|
||||
|
||||
@@ -2,10 +2,11 @@ Raw TCP/IP interface for lwIP
|
||||
|
||||
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
|
||||
|
||||
lwIP provides two Application Program's Interfaces (APIs) for programs
|
||||
lwIP provides three Application Program's Interfaces (APIs) for programs
|
||||
to use for communication with the TCP/IP code:
|
||||
* low-level "core" / "callback" or "raw" API.
|
||||
* higher-level "sequential" API.
|
||||
* BSD-style socket API.
|
||||
|
||||
The sequential API provides a way for ordinary, sequential, programs
|
||||
to use the lwIP stack. It is quite similar to the BSD socket API. The
|
||||
@@ -14,6 +15,45 @@ paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
|
||||
code and the application program must reside in different execution
|
||||
contexts (threads).
|
||||
|
||||
The socket API is a compatibility API for existing applications,
|
||||
currently it is built on top of the sequential API. It is meant to
|
||||
provide all functions needed to run socket API applications running
|
||||
on other platforms (e.g. unix / windows etc.). However, due to limitations
|
||||
in the specification of this API, there might be incompatibilities
|
||||
that require small modifications of existing programs.
|
||||
|
||||
** Threading
|
||||
|
||||
lwIP started targeting single-threaded environments. When adding multi-
|
||||
threading support, instead of making the core thread-safe, another
|
||||
approach was chosen: there is one main thread running the lwIP core
|
||||
(also known as the "tcpip_thread"). The raw API may only be used from
|
||||
this thread! Application threads using the sequential- or socket API
|
||||
communicate with this main thread through message passing.
|
||||
|
||||
As such, the list of functions that may be called from
|
||||
other threads or an ISR is very limited! Only functions
|
||||
from these API header files are thread-safe:
|
||||
- api.h
|
||||
- netbuf.h
|
||||
- netdb.h
|
||||
- netifapi.h
|
||||
- sockets.h
|
||||
- sys.h
|
||||
|
||||
Additionaly, memory (de-)allocation functions may be
|
||||
called from multiple threads (not ISR!) with NO_SYS=0
|
||||
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
|
||||
semaphores.
|
||||
|
||||
Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
|
||||
and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
|
||||
pbuf_free() may also be called from another thread or
|
||||
an ISR (since only then, mem_free - for PBUF_RAM - may
|
||||
be called from an ISR: otherwise, the HEAP is only
|
||||
protected by semaphores).
|
||||
|
||||
|
||||
** The remainder of this document discusses the "raw" API. **
|
||||
|
||||
The raw TCP/IP interface allows the application program to integrate
|
||||
@@ -128,8 +168,9 @@ incoming connections or be explicitly connected to another host.
|
||||
function specified as the fourth argument (the "connected" argument)
|
||||
when the connection is established. If the connection could not be
|
||||
properly established, either because the other host refused the
|
||||
connection or because the other host didn't answer, the "connected"
|
||||
function will be called with an the "err" argument set accordingly.
|
||||
connection or because the other host didn't answer, the "err"
|
||||
callback function of this pcb (registered with tcp_err, see below)
|
||||
will be called.
|
||||
|
||||
The tcp_connect() function can return ERR_MEM if no memory is
|
||||
available for enqueueing the SYN segment. If the SYN indeed was
|
||||
|
||||
@@ -195,6 +195,8 @@ cc.h - Architecture environment, some compiler specific, some
|
||||
Platform specific diagnostic output -
|
||||
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
|
||||
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
|
||||
Portability defines for printf formatters:
|
||||
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
|
||||
|
||||
"lightweight" synchronization mechanisms -
|
||||
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
|
||||
|
||||
@@ -119,19 +119,6 @@ netconn_delete(struct netconn *conn)
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of a netconn (as enum netconn_type).
|
||||
*
|
||||
* @param conn the netconn of which to get the type
|
||||
* @return the netconn_type of conn
|
||||
*/
|
||||
enum netconn_type
|
||||
netconn_type(struct netconn *conn)
|
||||
{
|
||||
LWIP_ERROR("netconn_type: invalid conn", (conn != NULL), return NETCONN_INVALID;);
|
||||
return conn->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local or remote IP address and port of a netconn.
|
||||
* For RAW netconns, this returns the protocol instead of a port!
|
||||
@@ -340,8 +327,9 @@ netconn_recv(struct netconn *conn)
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
|
||||
memp_free(MEMP_NETBUF, buf);
|
||||
conn->err = ERR_TIMEOUT;
|
||||
p = NULL;
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);
|
||||
@@ -439,7 +427,7 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
|
||||
|
||||
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
|
||||
msg.function = do_send;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.b = buf;
|
||||
@@ -459,7 +447,7 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
|
||||
* @return ERR_OK if data was sent, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags)
|
||||
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
|
||||
{
|
||||
struct api_msg msg;
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* forward declarations */
|
||||
#if LWIP_TCP
|
||||
static err_t do_writemore(struct netconn *conn);
|
||||
@@ -108,11 +110,13 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
|
||||
buf->addr = &(((struct ip_hdr*)(q->payload))->src);
|
||||
buf->port = pcb->protocol;
|
||||
|
||||
SYS_ARCH_INC(conn->recv_avail, q->tot_len);
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
|
||||
if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
|
||||
netbuf_delete(buf);
|
||||
return 0;
|
||||
} else {
|
||||
SYS_ARCH_INC(conn->recv_avail, q->tot_len);
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,14 +168,24 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
|
||||
buf->ptr = p;
|
||||
buf->addr = addr;
|
||||
buf->port = port;
|
||||
#if LWIP_NETBUF_RECVINFO
|
||||
{
|
||||
const struct ip_hdr* iphdr = ip_current_header();
|
||||
/* get the UDP header - always in the first pbuf, ensured by udp_input */
|
||||
const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
|
||||
buf->toaddr = (struct ip_addr*)&iphdr->dest;
|
||||
buf->toport = udphdr->dest;
|
||||
}
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
}
|
||||
|
||||
SYS_ARCH_INC(conn->recv_avail, p->tot_len);
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
|
||||
if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
|
||||
netbuf_delete(buf);
|
||||
return;
|
||||
} else {
|
||||
SYS_ARCH_INC(conn->recv_avail, p->tot_len);
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_UDP */
|
||||
@@ -206,10 +220,12 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
|
||||
|
||||
if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
|
||||
return ERR_MEM;
|
||||
} else {
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
@@ -365,8 +381,6 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
newconn->pcb.tcp = newpcb;
|
||||
setup_tcp(newconn);
|
||||
newconn->err = err;
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
|
||||
|
||||
if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
|
||||
/* When returning != ERR_OK, the connection is aborted in tcp_process(),
|
||||
@@ -374,7 +388,11 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
newconn->pcb.tcp = NULL;
|
||||
netconn_free(newconn);
|
||||
return ERR_MEM;
|
||||
} else {
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
@@ -528,11 +546,18 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
|
||||
conn->socket = -1;
|
||||
conn->callback = callback;
|
||||
conn->recv_avail = 0;
|
||||
#if LWIP_TCP
|
||||
conn->write_msg = NULL;
|
||||
conn->write_offset = 0;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->write_delayed = 0;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
conn->recv_timeout = 0;
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
#if LWIP_SO_RCVBUF
|
||||
conn->recv_bufsize = INT_MAX;
|
||||
conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
return conn;
|
||||
}
|
||||
@@ -598,11 +623,16 @@ do_close_internal(struct netconn *conn)
|
||||
LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
|
||||
|
||||
/* Set back some callback pointers */
|
||||
tcp_arg(conn->pcb.tcp, NULL);
|
||||
if (conn->pcb.tcp->state == LISTEN) {
|
||||
tcp_arg(conn->pcb.tcp, NULL);
|
||||
tcp_accept(conn->pcb.tcp, NULL);
|
||||
} else {
|
||||
tcp_recv(conn->pcb.tcp, NULL);
|
||||
tcp_accept(conn->pcb.tcp, NULL);
|
||||
/* some callbacks have to be reset if tcp_close is not successful */
|
||||
tcp_sent(conn->pcb.tcp, NULL);
|
||||
tcp_poll(conn->pcb.tcp, NULL, 4);
|
||||
tcp_err(conn->pcb.tcp, NULL);
|
||||
}
|
||||
/* Try to close the connection */
|
||||
err = tcp_close(conn->pcb.tcp);
|
||||
@@ -610,11 +640,6 @@ do_close_internal(struct netconn *conn)
|
||||
/* Closing succeeded */
|
||||
conn->state = NETCONN_NONE;
|
||||
/* Set back some callback pointers as conn is going away */
|
||||
tcp_err(conn->pcb.tcp, NULL);
|
||||
tcp_poll(conn->pcb.tcp, NULL, 4);
|
||||
tcp_sent(conn->pcb.tcp, NULL);
|
||||
tcp_recv(conn->pcb.tcp, NULL);
|
||||
tcp_arg(conn->pcb.tcp, NULL);
|
||||
conn->pcb.tcp = NULL;
|
||||
conn->err = ERR_OK;
|
||||
/* Trigger select() in socket layer. This send should something else so the
|
||||
@@ -623,6 +648,14 @@ do_close_internal(struct netconn *conn)
|
||||
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
|
||||
/* wake up the application task */
|
||||
sys_sem_signal(conn->op_completed);
|
||||
} else {
|
||||
/* Closing failed, restore some of the callbacks */
|
||||
/* Closing of listen pcb will never fail! */
|
||||
LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
|
||||
tcp_sent(conn->pcb.tcp, sent_tcp);
|
||||
tcp_poll(conn->pcb.tcp, poll_tcp, 4);
|
||||
tcp_err(conn->pcb.tcp, err_tcp);
|
||||
tcp_arg(conn->pcb.tcp, conn);
|
||||
}
|
||||
/* If closing didn't succeed, we get called again either
|
||||
from poll_tcp or from sent_tcp */
|
||||
@@ -783,6 +816,8 @@ do_connect(struct api_msg_msg *msg)
|
||||
break;
|
||||
#endif /* LWIP_TCP */
|
||||
default:
|
||||
LWIP_ERROR("Invalid netconn type", 0, do{ msg->conn->err = ERR_VAL;
|
||||
sys_sem_signal(msg->conn->op_completed); }while(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -894,7 +929,7 @@ do_send(struct api_msg_msg *msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Recv some data from a RAW or UDP pcb contained in a netconn
|
||||
* Indicate data has been received from a TCP pcb contained in a netconn
|
||||
* Called from netconn_recv
|
||||
*
|
||||
* @param msg the api_msg_msg pointing to the connection
|
||||
@@ -940,17 +975,19 @@ do_writemore(struct netconn *conn)
|
||||
void *dataptr;
|
||||
u16_t len, available;
|
||||
u8_t write_finished = 0;
|
||||
size_t diff;
|
||||
|
||||
LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
|
||||
|
||||
dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset;
|
||||
if ((conn->write_msg->msg.w.len - conn->write_offset > 0xffff)) { /* max_u16_t */
|
||||
diff = conn->write_msg->msg.w.len - conn->write_offset;
|
||||
if (diff > 0xffffUL) { /* max_u16_t */
|
||||
len = 0xffff;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->write_delayed = 1;
|
||||
#endif
|
||||
} else {
|
||||
len = conn->write_msg->msg.w.len - conn->write_offset;
|
||||
len = (u16_t)diff;
|
||||
}
|
||||
available = tcp_sndbuf(conn->pcb.tcp);
|
||||
if (available < len) {
|
||||
@@ -970,6 +1007,8 @@ do_writemore(struct netconn *conn)
|
||||
write_finished = 1;
|
||||
conn->write_msg = NULL;
|
||||
conn->write_offset = 0;
|
||||
/* API_EVENT might call tcp_tmr, so reset conn->state now */
|
||||
conn->state = NETCONN_NONE;
|
||||
}
|
||||
err = tcp_output_nagle(conn->pcb.tcp);
|
||||
conn->err = err;
|
||||
@@ -1027,6 +1066,8 @@ do_write(struct api_msg_msg *msg)
|
||||
#if LWIP_TCP
|
||||
msg->conn->state = NETCONN_WRITE;
|
||||
/* set all the variables used by do_writemore */
|
||||
LWIP_ASSERT("already writing", msg->conn->write_msg == NULL &&
|
||||
msg->conn->write_offset == 0);
|
||||
msg->conn->write_msg = msg;
|
||||
msg->conn->write_offset = 0;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
@@ -1119,7 +1160,7 @@ do_close(struct api_msg_msg *msg)
|
||||
#endif /* LWIP_TCP */
|
||||
{
|
||||
msg->conn->err = ERR_VAL;
|
||||
TCPIP_APIMSG_ACK(msg);
|
||||
sys_sem_signal(msg->conn->op_completed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,17 +44,17 @@ static const char *err_strerr[] = {
|
||||
"Ok.", /* ERR_OK 0 */
|
||||
"Out of memory error.", /* ERR_MEM -1 */
|
||||
"Buffer error.", /* ERR_BUF -2 */
|
||||
"Routing problem.", /* ERR_RTE -3 */
|
||||
"Connection aborted.", /* ERR_ABRT -4 */
|
||||
"Connection reset.", /* ERR_RST -5 */
|
||||
"Connection closed.", /* ERR_CLSD -6 */
|
||||
"Not connected.", /* ERR_CONN -7 */
|
||||
"Illegal value.", /* ERR_VAL -8 */
|
||||
"Illegal argument.", /* ERR_ARG -9 */
|
||||
"Address in use.", /* ERR_USE -10 */
|
||||
"Low-level netif error.", /* ERR_IF -11 */
|
||||
"Already connected.", /* ERR_ISCONN -12 */
|
||||
"Timeout.", /* ERR_TIMEOUT -13 */
|
||||
"Timeout.", /* ERR_TIMEOUT -3 */
|
||||
"Routing problem.", /* ERR_RTE -4 */
|
||||
"Connection aborted.", /* ERR_ABRT -5 */
|
||||
"Connection reset.", /* ERR_RST -6 */
|
||||
"Connection closed.", /* ERR_CLSD -7 */
|
||||
"Not connected.", /* ERR_CONN -8 */
|
||||
"Illegal value.", /* ERR_VAL -9 */
|
||||
"Illegal argument.", /* ERR_ARG -10 */
|
||||
"Address in use.", /* ERR_USE -11 */
|
||||
"Low-level netif error.", /* ERR_IF -12 */
|
||||
"Already connected.", /* ERR_ISCONN -13 */
|
||||
"Operation in progress." /* ERR_INPROGRESS -14 */
|
||||
};
|
||||
|
||||
|
||||
@@ -62,6 +62,11 @@ netbuf *netbuf_new(void)
|
||||
buf->p = NULL;
|
||||
buf->ptr = NULL;
|
||||
buf->addr = NULL;
|
||||
buf->port = 0;
|
||||
#if LWIP_NETBUF_RECVINFO
|
||||
buf->toaddr = NULL;
|
||||
buf->toport = 0;
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
return buf;
|
||||
} else {
|
||||
return NULL;
|
||||
@@ -158,14 +163,14 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
||||
* Chain one netbuf to another (@see pbuf_chain)
|
||||
*
|
||||
* @param head the first netbuf
|
||||
* @param tail netbuf to chain after head
|
||||
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
|
||||
*/
|
||||
void
|
||||
netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
||||
{
|
||||
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
|
||||
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
|
||||
pbuf_chain(head->p, tail->p);
|
||||
pbuf_cat(head->p, tail->p);
|
||||
head->ptr = head->p;
|
||||
memp_free(MEMP_NETBUF, tail);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** helper struct for gethostbyname_r to access the char* buffer */
|
||||
struct gethostbyname_r_helper {
|
||||
struct ip_addr *addrs;
|
||||
@@ -107,23 +110,23 @@ lwip_gethostbyname(const char *name)
|
||||
|
||||
#if DNS_DEBUG
|
||||
/* dump hostent */
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == 0x%08lX\n",(u32_t)(s_hostent.h_aliases)));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
|
||||
if (s_hostent.h_aliases != NULL) {
|
||||
u8_t idx;
|
||||
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == 0x%08lX\n", idx, s_hostent.h_aliases[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
|
||||
}
|
||||
}
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %lu\n", (u32_t)(s_hostent.h_addrtype)));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %lu\n", (u32_t)(s_hostent.h_length)));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == 0x%08lX\n", s_hostent.h_addr_list));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
|
||||
if (s_hostent.h_addr_list != NULL) {
|
||||
u8_t idx;
|
||||
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == 0x%08lX\n", idx, s_hostent.h_addr_list[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa(s_hostent.h_addr_list[idx])));
|
||||
}
|
||||
}
|
||||
#endif /* DNS_DEBUG */
|
||||
@@ -231,12 +234,6 @@ lwip_freeaddrinfo(struct addrinfo *ai)
|
||||
struct addrinfo *next;
|
||||
|
||||
while (ai != NULL) {
|
||||
if (ai->ai_addr != NULL) {
|
||||
mem_free(ai->ai_addr);
|
||||
}
|
||||
if (ai->ai_canonname != NULL) {
|
||||
mem_free(ai->ai_canonname);
|
||||
}
|
||||
next = ai->ai_next;
|
||||
mem_free(ai);
|
||||
ai = next;
|
||||
@@ -271,6 +268,8 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
struct addrinfo *ai;
|
||||
struct sockaddr_in *sa = NULL;
|
||||
int port_nr = 0;
|
||||
size_t total_size;
|
||||
size_t namelen = 0;
|
||||
|
||||
if (res == NULL) {
|
||||
return EAI_FAIL;
|
||||
@@ -297,19 +296,21 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
}
|
||||
} else {
|
||||
/* service location specified, use loopback address */
|
||||
addr.addr = INADDR_LOOPBACK;
|
||||
addr.addr = htonl(INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
ai = mem_malloc(sizeof(struct addrinfo));
|
||||
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
|
||||
if (nodename != NULL) {
|
||||
namelen = strlen(nodename);
|
||||
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
|
||||
total_size += namelen + 1;
|
||||
}
|
||||
ai = mem_malloc(total_size);
|
||||
if (ai == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
memset(ai, 0, sizeof(struct addrinfo));
|
||||
sa = mem_malloc(sizeof(struct sockaddr_in));
|
||||
if (sa == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
memset(sa, 0, sizeof(struct sockaddr_in));
|
||||
memset(ai, 0, total_size);
|
||||
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
|
||||
/* set up sockaddr */
|
||||
sa->sin_addr.s_addr = addr.addr;
|
||||
sa->sin_family = AF_INET;
|
||||
@@ -325,11 +326,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
}
|
||||
if (nodename != NULL) {
|
||||
/* copy nodename to canonname if specified */
|
||||
size_t namelen = strlen(nodename);
|
||||
ai->ai_canonname = mem_malloc(namelen + 1);
|
||||
if (ai->ai_canonname == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
||||
MEMCPY(ai->ai_canonname, nodename, namelen);
|
||||
ai->ai_canonname[namelen] = 0;
|
||||
}
|
||||
@@ -343,9 +340,6 @@ memerr:
|
||||
if (ai != NULL) {
|
||||
mem_free(ai);
|
||||
}
|
||||
if (sa != NULL) {
|
||||
mem_free(sa);
|
||||
}
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,20 @@ do_netifapi_netif_add( struct netifapi_msg_msg *msg)
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_set_addr() inside the tcpip_thread context.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_set_addr( struct netifapi_msg_msg *msg)
|
||||
{
|
||||
netif_set_addr( msg->netif,
|
||||
msg->msg.add.ipaddr,
|
||||
msg->msg.add.netmask,
|
||||
msg->msg.add.gw);
|
||||
msg->err = ERR_OK;
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
|
||||
* tcpip_thread context.
|
||||
@@ -103,6 +117,28 @@ netifapi_netif_add(struct netif *netif,
|
||||
return msg.msg.err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_set_addr() in a thread-safe way by running that function inside the
|
||||
* tcpip_thread context.
|
||||
*
|
||||
* @note for params @see netif_set_addr()
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_set_addr(struct netif *netif,
|
||||
struct ip_addr *ipaddr,
|
||||
struct ip_addr *netmask,
|
||||
struct ip_addr *gw)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_set_addr;
|
||||
msg.msg.netif = netif;
|
||||
msg.msg.msg.add.ipaddr = ipaddr;
|
||||
msg.msg.msg.add.netmask = netmask;
|
||||
msg.msg.msg.add.gw = gw;
|
||||
TCPIP_NETIFAPI(&msg);
|
||||
return msg.msg.err;
|
||||
}
|
||||
|
||||
/**
|
||||
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
|
||||
* way by running that function inside the tcpip_thread context.
|
||||
|
||||
@@ -66,7 +66,7 @@ struct lwip_socket {
|
||||
u16_t lastoffset;
|
||||
/** number of times data was received, set by event_callback(),
|
||||
tested by the receive and select functions */
|
||||
u16_t rcvevent;
|
||||
s16_t rcvevent;
|
||||
/** number of times data was received, set by event_callback(),
|
||||
tested by select */
|
||||
u16_t sendevent;
|
||||
@@ -128,17 +128,17 @@ static const int err_to_errno_table[] = {
|
||||
0, /* ERR_OK 0 No error, everything OK. */
|
||||
ENOMEM, /* ERR_MEM -1 Out of memory error. */
|
||||
ENOBUFS, /* ERR_BUF -2 Buffer error. */
|
||||
EHOSTUNREACH, /* ERR_RTE -3 Routing problem. */
|
||||
ECONNABORTED, /* ERR_ABRT -4 Connection aborted. */
|
||||
ECONNRESET, /* ERR_RST -5 Connection reset. */
|
||||
ESHUTDOWN, /* ERR_CLSD -6 Connection closed. */
|
||||
ENOTCONN, /* ERR_CONN -7 Not connected. */
|
||||
EINVAL, /* ERR_VAL -8 Illegal value. */
|
||||
EIO, /* ERR_ARG -9 Illegal argument. */
|
||||
EADDRINUSE, /* ERR_USE -10 Address in use. */
|
||||
-1, /* ERR_IF -11 Low-level netif error */
|
||||
-1, /* ERR_ISCONN -12 Already connected. */
|
||||
ETIMEDOUT, /* ERR_TIMEOUT -13 Timeout */
|
||||
ETIMEDOUT, /* ERR_TIMEOUT -3 Timeout */
|
||||
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
|
||||
ECONNABORTED, /* ERR_ABRT -5 Connection aborted. */
|
||||
ECONNRESET, /* ERR_RST -6 Connection reset. */
|
||||
ESHUTDOWN, /* ERR_CLSD -7 Connection closed. */
|
||||
ENOTCONN, /* ERR_CONN -8 Not connected. */
|
||||
EINVAL, /* ERR_VAL -9 Illegal value. */
|
||||
EIO, /* ERR_ARG -10 Illegal argument. */
|
||||
EADDRINUSE, /* ERR_USE -11 Address in use. */
|
||||
-1, /* ERR_IF -12 Low-level netif error */
|
||||
-1, /* ERR_ISCONN -13 Already connected. */
|
||||
EINPROGRESS /* ERR_INPROGRESS -14 Operation in progress */
|
||||
};
|
||||
|
||||
@@ -150,7 +150,9 @@ static const int err_to_errno_table[] = {
|
||||
err_to_errno_table[-(err)] : EIO)
|
||||
|
||||
#ifdef ERRNO
|
||||
#ifndef set_errno
|
||||
#define set_errno(err) errno = (err)
|
||||
#endif
|
||||
#else
|
||||
#define set_errno(err)
|
||||
#endif
|
||||
@@ -258,6 +260,12 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
if (!sock)
|
||||
return -1;
|
||||
|
||||
if ((sock->flags & O_NONBLOCK) && (sock->rcvevent <= 0)) {
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
|
||||
sock_set_errno(sock, EWOULDBLOCK);
|
||||
return -1;
|
||||
}
|
||||
|
||||
newconn = netconn_accept(sock->conn);
|
||||
if (!newconn) {
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err));
|
||||
@@ -273,16 +281,22 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
sin.sin_addr.s_addr = naddr.addr;
|
||||
/* Note that POSIX only requires us to check addr is non-NULL. addrlen must
|
||||
* not be NULL if addr is valid.
|
||||
*/
|
||||
if (NULL != addr) {
|
||||
LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
sin.sin_addr.s_addr = naddr.addr;
|
||||
|
||||
if (*addrlen > sizeof(sin))
|
||||
*addrlen = sizeof(sin);
|
||||
if (*addrlen > sizeof(sin))
|
||||
*addrlen = sizeof(sin);
|
||||
|
||||
SMEMCPY(addr, &sin, *addrlen);
|
||||
MEMCPY(addr, &sin, *addrlen);
|
||||
}
|
||||
|
||||
newsock = alloc_socket(newconn);
|
||||
if (newsock == -1) {
|
||||
@@ -307,14 +321,14 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
|
||||
|
||||
sock_set_errno(sock, 0);
|
||||
return newsock;
|
||||
}
|
||||
|
||||
int
|
||||
lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
|
||||
lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
|
||||
{
|
||||
struct lwip_socket *sock;
|
||||
struct ip_addr local_addr;
|
||||
@@ -326,15 +340,15 @@ lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
|
||||
return -1;
|
||||
|
||||
LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
|
||||
((((struct sockaddr_in *)name)->sin_family) == AF_INET)),
|
||||
((((const struct sockaddr_in *)name)->sin_family) == AF_INET)),
|
||||
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
|
||||
|
||||
local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
|
||||
local_port = ((struct sockaddr_in *)name)->sin_port;
|
||||
local_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr;
|
||||
local_port = ((const struct sockaddr_in *)name)->sin_port;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
|
||||
|
||||
err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
|
||||
|
||||
@@ -386,22 +400,22 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
|
||||
return -1;
|
||||
|
||||
LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
|
||||
((((struct sockaddr_in *)name)->sin_family) == AF_INET)),
|
||||
((((const struct sockaddr_in *)name)->sin_family) == AF_INET)),
|
||||
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
|
||||
|
||||
if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
|
||||
if (((const struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
|
||||
err = netconn_disconnect(sock->conn);
|
||||
} else {
|
||||
struct ip_addr remote_addr;
|
||||
u16_t remote_port;
|
||||
|
||||
remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
|
||||
remote_port = ((struct sockaddr_in *)name)->sin_port;
|
||||
remote_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr;
|
||||
remote_port = ((const struct sockaddr_in *)name)->sin_port;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
|
||||
|
||||
err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
|
||||
}
|
||||
@@ -458,7 +472,7 @@ lwip_listen(int s, int backlog)
|
||||
}
|
||||
|
||||
int
|
||||
lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||
lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
struct lwip_socket *sock;
|
||||
@@ -468,7 +482,7 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||
u16_t port;
|
||||
u8_t done = 0;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
|
||||
sock = get_socket(s);
|
||||
if (!sock)
|
||||
return -1;
|
||||
@@ -480,7 +494,13 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||
buf = sock->lastdata;
|
||||
} else {
|
||||
/* If this is non-blocking call, then check first */
|
||||
if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) {
|
||||
if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) &&
|
||||
(sock->rcvevent <= 0)) {
|
||||
if (off > 0) {
|
||||
/* already received data, return that */
|
||||
sock_set_errno(sock, 0);
|
||||
return off;
|
||||
}
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
|
||||
sock_set_errno(sock, EWOULDBLOCK);
|
||||
return -1;
|
||||
@@ -492,22 +512,29 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf));
|
||||
|
||||
if (!buf) {
|
||||
if (off > 0) {
|
||||
/* already received data, return that */
|
||||
sock_set_errno(sock, 0);
|
||||
return off;
|
||||
}
|
||||
/* We should really do some error checking here. */
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
|
||||
sock_set_errno(sock, (((sock->conn->pcb.ip!=NULL) && (sock->conn->err==ERR_OK))?ETIMEDOUT:err_to_errno(sock->conn->err)));
|
||||
sock_set_errno(sock, (((sock->conn->pcb.ip != NULL) && (sock->conn->err == ERR_OK))
|
||||
? ETIMEDOUT : err_to_errno(sock->conn->err)));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
buflen = netbuf_len(buf);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%d len=%d off=%d sock->lastoffset=%d\n", buflen, len, off, sock->lastoffset));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%"U16_F" sock->lastoffset=%"U16_F"\n",
|
||||
buflen, len, off, sock->lastoffset));
|
||||
|
||||
buflen -= sock->lastoffset;
|
||||
|
||||
if (len > buflen) {
|
||||
copylen = buflen;
|
||||
} else {
|
||||
copylen = len;
|
||||
copylen = (u16_t)len;
|
||||
}
|
||||
|
||||
/* copy the contents of the received buffer into
|
||||
@@ -517,20 +544,71 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||
off += copylen;
|
||||
|
||||
if (netconn_type(sock->conn) == NETCONN_TCP) {
|
||||
LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
|
||||
len -= copylen;
|
||||
if ( (len <= 0) || (buf->p->flags & PBUF_FLAG_PUSH) || !sock->rcvevent) {
|
||||
if ( (len <= 0) ||
|
||||
(buf->p->flags & PBUF_FLAG_PUSH) ||
|
||||
(sock->rcvevent <= 0) ||
|
||||
((flags & MSG_PEEK)!=0)) {
|
||||
done = 1;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
|
||||
/* Check to see from where the data was.*/
|
||||
if (done) {
|
||||
if (from && fromlen) {
|
||||
struct sockaddr_in sin;
|
||||
|
||||
if (netconn_type(sock->conn) == NETCONN_TCP) {
|
||||
addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
|
||||
netconn_getaddr(sock->conn, addr, &port, 0);
|
||||
} else {
|
||||
addr = netbuf_fromaddr(buf);
|
||||
port = netbuf_fromport(buf);
|
||||
}
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
sin.sin_addr.s_addr = addr->addr;
|
||||
|
||||
if (*fromlen > sizeof(sin)) {
|
||||
*fromlen = sizeof(sin);
|
||||
}
|
||||
|
||||
MEMCPY(from, &sin, *fromlen);
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off));
|
||||
} else {
|
||||
#if SOCKETS_DEBUG
|
||||
struct sockaddr_in sin;
|
||||
|
||||
if (netconn_type(sock->conn) == NETCONN_TCP) {
|
||||
addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
|
||||
netconn_getaddr(sock->conn, addr, &port, 0);
|
||||
} else {
|
||||
addr = netbuf_fromaddr(buf);
|
||||
port = netbuf_fromport(buf);
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off));
|
||||
#endif /* SOCKETS_DEBUG */
|
||||
}
|
||||
}
|
||||
|
||||
/* If we don't peek the incoming message... */
|
||||
if ((flags & MSG_PEEK)==0) {
|
||||
/* If this is a TCP socket, check if there is data left in the
|
||||
buffer. If so, it should be saved in the sock structure for next
|
||||
time around. */
|
||||
if ((sock->conn->type == NETCONN_TCP) && (buflen - copylen > 0)) {
|
||||
if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
|
||||
sock->lastdata = buf;
|
||||
sock->lastoffset += copylen;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf));
|
||||
@@ -540,85 +618,39 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf));
|
||||
netbuf_delete(buf);
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
/* Check to see from where the data was.*/
|
||||
if (from && fromlen) {
|
||||
struct sockaddr_in sin;
|
||||
|
||||
if (netconn_type(sock->conn) == NETCONN_TCP) {
|
||||
addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
|
||||
netconn_getaddr(sock->conn, addr, &port, 0);
|
||||
} else {
|
||||
addr = netbuf_fromaddr(buf);
|
||||
port = netbuf_fromport(buf);
|
||||
}
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
sin.sin_addr.s_addr = addr->addr;
|
||||
|
||||
if (*fromlen > sizeof(sin))
|
||||
*fromlen = sizeof(sin);
|
||||
|
||||
SMEMCPY(from, &sin, *fromlen);
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off));
|
||||
} else {
|
||||
#if SOCKETS_DEBUG
|
||||
struct sockaddr_in sin;
|
||||
|
||||
if (netconn_type(sock->conn) == NETCONN_TCP) {
|
||||
addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
|
||||
netconn_getaddr(sock->conn, addr, &port, 0);
|
||||
} else {
|
||||
addr = netbuf_fromaddr(buf);
|
||||
port = netbuf_fromport(buf);
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off));
|
||||
#endif /* SOCKETS_DEBUG */
|
||||
}
|
||||
|
||||
sock_set_errno(sock, 0);
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
lwip_read(int s, void *mem, int len)
|
||||
lwip_read(int s, void *mem, size_t len)
|
||||
{
|
||||
return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
lwip_recv(int s, void *mem, int len, unsigned int flags)
|
||||
lwip_recv(int s, void *mem, size_t len, int flags)
|
||||
{
|
||||
return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
lwip_send(int s, const void *data, int size, unsigned int flags)
|
||||
lwip_send(int s, const void *data, size_t size, int flags)
|
||||
{
|
||||
struct lwip_socket *sock;
|
||||
err_t err;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
|
||||
s, data, size, flags));
|
||||
|
||||
sock = get_socket(s);
|
||||
if (!sock)
|
||||
return -1;
|
||||
|
||||
if (sock->conn->type!=NETCONN_TCP) {
|
||||
if (sock->conn->type != NETCONN_TCP) {
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
return lwip_sendto(s, data, size, flags, NULL, 0);
|
||||
#else
|
||||
@@ -629,18 +661,19 @@ lwip_send(int s, const void *data, int size, unsigned int flags)
|
||||
|
||||
err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0));
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%d\n", s, err, size));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
return (err==ERR_OK?size:-1);
|
||||
return (err == ERR_OK ? (int)size : -1);
|
||||
}
|
||||
|
||||
int
|
||||
lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||
struct sockaddr *to, socklen_t tolen)
|
||||
lwip_sendto(int s, const void *data, size_t size, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen)
|
||||
{
|
||||
struct lwip_socket *sock;
|
||||
struct ip_addr remote_addr;
|
||||
int err;
|
||||
err_t err;
|
||||
u16_t short_size;
|
||||
#if !LWIP_TCPIP_CORE_LOCKING
|
||||
struct netbuf buf;
|
||||
u16_t remote_port;
|
||||
@@ -650,7 +683,7 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||
if (!sock)
|
||||
return -1;
|
||||
|
||||
if (sock->conn->type==NETCONN_TCP) {
|
||||
if (sock->conn->type == NETCONN_TCP) {
|
||||
#if LWIP_TCP
|
||||
return lwip_send(s, data, size, flags);
|
||||
#else
|
||||
@@ -659,11 +692,11 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||
#endif /* LWIP_TCP */
|
||||
}
|
||||
|
||||
LWIP_ASSERT("lwip_sendto: size must fit in u16_t",
|
||||
((size >= 0) && (size <= 0xffff)));
|
||||
LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
|
||||
short_size = (u16_t)size;
|
||||
LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
|
||||
((tolen == sizeof(struct sockaddr_in)) &&
|
||||
((((struct sockaddr_in *)to)->sin_family) == AF_INET))),
|
||||
((((const struct sockaddr_in *)to)->sin_family) == AF_INET))),
|
||||
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
@@ -675,15 +708,15 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||
err = ERR_MEM;
|
||||
} else {
|
||||
p->payload = (void*)data;
|
||||
p->len = p->tot_len = size;
|
||||
p->len = p->tot_len = short_size;
|
||||
|
||||
remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
|
||||
remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr;
|
||||
|
||||
LOCK_TCPIP_CORE();
|
||||
if (sock->conn->type==NETCONN_RAW) {
|
||||
err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);
|
||||
} else {
|
||||
err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((struct sockaddr_in *)to)->sin_port));
|
||||
err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((const struct sockaddr_in *)to)->sin_port));
|
||||
}
|
||||
UNLOCK_TCPIP_CORE();
|
||||
|
||||
@@ -694,8 +727,8 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||
/* initialize a buffer */
|
||||
buf.p = buf.ptr = NULL;
|
||||
if (to) {
|
||||
remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
|
||||
remote_port = ntohs(((struct sockaddr_in *)to)->sin_port);
|
||||
remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr;
|
||||
remote_port = ntohs(((const struct sockaddr_in *)to)->sin_port);
|
||||
buf.addr = &remote_addr;
|
||||
buf.port = remote_port;
|
||||
} else {
|
||||
@@ -705,24 +738,32 @@ lwip_sendto(int s, const void *data, int size, unsigned int flags,
|
||||
buf.port = 0;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=",
|
||||
s, data, size, flags));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=",
|
||||
s, data, short_size, flags));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", remote_port));
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
|
||||
|
||||
/* make the buffer point to the data that should be sent */
|
||||
if ((err = netbuf_ref(&buf, data, size)) == ERR_OK) {
|
||||
#if LWIP_NETIF_TX_SINGLE_PBUF
|
||||
/* Allocate a new netbuf and copy the data into it. */
|
||||
if (netbuf_alloc(&buf, short_size) == NULL) {
|
||||
err = ERR_MEM;
|
||||
} else {
|
||||
err = netbuf_take(&buf, data, short_size);
|
||||
}
|
||||
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
err = netbuf_ref(&buf, data, short_size);
|
||||
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
if (err == ERR_OK) {
|
||||
/* send the data */
|
||||
err = netconn_send(sock->conn, &buf);
|
||||
}
|
||||
|
||||
/* deallocated the buffer */
|
||||
if (buf.p != NULL) {
|
||||
pbuf_free(buf.p);
|
||||
}
|
||||
netbuf_free(&buf);
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
return (err==ERR_OK?size:-1);
|
||||
return (err == ERR_OK ? short_size : -1);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -778,7 +819,7 @@ lwip_socket(int domain, int type, int protocol)
|
||||
}
|
||||
|
||||
int
|
||||
lwip_write(int s, const void *data, int size)
|
||||
lwip_write(int s, const void *data, size_t size)
|
||||
{
|
||||
return lwip_send(s, data, size, 0);
|
||||
}
|
||||
@@ -815,7 +856,7 @@ lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
|
||||
if (FD_ISSET(i, readset)) {
|
||||
/* See if netconn of this socket is ready for read */
|
||||
p_sock = get_socket(i);
|
||||
if (p_sock && (p_sock->lastdata || p_sock->rcvevent)) {
|
||||
if (p_sock && (p_sock->lastdata || (p_sock->rcvevent > 0))) {
|
||||
FD_SET(i, &lreadset);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
|
||||
nready++;
|
||||
@@ -855,7 +896,8 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n",
|
||||
maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
|
||||
timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));
|
||||
timeout ? (long)timeout->tv_sec : (long)-1,
|
||||
timeout ? (long)timeout->tv_usec : (long)-1));
|
||||
|
||||
select_cb.next = 0;
|
||||
select_cb.readset = readset;
|
||||
@@ -1017,6 +1059,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
|
||||
sys_sem_signal(socksem);
|
||||
return;
|
||||
}
|
||||
s = conn->socket;
|
||||
sys_sem_signal(socksem);
|
||||
}
|
||||
|
||||
@@ -1062,7 +1105,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
|
||||
if (scb->sem_signalled == 0) {
|
||||
/* Test this select call for our socket */
|
||||
if (scb->readset && FD_ISSET(s, scb->readset))
|
||||
if (sock->rcvevent)
|
||||
if (sock->rcvevent > 0)
|
||||
break;
|
||||
if (scb->writeset && FD_ISSET(s, scb->writeset))
|
||||
if (sock->sendevent)
|
||||
@@ -1071,8 +1114,8 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
|
||||
}
|
||||
if (scb) {
|
||||
scb->sem_signalled = 1;
|
||||
sys_sem_signal(selectsem);
|
||||
sys_sem_signal(scb->sem);
|
||||
sys_sem_signal(selectsem);
|
||||
} else {
|
||||
sys_sem_signal(selectsem);
|
||||
break;
|
||||
@@ -1112,7 +1155,7 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
|
||||
|
||||
sin.sin_port = htons(sin.sin_port);
|
||||
sin.sin_addr.s_addr = naddr.addr;
|
||||
@@ -1120,7 +1163,7 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
|
||||
if (*namelen > sizeof(sin))
|
||||
*namelen = sizeof(sin);
|
||||
|
||||
SMEMCPY(name, &sin, *namelen);
|
||||
MEMCPY(name, &sin, *namelen);
|
||||
sock_set_errno(sock, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -1437,7 +1480,7 @@ lwip_getsockopt_internal(void *arg)
|
||||
break;
|
||||
case IP_MULTICAST_IF:
|
||||
((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%x\n",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
|
||||
s, *(u32_t *)optval));
|
||||
break;
|
||||
#endif /* LWIP_IGMP */
|
||||
@@ -1449,7 +1492,7 @@ lwip_getsockopt_internal(void *arg)
|
||||
case IPPROTO_TCP:
|
||||
switch (optname) {
|
||||
case TCP_NODELAY:
|
||||
*(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);
|
||||
*(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
|
||||
s, (*(int*)optval)?"on":"off") );
|
||||
break;
|
||||
@@ -1770,12 +1813,12 @@ lwip_setsockopt_internal(void *arg)
|
||||
switch (optname) {
|
||||
case IP_TTL:
|
||||
sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
|
||||
s, sock->conn->pcb.ip->ttl));
|
||||
break;
|
||||
case IP_TOS:
|
||||
sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
|
||||
s, sock->conn->pcb.ip->tos));
|
||||
break;
|
||||
#if LWIP_IGMP
|
||||
@@ -1810,33 +1853,33 @@ lwip_setsockopt_internal(void *arg)
|
||||
switch (optname) {
|
||||
case TCP_NODELAY:
|
||||
if (*(int*)optval) {
|
||||
sock->conn->pcb.tcp->flags |= TF_NODELAY;
|
||||
tcp_nagle_disable(sock->conn->pcb.tcp);
|
||||
} else {
|
||||
sock->conn->pcb.tcp->flags &= ~TF_NODELAY;
|
||||
tcp_nagle_enable(sock->conn->pcb.tcp);
|
||||
}
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
|
||||
s, (*(int *)optval)?"on":"off") );
|
||||
break;
|
||||
case TCP_KEEPALIVE:
|
||||
sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
|
||||
s, sock->conn->pcb.tcp->keep_idle));
|
||||
break;
|
||||
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
case TCP_KEEPIDLE:
|
||||
sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %lu\n",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
|
||||
s, sock->conn->pcb.tcp->keep_idle));
|
||||
break;
|
||||
case TCP_KEEPINTVL:
|
||||
sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %lu\n",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
|
||||
s, sock->conn->pcb.tcp->keep_intvl));
|
||||
break;
|
||||
case TCP_KEEPCNT:
|
||||
sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %lu\n",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
|
||||
s, sock->conn->pcb.tcp->keep_cnt));
|
||||
break;
|
||||
#endif /* LWIP_TCP_KEEPALIVE */
|
||||
@@ -1880,6 +1923,7 @@ lwip_ioctl(int s, long cmd, void *argp)
|
||||
{
|
||||
struct lwip_socket *sock = get_socket(s);
|
||||
u16_t buflen = 0;
|
||||
s16_t recv_avail;
|
||||
|
||||
if (!sock)
|
||||
return -1;
|
||||
@@ -1891,7 +1935,10 @@ lwip_ioctl(int s, long cmd, void *argp)
|
||||
return -1;
|
||||
}
|
||||
|
||||
SYS_ARCH_GET(sock->conn->recv_avail, *((u16_t*)argp));
|
||||
SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
|
||||
if (recv_avail < 0)
|
||||
recv_avail = 0;
|
||||
*((u16_t*)argp) = (u16_t)recv_avail;
|
||||
|
||||
/* Check if there is data left from the last recv operation. /maq 041215 */
|
||||
if (sock->lastdata) {
|
||||
@@ -1901,7 +1948,7 @@ lwip_ioctl(int s, long cmd, void *argp)
|
||||
*((u16_t*)argp) += buflen;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
|
||||
sock_set_errno(sock, 0);
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -297,11 +297,12 @@ tcpip_thread(void *arg)
|
||||
|
||||
case TCPIP_MSG_TIMEOUT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
||||
|
||||
if(msg->msg.tmo.msecs != 0xffffffff)
|
||||
sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
else
|
||||
sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
case TCPIP_MSG_UNTIMEOUT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
|
||||
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
|
||||
@@ -379,6 +380,14 @@ tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* call sys_timeout in tcpip_thread
|
||||
*
|
||||
* @param msec time in miliseconds for timeout
|
||||
* @param h function to be called on timeout
|
||||
* @param arg argument to pass to timeout function h
|
||||
* @return ERR_MEM on memory error, ERR_OK otherwise
|
||||
*/
|
||||
err_t
|
||||
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
{
|
||||
@@ -400,6 +409,34 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* call sys_untimeout in tcpip_thread
|
||||
*
|
||||
* @param msec time in miliseconds for timeout
|
||||
* @param h function to be called on timeout
|
||||
* @param arg argument to pass to timeout function h
|
||||
* @return ERR_MEM on memory error, ERR_OK otherwise
|
||||
*/
|
||||
err_t
|
||||
tcpip_untimeout(sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (mbox != SYS_MBOX_NULL) {
|
||||
msg = memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_UNTIMEOUT;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
#if LWIP_NETCONN
|
||||
/**
|
||||
* Call the lower part of a netconn_* function
|
||||
@@ -518,4 +555,42 @@ tcpip_init(void (* initfunc)(void *), void *arg)
|
||||
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple callback function used with tcpip_callback to free a pbuf
|
||||
* (pbuf_free has a wrong signature for tcpip_callback)
|
||||
*
|
||||
* @param p The pbuf (chain) to be dereferenced.
|
||||
*/
|
||||
static void
|
||||
pbuf_free_int(void *p)
|
||||
{
|
||||
struct pbuf *q = p;
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper function that allows you to free a pbuf from interrupt context.
|
||||
*
|
||||
* @param p The pbuf (chain) to be dereferenced.
|
||||
* @return ERR_OK if callback could be enqueued, an err_t if not
|
||||
*/
|
||||
err_t
|
||||
pbuf_free_callback(struct pbuf *p)
|
||||
{
|
||||
return tcpip_callback_with_block(pbuf_free_int, p, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper function that allows you to free heap memory from
|
||||
* interrupt context.
|
||||
*
|
||||
* @param m the heap memory to free
|
||||
* @return ERR_OK if callback could be enqueued, an err_t if not
|
||||
*/
|
||||
err_t
|
||||
mem_free_callback(void *m)
|
||||
{
|
||||
return tcpip_callback_with_block(mem_free, m, 0);
|
||||
}
|
||||
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
398
src/core/dhcp.c
398
src/core/dhcp.c
@@ -86,10 +86,23 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** global transaction identifier, must be
|
||||
* unique for each DHCP request. We simply increment, starting
|
||||
* with this value (easy to match with a packet analyzer) */
|
||||
static u32_t xid = 0xABCD0000;
|
||||
/** Default for DHCP_GLOBAL_XID is 0xABCD0000
|
||||
* This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
|
||||
* #define DHCP_GLOBAL_XID_HEADER "stdlib.h"
|
||||
* #define DHCP_GLOBAL_XID rand()
|
||||
*/
|
||||
#ifdef DHCP_GLOBAL_XID_HEADER
|
||||
#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */
|
||||
#endif
|
||||
|
||||
/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU
|
||||
* MTU is checked to be big enough in dhcp_start */
|
||||
#define DHCP_MAX_MSG_LEN(netif) (netif->mtu)
|
||||
#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576
|
||||
/** Minimum length for reply before packet is parsed */
|
||||
#define DHCP_MIN_REPLY_LEN 44
|
||||
|
||||
#define REBOOT_TRIES 2
|
||||
|
||||
/* DHCP client state machine functions */
|
||||
static void dhcp_handle_ack(struct netif *netif);
|
||||
@@ -98,17 +111,18 @@ static void dhcp_handle_offer(struct netif *netif);
|
||||
|
||||
static err_t dhcp_discover(struct netif *netif);
|
||||
static err_t dhcp_select(struct netif *netif);
|
||||
static void dhcp_check(struct netif *netif);
|
||||
static void dhcp_bind(struct netif *netif);
|
||||
#if DHCP_DOES_ARP_CHECK
|
||||
static void dhcp_check(struct netif *netif);
|
||||
static err_t dhcp_decline(struct netif *netif);
|
||||
#endif /* DHCP_DOES_ARP_CHECK */
|
||||
static err_t dhcp_rebind(struct netif *netif);
|
||||
static err_t dhcp_reboot(struct netif *netif);
|
||||
static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);
|
||||
|
||||
/* receive, unfold, parse and free incoming messages */
|
||||
static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
|
||||
static err_t dhcp_unfold_reply(struct dhcp *dhcp);
|
||||
static err_t dhcp_unfold_reply(struct dhcp *dhcp, struct pbuf *p);
|
||||
static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);
|
||||
static u8_t dhcp_get_option_byte(u8_t *ptr);
|
||||
#if 0
|
||||
@@ -152,7 +166,7 @@ static void
|
||||
dhcp_handle_nak(struct netif *netif)
|
||||
{
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",
|
||||
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
|
||||
/* Set the interface down since the address must no longer be used, as per RFC2131 */
|
||||
netif_set_down(netif);
|
||||
@@ -166,6 +180,7 @@ dhcp_handle_nak(struct netif *netif)
|
||||
dhcp_discover(netif);
|
||||
}
|
||||
|
||||
#if DHCP_DOES_ARP_CHECK
|
||||
/**
|
||||
* Checks if the offered IP address is already in use.
|
||||
*
|
||||
@@ -181,20 +196,21 @@ dhcp_check(struct netif *netif)
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
err_t result;
|
||||
u16_t msecs;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
|
||||
(s16_t)netif->name[1]));
|
||||
dhcp_set_state(dhcp, DHCP_CHECKING);
|
||||
/* create an ARP query for the offered IP address, expecting that no host
|
||||
responds, as the IP address should not be in use. */
|
||||
result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
|
||||
if (result != ERR_OK) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n"));
|
||||
}
|
||||
dhcp->tries++;
|
||||
msecs = 500;
|
||||
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
|
||||
dhcp_set_state(dhcp, DHCP_CHECKING);
|
||||
}
|
||||
#endif /* DHCP_DOES_ARP_CHECK */
|
||||
|
||||
/**
|
||||
* Remember the configuration offered by a DHCP server.
|
||||
@@ -207,7 +223,7 @@ dhcp_handle_offer(struct netif *netif)
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
/* obtain the server address */
|
||||
u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
|
||||
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
|
||||
if (option_ptr != NULL) {
|
||||
dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
|
||||
@@ -238,7 +254,8 @@ dhcp_select(struct netif *netif)
|
||||
const char *p;
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
|
||||
dhcp_set_state(dhcp, DHCP_REQUESTING);
|
||||
|
||||
/* create and initialize the DHCP message header */
|
||||
result = dhcp_create_request(netif);
|
||||
@@ -247,7 +264,7 @@ dhcp_select(struct netif *netif)
|
||||
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||
dhcp_option_short(dhcp, 576);
|
||||
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
|
||||
|
||||
/* MUST request the offered IP address */
|
||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||
@@ -264,7 +281,7 @@ dhcp_select(struct netif *netif)
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
p = (const char*)netif->hostname;
|
||||
if (p!=NULL) {
|
||||
if (p != NULL) {
|
||||
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
|
||||
while (*p) {
|
||||
dhcp_option_byte(dhcp, *p++);
|
||||
@@ -276,20 +293,15 @@ dhcp_select(struct netif *netif)
|
||||
/* shrink the pbuf to the actual content length */
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
/* TODO: we really should bind to a specific local interface here
|
||||
but we cannot specify an unconfigured netif as it is addressless */
|
||||
/* send broadcast to any DHCP server */
|
||||
udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
|
||||
/* reconnect to any (or to server here?!) */
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
dhcp_delete_request(netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
|
||||
dhcp_set_state(dhcp, DHCP_REQUESTING);
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n"));
|
||||
}
|
||||
dhcp->tries++;
|
||||
msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;
|
||||
msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
|
||||
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
|
||||
return result;
|
||||
@@ -369,7 +381,7 @@ static void
|
||||
dhcp_timeout(struct netif *netif)
|
||||
{
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_timeout()\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n"));
|
||||
/* back-off period has passed, or server selection timed out */
|
||||
if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
|
||||
@@ -384,6 +396,7 @@ dhcp_timeout(struct netif *netif)
|
||||
dhcp_release(netif);
|
||||
dhcp_discover(netif);
|
||||
}
|
||||
#if DHCP_DOES_ARP_CHECK
|
||||
/* received no ARP reply for the offered address (which is good) */
|
||||
} else if (dhcp->state == DHCP_CHECKING) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
|
||||
@@ -395,6 +408,7 @@ dhcp_timeout(struct netif *netif)
|
||||
/* bind the interface to the offered address */
|
||||
dhcp_bind(netif);
|
||||
}
|
||||
#endif /* DHCP_DOES_ARP_CHECK */
|
||||
}
|
||||
/* did not get response to renew request? */
|
||||
else if (dhcp->state == DHCP_RENEWING) {
|
||||
@@ -412,6 +426,12 @@ dhcp_timeout(struct netif *netif)
|
||||
dhcp_release(netif);
|
||||
dhcp_discover(netif);
|
||||
}
|
||||
} else if (dhcp->state == DHCP_REBOOTING) {
|
||||
if (dhcp->tries < REBOOT_TRIES) {
|
||||
dhcp_reboot(netif);
|
||||
} else {
|
||||
dhcp_discover(netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,8 +588,16 @@ dhcp_start(struct netif *netif)
|
||||
LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
|
||||
dhcp = netif->dhcp;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
|
||||
/* Remove the flag that says this netif is handled by DHCP,
|
||||
it is set when we succeeded starting. */
|
||||
netif->flags &= ~NETIF_FLAG_DHCP;
|
||||
|
||||
/* check MTU of the netif */
|
||||
if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* no DHCP client attached yet? */
|
||||
if (dhcp == NULL) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
|
||||
@@ -583,7 +611,13 @@ dhcp_start(struct netif *netif)
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
|
||||
/* already has DHCP client attached */
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
|
||||
if (dhcp->pcb != NULL) {
|
||||
udp_remove(dhcp->pcb);
|
||||
}
|
||||
LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL);
|
||||
LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
|
||||
dhcp->options_in == NULL && dhcp->options_in_len == 0);
|
||||
}
|
||||
|
||||
/* clear data structure */
|
||||
@@ -596,6 +630,9 @@ dhcp_start(struct netif *netif)
|
||||
netif->dhcp = dhcp = NULL;
|
||||
return ERR_MEM;
|
||||
}
|
||||
#if IP_SOF_BROADCAST
|
||||
dhcp->pcb->so_options|=SOF_BROADCAST;
|
||||
#endif /* IP_SOF_BROADCAST */
|
||||
/* set up local and remote port for the pcb */
|
||||
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
@@ -609,6 +646,7 @@ dhcp_start(struct netif *netif)
|
||||
dhcp_stop(netif);
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* Set the flag that says this netif is handled by DHCP. */
|
||||
netif->flags |= NETIF_FLAG_DHCP;
|
||||
return result;
|
||||
}
|
||||
@@ -625,23 +663,23 @@ dhcp_start(struct netif *netif)
|
||||
void
|
||||
dhcp_inform(struct netif *netif)
|
||||
{
|
||||
struct dhcp *dhcp, *old_dhcp = netif->dhcp;
|
||||
struct dhcp *dhcp, *old_dhcp;
|
||||
err_t result = ERR_OK;
|
||||
dhcp = mem_malloc(sizeof(struct dhcp));
|
||||
if (dhcp == NULL) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not allocate dhcp\n"));
|
||||
return;
|
||||
}
|
||||
netif->dhcp = dhcp;
|
||||
memset(dhcp, 0, sizeof(struct dhcp));
|
||||
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));
|
||||
dhcp->pcb = udp_new();
|
||||
if (dhcp->pcb == NULL) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));
|
||||
mem_free((void *)dhcp);
|
||||
return;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb"));
|
||||
goto free_dhcp_and_return;
|
||||
}
|
||||
old_dhcp = netif->dhcp;
|
||||
netif->dhcp = dhcp;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
|
||||
/* create and initialize the DHCP message header */
|
||||
result = dhcp_create_request(netif);
|
||||
@@ -651,30 +689,57 @@ dhcp_inform(struct netif *netif)
|
||||
dhcp_option_byte(dhcp, DHCP_INFORM);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||
/* TODO: use netif->mtu ?! */
|
||||
dhcp_option_short(dhcp, 576);
|
||||
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
|
||||
|
||||
dhcp_option_trailer(dhcp);
|
||||
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
#if IP_SOF_BROADCAST
|
||||
dhcp->pcb->so_options|=SOF_BROADCAST;
|
||||
#endif /* IP_SOF_BROADCAST */
|
||||
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||
udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
|
||||
udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
dhcp_delete_request(netif);
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n"));
|
||||
}
|
||||
|
||||
if (dhcp != NULL) {
|
||||
if (dhcp->pcb != NULL) {
|
||||
udp_remove(dhcp->pcb);
|
||||
}
|
||||
dhcp->pcb = NULL;
|
||||
mem_free((void *)dhcp);
|
||||
netif->dhcp = old_dhcp;
|
||||
udp_remove(dhcp->pcb);
|
||||
dhcp->pcb = NULL;
|
||||
netif->dhcp = old_dhcp;
|
||||
free_dhcp_and_return:
|
||||
mem_free((void *)dhcp);
|
||||
}
|
||||
|
||||
/** Handle a possible change in the network configuration.
|
||||
*
|
||||
* This enters the REBOOTING state to verify that the currently bound
|
||||
* address is still valid.
|
||||
*/
|
||||
void
|
||||
dhcp_network_changed(struct netif *netif)
|
||||
{
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
if (!dhcp)
|
||||
return;
|
||||
switch (dhcp->state) {
|
||||
case DHCP_REBINDING:
|
||||
case DHCP_RENEWING:
|
||||
case DHCP_BOUND:
|
||||
case DHCP_REBOOTING:
|
||||
netif_set_down(netif);
|
||||
dhcp->tries = 0;
|
||||
dhcp_reboot(netif);
|
||||
break;
|
||||
case DHCP_OFF:
|
||||
/* stay off */
|
||||
break;
|
||||
default:
|
||||
dhcp->tries = 0;
|
||||
dhcp_discover(netif);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,7 +753,7 @@ dhcp_inform(struct netif *netif)
|
||||
void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
|
||||
{
|
||||
LWIP_ERROR("netif != NULL", (netif != NULL), return;);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_arp_reply()\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n"));
|
||||
/* is a DHCP client doing an ARP check? */
|
||||
if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));
|
||||
@@ -696,7 +761,8 @@ void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
|
||||
were offered by the DHCP server? */
|
||||
if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
|
||||
/* we will not accept the offered address */
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||
("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
|
||||
dhcp_decline(netif);
|
||||
}
|
||||
}
|
||||
@@ -717,7 +783,7 @@ dhcp_decline(struct netif *netif)
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
err_t result = ERR_OK;
|
||||
u16_t msecs;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_decline()\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n"));
|
||||
dhcp_set_state(dhcp, DHCP_BACKING_OFF);
|
||||
/* create and initialize the DHCP message header */
|
||||
result = dhcp_create_request(netif);
|
||||
@@ -725,9 +791,6 @@ dhcp_decline(struct netif *netif)
|
||||
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
|
||||
dhcp_option_byte(dhcp, DHCP_DECLINE);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||
dhcp_option_short(dhcp, 576);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
|
||||
|
||||
@@ -735,14 +798,13 @@ dhcp_decline(struct netif *netif)
|
||||
/* resize pbuf to reflect true size of options */
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
/* @todo: should we really connect here? we are performing sendto() */
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
/* per section 4.4.4, broadcast DECLINE messages */
|
||||
udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
|
||||
dhcp_delete_request(netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("dhcp_decline: could not allocate DHCP request\n"));
|
||||
}
|
||||
dhcp->tries++;
|
||||
msecs = 10*1000;
|
||||
@@ -764,8 +826,9 @@ dhcp_discover(struct netif *netif)
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
err_t result = ERR_OK;
|
||||
u16_t msecs;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n"));
|
||||
ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
|
||||
dhcp_set_state(dhcp, DHCP_SELECTING);
|
||||
/* create and initialize the DHCP message header */
|
||||
result = dhcp_create_request(netif);
|
||||
if (result == ERR_OK) {
|
||||
@@ -774,7 +837,7 @@ dhcp_discover(struct netif *netif)
|
||||
dhcp_option_byte(dhcp, DHCP_DISCOVER);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||
dhcp_option_short(dhcp, 576);
|
||||
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
|
||||
dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
|
||||
@@ -787,25 +850,22 @@ dhcp_discover(struct netif *netif)
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
|
||||
udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
|
||||
dhcp_delete_request(netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
|
||||
dhcp_set_state(dhcp, DHCP_SELECTING);
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n"));
|
||||
}
|
||||
dhcp->tries++;
|
||||
#if LWIP_DHCP_AUTOIP_COOP
|
||||
/* that means we waited 57 seconds */
|
||||
if(dhcp->tries >= 9 && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {
|
||||
if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {
|
||||
dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;
|
||||
autoip_start(netif);
|
||||
}
|
||||
#endif /* LWIP_DHCP_AUTOIP_COOP */
|
||||
msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;
|
||||
msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
|
||||
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));
|
||||
return result;
|
||||
@@ -826,7 +886,7 @@ dhcp_bind(struct netif *netif)
|
||||
LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
|
||||
dhcp = netif->dhcp;
|
||||
LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
|
||||
|
||||
/* temporary DHCP lease? */
|
||||
if (dhcp->offered_t1_renew != 0xffffffffUL) {
|
||||
@@ -881,6 +941,13 @@ dhcp_bind(struct netif *netif)
|
||||
gw_addr.addr |= htonl(0x00000001);
|
||||
}
|
||||
|
||||
#if LWIP_DHCP_AUTOIP_COOP
|
||||
if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
|
||||
autoip_stop(netif);
|
||||
dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
|
||||
}
|
||||
#endif /* LWIP_DHCP_AUTOIP_COOP */
|
||||
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
|
||||
netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));
|
||||
@@ -904,7 +971,10 @@ dhcp_renew(struct netif *netif)
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
err_t result;
|
||||
u16_t msecs;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n"));
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
const char *p;
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n"));
|
||||
dhcp_set_state(dhcp, DHCP_RENEWING);
|
||||
|
||||
/* create and initialize the DHCP message header */
|
||||
@@ -915,8 +985,17 @@ dhcp_renew(struct netif *netif)
|
||||
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||
/* TODO: use netif->mtu in some way */
|
||||
dhcp_option_short(dhcp, 576);
|
||||
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
p = (const char*)netif->hostname;
|
||||
if (p != NULL) {
|
||||
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
|
||||
while (*p) {
|
||||
dhcp_option_byte(dhcp, *p++);
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
#if 0
|
||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||
@@ -932,13 +1011,12 @@ dhcp_renew(struct netif *netif)
|
||||
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
|
||||
udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
|
||||
dhcp_delete_request(netif);
|
||||
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n"));
|
||||
}
|
||||
dhcp->tries++;
|
||||
/* back-off on retries, but to a maximum of 20 seconds */
|
||||
@@ -959,6 +1037,9 @@ dhcp_rebind(struct netif *netif)
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
err_t result;
|
||||
u16_t msecs;
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
const char *p;
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));
|
||||
dhcp_set_state(dhcp, DHCP_REBINDING);
|
||||
|
||||
@@ -970,7 +1051,17 @@ dhcp_rebind(struct netif *netif)
|
||||
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||
dhcp_option_short(dhcp, 576);
|
||||
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
p = (const char*)netif->hostname;
|
||||
if (p != NULL) {
|
||||
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
|
||||
while (*p) {
|
||||
dhcp_option_byte(dhcp, *p++);
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
#if 0
|
||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||
@@ -985,12 +1076,11 @@ dhcp_rebind(struct netif *netif)
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
/* broadcast to server */
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
|
||||
dhcp_delete_request(netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n"));
|
||||
}
|
||||
dhcp->tries++;
|
||||
msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
|
||||
@@ -999,6 +1089,52 @@ dhcp_rebind(struct netif *netif)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter REBOOTING state to verify an existing lease
|
||||
*
|
||||
* @param netif network interface which must reboot
|
||||
*/
|
||||
static err_t
|
||||
dhcp_reboot(struct netif *netif)
|
||||
{
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
err_t result;
|
||||
u16_t msecs;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n"));
|
||||
dhcp_set_state(dhcp, DHCP_REBOOTING);
|
||||
|
||||
/* create and initialize the DHCP message header */
|
||||
result = dhcp_create_request(netif);
|
||||
if (result == ERR_OK) {
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
|
||||
dhcp_option_byte(dhcp, DHCP_REQUEST);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||
dhcp_option_short(dhcp, 576);
|
||||
|
||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
|
||||
|
||||
dhcp_option_trailer(dhcp);
|
||||
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
/* broadcast to server */
|
||||
udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
|
||||
dhcp_delete_request(netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n"));
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n"));
|
||||
}
|
||||
dhcp->tries++;
|
||||
msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
|
||||
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Release a DHCP lease.
|
||||
*
|
||||
@@ -1010,7 +1146,7 @@ dhcp_release(struct netif *netif)
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
err_t result;
|
||||
u16_t msecs;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_release()\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n"));
|
||||
|
||||
/* idle DHCP client */
|
||||
dhcp_set_state(dhcp, DHCP_OFF);
|
||||
@@ -1031,12 +1167,11 @@ dhcp_release(struct netif *netif)
|
||||
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
|
||||
udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
|
||||
dhcp_delete_request(netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n"));
|
||||
}
|
||||
dhcp->tries++;
|
||||
msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
|
||||
@@ -1063,20 +1198,25 @@ dhcp_stop(struct netif *netif)
|
||||
{
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
|
||||
/* Remove the flag that says this netif is handled by DHCP. */
|
||||
netif->flags &= ~NETIF_FLAG_DHCP;
|
||||
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_stop()\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n"));
|
||||
/* netif is DHCP configured? */
|
||||
if (dhcp != NULL) {
|
||||
#if LWIP_DHCP_AUTOIP_COOP
|
||||
if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
|
||||
autoip_stop(netif);
|
||||
dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
|
||||
}
|
||||
#endif /* LWIP_DHCP_AUTOIP_COOP */
|
||||
|
||||
if (dhcp->pcb != NULL) {
|
||||
udp_remove(dhcp->pcb);
|
||||
dhcp->pcb = NULL;
|
||||
}
|
||||
if (dhcp->p != NULL) {
|
||||
pbuf_free(dhcp->p);
|
||||
dhcp->p = NULL;
|
||||
}
|
||||
/* free unfolded reply */
|
||||
dhcp_free_reply(dhcp);
|
||||
LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
|
||||
dhcp->options_in == NULL && dhcp->options_in_len == 0);
|
||||
mem_free((void *)dhcp);
|
||||
netif->dhcp = NULL;
|
||||
}
|
||||
@@ -1150,39 +1290,44 @@ dhcp_option_long(struct dhcp *dhcp, u32_t value)
|
||||
*
|
||||
*/
|
||||
static err_t
|
||||
dhcp_unfold_reply(struct dhcp *dhcp)
|
||||
dhcp_unfold_reply(struct dhcp *dhcp, struct pbuf *p)
|
||||
{
|
||||
u16_t ret;
|
||||
LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("dhcp->p != NULL", (dhcp->p != NULL), return ERR_VAL;);
|
||||
/* free any left-overs from previous unfolds */
|
||||
dhcp_free_reply(dhcp);
|
||||
/* options present? */
|
||||
if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) {
|
||||
dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
|
||||
if (p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) {
|
||||
dhcp->options_in_len = p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
|
||||
dhcp->options_in = mem_malloc(dhcp->options_in_len);
|
||||
if (dhcp->options_in == NULL) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
|
||||
dhcp->options_in_len = 0;
|
||||
return ERR_MEM;
|
||||
}
|
||||
}
|
||||
dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
|
||||
if (dhcp->msg_in == NULL) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));
|
||||
mem_free((void *)dhcp->options_in);
|
||||
dhcp->options_in = NULL;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));
|
||||
if (dhcp->options_in != NULL) {
|
||||
mem_free(dhcp->options_in);
|
||||
dhcp->options_in = NULL;
|
||||
dhcp->options_in_len = 0;
|
||||
}
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/** copy the DHCP message without options */
|
||||
ret = pbuf_copy_partial(dhcp->p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0);
|
||||
ret = pbuf_copy_partial(p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0);
|
||||
LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n",
|
||||
sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN));
|
||||
|
||||
if (dhcp->options_in != NULL) {
|
||||
/** copy the DHCP options */
|
||||
ret = pbuf_copy_partial(dhcp->p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
|
||||
ret = pbuf_copy_partial(p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
|
||||
LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n",
|
||||
dhcp->options_in_len));
|
||||
@@ -1194,7 +1339,6 @@ dhcp_unfold_reply(struct dhcp *dhcp)
|
||||
/**
|
||||
* Free the incoming DHCP message including contiguous copy of
|
||||
* its DHCP options.
|
||||
*
|
||||
*/
|
||||
static void dhcp_free_reply(struct dhcp *dhcp)
|
||||
{
|
||||
@@ -1203,14 +1347,13 @@ static void dhcp_free_reply(struct dhcp *dhcp)
|
||||
dhcp->msg_in = NULL;
|
||||
}
|
||||
if (dhcp->options_in) {
|
||||
mem_free((void *)dhcp->options_in);
|
||||
mem_free(dhcp->options_in);
|
||||
dhcp->options_in = NULL;
|
||||
dhcp->options_in_len = 0;
|
||||
}
|
||||
LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If an incoming DHCP message is in response to us, then trigger the state machine
|
||||
*/
|
||||
@@ -1222,7 +1365,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
|
||||
u8_t *options_ptr;
|
||||
u8_t msg_type;
|
||||
u8_t i;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
|
||||
(u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),
|
||||
(u16_t)(ntohl(addr->addr) >> 8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
|
||||
@@ -1231,28 +1374,38 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
LWIP_UNUSED_ARG(addr);
|
||||
LWIP_UNUSED_ARG(port);
|
||||
dhcp->p = p;
|
||||
/* TODO: check packet length before reading them */
|
||||
|
||||
LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
|
||||
dhcp->options_in == NULL && dhcp->options_in_len == 0);
|
||||
|
||||
if (p->len < DHCP_MIN_REPLY_LEN) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message too short\n"));
|
||||
goto free_pbuf_and_return;
|
||||
}
|
||||
|
||||
if (reply_msg->op != DHCP_BOOTREPLY) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
|
||||
goto free_pbuf_and_return;
|
||||
}
|
||||
/* iterate through hardware address and match against DHCP message */
|
||||
for (i = 0; i < netif->hwaddr_len; i++) {
|
||||
if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
|
||||
("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
|
||||
(u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
|
||||
goto free_pbuf_and_return;
|
||||
}
|
||||
}
|
||||
/* match transaction ID against what we expected */
|
||||
if (ntohl(reply_msg->xid) != dhcp->xid) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
|
||||
("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
|
||||
goto free_pbuf_and_return;
|
||||
}
|
||||
/* option fields could be unfold? */
|
||||
if (dhcp_unfold_reply(dhcp) != ERR_OK) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));
|
||||
if (dhcp_unfold_reply(dhcp, p) != ERR_OK) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("problem unfolding DHCP message - too short on memory?\n"));
|
||||
goto free_pbuf_and_return;
|
||||
}
|
||||
|
||||
@@ -1260,7 +1413,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
|
||||
/* obtain pointer to DHCP message type */
|
||||
options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);
|
||||
if (options_ptr == NULL) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
|
||||
goto free_pbuf_and_return;
|
||||
}
|
||||
|
||||
@@ -1268,7 +1421,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
|
||||
msg_type = dhcp_get_option_byte(options_ptr + 2);
|
||||
/* message type is DHCP ACK? */
|
||||
if (msg_type == DHCP_ACK) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_ACK received\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n"));
|
||||
/* in requesting state? */
|
||||
if (dhcp->state == DHCP_REQUESTING) {
|
||||
dhcp_handle_ack(netif);
|
||||
@@ -1291,20 +1444,20 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_
|
||||
else if ((msg_type == DHCP_NAK) &&
|
||||
((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
|
||||
(dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_NAK received\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n"));
|
||||
dhcp->request_timeout = 0;
|
||||
dhcp_handle_nak(netif);
|
||||
}
|
||||
/* received a DHCP_OFFER in DHCP_SELECTING state? */
|
||||
else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
|
||||
dhcp->request_timeout = 0;
|
||||
/* remember offered lease */
|
||||
dhcp_handle_offer(netif);
|
||||
}
|
||||
free_pbuf_and_return:
|
||||
dhcp_free_reply(dhcp);
|
||||
pbuf_free(p);
|
||||
dhcp->p = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1317,6 +1470,20 @@ dhcp_create_request(struct netif *netif)
|
||||
{
|
||||
struct dhcp *dhcp;
|
||||
u16_t i;
|
||||
#ifndef DHCP_GLOBAL_XID
|
||||
/** default global transaction identifier starting value (easy to match
|
||||
* with a packet analyser). We simply increment for each new request.
|
||||
* Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
|
||||
* at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
|
||||
static u32_t xid = 0xABCD0000;
|
||||
#else
|
||||
static u32_t xid;
|
||||
static u8_t xid_initialised = 0;
|
||||
if (!xid_initialised) {
|
||||
xid = DHCP_GLOBAL_XID;
|
||||
xid_initialised = !xid_initialised;
|
||||
}
|
||||
#endif
|
||||
LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;);
|
||||
dhcp = netif->dhcp;
|
||||
LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
|
||||
@@ -1324,15 +1491,19 @@ dhcp_create_request(struct netif *netif)
|
||||
LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
|
||||
dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
|
||||
if (dhcp->p_out == NULL) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("dhcp_create_request(): could not allocate pbuf\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg",
|
||||
(dhcp->p_out->len >= sizeof(struct dhcp_msg)));
|
||||
|
||||
/* give unique transaction identifier to this request */
|
||||
dhcp->xid = xid++;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));
|
||||
/* reuse transaction identifier in retransmissions */
|
||||
if (dhcp->tries==0)
|
||||
xid++;
|
||||
dhcp->xid = xid;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
|
||||
("transaction id xid(%"X32_F")\n", xid));
|
||||
|
||||
dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
|
||||
|
||||
@@ -1345,7 +1516,10 @@ dhcp_create_request(struct netif *netif)
|
||||
dhcp->msg_out->xid = htonl(dhcp->xid);
|
||||
dhcp->msg_out->secs = 0;
|
||||
dhcp->msg_out->flags = 0;
|
||||
dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;
|
||||
dhcp->msg_out->ciaddr.addr = 0;
|
||||
if (dhcp->state==DHCP_BOUND || dhcp->state==DHCP_RENEWING || dhcp->state==DHCP_REBINDING) {
|
||||
dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;
|
||||
}
|
||||
dhcp->msg_out->yiaddr.addr = 0;
|
||||
dhcp->msg_out->siaddr.addr = 0;
|
||||
dhcp->msg_out->giaddr.addr = 0;
|
||||
@@ -1436,7 +1610,7 @@ static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
|
||||
/* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
|
||||
/* are the sname and/or file field overloaded with options? */
|
||||
if (options[offset] == DHCP_OPTION_OVERLOAD) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("overloaded message detected\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded message detected\n"));
|
||||
/* skip option type and length */
|
||||
offset += 2;
|
||||
overload = options[offset++];
|
||||
@@ -1458,16 +1632,16 @@ static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
|
||||
if (overload != DHCP_OVERLOAD_NONE) {
|
||||
u16_t field_len;
|
||||
if (overload == DHCP_OVERLOAD_FILE) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded file field\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n"));
|
||||
options = (u8_t *)&dhcp->msg_in->file;
|
||||
field_len = DHCP_FILE_LEN;
|
||||
} else if (overload == DHCP_OVERLOAD_SNAME) {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname field\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n"));
|
||||
options = (u8_t *)&dhcp->msg_in->sname;
|
||||
field_len = DHCP_SNAME_LEN;
|
||||
/* TODO: check if else if () is necessary */
|
||||
} else {
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname and file field\n"));
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
|
||||
options = (u8_t *)&dhcp->msg_in->sname;
|
||||
field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;
|
||||
}
|
||||
|
||||
226
src/core/dns.c
226
src/core/dns.c
@@ -127,18 +127,19 @@
|
||||
PACK_STRUCT_BEGIN
|
||||
/** DNS message header */
|
||||
struct dns_hdr {
|
||||
u16_t id;
|
||||
u8_t flags1;
|
||||
u8_t flags2;
|
||||
u16_t numquestions;
|
||||
u16_t numanswers;
|
||||
u16_t numauthrr;
|
||||
u16_t numextrarr;
|
||||
PACK_STRUCT_FIELD(u16_t id);
|
||||
PACK_STRUCT_FIELD(u8_t flags1);
|
||||
PACK_STRUCT_FIELD(u8_t flags2);
|
||||
PACK_STRUCT_FIELD(u16_t numquestions);
|
||||
PACK_STRUCT_FIELD(u16_t numanswers);
|
||||
PACK_STRUCT_FIELD(u16_t numauthrr);
|
||||
PACK_STRUCT_FIELD(u16_t numextrarr);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
#define SIZEOF_DNS_HDR 12
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
@@ -148,13 +149,14 @@ PACK_STRUCT_BEGIN
|
||||
struct dns_query {
|
||||
/* DNS query record starts with either a domain name or a pointer
|
||||
to a name already present somewhere in the packet. */
|
||||
u16_t type;
|
||||
u16_t class;
|
||||
PACK_STRUCT_FIELD(u16_t type);
|
||||
PACK_STRUCT_FIELD(u16_t class);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
#define SIZEOF_DNS_QUERY 4
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
@@ -164,15 +166,16 @@ PACK_STRUCT_BEGIN
|
||||
struct dns_answer {
|
||||
/* DNS answer record starts with either a domain name or a pointer
|
||||
to a name already present somewhere in the packet. */
|
||||
u16_t type;
|
||||
u16_t class;
|
||||
u32_t ttl;
|
||||
u16_t len;
|
||||
PACK_STRUCT_FIELD(u16_t type);
|
||||
PACK_STRUCT_FIELD(u16_t class);
|
||||
PACK_STRUCT_FIELD(u32_t ttl);
|
||||
PACK_STRUCT_FIELD(u16_t len);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
#define SIZEOF_DNS_ANSWER 10
|
||||
|
||||
/** DNS table entry */
|
||||
struct dns_table_entry {
|
||||
@@ -190,6 +193,40 @@ struct dns_table_entry {
|
||||
void *arg;
|
||||
};
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
/** struct used for local host-list */
|
||||
struct local_hostlist_entry {
|
||||
/** static hostname */
|
||||
const char *name;
|
||||
/** static host address in network byteorder */
|
||||
u32_t addr;
|
||||
struct local_hostlist_entry *next;
|
||||
};
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
/** Local host-list. For hostnames in this list, no
|
||||
* external name resolution is performed */
|
||||
static struct local_hostlist_entry *local_hostlist_dynamic;
|
||||
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
|
||||
/** Defining this allows the local_hostlist_static to be placed in a different
|
||||
* linker section (e.g. FLASH) */
|
||||
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
|
||||
#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
|
||||
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
|
||||
/** Defining this allows the local_hostlist_static to be placed in a different
|
||||
* linker section (e.g. FLASH) */
|
||||
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
|
||||
#define DNS_LOCAL_HOSTLIST_STORAGE_POST
|
||||
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
|
||||
DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
|
||||
DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
|
||||
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
|
||||
static void dns_init_local();
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
|
||||
|
||||
/* forward declarations */
|
||||
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
|
||||
@@ -241,6 +278,9 @@ dns_init()
|
||||
dns_setserver(0, &dnsserver);
|
||||
}
|
||||
}
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
dns_init_local();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,6 +328,119 @@ dns_tmr(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
static void
|
||||
dns_init_local()
|
||||
{
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
|
||||
int i;
|
||||
struct local_hostlist_entry *entry;
|
||||
/* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
|
||||
struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
|
||||
for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
|
||||
entry = mem_malloc(sizeof(struct local_hostlist_entry));
|
||||
LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
|
||||
if (entry != NULL) {
|
||||
struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
|
||||
entry->name = init_entry->name;
|
||||
entry->addr = init_entry->addr;
|
||||
entry->next = local_hostlist_dynamic;
|
||||
local_hostlist_dynamic = entry;
|
||||
}
|
||||
}
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the local host-list for a hostname.
|
||||
*
|
||||
* @param hostname Hostname to look for in the local host-list
|
||||
* @return The first IP address for the hostname in the local host-list or
|
||||
* INADDR_NONE if not found.
|
||||
*/
|
||||
static u32_t
|
||||
dns_lookup_local(const char *hostname)
|
||||
{
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
struct local_hostlist_entry *entry = local_hostlist_dynamic;
|
||||
while(entry != NULL) {
|
||||
if(strcmp(entry->name, hostname) == 0) {
|
||||
return entry->addr;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
int i;
|
||||
for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
|
||||
if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
|
||||
return local_hostlist_static[i].addr;
|
||||
}
|
||||
}
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
return INADDR_NONE;
|
||||
}
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
/** Remove all entries from the local host-list for a specific hostname
|
||||
* and/or IP addess
|
||||
*
|
||||
* @param hostname hostname for which entries shall be removed from the local
|
||||
* host-list
|
||||
* @param addr address for which entries shall be removed from the local host-list
|
||||
* @return the number of removed entries
|
||||
*/
|
||||
int
|
||||
dns_local_removehost(const char *hostname, const struct ip_addr *addr)
|
||||
{
|
||||
int removed = 0;
|
||||
struct local_hostlist_entry *entry = local_hostlist_dynamic;
|
||||
struct local_hostlist_entry *last_entry = NULL;
|
||||
while (entry != NULL) {
|
||||
if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
|
||||
((addr == NULL) || (entry->addr == addr->addr))) {
|
||||
struct local_hostlist_entry *free_entry;
|
||||
if (last_entry != NULL) {
|
||||
last_entry->next = entry->next;
|
||||
} else {
|
||||
local_hostlist_dynamic = entry->next;
|
||||
}
|
||||
free_entry = entry;
|
||||
entry = entry->next;
|
||||
mem_free(free_entry);
|
||||
removed++;
|
||||
} else {
|
||||
last_entry = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a hostname/IP address pair to the local host-list.
|
||||
* Duplicates are not checked.
|
||||
*
|
||||
* @param hostname hostname of the new entry
|
||||
* @param addr IP address of the new entry
|
||||
* @return ERR_OK if succeeded or ERR_MEM on memory error
|
||||
*/
|
||||
err_t
|
||||
dns_local_addhost(const char *hostname, const struct ip_addr *addr)
|
||||
{
|
||||
struct local_hostlist_entry *entry;
|
||||
entry = mem_malloc(sizeof(struct local_hostlist_entry));
|
||||
if (entry == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
entry->name = hostname;
|
||||
entry->addr = addr->addr;
|
||||
entry->next = local_hostlist_dynamic;
|
||||
local_hostlist_dynamic = entry;
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
|
||||
/**
|
||||
* Look up a hostname in the array of known hostnames.
|
||||
*
|
||||
@@ -298,13 +451,26 @@ dns_tmr(void)
|
||||
*
|
||||
* @param name the hostname to look up
|
||||
* @return the hostname's IP address, as u32_t (instead of struct ip_addr to
|
||||
* better check for failure: != 0) or 0 if the hostname was not found
|
||||
* in the cached dns_table.
|
||||
* better check for failure: != INADDR_NONE) or INADDR_NONE if the hostname
|
||||
* was not found in the cached dns_table.
|
||||
*/
|
||||
static u32_t
|
||||
dns_lookup(const char *name)
|
||||
{
|
||||
u8_t i;
|
||||
#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
|
||||
u32_t addr;
|
||||
#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
if ((addr = dns_lookup_local(name)) != INADDR_NONE) {
|
||||
return addr;
|
||||
}
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
#ifdef DNS_LOOKUP_LOCAL_EXTERN
|
||||
if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != INADDR_NONE) {
|
||||
return addr;
|
||||
}
|
||||
#endif /* DNS_LOOKUP_LOCAL_EXTERN */
|
||||
|
||||
/* Walk through name list, return entry if found. If not, return NULL. */
|
||||
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
||||
@@ -317,7 +483,7 @@ dns_lookup(const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return INADDR_NONE;
|
||||
}
|
||||
|
||||
#if DNS_DOES_NAME_CHECK
|
||||
@@ -415,17 +581,17 @@ dns_send(u8_t numdns, const char* name, u8_t id)
|
||||
LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0);
|
||||
|
||||
/* if here, we have either a new query or a retry on a previous query to process */
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dns_hdr) + DNS_MAX_NAME_LENGTH +
|
||||
sizeof(struct dns_query), PBUF_RAM);
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
|
||||
SIZEOF_DNS_QUERY, PBUF_RAM);
|
||||
if (p != NULL) {
|
||||
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
|
||||
/* fill dns header */
|
||||
hdr = (struct dns_hdr*)p->payload;
|
||||
memset(hdr, 0, sizeof(struct dns_hdr));
|
||||
memset(hdr, 0, SIZEOF_DNS_HDR);
|
||||
hdr->id = htons(id);
|
||||
hdr->flags1 = DNS_FLAG1_RD;
|
||||
hdr->numquestions = htons(1);
|
||||
query = (char*)hdr + sizeof(struct dns_hdr);
|
||||
query = (char*)hdr + SIZEOF_DNS_HDR;
|
||||
pHostname = name;
|
||||
--pHostname;
|
||||
|
||||
@@ -446,10 +612,10 @@ dns_send(u8_t numdns, const char* name, u8_t id)
|
||||
/* fill dns query */
|
||||
qry.type = htons(DNS_RRTYPE_A);
|
||||
qry.class = htons(DNS_RRCLASS_IN);
|
||||
MEMCPY( query, &qry, sizeof(struct dns_query));
|
||||
MEMCPY( query, &qry, SIZEOF_DNS_QUERY);
|
||||
|
||||
/* resize pbuf to the exact dns query */
|
||||
pbuf_realloc(p, (query + sizeof(struct dns_query)) - ((char*)(p->payload)));
|
||||
pbuf_realloc(p, (query + SIZEOF_DNS_QUERY) - ((char*)(p->payload)));
|
||||
|
||||
/* connect to the server for faster receiving */
|
||||
udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
|
||||
@@ -591,7 +757,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
}
|
||||
|
||||
/* is the dns message big enough ? */
|
||||
if (p->tot_len < (sizeof(struct dns_hdr) + sizeof(struct dns_query) + sizeof(struct dns_answer))) {
|
||||
if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
|
||||
/* free pbuf and return */
|
||||
goto memerr1;
|
||||
@@ -632,7 +798,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
|
||||
#if DNS_DOES_NAME_CHECK
|
||||
/* Check if the name in the "question" part match with the name in the entry. */
|
||||
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + sizeof(struct dns_hdr)) != 0) {
|
||||
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
|
||||
/* call callback to indicate error, clean up memory and return */
|
||||
goto responseerr;
|
||||
@@ -640,14 +806,14 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
#endif /* DNS_DOES_NAME_CHECK */
|
||||
|
||||
/* Skip the name in the "question" part */
|
||||
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + sizeof(struct dns_hdr)) + sizeof(struct dns_query);
|
||||
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
|
||||
|
||||
while(nanswers > 0) {
|
||||
/* skip answer resource record's host name */
|
||||
pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
|
||||
|
||||
/* Check for IP address type and Internet class. Others are discarded. */
|
||||
MEMCPY(&ans, pHostname, sizeof(struct dns_answer));
|
||||
MEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
|
||||
if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) {
|
||||
/* read the answer resource record's TTL, and maximize it if needed */
|
||||
pEntry->ttl = ntohl(ans.ttl);
|
||||
@@ -655,7 +821,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
pEntry->ttl = DNS_MAX_TTL;
|
||||
}
|
||||
/* read the IP address after answer resource record's header */
|
||||
MEMCPY( &(pEntry->ipaddr), (pHostname+sizeof(struct dns_answer)), sizeof(struct ip_addr));
|
||||
MEMCPY( &(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(struct ip_addr));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
|
||||
ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
||||
@@ -666,7 +832,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
/* deallocate memory and return */
|
||||
goto memerr2;
|
||||
} else {
|
||||
pHostname = pHostname + sizeof(struct dns_answer) + htons(ans.len);
|
||||
pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
|
||||
}
|
||||
--nanswers;
|
||||
}
|
||||
@@ -795,7 +961,7 @@ dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback
|
||||
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
if (strcmp(hostname,"localhost")==0) {
|
||||
addr->addr = INADDR_LOOPBACK;
|
||||
addr->addr = htonl(INADDR_LOOPBACK);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_HAVE_LOOPIF */
|
||||
@@ -803,7 +969,7 @@ dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback
|
||||
/* host name already in octet notation? set ip addr and return ERR_OK
|
||||
* already have this address cached? */
|
||||
if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||
|
||||
((addr->addr = dns_lookup(hostname)) != 0)) {
|
||||
((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/snmp_msg.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
@@ -61,6 +62,9 @@
|
||||
#ifndef BYTE_ORDER
|
||||
#error "BYTE_ORDER is not defined, you have to define it in your cc.h"
|
||||
#endif
|
||||
#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
|
||||
#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_ARP && ARP_QUEUEING)
|
||||
#error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
|
||||
#endif
|
||||
@@ -155,6 +159,18 @@
|
||||
#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
|
||||
#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
|
||||
#endif
|
||||
#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
|
||||
#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
|
||||
#endif
|
||||
#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
|
||||
#error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
|
||||
#endif
|
||||
#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
|
||||
#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
|
||||
#endif
|
||||
#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
|
||||
#error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
|
||||
#endif
|
||||
|
||||
|
||||
/* Compile-time checks for deprecated options.
|
||||
@@ -195,6 +211,8 @@ lwip_sanity_check(void)
|
||||
#if LWIP_TCP
|
||||
if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
|
||||
if (TCP_SND_BUF < 2 * TCP_MSS)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
|
||||
if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
|
||||
if (TCP_SNDLOWAT > TCP_SND_BUF)
|
||||
@@ -241,6 +259,9 @@ lwip_init(void)
|
||||
#if LWIP_TCP
|
||||
tcp_init();
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_SNMP
|
||||
snmp_init();
|
||||
#endif /* LWIP_SNMP */
|
||||
#if LWIP_AUTOIP
|
||||
autoip_init();
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
@@ -76,7 +76,15 @@
|
||||
#include <stdlib.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 */
|
||||
#ifndef LWIP_AUTOIP_RAND
|
||||
#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
|
||||
@@ -86,11 +94,24 @@
|
||||
(netif->autoip?netif->autoip->tried_llipaddr:0))
|
||||
#endif /* LWIP_AUTOIP_RAND */
|
||||
|
||||
/**
|
||||
* Macro that generates the initial IP address to be tried by AUTOIP.
|
||||
* If you want to override this, define it to something else in lwipopts.h.
|
||||
*/
|
||||
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
|
||||
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
|
||||
htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
|
||||
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
|
||||
#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
|
||||
|
||||
/* static functions */
|
||||
static void autoip_handle_arp_conflict(struct netif *netif);
|
||||
|
||||
/* creates random LL IP-Address for a network interface */
|
||||
static void autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr);
|
||||
/* creates a pseudo random LL IP-Address for a network interface */
|
||||
static void autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr);
|
||||
|
||||
/* sends an ARP probe */
|
||||
static err_t autoip_arp_probe(struct netif *netif);
|
||||
|
||||
/* sends an ARP announce */
|
||||
static err_t autoip_arp_announce(struct netif *netif);
|
||||
@@ -98,13 +119,16 @@ static err_t autoip_arp_announce(struct netif *netif);
|
||||
/* configure interface for use with current LL IP-Address */
|
||||
static err_t autoip_bind(struct netif *netif);
|
||||
|
||||
/* start sending probes for llipaddr */
|
||||
static void autoip_start_probing(struct netif *netif);
|
||||
|
||||
/**
|
||||
* Initialize this module
|
||||
*/
|
||||
void
|
||||
autoip_init(void)
|
||||
{
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n"));
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,19 +145,19 @@ autoip_handle_arp_conflict(struct netif *netif)
|
||||
/* retreat, there was a conflicting ARP in the last
|
||||
* DEFEND_INTERVAL seconds
|
||||
*/
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
|
||||
|
||||
/* TODO: close all TCP sessions */
|
||||
autoip_start(netif);
|
||||
} else {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
|
||||
autoip_arp_announce(netif);
|
||||
netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
}
|
||||
} else {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
|
||||
/* TODO: close all TCP sessions */
|
||||
autoip_start(netif);
|
||||
@@ -144,30 +168,46 @@ autoip_handle_arp_conflict(struct netif *netif)
|
||||
* Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
|
||||
*
|
||||
* @param netif network interface on which create the IP-Address
|
||||
* @param RandomIPAddr ip address to initialize
|
||||
* @param ipaddr ip address to initialize
|
||||
*/
|
||||
static void
|
||||
autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr)
|
||||
autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
{
|
||||
/* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
|
||||
* compliant to RFC 3927 Section 2.1
|
||||
* We have 254 * 256 possibilities
|
||||
*/
|
||||
|
||||
RandomIPAddr->addr = (0xA9FE0100 + ((u32_t)(((u8_t)(netif->hwaddr[4])) |
|
||||
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)) + netif->autoip->tried_llipaddr);
|
||||
* We have 254 * 256 possibilities */
|
||||
|
||||
if (RandomIPAddr->addr>0xA9FEFEFF) {
|
||||
RandomIPAddr->addr = (0xA9FE0100 + (RandomIPAddr->addr-0xA9FEFEFF));
|
||||
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
|
||||
addr += netif->autoip->tried_llipaddr;
|
||||
addr = AUTOIP_NET | (addr & 0xffff);
|
||||
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
|
||||
|
||||
if (addr < AUTOIP_RANGE_START) {
|
||||
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
||||
}
|
||||
if (RandomIPAddr->addr<0xA9FE0100) {
|
||||
RandomIPAddr->addr = (0xA9FEFEFF - (0xA9FE0100-RandomIPAddr->addr));
|
||||
if (addr > AUTOIP_RANGE_END) {
|
||||
addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
||||
}
|
||||
RandomIPAddr->addr = htonl(RandomIPAddr->addr);
|
||||
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
|
||||
(addr <= AUTOIP_RANGE_END));
|
||||
ipaddr->addr = htonl(addr);
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
("autoip_create_rand_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
|
||||
(u16_t)(netif->autoip->tried_llipaddr), (u32_t)(RandomIPAddr->addr)));
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
|
||||
(u16_t)(netif->autoip->tried_llipaddr), (u32_t)(ipaddr->addr)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an ARP probe from a network interface
|
||||
*
|
||||
* @param netif network interface used to send the probe
|
||||
*/
|
||||
static err_t
|
||||
autoip_arp_probe(struct netif *netif)
|
||||
{
|
||||
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
|
||||
(struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero,
|
||||
&netif->autoip->llipaddr, ARP_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +234,7 @@ autoip_bind(struct netif *netif)
|
||||
struct autoip *autoip = netif->autoip;
|
||||
struct ip_addr sn_mask, gw_addr;
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n",
|
||||
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr));
|
||||
|
||||
@@ -258,8 +298,18 @@ autoip_start(struct netif *netif)
|
||||
autoip->lastconflict = 0;
|
||||
}
|
||||
|
||||
autoip_create_rand_addr(netif, &(autoip->llipaddr));
|
||||
autoip_create_addr(netif, &(autoip->llipaddr));
|
||||
autoip->tried_llipaddr++;
|
||||
autoip_start_probing(netif);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
autoip_start_probing(struct netif *netif)
|
||||
{
|
||||
struct autoip *autoip = netif->autoip;
|
||||
|
||||
autoip->state = AUTOIP_STATE_PROBING;
|
||||
autoip->sent_num = 0;
|
||||
|
||||
@@ -274,12 +324,24 @@ autoip_start(struct netif *netif)
|
||||
* accquiring and probing address
|
||||
* compliant to RFC 3927 Section 2.2.1
|
||||
*/
|
||||
|
||||
if(autoip->tried_llipaddr > MAX_CONFLICTS) {
|
||||
autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
/**
|
||||
* Handle a possible change in the network configuration.
|
||||
*
|
||||
* If there is an AutoIP address configured, take the interface down
|
||||
* and begin probing with the same address.
|
||||
*/
|
||||
void
|
||||
autoip_network_changed(struct netif *netif)
|
||||
{
|
||||
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
|
||||
netif_set_down(netif);
|
||||
autoip_start_probing(netif);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,13 +381,13 @@ autoip_tmr()
|
||||
if(netif->autoip->ttw > 0) {
|
||||
netif->autoip->ttw--;
|
||||
} else {
|
||||
if(netif->autoip->sent_num == PROBE_NUM) {
|
||||
if(netif->autoip->sent_num >= PROBE_NUM) {
|
||||
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
|
||||
netif->autoip->sent_num = 0;
|
||||
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
|
||||
} else {
|
||||
etharp_request(netif, &(netif->autoip->llipaddr));
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
|
||||
autoip_arp_probe(netif);
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_tmr() PROBING Sent Probe\n"));
|
||||
netif->autoip->sent_num++;
|
||||
/* calculate time to wait to next probe */
|
||||
@@ -342,21 +404,24 @@ autoip_tmr()
|
||||
} else {
|
||||
if(netif->autoip->sent_num == 0) {
|
||||
/* We are here the first time, so we waited ANNOUNCE_WAIT seconds
|
||||
* Now we can bind to an IP address and use it
|
||||
* Now we can bind to an IP address and use it.
|
||||
*
|
||||
* autoip_bind calls netif_set_up. This triggers a gratuitous ARP
|
||||
* which counts as an announcement.
|
||||
*/
|
||||
autoip_bind(netif);
|
||||
}
|
||||
|
||||
if(netif->autoip->sent_num == ANNOUNCE_NUM) {
|
||||
netif->autoip->state = AUTOIP_STATE_BOUND;
|
||||
netif->autoip->sent_num = 0;
|
||||
netif->autoip->ttw = 0;
|
||||
} else {
|
||||
autoip_arp_announce(netif);
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_tmr() ANNOUNCING Sent Announce\n"));
|
||||
netif->autoip->sent_num++;
|
||||
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
}
|
||||
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
netif->autoip->sent_num++;
|
||||
|
||||
if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
|
||||
netif->autoip->state = AUTOIP_STATE_BOUND;
|
||||
netif->autoip->sent_num = 0;
|
||||
netif->autoip->ttw = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -376,7 +441,7 @@ autoip_tmr()
|
||||
void
|
||||
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
{
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n"));
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
|
||||
if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
|
||||
/* when ip.src == llipaddr && hw.src != netif->hwaddr
|
||||
*
|
||||
@@ -395,8 +460,8 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
|
||||
* structure packing (not using structure copy which breaks strict-aliasing rules).
|
||||
*/
|
||||
MEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
|
||||
MEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
|
||||
SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
|
||||
SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
|
||||
|
||||
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
|
||||
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
|
||||
@@ -410,7 +475,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
|
||||
(ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
|
||||
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||
("autoip_arp_reply(): Probe Conflict detected\n"));
|
||||
autoip_start(netif);
|
||||
}
|
||||
@@ -421,7 +486,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
*/
|
||||
if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
|
||||
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
|
||||
autoip_handle_arp_conflict(netif);
|
||||
}
|
||||
|
||||
@@ -53,9 +53,18 @@
|
||||
|
||||
#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 */
|
||||
#define ICMP_DEST_UNREACH_DATASIZE 8
|
||||
|
||||
static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
|
||||
|
||||
/**
|
||||
* Processes ICMP input packets, called from ip_input().
|
||||
*
|
||||
@@ -94,13 +103,30 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
#endif /* LWIP_DEBUG */
|
||||
switch (type) {
|
||||
case ICMP_ECHO:
|
||||
/* broadcast or multicast destination address? */
|
||||
if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
pbuf_free(p);
|
||||
return;
|
||||
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
|
||||
{
|
||||
int accepted = 1;
|
||||
#if !LWIP_MULTICAST_PING
|
||||
/* multicast destination address? */
|
||||
if (ip_addr_ismulticast(&iphdr->dest)) {
|
||||
accepted = 0;
|
||||
}
|
||||
#endif /* LWIP_MULTICAST_PING */
|
||||
#if !LWIP_BROADCAST_PING
|
||||
/* broadcast destination address? */
|
||||
if (ip_addr_isbroadcast(&iphdr->dest, inp)) {
|
||||
accepted = 0;
|
||||
}
|
||||
#endif /* LWIP_BROADCAST_PING */
|
||||
/* broadcast or multicast destination address not acceptd? */
|
||||
if (!accepted) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
|
||||
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
|
||||
@@ -113,6 +139,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
snmp_inc_icmpinerrors();
|
||||
return;
|
||||
}
|
||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
||||
/* p is not big enough to contain link headers
|
||||
* allocate a new one and copy p into it
|
||||
@@ -153,6 +180,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
goto memerr;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||
/* At this point, all checks are OK. */
|
||||
/* We generate an answer by switching the dest and src ip addresses,
|
||||
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
|
||||
@@ -205,11 +233,13 @@ lenerr:
|
||||
ICMP_STATS_INC(icmp.lenerr);
|
||||
snmp_inc_icmpinerrors();
|
||||
return;
|
||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||
memerr:
|
||||
pbuf_free(p);
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
snmp_inc_icmpinerrors();
|
||||
return;
|
||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,40 +254,7 @@ memerr:
|
||||
void
|
||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_dur_hdr *idur;
|
||||
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
|
||||
PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
(q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
idur = q->payload;
|
||||
ICMPH_TYPE_SET(idur, ICMP_DUR);
|
||||
ICMPH_CODE_SET(idur, t);
|
||||
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), p->payload,
|
||||
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
||||
|
||||
/* calculate checksum */
|
||||
idur->chksum = 0;
|
||||
idur->chksum = inet_chksum(idur, q->len);
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
/* increase number of messages attempted to send */
|
||||
snmp_inc_icmpoutmsgs();
|
||||
/* increase number of destination unreachable messages attempted to send */
|
||||
snmp_inc_icmpoutdestunreachs();
|
||||
|
||||
ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
icmp_send_response(p, ICMP_DUR, t);
|
||||
}
|
||||
|
||||
#if IP_FORWARD || IP_REASSEMBLY
|
||||
@@ -270,20 +267,37 @@ icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
*/
|
||||
void
|
||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
{
|
||||
icmp_send_response(p, ICMP_TE, t);
|
||||
}
|
||||
|
||||
#endif /* IP_FORWARD || IP_REASSEMBLY */
|
||||
|
||||
/**
|
||||
* Send an icmp packet in response to an incoming packet.
|
||||
*
|
||||
* @param p the input packet for which the 'unreachable' should be sent,
|
||||
* p->payload pointing to the IP header
|
||||
* @param type Type of the ICMP header
|
||||
* @param code Code of the ICMP header
|
||||
*/
|
||||
static void
|
||||
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_te_hdr *tehdr;
|
||||
/* we can use the echo header here */
|
||||
struct icmp_echo_hdr *icmphdr;
|
||||
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
|
||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
|
||||
PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
(q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
|
||||
(q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
|
||||
|
||||
iphdr = p->payload;
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
|
||||
@@ -292,17 +306,19 @@ icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
|
||||
|
||||
tehdr = q->payload;
|
||||
ICMPH_TYPE_SET(tehdr, ICMP_TE);
|
||||
ICMPH_CODE_SET(tehdr, t);
|
||||
icmphdr = q->payload;
|
||||
icmphdr->type = type;
|
||||
icmphdr->code = code;
|
||||
icmphdr->id = 0;
|
||||
icmphdr->seqno = 0;
|
||||
|
||||
/* copy fields from original packet */
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), (u8_t *)p->payload,
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
|
||||
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
||||
|
||||
/* calculate checksum */
|
||||
tehdr->chksum = 0;
|
||||
tehdr->chksum = inet_chksum(tehdr, q->len);
|
||||
icmphdr->chksum = 0;
|
||||
icmphdr->chksum = inet_chksum(icmphdr, q->len);
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
/* increase number of messages attempted to send */
|
||||
snmp_inc_icmpoutmsgs();
|
||||
@@ -312,6 +328,4 @@ icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
#endif /* IP_FORWARD */
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
@@ -128,7 +128,7 @@ igmp_dump_group_list()
|
||||
while (group != NULL) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
|
||||
group = group->next;
|
||||
}
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
||||
@@ -147,7 +147,7 @@ igmp_start(struct netif *netif)
|
||||
{
|
||||
struct igmp_group* group;
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
|
||||
|
||||
group = igmp_lookup_group(netif, &allsystems);
|
||||
|
||||
@@ -159,7 +159,7 @@ igmp_start(struct netif *netif)
|
||||
if (netif->igmp_mac_filter != NULL) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||
netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ igmp_stop(struct netif *netif)
|
||||
if (netif->igmp_mac_filter != NULL) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
|
||||
}
|
||||
/* free group */
|
||||
@@ -223,7 +223,7 @@ igmp_report_groups( struct netif *netif)
|
||||
{
|
||||
struct igmp_group *group = igmp_group_list;
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
|
||||
|
||||
while (group != NULL) {
|
||||
if (group->interface == netif) {
|
||||
@@ -295,7 +295,7 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
|
||||
ip_addr_debug_print(IGMP_DEBUG, addr);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) ifp));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
|
||||
|
||||
return group;
|
||||
}
|
||||
@@ -361,7 +361,7 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) inp));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
|
||||
|
||||
/* Now calculate and check the checksum */
|
||||
igmp = (struct igmp_msg *)p->payload;
|
||||
@@ -439,7 +439,8 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %x in state %x on group %x on if %x\n", (int) igmp->igmp_msgtype, (int) group->group_state, (int) &group, (int) group->interface));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
|
||||
igmp->igmp_msgtype, group->group_state, &group, group->interface));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -488,7 +489,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
|
||||
}
|
||||
|
||||
@@ -563,7 +564,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||
if (netif->igmp_mac_filter != NULL) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
|
||||
}
|
||||
|
||||
@@ -624,7 +625,7 @@ igmp_timeout(struct igmp_group *group)
|
||||
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
|
||||
|
||||
igmp_send(group, IGMP_V2_MEMB_REPORT);
|
||||
}
|
||||
@@ -666,7 +667,8 @@ igmp_stop_timer(struct igmp_group *group)
|
||||
void
|
||||
igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
|
||||
{
|
||||
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
|
||||
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
|
||||
((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
|
||||
igmp_start_timer(group, (maxresp)/2);
|
||||
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
|
||||
}
|
||||
@@ -695,64 +697,11 @@ err_t
|
||||
igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t proto, struct netif *netif)
|
||||
{
|
||||
static u16_t ip_id = 0;
|
||||
struct ip_hdr * iphdr = NULL;
|
||||
u16_t * ra = NULL;
|
||||
|
||||
/* First write in the "router alert" */
|
||||
if (pbuf_header(p, ROUTER_ALERTLEN)) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
/* This is the "router alert" option */
|
||||
ra = p->payload;
|
||||
u16_t ra[2];
|
||||
ra[0] = htons (ROUTER_ALERT);
|
||||
ra[1] = 0x0000; /* Router shall examine packet */
|
||||
|
||||
/* now the normal ip header */
|
||||
if (pbuf_header(p, IP_HLEN)) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
/* Should the IP header be generated or is it already included in p? */
|
||||
if (dest != IP_HDRINCL) {
|
||||
/** @todo should be shared with ip.c - ip_output_if */
|
||||
IPH_TTL_SET(iphdr, ttl);
|
||||
IPH_PROTO_SET(iphdr, proto);
|
||||
|
||||
ip_addr_set(&(iphdr->dest), dest);
|
||||
|
||||
IPH_VHLTOS_SET(iphdr, 4, ((IP_HLEN + ROUTER_ALERTLEN) / 4), 0/*tos*/);
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
IPH_OFFSET_SET(iphdr, 0);
|
||||
IPH_ID_SET(iphdr, htons(ip_id));
|
||||
++ip_id;
|
||||
|
||||
if (ip_addr_isany(src)) {
|
||||
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
|
||||
} else {
|
||||
ip_addr_set(&(iphdr->src), src);
|
||||
}
|
||||
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
#if CHECKSUM_GEN_IP
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, (IP_HLEN + ROUTER_ALERTLEN)));
|
||||
#endif
|
||||
} else {
|
||||
dest = &(iphdr->dest);
|
||||
}
|
||||
|
||||
#if IP_DEBUG
|
||||
ip_debug_print(p);
|
||||
#endif
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: sending to if %x\n", (int) netif));
|
||||
|
||||
return netif->output(netif, p, dest);
|
||||
return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -796,10 +745,10 @@ igmp_send(struct igmp_group *group, u8_t type)
|
||||
igmp->igmp_checksum = 0;
|
||||
igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
|
||||
|
||||
igmp_ip_output_if( p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
|
||||
igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
|
||||
}
|
||||
|
||||
pbuf_free (p);
|
||||
pbuf_free(p);
|
||||
} else {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
|
||||
}
|
||||
|
||||
@@ -83,7 +83,8 @@ int
|
||||
inet_aton(const char *cp, struct in_addr *addr)
|
||||
{
|
||||
u32_t val;
|
||||
int base, n, c;
|
||||
u8_t base;
|
||||
char c;
|
||||
u32_t parts[4];
|
||||
u32_t *pp = parts;
|
||||
|
||||
@@ -133,14 +134,13 @@ inet_aton(const char *cp, struct in_addr *addr)
|
||||
/*
|
||||
* Check for trailing characters.
|
||||
*/
|
||||
if (c != '\0' && (!isprint(c) || !isspace(c)))
|
||||
if (c != '\0' && !isspace(c))
|
||||
return (0);
|
||||
/*
|
||||
* Concoct the address according to
|
||||
* the number of parts specified.
|
||||
*/
|
||||
n = pp - parts + 1;
|
||||
switch (n) {
|
||||
switch (pp - parts + 1) {
|
||||
|
||||
case 0:
|
||||
return (0); /* initial nondigit */
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* These are some reference implementations of the checksum algorithm, with the
|
||||
* aim of being simple, correct and fully portable. Checksumming is the
|
||||
@@ -65,6 +65,18 @@
|
||||
# define LWIP_CHKSUM_ALGORITHM 0
|
||||
#endif
|
||||
|
||||
/** Like the name says... */
|
||||
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
/* little endian and PLATFORM_BYTESWAP defined */
|
||||
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
|
||||
#else
|
||||
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
|
||||
#define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8)
|
||||
#endif
|
||||
|
||||
/** Split an u32_t in two u16_ts and add them up */
|
||||
#define FOLD_U32T(u) ((u >> 16) + (u & 0x0000ffffUL))
|
||||
|
||||
#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
|
||||
/**
|
||||
* lwip checksum
|
||||
@@ -86,8 +98,7 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
acc = 0;
|
||||
/* dataptr may be at odd or even addresses */
|
||||
octetptr = (u8_t*)dataptr;
|
||||
while (len > 1)
|
||||
{
|
||||
while (len > 1) {
|
||||
/* declare first octet as most significant
|
||||
thus assume network order, ignoring host order */
|
||||
src = (*octetptr) << 8;
|
||||
@@ -98,15 +109,14 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
acc += src;
|
||||
len -= 2;
|
||||
}
|
||||
if (len > 0)
|
||||
{
|
||||
if (len > 0) {
|
||||
/* accumulate remaining octet */
|
||||
src = (*octetptr) << 8;
|
||||
acc += src;
|
||||
}
|
||||
/* add deferred carry bits */
|
||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||
if ((acc & 0xffff0000) != 0) {
|
||||
if ((acc & 0xffff0000UL) != 0) {
|
||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||
}
|
||||
/* This maybe a little confusing: reorder sum using htons()
|
||||
@@ -154,19 +164,22 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
}
|
||||
|
||||
/* Consume left-over byte, if any */
|
||||
if (len > 0)
|
||||
if (len > 0) {
|
||||
((u8_t *)&t)[0] = *(u8_t *)ps;;
|
||||
}
|
||||
|
||||
/* Add end bytes */
|
||||
sum += t;
|
||||
|
||||
/* Fold 32-bit sum to 16 bits */
|
||||
while ((sum >> 16) != 0)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
sum = FOLD_U32T(sum);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
/* Swap if alignment was odd */
|
||||
if (odd)
|
||||
sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
|
||||
if (odd) {
|
||||
sum = SWAP_BYTES_IN_WORD(sum);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
@@ -211,18 +224,20 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
|
||||
while (len > 7) {
|
||||
tmp = sum + *pl++; /* ping */
|
||||
if (tmp < sum)
|
||||
if (tmp < sum) {
|
||||
tmp++; /* add back carry */
|
||||
}
|
||||
|
||||
sum = tmp + *pl++; /* pong */
|
||||
if (sum < tmp)
|
||||
if (sum < tmp) {
|
||||
sum++; /* add back carry */
|
||||
}
|
||||
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
/* make room in upper bits */
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
ps = (u16_t *)pl;
|
||||
|
||||
@@ -233,16 +248,20 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
}
|
||||
|
||||
/* dangling tail byte remaining? */
|
||||
if (len > 0) /* include odd byte */
|
||||
if (len > 0) { /* include odd byte */
|
||||
((u8_t *)&t)[0] = *(u8_t *)ps;
|
||||
}
|
||||
|
||||
sum += t; /* add end bytes */
|
||||
|
||||
while ((sum >> 16) != 0) /* combine halves */
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
sum = FOLD_U32T(sum);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
if (odd)
|
||||
sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
|
||||
if (odd) {
|
||||
sum = SWAP_BYTES_IN_WORD(sum);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
@@ -277,18 +296,18 @@ inet_chksum_pseudo(struct pbuf *p,
|
||||
(void *)q, (void *)q->next));
|
||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
/* just executing this next line is probably faster that the if statement needed
|
||||
to check whether we really need to execute it, and does no harm */
|
||||
acc = FOLD_U32T(acc);
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
acc += (src->addr & 0xffffUL);
|
||||
acc += ((src->addr >> 16) & 0xffffUL);
|
||||
@@ -297,9 +316,10 @@ inet_chksum_pseudo(struct pbuf *p,
|
||||
acc += (u32_t)htons((u16_t)proto);
|
||||
acc += (u32_t)htons(proto_len);
|
||||
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
acc = FOLD_U32T(acc);
|
||||
acc = FOLD_U32T(acc);
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||
return (u16_t)~(acc & 0xffffUL);
|
||||
}
|
||||
@@ -316,6 +336,8 @@ inet_chksum_pseudo(struct pbuf *p,
|
||||
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
/* Currently only used by UDPLITE, although this could change in the future. */
|
||||
#if LWIP_UDPLITE
|
||||
u16_t
|
||||
inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
@@ -340,18 +362,17 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
chksum_len -= chklen;
|
||||
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
/* fold the upper bit down */
|
||||
acc = FOLD_U32T(acc);
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
acc += (src->addr & 0xffffUL);
|
||||
acc += ((src->addr >> 16) & 0xffffUL);
|
||||
@@ -360,12 +381,14 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
acc += (u32_t)htons((u16_t)proto);
|
||||
acc += (u32_t)htons(proto_len);
|
||||
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
acc = FOLD_U32T(acc);
|
||||
acc = FOLD_U32T(acc);
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||
return (u16_t)~(acc & 0xffffUL);
|
||||
}
|
||||
#endif /* LWIP_UDPLITE */
|
||||
|
||||
/* inet_chksum:
|
||||
*
|
||||
@@ -380,13 +403,7 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
u16_t
|
||||
inet_chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u32_t acc;
|
||||
|
||||
acc = LWIP_CHKSUM(dataptr, len);
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
return (u16_t)~(acc & 0xffff);
|
||||
return ~LWIP_CHKSUM(dataptr, len);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -407,17 +424,15 @@ inet_chksum_pbuf(struct pbuf *p)
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
acc = FOLD_U32T(acc);
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
return (u16_t)~(acc & 0xffffUL);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,19 @@
|
||||
#include "lwip/stats.h"
|
||||
#include "arch/perf.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* The interface that provided the packet for the current callback
|
||||
* invocation.
|
||||
*/
|
||||
struct netif *current_netif;
|
||||
|
||||
/**
|
||||
* Header of the input packet currently being processed.
|
||||
*/
|
||||
const struct ip_hdr *current_header;
|
||||
|
||||
/**
|
||||
* Finds the appropriate network interface for a given IP address. It
|
||||
* searches the list of network interfaces linearly. A match is found
|
||||
@@ -81,7 +94,7 @@ ip_route(struct ip_addr *dest)
|
||||
}
|
||||
}
|
||||
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
snmp_inc_ipoutnoroutes();
|
||||
return NULL;
|
||||
@@ -189,7 +202,7 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
/* identify the IP header */
|
||||
iphdr = p->payload;
|
||||
if (IPH_V(iphdr) != 4) {
|
||||
LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
|
||||
ip_debug_print(p);
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.err);
|
||||
@@ -207,13 +220,16 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
/* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
|
||||
if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
|
||||
if (iphdr_hlen > p->len)
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
|
||||
iphdr_hlen, p->len));
|
||||
if (iphdr_len > p->tot_len)
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "
|
||||
"IP packet dropped.\n",
|
||||
iphdr_len, p->tot_len));
|
||||
if (iphdr_hlen > p->len) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
|
||||
iphdr_hlen, p->len));
|
||||
}
|
||||
if (iphdr_len > p->tot_len) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
|
||||
iphdr_len, p->tot_len));
|
||||
}
|
||||
/* free (drop) packet pbufs */
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.lenerr);
|
||||
@@ -226,7 +242,8 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
#if CHECKSUM_CHECK_IP
|
||||
if (inet_chksum(iphdr, iphdr_hlen) != 0) {
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
|
||||
ip_debug_print(p);
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.chkerr);
|
||||
@@ -295,10 +312,10 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
if (netif == NULL) {
|
||||
/* remote port is DHCP server? */
|
||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
|
||||
ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
|
||||
if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
|
||||
netif = inp;
|
||||
check_ip_src = 0;
|
||||
}
|
||||
@@ -308,12 +325,13 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
/* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
|
||||
#if LWIP_DHCP
|
||||
if (check_ip_src)
|
||||
/* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
|
||||
if (check_ip_src && (iphdr->src.addr != 0))
|
||||
#endif /* LWIP_DHCP */
|
||||
{ if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
|
||||
(ip_addr_ismulticast(&(iphdr->src)))) {
|
||||
/* packet source is not valid */
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
|
||||
/* free (drop) packet pbufs */
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.drop);
|
||||
@@ -326,7 +344,7 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
/* packet not for us? */
|
||||
if (netif == NULL) {
|
||||
/* packet not for us, route or discard */
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
|
||||
#if IP_FORWARD
|
||||
/* non-broadcast packet? */
|
||||
if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
|
||||
@@ -355,7 +373,7 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
iphdr = p->payload;
|
||||
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
|
||||
ntohs(IPH_OFFSET(iphdr))));
|
||||
IP_STATS_INC(ip.opterr);
|
||||
IP_STATS_INC(ip.drop);
|
||||
@@ -373,7 +391,7 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
#else
|
||||
if (iphdr_hlen > IP_HLEN) {
|
||||
#endif /* LWIP_IGMP */
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.opterr);
|
||||
IP_STATS_INC(ip.drop);
|
||||
@@ -388,6 +406,9 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
ip_debug_print(p);
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
|
||||
|
||||
current_netif = inp;
|
||||
current_header = iphdr;
|
||||
|
||||
#if LWIP_RAW
|
||||
/* raw input did not eat the packet? */
|
||||
if (raw_input(p, inp) == 0)
|
||||
@@ -432,7 +453,7 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
#endif /* LWIP_ICMP */
|
||||
pbuf_free(p);
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
|
||||
|
||||
IP_STATS_INC(ip.proterr);
|
||||
IP_STATS_INC(ip.drop);
|
||||
@@ -440,6 +461,9 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
}
|
||||
|
||||
current_netif = NULL;
|
||||
current_header = NULL;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -473,6 +497,21 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t tos,
|
||||
u8_t proto, struct netif *netif)
|
||||
{
|
||||
#if IP_OPTIONS_SEND
|
||||
return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as ip_output_if() but with the possibility to include IP options:
|
||||
*
|
||||
* @ param ip_options pointer to the IP options, copied into the IP header
|
||||
* @ param optlen length of ip_options
|
||||
*/
|
||||
err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
|
||||
u16_t optlen)
|
||||
{
|
||||
#endif /* IP_OPTIONS_SEND */
|
||||
struct ip_hdr *iphdr;
|
||||
static u16_t ip_id = 0;
|
||||
|
||||
@@ -480,9 +519,30 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
|
||||
/* Should the IP header be generated or is it already included in p? */
|
||||
if (dest != IP_HDRINCL) {
|
||||
u16_t ip_hlen = IP_HLEN;
|
||||
#if IP_OPTIONS_SEND
|
||||
u16_t optlen_aligned = 0;
|
||||
if (optlen != 0) {
|
||||
/* round up to a multiple of 4 */
|
||||
optlen_aligned = ((optlen + 3) & ~3);
|
||||
ip_hlen += optlen_aligned;
|
||||
/* First write in the IP options */
|
||||
if (pbuf_header(p, optlen_aligned)) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
|
||||
IP_STATS_INC(ip.err);
|
||||
snmp_inc_ipoutdiscards();
|
||||
return ERR_BUF;
|
||||
}
|
||||
MEMCPY(p->payload, ip_options, optlen);
|
||||
if (optlen < optlen_aligned) {
|
||||
/* zero the remaining bytes */
|
||||
memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
|
||||
}
|
||||
}
|
||||
#endif /* IP_OPTIONS_SEND */
|
||||
/* generate IP header */
|
||||
if (pbuf_header(p, IP_HLEN)) {
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
|
||||
|
||||
IP_STATS_INC(ip.err);
|
||||
snmp_inc_ipoutdiscards();
|
||||
@@ -498,7 +558,7 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
|
||||
ip_addr_set(&(iphdr->dest), dest);
|
||||
|
||||
IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);
|
||||
IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
IPH_OFFSET_SET(iphdr, 0);
|
||||
IPH_ID_SET(iphdr, htons(ip_id));
|
||||
@@ -512,7 +572,7 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
#if CHECKSUM_GEN_IP
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
|
||||
#endif
|
||||
} else {
|
||||
/* IP header already included in p */
|
||||
@@ -520,19 +580,26 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
dest = &(iphdr->dest);
|
||||
}
|
||||
|
||||
#if IP_FRAG
|
||||
/* don't fragment if interface has mtu set to 0 [loopif] */
|
||||
if (netif->mtu && (p->tot_len > netif->mtu))
|
||||
return ip_frag(p,netif,dest);
|
||||
#endif
|
||||
|
||||
IP_STATS_INC(ip.xmit);
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
|
||||
ip_debug_print(p);
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
|
||||
#if ENABLE_LOOPBACK
|
||||
if (ip_addr_cmp(dest, &netif->ip_addr)) {
|
||||
/* Packet to self, enqueue it for loopback */
|
||||
LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
|
||||
return netif_loop_output(netif, p, dest);
|
||||
}
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
#if IP_FRAG
|
||||
/* don't fragment if interface has mtu set to 0 [loopif] */
|
||||
if (netif->mtu && (p->tot_len > netif->mtu)) {
|
||||
return ip_frag(p,netif,dest);
|
||||
}
|
||||
#endif
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
|
||||
return netif->output(netif, p, dest);
|
||||
}
|
||||
|
||||
@@ -560,12 +627,54 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
struct netif *netif;
|
||||
|
||||
if ((netif = ip_route(dest)) == NULL) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
|
||||
* before calling ip_output_if.
|
||||
*
|
||||
* @param p the packet to send (p->payload points to the data, e.g. next
|
||||
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
||||
header and p->payload points to that IP header)
|
||||
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
||||
* IP address of the netif used to send is used as source address)
|
||||
* @param dest the destination IP address to send the packet to
|
||||
* @param ttl the TTL value to be set in the IP header
|
||||
* @param tos the TOS value to be set in the IP header
|
||||
* @param proto the PROTOCOL to be set in the IP header
|
||||
* @param addr_hint address hint pointer set to netif->addr_hint before
|
||||
* calling ip_output_if()
|
||||
*
|
||||
* @return ERR_RTE if no route is found
|
||||
* see ip_output_if() for more return values
|
||||
*/
|
||||
err_t
|
||||
ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
|
||||
{
|
||||
struct netif *netif;
|
||||
err_t err;
|
||||
|
||||
if ((netif = ip_route(dest)) == NULL) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
netif->addr_hint = addr_hint;
|
||||
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||
netif->addr_hint = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
|
||||
#if IP_DEBUG
|
||||
/* Print an IP header by using LWIP_DEBUGF
|
||||
* @param p an IP packet, p->payload pointing to the IP header
|
||||
|
||||
@@ -81,12 +81,21 @@
|
||||
/** This is a helper struct which holds the starting
|
||||
* offset and the ending offset of this fragment to
|
||||
* easily chain the fragments.
|
||||
* It has to be packed since it has to fit inside the IP header.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_reass_helper {
|
||||
struct pbuf *next_pbuf;
|
||||
u16_t start;
|
||||
u16_t end;
|
||||
};
|
||||
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
|
||||
PACK_STRUCT_FIELD(u16_t start);
|
||||
PACK_STRUCT_FIELD(u16_t end);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
|
||||
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
|
||||
@@ -599,7 +608,7 @@ nullreturn:
|
||||
|
||||
#if IP_FRAG
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];
|
||||
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
|
||||
/**
|
||||
|
||||
@@ -327,6 +327,28 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
return ip_output_if (p, src, dest, ttl, proto, netif);
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
err_t
|
||||
ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
|
||||
{
|
||||
struct netif *netif;
|
||||
err_t err;
|
||||
|
||||
if ((netif = ip_route(dest)) == NULL) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
netif->addr_hint = addr_hint;
|
||||
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||
netif->addr_hint = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
|
||||
#if IP_DEBUG
|
||||
void
|
||||
ip_debug_print(struct pbuf *p)
|
||||
|
||||
284
src/core/mem.c
284
src/core/mem.c
@@ -67,14 +67,6 @@
|
||||
#if MEM_USE_POOLS
|
||||
/* lwIP head implemented with different sized pools */
|
||||
|
||||
/**
|
||||
* This structure is used to save the pool one element came from.
|
||||
*/
|
||||
struct mem_helper
|
||||
{
|
||||
memp_t poolnr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate memory: determine the smallest pool that is big enough
|
||||
* to contain an element of 'size' and get an element from that pool.
|
||||
@@ -85,13 +77,17 @@ struct mem_helper
|
||||
void *
|
||||
mem_malloc(mem_size_t size)
|
||||
{
|
||||
struct mem_helper *element;
|
||||
struct memp_malloc_helper *element;
|
||||
memp_t poolnr;
|
||||
mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
|
||||
|
||||
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) {
|
||||
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||
again:
|
||||
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
||||
/* is this pool big enough to hold an element of the required size
|
||||
plus a struct mem_helper that saves the pool this element came from? */
|
||||
if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) {
|
||||
plus a struct memp_malloc_helper that saves the pool this element came from? */
|
||||
if (required_size <= memp_sizes[poolnr]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -99,17 +95,23 @@ mem_malloc(mem_size_t size)
|
||||
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
|
||||
return NULL;
|
||||
}
|
||||
element = (struct mem_helper*)memp_malloc(poolnr);
|
||||
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
|
||||
if (element == NULL) {
|
||||
/* No need to DEBUGF or ASSERT: This error is already
|
||||
taken care of in memp.c */
|
||||
/** @todo: we could try a bigger pool if this one is empty! */
|
||||
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||
/** Try a bigger pool if this one is empty! */
|
||||
if (poolnr < MEMP_POOL_LAST) {
|
||||
poolnr++;
|
||||
goto again;
|
||||
}
|
||||
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* save the pool number this element came from */
|
||||
element->poolnr = poolnr;
|
||||
/* and return a pointer to the memory directly after the struct mem_helper */
|
||||
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
|
||||
element++;
|
||||
|
||||
return element;
|
||||
@@ -125,12 +127,12 @@ mem_malloc(mem_size_t size)
|
||||
void
|
||||
mem_free(void *rmem)
|
||||
{
|
||||
struct mem_helper *hmem = (struct mem_helper*)rmem;
|
||||
struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
|
||||
|
||||
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
|
||||
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
|
||||
|
||||
/* get the original struct mem_helper */
|
||||
/* get the original struct memp_malloc_helper */
|
||||
hmem--;
|
||||
|
||||
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
|
||||
@@ -177,9 +179,36 @@ static u8_t *ram;
|
||||
static struct mem *ram_end;
|
||||
/** pointer to the lowest free block, this is used for faster search */
|
||||
static struct mem *lfree;
|
||||
|
||||
/** concurrent access protection */
|
||||
static sys_sem_t mem_sem;
|
||||
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
|
||||
static volatile u8_t mem_free_count;
|
||||
|
||||
/* Allow mem_free from other (e.g. interrupt) context */
|
||||
#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
|
||||
#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
|
||||
#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
|
||||
#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
|
||||
#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
|
||||
#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
|
||||
|
||||
#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
/* Protect the heap only by using a semaphore */
|
||||
#define LWIP_MEM_FREE_DECL_PROTECT()
|
||||
#define LWIP_MEM_FREE_PROTECT() sys_arch_sem_wait(mem_sem, 0)
|
||||
#define LWIP_MEM_FREE_UNPROTECT() sys_sem_signal(mem_sem)
|
||||
/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
|
||||
#define LWIP_MEM_ALLOC_DECL_PROTECT()
|
||||
#define LWIP_MEM_ALLOC_PROTECT()
|
||||
#define LWIP_MEM_ALLOC_UNPROTECT()
|
||||
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
|
||||
/**
|
||||
* "Plug holes" by combining adjacent empty struct mems.
|
||||
* After this function is through, there should not exist
|
||||
@@ -255,9 +284,7 @@ mem_init(void)
|
||||
/* initialize the lowest-free pointer to the start of the heap */
|
||||
lfree = (struct mem *)ram;
|
||||
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.avail = MEM_SIZE_ALIGNED;
|
||||
#endif /* MEM_STATS */
|
||||
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,27 +297,28 @@ void
|
||||
mem_free(void *rmem)
|
||||
{
|
||||
struct mem *mem;
|
||||
LWIP_MEM_FREE_DECL_PROTECT();
|
||||
|
||||
if (rmem == NULL) {
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
|
||||
|
||||
/* protect the heap from concurrent access */
|
||||
sys_arch_sem_wait(mem_sem, 0);
|
||||
|
||||
LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||
(u8_t *)rmem < (u8_t *)ram_end);
|
||||
|
||||
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
||||
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
|
||||
#if MEM_STATS
|
||||
++lwip_stats.mem.err;
|
||||
#endif /* MEM_STATS */
|
||||
sys_sem_signal(mem_sem);
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
|
||||
/* protect mem stats from concurrent access */
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
MEM_STATS_INC(illegal);
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
return;
|
||||
}
|
||||
/* protect the heap from concurrent access */
|
||||
LWIP_MEM_FREE_PROTECT();
|
||||
/* Get the corresponding struct mem ... */
|
||||
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
/* ... which has to be in a used state ... */
|
||||
@@ -303,13 +331,14 @@ mem_free(void *rmem)
|
||||
lfree = mem;
|
||||
}
|
||||
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);
|
||||
#endif /* MEM_STATS */
|
||||
MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram));
|
||||
|
||||
/* finally, see if prev or next are free also */
|
||||
plug_holes(mem);
|
||||
sys_sem_signal(mem_sem);
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 1;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
LWIP_MEM_FREE_UNPROTECT();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,6 +350,8 @@ mem_free(void *rmem)
|
||||
* @param newsize required size after shrinking (needs to be smaller than or
|
||||
* equal to the previous size)
|
||||
* @return for compatibility reasons: is always == rmem, at the moment
|
||||
* or NULL if newsize is > old size, in which case rmem is NOT touched
|
||||
* or freed!
|
||||
*/
|
||||
void *
|
||||
mem_realloc(void *rmem, mem_size_t newsize)
|
||||
@@ -328,6 +359,8 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
mem_size_t size;
|
||||
mem_size_t ptr, ptr2;
|
||||
struct mem *mem, *mem2;
|
||||
/* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
|
||||
LWIP_MEM_FREE_DECL_PROTECT();
|
||||
|
||||
/* Expand the size of the allocated memory region so that we can
|
||||
adjust for alignment. */
|
||||
@@ -346,7 +379,12 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
(u8_t *)rmem < (u8_t *)ram_end);
|
||||
|
||||
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
||||
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_realloc: illegal memory\n"));
|
||||
/* protect mem stats from concurrent access */
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
MEM_STATS_INC(illegal);
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
return rmem;
|
||||
}
|
||||
/* Get the corresponding struct mem ... */
|
||||
@@ -366,11 +404,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
}
|
||||
|
||||
/* protect the heap from concurrent access */
|
||||
sys_arch_sem_wait(mem_sem, 0);
|
||||
LWIP_MEM_FREE_PROTECT();
|
||||
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.used -= (size - newsize);
|
||||
#endif /* MEM_STATS */
|
||||
MEM_STATS_DEC_USED(used, (size - newsize));
|
||||
|
||||
mem2 = (struct mem *)&ram[mem->next];
|
||||
if(mem2->used == 0) {
|
||||
@@ -426,7 +462,10 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
-> don't do anyhting.
|
||||
-> the remaining space stays unused since it is too small
|
||||
} */
|
||||
sys_sem_signal(mem_sem);
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 1;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
LWIP_MEM_FREE_UNPROTECT();
|
||||
return rmem;
|
||||
}
|
||||
|
||||
@@ -444,6 +483,10 @@ mem_malloc(mem_size_t size)
|
||||
{
|
||||
mem_size_t ptr, ptr2;
|
||||
struct mem *mem, *mem2;
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
u8_t local_mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
LWIP_MEM_ALLOC_DECL_PROTECT();
|
||||
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
@@ -464,88 +507,101 @@ mem_malloc(mem_size_t size)
|
||||
|
||||
/* protect the heap from concurrent access */
|
||||
sys_arch_sem_wait(mem_sem, 0);
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
/* run as long as a mem_free disturbed mem_malloc */
|
||||
do {
|
||||
local_mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
/* Scan through the heap searching for a free block that is big enough,
|
||||
* beginning with the lowest free block.
|
||||
*/
|
||||
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
|
||||
ptr = ((struct mem *)&ram[ptr])->next) {
|
||||
mem = (struct mem *)&ram[ptr];
|
||||
|
||||
if ((!mem->used) &&
|
||||
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
|
||||
/* mem is not used and at least perfect fit is possible:
|
||||
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
|
||||
|
||||
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
|
||||
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
|
||||
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
|
||||
* -> split large block, create empty remainder,
|
||||
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
|
||||
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
|
||||
* struct mem would fit in but no data between mem2 and mem2->next
|
||||
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
||||
* region that couldn't hold data, but when mem->next gets freed,
|
||||
* the 2 regions would be combined, resulting in more free memory
|
||||
*/
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
|
||||
/* create mem2 struct */
|
||||
mem2 = (struct mem *)&ram[ptr2];
|
||||
mem2->used = 0;
|
||||
mem2->next = mem->next;
|
||||
mem2->prev = ptr;
|
||||
/* and insert it between mem and mem->next */
|
||||
mem->next = ptr2;
|
||||
mem->used = 1;
|
||||
|
||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
||||
}
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);
|
||||
if (lwip_stats.mem.max < lwip_stats.mem.used) {
|
||||
lwip_stats.mem.max = lwip_stats.mem.used;
|
||||
}
|
||||
#endif /* MEM_STATS */
|
||||
} else {
|
||||
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
|
||||
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
|
||||
* take care of this).
|
||||
* -> near fit or excact fit: do not split, no mem2 creation
|
||||
* also can't move mem->next directly behind mem, since mem->next
|
||||
* will always be used at this point!
|
||||
*/
|
||||
mem->used = 1;
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.used += mem->next - ((u8_t *)mem - ram);
|
||||
if (lwip_stats.mem.max < lwip_stats.mem.used) {
|
||||
lwip_stats.mem.max = lwip_stats.mem.used;
|
||||
}
|
||||
#endif /* MEM_STATS */
|
||||
/* Scan through the heap searching for a free block that is big enough,
|
||||
* beginning with the lowest free block.
|
||||
*/
|
||||
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
|
||||
ptr = ((struct mem *)&ram[ptr])->next) {
|
||||
mem = (struct mem *)&ram[ptr];
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 0;
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
/* allow mem_free to run */
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
if (mem_free_count != 0) {
|
||||
local_mem_free_count = mem_free_count;
|
||||
}
|
||||
mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
if (mem == lfree) {
|
||||
/* Find next free block after mem and update lowest free pointer */
|
||||
while (lfree->used && lfree != ram_end) {
|
||||
lfree = (struct mem *)&ram[lfree->next];
|
||||
if ((!mem->used) &&
|
||||
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
|
||||
/* mem is not used and at least perfect fit is possible:
|
||||
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
|
||||
|
||||
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
|
||||
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
|
||||
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
|
||||
* -> split large block, create empty remainder,
|
||||
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
|
||||
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
|
||||
* struct mem would fit in but no data between mem2 and mem2->next
|
||||
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
||||
* region that couldn't hold data, but when mem->next gets freed,
|
||||
* the 2 regions would be combined, resulting in more free memory
|
||||
*/
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
|
||||
/* create mem2 struct */
|
||||
mem2 = (struct mem *)&ram[ptr2];
|
||||
mem2->used = 0;
|
||||
mem2->next = mem->next;
|
||||
mem2->prev = ptr;
|
||||
/* and insert it between mem and mem->next */
|
||||
mem->next = ptr2;
|
||||
mem->used = 1;
|
||||
|
||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
||||
}
|
||||
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
|
||||
} else {
|
||||
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
|
||||
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
|
||||
* take care of this).
|
||||
* -> near fit or excact fit: do not split, no mem2 creation
|
||||
* also can't move mem->next directly behind mem, since mem->next
|
||||
* will always be used at this point!
|
||||
*/
|
||||
mem->used = 1;
|
||||
MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram));
|
||||
}
|
||||
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
|
||||
}
|
||||
sys_sem_signal(mem_sem);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
|
||||
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
|
||||
(unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
|
||||
LWIP_ASSERT("mem_malloc: sanity check alignment",
|
||||
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
|
||||
|
||||
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
|
||||
if (mem == lfree) {
|
||||
/* Find next free block after mem and update lowest free pointer */
|
||||
while (lfree->used && lfree != ram_end) {
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
/* prevent high interrupt latency... */
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
lfree = (struct mem *)&ram[lfree->next];
|
||||
}
|
||||
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
|
||||
}
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
sys_sem_signal(mem_sem);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
|
||||
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
|
||||
((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
|
||||
LWIP_ASSERT("mem_malloc: sanity check alignment",
|
||||
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
|
||||
|
||||
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
|
||||
#if MEM_STATS
|
||||
++lwip_stats.mem.err;
|
||||
#endif /* MEM_STATS */
|
||||
#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 | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
|
||||
MEM_STATS_INC(err);
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
sys_sem_signal(mem_sem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
struct memp {
|
||||
struct memp *next;
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
@@ -109,15 +111,23 @@ struct memp {
|
||||
* Elements form a linked list. */
|
||||
static struct memp *memp_tab[MEMP_MAX];
|
||||
|
||||
#else /* MEMP_MEM_MALLOC */
|
||||
|
||||
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
|
||||
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
/** This array holds the element sizes of each pool. */
|
||||
#if !MEM_USE_POOLS
|
||||
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
|
||||
static
|
||||
#endif
|
||||
const u16_t memp_sizes[MEMP_MAX] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) MEMP_ALIGN_SIZE(size),
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
|
||||
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
/** This array holds the number of elements in each pool. */
|
||||
static const u16_t memp_num[MEMP_MAX] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) (num),
|
||||
@@ -183,7 +193,7 @@ memp_overflow_check_element(struct memp *p, u16_t memp_size)
|
||||
}
|
||||
#endif
|
||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE + memp_size - MEMP_SANITY_REGION_AFTER_ALIGNED;
|
||||
m = (u8_t*)p + MEMP_SIZE + memp_size;
|
||||
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
|
||||
if (m[k] != 0xcd) {
|
||||
LWIP_ASSERT("detected memp overflow!", 0);
|
||||
@@ -208,7 +218,7 @@ memp_overflow_check_all(void)
|
||||
p = p;
|
||||
for (j = 0; j < memp_num[i]; ++j) {
|
||||
memp_overflow_check_element(p, memp_sizes[i]);
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,10 +242,10 @@ memp_overflow_init(void)
|
||||
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
|
||||
#endif
|
||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i] - MEMP_SANITY_REGION_AFTER_ALIGNED;
|
||||
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
|
||||
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
#endif
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,13 +262,12 @@ memp_init(void)
|
||||
struct memp *memp;
|
||||
u16_t i, j;
|
||||
|
||||
#if MEMP_STATS
|
||||
for (i = 0; i < MEMP_MAX; ++i) {
|
||||
lwip_stats.memp[i].used = lwip_stats.memp[i].max =
|
||||
lwip_stats.memp[i].err = 0;
|
||||
lwip_stats.memp[i].avail = memp_num[i];
|
||||
MEMP_STATS_AVAIL(used, i, 0);
|
||||
MEMP_STATS_AVAIL(max, i, 0);
|
||||
MEMP_STATS_AVAIL(err, i, 0);
|
||||
MEMP_STATS_AVAIL(avail, i, memp_num[i]);
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
|
||||
memp = LWIP_MEM_ALIGN(memp_memory);
|
||||
/* for every pool: */
|
||||
@@ -268,7 +277,11 @@ memp_init(void)
|
||||
for (j = 0; j < memp_num[i]; ++j) {
|
||||
memp->next = memp_tab[i];
|
||||
memp_tab[i] = memp;
|
||||
memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);
|
||||
memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
+ MEMP_SANITY_REGION_AFTER_ALIGNED
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
@@ -308,27 +321,20 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
|
||||
|
||||
memp = memp_tab[type];
|
||||
|
||||
if (memp != NULL) {
|
||||
memp_tab[type] = memp->next;
|
||||
if (memp != NULL) {
|
||||
memp_tab[type] = memp->next;
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
memp->next = NULL;
|
||||
memp->file = file;
|
||||
memp->line = line;
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
#if MEMP_STATS
|
||||
++lwip_stats.memp[type].used;
|
||||
if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {
|
||||
lwip_stats.memp[type].max = lwip_stats.memp[type].used;
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
MEMP_STATS_INC_USED(used, type);
|
||||
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
||||
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
|
||||
memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);
|
||||
} else {
|
||||
LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
|
||||
#if MEMP_STATS
|
||||
++lwip_stats.memp[type].err;
|
||||
#endif /* MEMP_STATS */
|
||||
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
|
||||
MEMP_STATS_INC(err, type);
|
||||
}
|
||||
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
@@ -365,9 +371,7 @@ memp_free(memp_t type, void *mem)
|
||||
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
#if MEMP_STATS
|
||||
lwip_stats.memp[type].used--;
|
||||
#endif /* MEMP_STATS */
|
||||
MEMP_STATS_DEC(used, type);
|
||||
|
||||
memp->next = memp_tab[type];
|
||||
memp_tab[type] = memp;
|
||||
@@ -378,3 +382,5 @@ memp_free(memp_t type, void *mem)
|
||||
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
}
|
||||
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
232
src/core/netif.c
232
src/core/netif.c
@@ -45,6 +45,19 @@
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "netif/etharp.h"
|
||||
#if ENABLE_LOOPBACK
|
||||
#include "lwip/sys.h"
|
||||
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
#include "lwip/tcpip.h"
|
||||
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
#if LWIP_AUTOIP
|
||||
#include "lwip/autoip.h"
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_DHCP
|
||||
#include "lwip/dhcp.h"
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }
|
||||
@@ -106,6 +119,10 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
#if LWIP_IGMP
|
||||
netif->igmp_mac_filter = NULL;
|
||||
#endif /* LWIP_IGMP */
|
||||
#if ENABLE_LOOPBACK
|
||||
netif->loop_first = NULL;
|
||||
netif->loop_last = NULL;
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
/* remember netif specific state information data */
|
||||
netif->state = state;
|
||||
@@ -114,6 +131,9 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
|
||||
netif->loop_cnt_current = 0;
|
||||
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
|
||||
|
||||
netif_set_addr(netif, ipaddr, netmask, gw);
|
||||
|
||||
@@ -258,14 +278,14 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)
|
||||
{
|
||||
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
|
||||
LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
|
||||
pcb = tcp_active_pcbs;
|
||||
while (pcb != NULL) {
|
||||
/* PCB bound to current local interface address? */
|
||||
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
|
||||
/* this connection must be aborted */
|
||||
struct tcp_pcb *next = pcb->next;
|
||||
LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
|
||||
tcp_abort(pcb);
|
||||
pcb = next;
|
||||
} else {
|
||||
@@ -290,7 +310,7 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
snmp_insert_ipaddridx_tree(netif);
|
||||
snmp_insert_iprteidx_tree(0,netif);
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
netif->name[0], netif->name[1],
|
||||
ip4_addr1(&netif->ip_addr),
|
||||
ip4_addr2(&netif->ip_addr),
|
||||
@@ -310,7 +330,7 @@ void
|
||||
netif_set_gw(struct netif *netif, struct ip_addr *gw)
|
||||
{
|
||||
ip_addr_set(&(netif->gw), gw);
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
netif->name[0], netif->name[1],
|
||||
ip4_addr1(&netif->gw),
|
||||
ip4_addr2(&netif->gw),
|
||||
@@ -334,7 +354,7 @@ netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
|
||||
/* set new netmask to netif */
|
||||
ip_addr_set(&(netif->netmask), netmask);
|
||||
snmp_insert_iprteidx_tree(0, netif);
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
netif->name[0], netif->name[1],
|
||||
ip4_addr1(&netif->netmask),
|
||||
ip4_addr2(&netif->netmask),
|
||||
@@ -388,16 +408,18 @@ void netif_set_up(struct netif *netif)
|
||||
NETIF_STATUS_CALLBACK(netif);
|
||||
|
||||
#if LWIP_ARP
|
||||
/** For Ethernet network interfaces, we would like to send a
|
||||
* "gratuitous ARP"; this is an ARP packet sent by a node in order
|
||||
* to spontaneously cause other nodes to update an entry in their
|
||||
* ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
|
||||
*/
|
||||
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||
etharp_query(netif, &(netif->ip_addr), NULL);
|
||||
etharp_gratuitous(netif);
|
||||
}
|
||||
#endif /* LWIP_ARP */
|
||||
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* resend IGMP memberships */
|
||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||
igmp_report_groups( netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,24 +472,33 @@ void netif_set_link_up(struct netif *netif )
|
||||
{
|
||||
netif->flags |= NETIF_FLAG_LINK_UP;
|
||||
|
||||
#if LWIP_DHCP
|
||||
if (netif->dhcp) {
|
||||
dhcp_network_changed(netif);
|
||||
}
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
#if LWIP_AUTOIP
|
||||
if (netif->autoip) {
|
||||
autoip_network_changed(netif);
|
||||
}
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
if (netif->flags & NETIF_FLAG_UP) {
|
||||
#if LWIP_ARP
|
||||
/** For Ethernet network interfaces, we would like to send a
|
||||
* "gratuitous ARP"; this is an ARP packet sent by a node in order
|
||||
* to spontaneously cause other nodes to update an entry in their
|
||||
* ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
|
||||
*/
|
||||
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||
etharp_query(netif, &(netif->ip_addr), NULL);
|
||||
etharp_gratuitous(netif);
|
||||
}
|
||||
#endif /* LWIP_ARP */
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* resend IGMP memberships */
|
||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||
igmp_report_groups( netif);
|
||||
}
|
||||
/* resend IGMP memberships */
|
||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||
igmp_report_groups( netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
}
|
||||
NETIF_LINK_CALLBACK(netif);
|
||||
}
|
||||
|
||||
@@ -493,7 +524,158 @@ u8_t netif_is_link_up(struct netif *netif)
|
||||
*/
|
||||
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif ))
|
||||
{
|
||||
if ( netif )
|
||||
netif->link_callback = link_callback;
|
||||
if (netif) {
|
||||
netif->link_callback = link_callback;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||
|
||||
#if ENABLE_LOOPBACK
|
||||
/**
|
||||
* Send an IP packet to be received on the same netif (loopif-like).
|
||||
* The pbuf is simply copied and handed back to netif->input.
|
||||
* In multithreaded mode, this is done directly since netif->input must put
|
||||
* the packet on a queue.
|
||||
* In callback mode, the packet is put on an internal queue and is fed to
|
||||
* netif->input by netif_poll().
|
||||
*
|
||||
* @param netif the lwip network interface structure
|
||||
* @param p the (IP) packet to 'send'
|
||||
* @param ipaddr the ip address to send the packet to (not used)
|
||||
* @return ERR_OK if the packet has been sent
|
||||
* ERR_MEM if the pbuf used to copy the packet couldn't be allocated
|
||||
*/
|
||||
err_t
|
||||
netif_loop_output(struct netif *netif, struct pbuf *p,
|
||||
struct ip_addr *ipaddr)
|
||||
{
|
||||
struct pbuf *r;
|
||||
err_t err;
|
||||
struct pbuf *last;
|
||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||
u8_t clen = 0;
|
||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
|
||||
/* Allocate a new pbuf */
|
||||
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
|
||||
if (r == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||
clen = pbuf_clen(r);
|
||||
/* check for overflow or too many pbuf on queue */
|
||||
if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
|
||||
((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
|
||||
pbuf_free(r);
|
||||
r = NULL;
|
||||
return ERR_MEM;
|
||||
}
|
||||
netif->loop_cnt_current += clen;
|
||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||
|
||||
/* Copy the whole pbuf queue p into the single pbuf r */
|
||||
if ((err = pbuf_copy(r, p)) != ERR_OK) {
|
||||
pbuf_free(r);
|
||||
r = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Put the packet on a linked list which gets emptied through calling
|
||||
netif_poll(). */
|
||||
|
||||
/* let last point to the last pbuf in chain r */
|
||||
for (last = r; last->next != NULL; last = last->next);
|
||||
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
if(netif->loop_first != NULL) {
|
||||
LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
|
||||
netif->loop_last->next = r;
|
||||
netif->loop_last = last;
|
||||
} else {
|
||||
netif->loop_first = r;
|
||||
netif->loop_last = last;
|
||||
}
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
|
||||
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
/* For multithreading environment, schedule a call to netif_poll */
|
||||
tcpip_callback((void (*)(void *))(netif_poll), netif);
|
||||
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_poll() in the main loop of your application. This is to prevent
|
||||
* reentering non-reentrant functions like tcp_input(). Packets passed to
|
||||
* netif_loop_output() are put on a list that is passed to netif->input() by
|
||||
* netif_poll().
|
||||
*/
|
||||
void
|
||||
netif_poll(struct netif *netif)
|
||||
{
|
||||
struct pbuf *in;
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
|
||||
do {
|
||||
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
in = netif->loop_first;
|
||||
if(in != NULL) {
|
||||
struct pbuf *in_end = in;
|
||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||
u8_t clen = pbuf_clen(in);
|
||||
/* adjust the number of pbufs on queue */
|
||||
LWIP_ASSERT("netif->loop_cnt_current underflow",
|
||||
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
|
||||
netif->loop_cnt_current -= clen;
|
||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||
while(in_end->len != in_end->tot_len) {
|
||||
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
|
||||
in_end = in_end->next;
|
||||
}
|
||||
/* 'in_end' now points to the last pbuf from 'in' */
|
||||
if(in_end == netif->loop_last) {
|
||||
/* this was the last pbuf in the list */
|
||||
netif->loop_first = netif->loop_last = NULL;
|
||||
} else {
|
||||
/* pop the pbuf off the list */
|
||||
netif->loop_first = in_end->next;
|
||||
LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
|
||||
}
|
||||
/* De-queue the pbuf from its successors on the 'loop_' list. */
|
||||
in_end->next = NULL;
|
||||
}
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
|
||||
if(in != NULL) {
|
||||
/* loopback packets are always IP packets! */
|
||||
if(ip_input(in, netif) != ERR_OK) {
|
||||
pbuf_free(in);
|
||||
}
|
||||
/* Don't reference the packet any more! */
|
||||
in = NULL;
|
||||
}
|
||||
/* go on while there is a packet on the list */
|
||||
} while(netif->loop_first != NULL);
|
||||
}
|
||||
|
||||
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
/**
|
||||
* Calls netif_poll() for every netif on the netif_list.
|
||||
*/
|
||||
void
|
||||
netif_poll_all(void)
|
||||
{
|
||||
struct netif *netif = netif_list;
|
||||
/* loop through netifs */
|
||||
while (netif != NULL) {
|
||||
netif_poll(netif);
|
||||
/* proceed to next network interface */
|
||||
netif = netif->next;
|
||||
}
|
||||
}
|
||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
198
src/core/pbuf.c
198
src/core/pbuf.c
@@ -70,6 +70,9 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "arch/perf.h"
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
#include "lwip/tcp.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -78,6 +81,72 @@
|
||||
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
|
||||
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
|
||||
|
||||
#if !TCP_QUEUE_OOSEQ || NO_SYS
|
||||
#define PBUF_POOL_IS_EMPTY()
|
||||
#else /* !TCP_QUEUE_OOSEQ || NO_SYS */
|
||||
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
|
||||
#ifndef PBUF_POOL_FREE_OOSEQ
|
||||
#define PBUF_POOL_FREE_OOSEQ 1
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||
|
||||
#if PBUF_POOL_FREE_OOSEQ
|
||||
#include "lwip/tcpip.h"
|
||||
#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
|
||||
static u8_t pbuf_free_ooseq_queued;
|
||||
/**
|
||||
* Attempt to reclaim some memory from queued out-of-sequence TCP segments
|
||||
* if we run out of pool pbufs. It's better to give priority to new packets
|
||||
* if we're running out.
|
||||
*
|
||||
* This must be done in the correct thread context therefore this function
|
||||
* can only be used with NO_SYS=0 and through tcpip_callback.
|
||||
*/
|
||||
static void
|
||||
pbuf_free_ooseq(void* arg)
|
||||
{
|
||||
struct tcp_pcb* pcb;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
pbuf_free_ooseq_queued = 0;
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
|
||||
for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
|
||||
if (NULL != pcb->ooseq) {
|
||||
/** Free the ooseq pbufs of one PCB only */
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
|
||||
tcp_segs_free(pcb->ooseq);
|
||||
pcb->ooseq = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Queue a call to pbuf_free_ooseq if not already queued. */
|
||||
static void
|
||||
pbuf_pool_is_empty(void)
|
||||
{
|
||||
u8_t queued;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
queued = pbuf_free_ooseq_queued;
|
||||
pbuf_free_ooseq_queued = 1;
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
|
||||
if(!queued) {
|
||||
/* queue a call to pbuf_free_ooseq if not already queued */
|
||||
if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
pbuf_free_ooseq_queued = 0;
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||
#endif /* !TCP_QUEUE_OOSEQ || NO_SYS */
|
||||
|
||||
/**
|
||||
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
|
||||
*
|
||||
@@ -115,7 +184,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
struct pbuf *p, *q, *r;
|
||||
u16_t offset;
|
||||
s32_t rem_len; /* remaining length */
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
|
||||
|
||||
/* determine header offset */
|
||||
offset = 0;
|
||||
@@ -142,9 +211,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
switch (type) {
|
||||
case PBUF_POOL:
|
||||
/* allocate head of pbuf chain into p */
|
||||
p = memp_malloc(MEMP_PBUF_POOL);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
|
||||
p = memp_malloc(MEMP_PBUF_POOL);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
|
||||
if (p == NULL) {
|
||||
PBUF_POOL_IS_EMPTY();
|
||||
return NULL;
|
||||
}
|
||||
p->type = type;
|
||||
@@ -161,6 +231,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
|
||||
((u8_t*)p->payload + p->len <=
|
||||
(u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
|
||||
LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
|
||||
(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
|
||||
/* set reference count (needed here in case we fail) */
|
||||
p->ref = 1;
|
||||
|
||||
@@ -174,6 +246,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
while (rem_len > 0) {
|
||||
q = memp_malloc(MEMP_PBUF_POOL);
|
||||
if (q == NULL) {
|
||||
PBUF_POOL_IS_EMPTY();
|
||||
/* free chain so far allocated */
|
||||
pbuf_free(p);
|
||||
/* bail out unsuccesfully */
|
||||
@@ -227,7 +300,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
/* only allocate memory for the pbuf structure */
|
||||
p = memp_malloc(MEMP_PBUF);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
|
||||
(type == PBUF_ROM) ? "ROM" : "REF"));
|
||||
return NULL;
|
||||
}
|
||||
@@ -245,7 +319,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
p->ref = 1;
|
||||
/* set flags */
|
||||
p->flags = 0;
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -272,6 +346,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
|
||||
u16_t rem_len; /* remaining length */
|
||||
s32_t grow;
|
||||
|
||||
LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
|
||||
LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
|
||||
p->type == PBUF_ROM ||
|
||||
p->type == PBUF_RAM ||
|
||||
@@ -299,6 +374,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
|
||||
q->tot_len += (u16_t)grow;
|
||||
/* proceed to next pbuf in chain */
|
||||
q = q->next;
|
||||
LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
|
||||
}
|
||||
/* we have now reached the new last pbuf (in q) */
|
||||
/* rem_len == desired length for pbuf q */
|
||||
@@ -383,9 +459,9 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
|
||||
p->payload = (u8_t *)p->payload - header_size_increment;
|
||||
/* boundary check fails? */
|
||||
if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
|
||||
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
|
||||
(void *)p->payload,
|
||||
(void *)(p + 1)));\
|
||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
|
||||
(void *)p->payload, (void *)(p + 1)));
|
||||
/* restore old payload pointer */
|
||||
p->payload = payload;
|
||||
/* bail out unsuccesfully */
|
||||
@@ -412,7 +488,7 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
|
||||
p->len += header_size_increment;
|
||||
p->tot_len += header_size_increment;
|
||||
|
||||
LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
|
||||
(void *)payload, (void *)p->payload, header_size_increment));
|
||||
|
||||
return 0;
|
||||
@@ -461,10 +537,11 @@ pbuf_free(struct pbuf *p)
|
||||
if (p == NULL) {
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
/* if assertions are disabled, proceed with debug output */
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("pbuf_free(p == NULL) was called.\n"));
|
||||
return 0;
|
||||
}
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
|
||||
|
||||
PERF_START;
|
||||
|
||||
@@ -491,7 +568,7 @@ pbuf_free(struct pbuf *p)
|
||||
if (ref == 0) {
|
||||
/* remember next pbuf in chain for next iteration */
|
||||
q = p->next;
|
||||
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));
|
||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
|
||||
type = p->type;
|
||||
/* is this a pbuf from the pool? */
|
||||
if (type == PBUF_POOL) {
|
||||
@@ -509,7 +586,7 @@ pbuf_free(struct pbuf *p)
|
||||
/* p->ref > 0, this pbuf is still referenced to */
|
||||
/* (and so the remaining pbufs in chain as well) */
|
||||
} else {
|
||||
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
|
||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
|
||||
/* stop walking through the chain */
|
||||
p = NULL;
|
||||
}
|
||||
@@ -614,7 +691,7 @@ pbuf_chain(struct pbuf *h, struct pbuf *t)
|
||||
pbuf_cat(h, t);
|
||||
/* t is now referenced by h */
|
||||
pbuf_ref(t);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -643,10 +720,10 @@ pbuf_dechain(struct pbuf *p)
|
||||
/* total length of pbuf p is its own length only */
|
||||
p->tot_len = p->len;
|
||||
/* q is no longer referenced by p, free it */
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
|
||||
tail_gone = pbuf_free(q);
|
||||
if (tail_gone > 0) {
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
|
||||
("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
|
||||
}
|
||||
/* return remaining tail or NULL if deallocated */
|
||||
@@ -667,8 +744,8 @@ pbuf_dechain(struct pbuf *p)
|
||||
*
|
||||
* @note Only one packet is copied, no packet queue!
|
||||
*
|
||||
* @param p_to pbuf source of the copy
|
||||
* @param p_from pbuf destination of the copy
|
||||
* @param p_to pbuf destination of the copy
|
||||
* @param p_from pbuf source of the copy
|
||||
*
|
||||
* @return ERR_OK if pbuf was copied
|
||||
* ERR_ARG if one of the pbufs is NULL or p_to is not big
|
||||
@@ -679,7 +756,7 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
||||
{
|
||||
u16_t offset_to=0, offset_from=0, len;
|
||||
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n",
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
|
||||
(void*)p_to, (void*)p_from));
|
||||
|
||||
/* is the target big enough to hold the source? */
|
||||
@@ -725,7 +802,7 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
||||
(p_to->next == NULL), return ERR_VAL;);
|
||||
}
|
||||
} while (p_from);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n"));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -735,8 +812,10 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
||||
*
|
||||
* @param buf the pbuf from which to copy data
|
||||
* @param dataptr the application supplied buffer
|
||||
* @param len length of data to copy (dataptr must be big enough)
|
||||
* @param len length of data to copy (dataptr must be big enough). No more
|
||||
* than buf->tot_len will be copied, irrespective of len
|
||||
* @param offset offset into the packet buffer from where to begin copying len bytes
|
||||
* @return the number of bytes copied, or 0 on failure
|
||||
*/
|
||||
u16_t
|
||||
pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||
@@ -746,8 +825,8 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||
u16_t buf_copy_len;
|
||||
u16_t copied_total = 0;
|
||||
|
||||
LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
|
||||
LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
|
||||
LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
|
||||
LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
|
||||
|
||||
left = 0;
|
||||
|
||||
@@ -775,3 +854,76 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||
}
|
||||
return copied_total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy application supplied data into a pbuf.
|
||||
* This function can only be used to copy the equivalent of buf->tot_len data.
|
||||
*
|
||||
* @param buf pbuf to fill with data
|
||||
* @param dataptr application supplied data buffer
|
||||
* @param len length of the application supplied data buffer
|
||||
*
|
||||
* @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
|
||||
*/
|
||||
err_t
|
||||
pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
|
||||
{
|
||||
struct pbuf *p;
|
||||
u16_t buf_copy_len;
|
||||
u16_t total_copy_len = len;
|
||||
u16_t copied_total = 0;
|
||||
|
||||
LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
|
||||
LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
|
||||
|
||||
if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
|
||||
for(p = buf; total_copy_len != 0; p = p->next) {
|
||||
LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
|
||||
buf_copy_len = total_copy_len;
|
||||
if (buf_copy_len > p->len) {
|
||||
/* this pbuf cannot hold all remaining data */
|
||||
buf_copy_len = p->len;
|
||||
}
|
||||
/* copy the necessary parts of the buffer */
|
||||
MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
|
||||
total_copy_len -= buf_copy_len;
|
||||
copied_total += buf_copy_len;
|
||||
}
|
||||
LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single pbuf out of a queue of pbufs.
|
||||
*
|
||||
* @remark: The source pbuf 'p' is not freed by this function because that can
|
||||
* be illegal in some places!
|
||||
*
|
||||
* @param p the source pbuf
|
||||
* @param layer pbuf_layer of the new pbuf
|
||||
*
|
||||
* @return a new, single pbuf (p->next is NULL)
|
||||
* or the old pbuf if allocation fails
|
||||
*/
|
||||
struct pbuf*
|
||||
pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
|
||||
{
|
||||
struct pbuf *q;
|
||||
err_t err;
|
||||
if (p->next == NULL) {
|
||||
return p;
|
||||
}
|
||||
q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
/* @todo: what do we do now? */
|
||||
return p;
|
||||
}
|
||||
err = pbuf_copy(q, p);
|
||||
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
|
||||
pbuf_free(p);
|
||||
return q;
|
||||
}
|
||||
|
||||
@@ -93,24 +93,29 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||
/* this allows multiple pcbs to match against the packet by design */
|
||||
while ((eaten == 0) && (pcb != NULL)) {
|
||||
if (pcb->protocol == proto) {
|
||||
/* receive callback function available? */
|
||||
if (pcb->recv != NULL) {
|
||||
/* the receive callback function did not eat the packet? */
|
||||
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)
|
||||
{
|
||||
/* receive function ate the packet */
|
||||
p = NULL;
|
||||
eaten = 1;
|
||||
if (prev != NULL) {
|
||||
/* move the pcb to the front of raw_pcbs so that is
|
||||
found faster next time */
|
||||
prev->next = pcb->next;
|
||||
pcb->next = raw_pcbs;
|
||||
raw_pcbs = pcb;
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
/* broadcast filter? */
|
||||
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp))
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
{
|
||||
/* receive callback function available? */
|
||||
if (pcb->recv != NULL) {
|
||||
/* the receive callback function did not eat the packet? */
|
||||
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) {
|
||||
/* receive function ate the packet */
|
||||
p = NULL;
|
||||
eaten = 1;
|
||||
if (prev != NULL) {
|
||||
/* move the pcb to the front of raw_pcbs so that is
|
||||
found faster next time */
|
||||
prev->next = pcb->next;
|
||||
pcb->next = raw_pcbs;
|
||||
raw_pcbs = pcb;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no receive callback function was set for this raw PCB */
|
||||
}
|
||||
/* no receive callback function was set for this raw PCB */
|
||||
/* drop the packet */
|
||||
}
|
||||
prev = pcb;
|
||||
@@ -205,7 +210,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
struct ip_addr *src_ip;
|
||||
struct pbuf *q; /* q will be sent down the stack */
|
||||
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_sendto\n"));
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
|
||||
|
||||
/* not enough space to add an IP header to first pbuf in given p chain? */
|
||||
if (pbuf_header(p, IP_HLEN)) {
|
||||
@@ -213,7 +218,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
|
||||
/* new header pbuf could not be allocated? */
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* chain header q in front of given pbuf p */
|
||||
@@ -228,9 +233,9 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
return ERR_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((netif = ip_route(ipaddr)) == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
|
||||
/* free any temporary header pbuf allocated by pbuf_header() */
|
||||
if (q != p) {
|
||||
pbuf_free(q);
|
||||
@@ -238,6 +243,18 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
#if IP_SOF_BROADCAST
|
||||
/* broadcast filter? */
|
||||
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif) ) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
|
||||
/* free any temporary header pbuf allocated by pbuf_header() */
|
||||
if (q != p) {
|
||||
pbuf_free(q);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
#endif /* IP_SOF_BROADCAST */
|
||||
|
||||
if (ip_addr_isany(&pcb->local_ip)) {
|
||||
/* use outgoing network interface IP address as source address */
|
||||
src_ip = &(netif->ip_addr);
|
||||
@@ -318,7 +335,7 @@ struct raw_pcb *
|
||||
raw_new(u8_t proto) {
|
||||
struct raw_pcb *pcb;
|
||||
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_new\n"));
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
|
||||
|
||||
pcb = memp_malloc(MEMP_RAW_PCB);
|
||||
/* could allocate RAW PCB? */
|
||||
|
||||
@@ -2077,25 +2077,25 @@ void snmp_get_snmpenableauthentraps(u8_t *value)
|
||||
void
|
||||
noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
|
||||
{
|
||||
if (ident_len){}
|
||||
if (ident){}
|
||||
LWIP_UNUSED_ARG(ident_len);
|
||||
LWIP_UNUSED_ARG(ident);
|
||||
od->instance = MIB_OBJECT_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
noleafs_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
{
|
||||
if (od){}
|
||||
if (len){}
|
||||
if (value){}
|
||||
LWIP_UNUSED_ARG(od);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
LWIP_UNUSED_ARG(value);
|
||||
}
|
||||
|
||||
u8_t
|
||||
noleafs_set_test(struct obj_def *od, u16_t len, void *value)
|
||||
{
|
||||
if (od){}
|
||||
if (len){}
|
||||
if (value){}
|
||||
LWIP_UNUSED_ARG(od);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
LWIP_UNUSED_ARG(value);
|
||||
/* can't set */
|
||||
return 0;
|
||||
}
|
||||
@@ -2103,9 +2103,9 @@ noleafs_set_test(struct obj_def *od, u16_t len, void *value)
|
||||
void
|
||||
noleafs_set_value(struct obj_def *od, u16_t len, void *value)
|
||||
{
|
||||
if (od){}
|
||||
if (len){}
|
||||
if (value){}
|
||||
LWIP_UNUSED_ARG(od);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
LWIP_UNUSED_ARG(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -2205,10 +2205,10 @@ system_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
switch (id)
|
||||
{
|
||||
case 1: /* sysDescr */
|
||||
ocstrncpy(value,sysdescr_ptr,len);
|
||||
ocstrncpy(value,sysdescr_ptr, len);
|
||||
break;
|
||||
case 2: /* sysObjectID */
|
||||
objectidncpy((s32_t*)value,(s32_t*)sysobjid.id,len / sizeof(s32_t));
|
||||
objectidncpy((s32_t*)value, (s32_t*)sysobjid.id, (u8_t)(len / sizeof(s32_t)));
|
||||
break;
|
||||
case 3: /* sysUpTime */
|
||||
{
|
||||
@@ -2238,7 +2238,7 @@ system_set_test(struct obj_def *od, u16_t len, void *value)
|
||||
{
|
||||
u8_t id, set_ok;
|
||||
|
||||
if (value) {}
|
||||
LWIP_UNUSED_ARG(value);
|
||||
set_ok = 0;
|
||||
id = od->id_inst_ptr[0];
|
||||
switch (id)
|
||||
@@ -2332,7 +2332,7 @@ interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
|
||||
static void
|
||||
interfaces_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
{
|
||||
if (len){}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
if (od->id_inst_ptr[0] == 1)
|
||||
{
|
||||
s32_t *sint_ptr = value;
|
||||
@@ -2606,7 +2606,7 @@ ifentry_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
}
|
||||
break;
|
||||
case 22: /* ifSpecific */
|
||||
objectidncpy((s32_t*)value,(s32_t*)ifspecific.id,len / sizeof(s32_t));
|
||||
objectidncpy((s32_t*)value, (s32_t*)ifspecific.id, (u8_t)(len / sizeof(s32_t)));
|
||||
break;
|
||||
};
|
||||
}
|
||||
@@ -2724,7 +2724,8 @@ atentry_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
struct ip_addr ip;
|
||||
struct netif *netif;
|
||||
|
||||
if (len) {}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */
|
||||
|
||||
snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
|
||||
snmp_oidtoip(&od->id_inst_ptr[2], &ip);
|
||||
@@ -2831,7 +2832,7 @@ ip_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
{
|
||||
u8_t id;
|
||||
|
||||
if (len) {}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
id = od->id_inst_ptr[0];
|
||||
switch (id)
|
||||
{
|
||||
@@ -2985,7 +2986,7 @@ ip_set_test(struct obj_def *od, u16_t len, void *value)
|
||||
u8_t id, set_ok;
|
||||
s32_t *sint_ptr = value;
|
||||
|
||||
if (len) {}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
set_ok = 0;
|
||||
id = od->id_inst_ptr[0];
|
||||
switch (id)
|
||||
@@ -3065,7 +3066,7 @@ ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
struct ip_addr ip;
|
||||
struct netif *netif = netif_list;
|
||||
|
||||
if (len) {}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
snmp_oidtoip(&od->id_inst_ptr[1], &ip);
|
||||
ip.addr = htonl(ip.addr);
|
||||
ifidx = 0;
|
||||
@@ -3342,7 +3343,7 @@ ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
}
|
||||
break;
|
||||
case 13: /* ipRouteInfo */
|
||||
objectidncpy((s32_t*)value,(s32_t*)iprouteinfo.id,len / sizeof(s32_t));
|
||||
objectidncpy((s32_t*)value, (s32_t*)iprouteinfo.id, (u8_t)(len / sizeof(s32_t)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3408,7 +3409,8 @@ ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
struct ip_addr ip;
|
||||
struct netif *netif;
|
||||
|
||||
if (len) {}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */
|
||||
|
||||
snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
|
||||
snmp_oidtoip(&od->id_inst_ptr[2], &ip);
|
||||
@@ -3482,7 +3484,7 @@ icmp_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
u32_t *uint_ptr = value;
|
||||
u8_t id;
|
||||
|
||||
if (len){}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
id = od->id_inst_ptr[0];
|
||||
switch (id)
|
||||
{
|
||||
@@ -3636,7 +3638,7 @@ tcp_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
s32_t *sint_ptr = value;
|
||||
u8_t id;
|
||||
|
||||
if (len){}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
id = od->id_inst_ptr[0];
|
||||
switch (id)
|
||||
{
|
||||
@@ -3804,7 +3806,7 @@ udp_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
u32_t *uint_ptr = value;
|
||||
u8_t id;
|
||||
|
||||
if (len){}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
id = od->id_inst_ptr[0];
|
||||
switch (id)
|
||||
{
|
||||
@@ -3870,7 +3872,7 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
struct ip_addr ip;
|
||||
u16_t port;
|
||||
|
||||
if (len){}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
snmp_oidtoip(&od->id_inst_ptr[1], &ip);
|
||||
ip.addr = htonl(ip.addr);
|
||||
port = od->id_inst_ptr[5];
|
||||
@@ -3977,7 +3979,7 @@ snmp_get_value(struct obj_def *od, u16_t len, void *value)
|
||||
u32_t *uint_ptr = value;
|
||||
u8_t id;
|
||||
|
||||
if (len){}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
id = od->id_inst_ptr[0];
|
||||
switch (id)
|
||||
{
|
||||
@@ -4080,7 +4082,7 @@ snmp_set_test(struct obj_def *od, u16_t len, void *value)
|
||||
{
|
||||
u8_t id, set_ok;
|
||||
|
||||
if (len) {}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
set_ok = 0;
|
||||
id = od->id_inst_ptr[0];
|
||||
if (id == 30)
|
||||
@@ -4113,7 +4115,7 @@ snmp_set_value(struct obj_def *od, u16_t len, void *value)
|
||||
{
|
||||
u8_t id;
|
||||
|
||||
if (len) {}
|
||||
LWIP_UNUSED_ARG(len);
|
||||
id = od->id_inst_ptr[0];
|
||||
if (id == 30)
|
||||
{
|
||||
|
||||
@@ -118,7 +118,7 @@ snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
|
||||
u16_t i;
|
||||
|
||||
i = 0;
|
||||
while (nif != netif)
|
||||
while ((nif != NULL) && (nif != netif))
|
||||
{
|
||||
nif = nif->next;
|
||||
i++;
|
||||
|
||||
@@ -589,9 +589,10 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
{
|
||||
struct mib_external_node *en;
|
||||
|
||||
/** set_value_a() @todo: use reply value?? */
|
||||
/** set_value_a() */
|
||||
en = msg_ps->ext_mib_node;
|
||||
en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
|
||||
en->set_value_a(request_id, &msg_ps->ext_object_def,
|
||||
msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);
|
||||
|
||||
/** @todo use set_value_pc() if toobig */
|
||||
msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
|
||||
@@ -1145,7 +1146,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
|
||||
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
||||
if ((derr != ERR_OK) ||
|
||||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
|
||||
(len <= 0) || (len > vb_len))
|
||||
(len == 0) || (len > vb_len))
|
||||
{
|
||||
snmp_inc_snmpinasnparseerrs();
|
||||
/* free varbinds (if available) */
|
||||
|
||||
@@ -54,7 +54,6 @@ stats_display_proto(struct stats_proto *proto, char *name)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
|
||||
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
|
||||
LWIP_PLATFORM_DIAG(("rexmit: %"STAT_COUNTER_F"\n\t", proto->rexmit));
|
||||
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));
|
||||
LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
|
||||
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));
|
||||
@@ -68,6 +67,7 @@ stats_display_proto(struct stats_proto *proto, char *name)
|
||||
LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));
|
||||
}
|
||||
|
||||
#if IGMP_STATS
|
||||
void
|
||||
stats_display_igmp(struct stats_igmp *igmp)
|
||||
{
|
||||
@@ -82,7 +82,9 @@ stats_display_igmp(struct stats_igmp *igmp)
|
||||
LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed));
|
||||
LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed));
|
||||
}
|
||||
#endif /* IGMP_STATS */
|
||||
|
||||
#if MEM_STATS || MEMP_STATS
|
||||
void
|
||||
stats_display_mem(struct stats_mem *mem, char *name)
|
||||
{
|
||||
@@ -93,48 +95,53 @@ stats_display_mem(struct stats_mem *mem, char *name)
|
||||
LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));
|
||||
}
|
||||
|
||||
void
|
||||
stats_display(void)
|
||||
{
|
||||
#if MEMP_STATS
|
||||
s16_t i;
|
||||
void
|
||||
stats_display_memp(struct stats_mem *mem, int index)
|
||||
{
|
||||
char * memp_names[] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) desc,
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
#endif
|
||||
#if LINK_STATS
|
||||
stats_display_proto(&lwip_stats.link, "LINK");
|
||||
#endif
|
||||
#if ETHARP_STATS
|
||||
stats_display_proto(&lwip_stats.etharp, "ETHARP");
|
||||
#endif
|
||||
#if IPFRAG_STATS
|
||||
stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");
|
||||
#endif
|
||||
#if IP_STATS
|
||||
stats_display_proto(&lwip_stats.ip, "IP");
|
||||
#endif
|
||||
#if ICMP_STATS
|
||||
stats_display_proto(&lwip_stats.icmp, "ICMP");
|
||||
#endif
|
||||
#if IGMP_STATS
|
||||
stats_display_igmp(&lwip_stats.igmp);
|
||||
#endif
|
||||
#if UDP_STATS
|
||||
stats_display_proto(&lwip_stats.udp, "UDP");
|
||||
#endif
|
||||
#if TCP_STATS
|
||||
stats_display_proto(&lwip_stats.tcp, "TCP");
|
||||
#endif
|
||||
#if MEM_STATS
|
||||
stats_display_mem(&lwip_stats.mem, "HEAP");
|
||||
#endif
|
||||
#if MEMP_STATS
|
||||
for (i = 0; i < MEMP_MAX; i++) {
|
||||
stats_display_mem(&lwip_stats.memp[i], memp_names[i]);
|
||||
if(index < MEMP_MAX) {
|
||||
stats_display_mem(mem, memp_names[index]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
#endif /* MEM_STATS || MEMP_STATS */
|
||||
|
||||
#if SYS_STATS
|
||||
void
|
||||
stats_display_sys(struct stats_sys *sys)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
|
||||
LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
|
||||
LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
|
||||
LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
|
||||
LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
|
||||
LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
|
||||
LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err));
|
||||
}
|
||||
#endif /* SYS_STATS */
|
||||
|
||||
void
|
||||
stats_display(void)
|
||||
{
|
||||
s16_t i;
|
||||
|
||||
LINK_STATS_DISPLAY();
|
||||
ETHARP_STATS_DISPLAY();
|
||||
IPFRAG_STATS_DISPLAY();
|
||||
IP_STATS_DISPLAY();
|
||||
IGMP_STATS_DISPLAY();
|
||||
ICMP_STATS_DISPLAY();
|
||||
UDP_STATS_DISPLAY();
|
||||
TCP_STATS_DISPLAY();
|
||||
MEM_STATS_DISPLAY();
|
||||
for (i = 0; i < MEMP_MAX; i++) {
|
||||
MEMP_STATS_DISPLAY(i);
|
||||
}
|
||||
SYS_STATS_DISPLAY();
|
||||
}
|
||||
#endif /* LWIP_STATS_DISPLAY */
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ struct sswt_cb
|
||||
void
|
||||
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||
{
|
||||
u32_t time;
|
||||
u32_t time_needed;
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeo *tmptimeout;
|
||||
sys_timeout_handler h;
|
||||
@@ -76,18 +76,18 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||
|
||||
if (!timeouts || !timeouts->next) {
|
||||
UNLOCK_TCPIP_CORE();
|
||||
time = sys_arch_mbox_fetch(mbox, msg, 0);
|
||||
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
|
||||
LOCK_TCPIP_CORE();
|
||||
} else {
|
||||
if (timeouts->next->time > 0) {
|
||||
UNLOCK_TCPIP_CORE();
|
||||
time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
|
||||
time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
|
||||
LOCK_TCPIP_CORE();
|
||||
} else {
|
||||
time = SYS_ARCH_TIMEOUT;
|
||||
time_needed = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time == SYS_ARCH_TIMEOUT) {
|
||||
if (time_needed == SYS_ARCH_TIMEOUT) {
|
||||
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
||||
could be fetched. We should now call the timeout handler and
|
||||
deallocate the memory allocated for the timeout. */
|
||||
@@ -97,7 +97,7 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||
arg = tmptimeout->arg;
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
if (h != NULL) {
|
||||
LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg));
|
||||
LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", *(void**)&h, arg));
|
||||
h(arg);
|
||||
}
|
||||
|
||||
@@ -107,8 +107,8 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
||||
occured. The time variable is set to the number of
|
||||
milliseconds we waited for the message. */
|
||||
if (time < timeouts->next->time) {
|
||||
timeouts->next->time -= time;
|
||||
if (time_needed < timeouts->next->time) {
|
||||
timeouts->next->time -= time_needed;
|
||||
} else {
|
||||
timeouts->next->time = 0;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||
void
|
||||
sys_sem_wait(sys_sem_t sem)
|
||||
{
|
||||
u32_t time;
|
||||
u32_t time_needed;
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeo *tmptimeout;
|
||||
sys_timeout_handler h;
|
||||
@@ -139,12 +139,12 @@ sys_sem_wait(sys_sem_t sem)
|
||||
sys_arch_sem_wait(sem, 0);
|
||||
} else {
|
||||
if (timeouts->next->time > 0) {
|
||||
time = sys_arch_sem_wait(sem, timeouts->next->time);
|
||||
time_needed = sys_arch_sem_wait(sem, timeouts->next->time);
|
||||
} else {
|
||||
time = SYS_ARCH_TIMEOUT;
|
||||
time_needed = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time == SYS_ARCH_TIMEOUT) {
|
||||
if (time_needed == SYS_ARCH_TIMEOUT) {
|
||||
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
||||
could be fetched. We should now call the timeout handler and
|
||||
deallocate the memory allocated for the timeout. */
|
||||
@@ -154,7 +154,7 @@ sys_sem_wait(sys_sem_t sem)
|
||||
arg = tmptimeout->arg;
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
if (h != NULL) {
|
||||
LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void*)&h, (void *)arg));
|
||||
LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", *(void**)&h, (void *)arg));
|
||||
h(arg);
|
||||
}
|
||||
|
||||
@@ -164,8 +164,8 @@ sys_sem_wait(sys_sem_t sem)
|
||||
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
||||
occured. The time variable is set to the number of
|
||||
milliseconds we waited for the message. */
|
||||
if (time < timeouts->next->time) {
|
||||
timeouts->next->time -= time;
|
||||
if (time_needed < timeouts->next->time) {
|
||||
timeouts->next->time -= time_needed;
|
||||
} else {
|
||||
timeouts->next->time = 0;
|
||||
}
|
||||
@@ -203,7 +203,7 @@ sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
|
||||
(void *)timeout, msecs, (void*)&h, (void *)arg));
|
||||
(void *)timeout, msecs, *(void**)&h, (void *)arg));
|
||||
|
||||
if (timeouts == NULL) {
|
||||
LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
|
||||
@@ -264,13 +264,15 @@ sys_untimeout(sys_timeout_handler h, void *arg)
|
||||
if ((t->h == h) && (t->arg == arg)) {
|
||||
/* We have a match */
|
||||
/* Unlink from previous in list */
|
||||
if (prev_t == NULL)
|
||||
if (prev_t == NULL) {
|
||||
timeouts->next = t->next;
|
||||
else
|
||||
} else {
|
||||
prev_t->next = t->next;
|
||||
}
|
||||
/* If not the last one, add time of this one back to next */
|
||||
if (t->next != NULL)
|
||||
if (t->next != NULL) {
|
||||
t->next->time += t->time;
|
||||
}
|
||||
memp_free(MEMP_SYS_TIMEOUT, t);
|
||||
return;
|
||||
}
|
||||
|
||||
221
src/core/tcp.c
221
src/core/tcp.c
@@ -49,9 +49,25 @@
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
const char *tcp_state_str[] = {
|
||||
"CLOSED",
|
||||
"LISTEN",
|
||||
"SYN_SENT",
|
||||
"SYN_RCVD",
|
||||
"ESTABLISHED",
|
||||
"FIN_WAIT_1",
|
||||
"FIN_WAIT_2",
|
||||
"CLOSE_WAIT",
|
||||
"CLOSING",
|
||||
"LAST_ACK",
|
||||
"TIME_WAIT"
|
||||
};
|
||||
|
||||
/* Incremented every coarse grained timer shot (typically every 500 ms). */
|
||||
u32_t tcp_ticks;
|
||||
const u8_t tcp_backoff[13] =
|
||||
@@ -186,14 +202,15 @@ tcp_close(struct tcp_pcb *pcb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts a connection by sending a RST to the remote host and deletes
|
||||
* the local protocol control block. This is done when a connection is
|
||||
* killed because of shortage of memory.
|
||||
* Abandons a connection and optionally sends a RST to the remote
|
||||
* host. Deletes the local protocol control block. This is done when
|
||||
* a connection is killed because of shortage of memory.
|
||||
*
|
||||
* @param pcb the tcp_pcb to abort
|
||||
* @param reset boolean to indicate whether a reset should be sent
|
||||
*/
|
||||
void
|
||||
tcp_abort(struct tcp_pcb *pcb)
|
||||
tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||
{
|
||||
u32_t seqno, ackno;
|
||||
u16_t remote_port, local_port;
|
||||
@@ -235,8 +252,10 @@ tcp_abort(struct tcp_pcb *pcb)
|
||||
#endif /* TCP_QUEUE_OOSEQ */
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));
|
||||
tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
|
||||
if (reset) {
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
|
||||
tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +277,7 @@ tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
{
|
||||
struct tcp_pcb *cpcb;
|
||||
|
||||
LWIP_ERROR("tcp_connect: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
|
||||
LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
|
||||
|
||||
if (port == 0) {
|
||||
port = tcp_new_port();
|
||||
@@ -380,6 +399,33 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||
return (struct tcp_pcb *)lpcb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state that tracks the available window space to advertise.
|
||||
*
|
||||
* Returns how much extra window would be advertised if we sent an
|
||||
* update now.
|
||||
*/
|
||||
u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
|
||||
{
|
||||
u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;
|
||||
|
||||
if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) {
|
||||
/* we can advertise more window */
|
||||
pcb->rcv_ann_wnd = pcb->rcv_wnd;
|
||||
return new_right_edge - pcb->rcv_ann_right_edge;
|
||||
} else {
|
||||
if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {
|
||||
/* Can happen due to other end sending out of advertised window,
|
||||
* but within actual available (but not yet advertised) window */
|
||||
pcb->rcv_ann_wnd = 0;
|
||||
} else {
|
||||
/* keep the right edge of window constant */
|
||||
pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should be called by the application when it has
|
||||
* processed the data. The purpose is to advertise a larger window
|
||||
@@ -391,40 +437,23 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||
void
|
||||
tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||
{
|
||||
if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {
|
||||
pcb->rcv_wnd = TCP_WND;
|
||||
pcb->rcv_ann_wnd = TCP_WND;
|
||||
} else {
|
||||
pcb->rcv_wnd += len;
|
||||
if (pcb->rcv_wnd >= pcb->mss) {
|
||||
pcb->rcv_ann_wnd = pcb->rcv_wnd;
|
||||
}
|
||||
}
|
||||
int wnd_inflation;
|
||||
|
||||
if (!(pcb->flags & TF_ACK_DELAY) &&
|
||||
!(pcb->flags & TF_ACK_NOW)) {
|
||||
/*
|
||||
* We send an ACK here (if one is not already pending, hence
|
||||
* the above tests) as tcp_recved() implies that the application
|
||||
* has processed some data, and so we can open the receiver's
|
||||
* window to allow more to be transmitted. This could result in
|
||||
* two ACKs being sent for each received packet in some limited cases
|
||||
* (where the application is only receiving data, and is slow to
|
||||
* process it) but it is necessary to guarantee that the sender can
|
||||
* continue to transmit.
|
||||
*/
|
||||
tcp_ack(pcb);
|
||||
}
|
||||
else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {
|
||||
/* If we can send a window update such that there is a full
|
||||
* segment available in the window, do so now. This is sort of
|
||||
* nagle-like in its goals, and tries to hit a compromise between
|
||||
* sending acks each time the window is updated, and only sending
|
||||
* window updates when a timer expires. The "threshold" used
|
||||
* above (currently TCP_WND/2) can be tuned to be more or less
|
||||
* aggressive */
|
||||
LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
|
||||
len <= 0xffff - pcb->rcv_wnd );
|
||||
|
||||
pcb->rcv_wnd += len;
|
||||
if (pcb->rcv_wnd > TCP_WND)
|
||||
pcb->rcv_wnd = TCP_WND;
|
||||
|
||||
wnd_inflation = tcp_update_rcv_ann_wnd(pcb);
|
||||
|
||||
/* If the change in the right edge of window is significant (default
|
||||
* watermark is TCP_WND/2), then send an explicit update now.
|
||||
* Otherwise wait for a packet to be sent in the normal course of
|
||||
* events (or more window to be available later) */
|
||||
if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD)
|
||||
tcp_ack_now(pcb);
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
|
||||
len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
|
||||
@@ -485,7 +514,6 @@ err_t
|
||||
tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
|
||||
err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
|
||||
{
|
||||
u32_t optdata;
|
||||
err_t ret;
|
||||
u32_t iss;
|
||||
|
||||
@@ -508,8 +536,10 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
|
||||
pcb->snd_lbb = iss - 1;
|
||||
pcb->rcv_wnd = TCP_WND;
|
||||
pcb->rcv_ann_wnd = TCP_WND;
|
||||
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
|
||||
pcb->snd_wnd = TCP_WND;
|
||||
/* The send MSS is updated when an MSS option is received. */
|
||||
/* As initial send MSS, we use TCP_MSS but limit it to 536.
|
||||
The send MSS is updated when an MSS option is received. */
|
||||
pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
|
||||
@@ -525,10 +555,11 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
|
||||
|
||||
snmp_inc_tcpactiveopens();
|
||||
|
||||
/* Build an MSS option */
|
||||
optdata = TCP_BUILD_MSS_OPTION();
|
||||
|
||||
ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);
|
||||
ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
| TF_SEG_OPTS_TS
|
||||
#endif
|
||||
);
|
||||
if (ret == ERR_OK) {
|
||||
tcp_output(pcb);
|
||||
}
|
||||
@@ -548,6 +579,7 @@ tcp_slowtmr(void)
|
||||
struct tcp_pcb *pcb, *pcb2, *prev;
|
||||
u16_t eff_wnd;
|
||||
u8_t pcb_remove; /* flag if a PCB should be removed */
|
||||
u8_t pcb_reset; /* flag if a RST should be sent when removing */
|
||||
err_t err;
|
||||
|
||||
err = ERR_OK;
|
||||
@@ -567,6 +599,7 @@ tcp_slowtmr(void)
|
||||
LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
|
||||
|
||||
pcb_remove = 0;
|
||||
pcb_reset = 0;
|
||||
|
||||
if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
|
||||
++pcb_remove;
|
||||
@@ -650,7 +683,8 @@ tcp_slowtmr(void)
|
||||
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
|
||||
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
|
||||
|
||||
tcp_abort(pcb);
|
||||
++pcb_remove;
|
||||
++pcb_reset;
|
||||
}
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
else if((u32_t)(tcp_ticks - pcb->tmr) >
|
||||
@@ -710,6 +744,10 @@ tcp_slowtmr(void)
|
||||
}
|
||||
|
||||
TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
|
||||
if (pcb_reset) {
|
||||
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
}
|
||||
|
||||
pcb2 = pcb->next;
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
@@ -883,11 +921,12 @@ tcp_seg_copy(struct tcp_seg *seg)
|
||||
* Default receive callback that is called if the user didn't register
|
||||
* a recv callback for the pcb.
|
||||
*/
|
||||
static err_t
|
||||
err_t
|
||||
tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||
{
|
||||
arg = arg;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
if (p != NULL) {
|
||||
tcp_recved(pcb, p->tot_len);
|
||||
pbuf_free(p);
|
||||
} else if (err == ERR_OK) {
|
||||
return tcp_close(pcb);
|
||||
@@ -977,9 +1016,18 @@ tcp_alloc(u8_t prio)
|
||||
pcb = memp_malloc(MEMP_TCP_PCB);
|
||||
if (pcb == NULL) {
|
||||
/* Try killing active connections with lower priority than the new one. */
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio));
|
||||
tcp_kill_prio(prio);
|
||||
/* Try to allocate a tcp_pcb again. */
|
||||
pcb = memp_malloc(MEMP_TCP_PCB);
|
||||
if (pcb != NULL) {
|
||||
/* adjust err stats: memp_malloc failed twice before */
|
||||
MEMP_STATS_DEC(err, MEMP_TCP_PCB);
|
||||
}
|
||||
}
|
||||
if (pcb != NULL) {
|
||||
/* adjust err stats: timewait PCB was freed above */
|
||||
MEMP_STATS_DEC(err, MEMP_TCP_PCB);
|
||||
}
|
||||
}
|
||||
if (pcb != NULL) {
|
||||
@@ -991,7 +1039,8 @@ tcp_alloc(u8_t prio)
|
||||
pcb->rcv_ann_wnd = TCP_WND;
|
||||
pcb->tos = 0;
|
||||
pcb->ttl = TCP_TTL;
|
||||
/* The send MSS is updated when an MSS option is received. */
|
||||
/* As initial send MSS, we use TCP_MSS but limit it to 536.
|
||||
The send MSS is updated when an MSS option is received. */
|
||||
pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
|
||||
pcb->rto = 3000 / TCP_SLOW_INTERVAL;
|
||||
pcb->sa = 0;
|
||||
@@ -1001,7 +1050,6 @@ tcp_alloc(u8_t prio)
|
||||
iss = tcp_next_iss();
|
||||
pcb->snd_wl2 = iss;
|
||||
pcb->snd_nxt = iss;
|
||||
pcb->snd_max = iss;
|
||||
pcb->lastack = iss;
|
||||
pcb->snd_lbb = iss;
|
||||
pcb->tmr = tcp_ticks;
|
||||
@@ -1112,7 +1160,7 @@ void
|
||||
tcp_accept(struct tcp_pcb *pcb,
|
||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
|
||||
{
|
||||
((struct tcp_pcb_listen *)pcb)->accept = accept;
|
||||
pcb->accept = accept;
|
||||
}
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
|
||||
@@ -1148,6 +1196,27 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
|
||||
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
if (pcb->state == SYN_RCVD) {
|
||||
/* Need to find the corresponding listen_pcb and decrease its accepts_pending */
|
||||
struct tcp_pcb_listen *lpcb;
|
||||
LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL",
|
||||
tcp_listen_pcbs.listen_pcbs != NULL);
|
||||
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
if ((lpcb->local_port == pcb->local_port) &&
|
||||
(ip_addr_isany(&lpcb->local_ip) ||
|
||||
ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
|
||||
/* port and address of the listen pcb match the timed-out pcb */
|
||||
LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
|
||||
lpcb->accepts_pending > 0);
|
||||
lpcb->accepts_pending--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
|
||||
if (pcb->refused_data != NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
|
||||
pbuf_free(pcb->refused_data);
|
||||
@@ -1181,7 +1250,7 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
|
||||
* Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
|
||||
*
|
||||
* @param pcblist PCB list to purge.
|
||||
* @param pcb tcp_pcb to purge. The pcb itself is also deallocated!
|
||||
* @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated!
|
||||
*/
|
||||
void
|
||||
tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
|
||||
@@ -1242,13 +1311,21 @@ tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr)
|
||||
mss_s = outif->mtu - IP_HLEN - TCP_HLEN;
|
||||
/* RFC 1122, chap 4.2.2.6:
|
||||
* Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
|
||||
* but we only send options with SYN and that is never filled with data! */
|
||||
* We correct for TCP options in tcp_enqueue(), and don't support
|
||||
* IP options
|
||||
*/
|
||||
sendmss = LWIP_MIN(sendmss, mss_s);
|
||||
}
|
||||
return sendmss;
|
||||
}
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
const char*
|
||||
tcp_debug_state_str(enum tcp_state s)
|
||||
{
|
||||
return tcp_state_str[s];
|
||||
}
|
||||
|
||||
#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
|
||||
/**
|
||||
* Print a tcp header for debugging purposes.
|
||||
@@ -1294,42 +1371,7 @@ tcp_debug_print(struct tcp_hdr *tcphdr)
|
||||
void
|
||||
tcp_debug_print_state(enum tcp_state s)
|
||||
{
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("State: "));
|
||||
switch (s) {
|
||||
case CLOSED:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));
|
||||
break;
|
||||
case LISTEN:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));
|
||||
break;
|
||||
case SYN_SENT:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));
|
||||
break;
|
||||
case SYN_RCVD:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));
|
||||
break;
|
||||
case ESTABLISHED:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));
|
||||
break;
|
||||
case FIN_WAIT_1:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));
|
||||
break;
|
||||
case FIN_WAIT_2:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));
|
||||
break;
|
||||
case CLOSE_WAIT:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));
|
||||
break;
|
||||
case CLOSING:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));
|
||||
break;
|
||||
case LAST_ACK:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));
|
||||
break;
|
||||
case TIME_WAIT:
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));
|
||||
break;
|
||||
}
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1364,6 +1406,7 @@ tcp_debug_print_flags(u8_t flags)
|
||||
if (flags & TCP_CWR) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
|
||||
}
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,7 +74,7 @@ struct tcp_pcb *tcp_input_pcb;
|
||||
|
||||
/* Forward declarations. */
|
||||
static err_t tcp_process(struct tcp_pcb *pcb);
|
||||
static u8_t tcp_receive(struct tcp_pcb *pcb);
|
||||
static void tcp_receive(struct tcp_pcb *pcb);
|
||||
static void tcp_parseopt(struct tcp_pcb *pcb);
|
||||
|
||||
static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
|
||||
@@ -169,8 +169,8 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
|
||||
tcphdr->wnd = ntohs(tcphdr->wnd);
|
||||
|
||||
flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;
|
||||
tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);
|
||||
flags = TCPH_FLAGS(tcphdr);
|
||||
tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
|
||||
|
||||
/* Demultiplex an incoming segment. First, we check if it is destined
|
||||
for an active connection. */
|
||||
@@ -288,10 +288,8 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tcp_input_pcb = pcb;
|
||||
err = tcp_process(pcb);
|
||||
tcp_input_pcb = NULL;
|
||||
/* A return value of ERR_ABRT means that tcp_abort() was called
|
||||
and that the pcb has been freed. If so, we don't do anything. */
|
||||
if (err != ERR_ABRT) {
|
||||
@@ -338,12 +336,17 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);
|
||||
}
|
||||
|
||||
/* If there were no errors, we try to send something out. */
|
||||
if (err == ERR_OK) {
|
||||
tcp_output(pcb);
|
||||
}
|
||||
tcp_input_pcb = NULL;
|
||||
/* Try to send something out. */
|
||||
tcp_output(pcb);
|
||||
#if TCP_INPUT_DEBUG
|
||||
#if TCP_DEBUG
|
||||
tcp_debug_print_state(pcb->state);
|
||||
#endif /* TCP_DEBUG */
|
||||
#endif /* TCP_INPUT_DEBUG */
|
||||
}
|
||||
}
|
||||
tcp_input_pcb = NULL;
|
||||
|
||||
|
||||
/* give up our reference to inseg.p */
|
||||
@@ -352,12 +355,6 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
pbuf_free(inseg.p);
|
||||
inseg.p = NULL;
|
||||
}
|
||||
#if TCP_INPUT_DEBUG
|
||||
#if TCP_DEBUG
|
||||
tcp_debug_print_state(pcb->state);
|
||||
#endif /* TCP_DEBUG */
|
||||
#endif /* TCP_INPUT_DEBUG */
|
||||
|
||||
} else {
|
||||
|
||||
/* If no matching PCB was found, send a TCP RST (reset) to the
|
||||
@@ -393,7 +390,7 @@ static err_t
|
||||
tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
{
|
||||
struct tcp_pcb *npcb;
|
||||
u32_t optdata;
|
||||
err_t rc;
|
||||
|
||||
/* In the LISTEN state, we check for incoming SYN segments,
|
||||
creates a new PCB, and responds with a SYN|ACK. */
|
||||
@@ -408,6 +405,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
if (pcb->accepts_pending >= pcb->backlog) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
|
||||
return ERR_ABRT;
|
||||
}
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
@@ -430,6 +428,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
npcb->remote_port = tcphdr->src;
|
||||
npcb->state = SYN_RCVD;
|
||||
npcb->rcv_nxt = seqno + 1;
|
||||
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
|
||||
npcb->snd_wnd = tcphdr->wnd;
|
||||
npcb->ssthresh = npcb->snd_wnd;
|
||||
npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
|
||||
@@ -451,10 +450,17 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
|
||||
snmp_inc_tcppassiveopens();
|
||||
|
||||
/* Build an MSS option. */
|
||||
optdata = TCP_BUILD_MSS_OPTION();
|
||||
/* Send a SYN|ACK together with the MSS option. */
|
||||
tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4);
|
||||
rc = tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
/* and maybe include the TIMESTAMP option */
|
||||
| (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0)
|
||||
#endif
|
||||
);
|
||||
if (rc != ERR_OK) {
|
||||
tcp_abandon(npcb, 0);
|
||||
return rc;
|
||||
}
|
||||
return tcp_output(npcb);
|
||||
}
|
||||
return ERR_OK;
|
||||
@@ -472,13 +478,36 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
static err_t
|
||||
tcp_timewait_input(struct tcp_pcb *pcb)
|
||||
{
|
||||
if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {
|
||||
pcb->rcv_nxt = seqno + tcplen;
|
||||
/* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
|
||||
/* RFC 793 3.9 Event Processing - Segment Arrives:
|
||||
* - first check sequence number - we skip that one in TIME_WAIT (always
|
||||
* acceptable since we only send ACKs)
|
||||
* - second check the RST bit (... return) */
|
||||
if (flags & TCP_RST) {
|
||||
return ERR_OK;
|
||||
}
|
||||
if (tcplen > 0) {
|
||||
tcp_ack_now(pcb);
|
||||
/* - fourth, check the SYN bit, */
|
||||
if (flags & TCP_SYN) {
|
||||
/* If an incoming segment is not acceptable, an acknowledgment
|
||||
should be sent in reply */
|
||||
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
|
||||
/* If the SYN is in the window it is an error, send a reset */
|
||||
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
return ERR_OK;
|
||||
}
|
||||
} else if (flags & TCP_FIN) {
|
||||
/* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
|
||||
Restart the 2 MSL time-wait timeout.*/
|
||||
pcb->tmr = tcp_ticks;
|
||||
}
|
||||
return tcp_output(pcb);
|
||||
|
||||
if ((tcplen > 0)) {
|
||||
/* Acknowledge data, FIN or out-of-window SYN */
|
||||
pcb->flags |= TF_ACK_NOW;
|
||||
return tcp_output(pcb);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,7 +527,6 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
struct tcp_seg *rseg;
|
||||
u8_t acceptable = 0;
|
||||
err_t err;
|
||||
u8_t accepted_inseq;
|
||||
|
||||
err = ERR_OK;
|
||||
|
||||
@@ -511,7 +539,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
}
|
||||
} else {
|
||||
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
|
||||
pcb->rcv_nxt+pcb->rcv_ann_wnd)) {
|
||||
pcb->rcv_nxt+pcb->rcv_wnd)) {
|
||||
acceptable = 1;
|
||||
}
|
||||
}
|
||||
@@ -519,7 +547,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
if (acceptable) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
|
||||
LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
|
||||
recv_flags = TF_RESET;
|
||||
recv_flags |= TF_RESET;
|
||||
pcb->flags &= ~TF_ACK_DELAY;
|
||||
return ERR_RST;
|
||||
} else {
|
||||
@@ -531,10 +559,18 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
|
||||
/* Cope with new connection attempt after remote end crashed */
|
||||
tcp_ack_now(pcb);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Update the PCB (in)activity timer. */
|
||||
pcb->tmr = tcp_ticks;
|
||||
pcb->keep_cnt_sent = 0;
|
||||
|
||||
tcp_parseopt(pcb);
|
||||
|
||||
/* Do different things depending on the TCP state. */
|
||||
switch (pcb->state) {
|
||||
case SYN_SENT:
|
||||
@@ -545,14 +581,12 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
&& ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
|
||||
pcb->snd_buf++;
|
||||
pcb->rcv_nxt = seqno + 1;
|
||||
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
|
||||
pcb->lastack = ackno;
|
||||
pcb->snd_wnd = tcphdr->wnd;
|
||||
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
|
||||
pcb->state = ESTABLISHED;
|
||||
|
||||
/* Parse any options in the SYNACK before using pcb->mss since that
|
||||
* can be changed by the received options! */
|
||||
tcp_parseopt(pcb);
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
@@ -592,8 +626,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
}
|
||||
break;
|
||||
case SYN_RCVD:
|
||||
if (flags & TCP_ACK &&
|
||||
!(flags & TCP_RST)) {
|
||||
if (flags & TCP_ACK) {
|
||||
/* expected ACK number? */
|
||||
if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
|
||||
u16_t old_cwnd;
|
||||
@@ -613,11 +646,16 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
old_cwnd = pcb->cwnd;
|
||||
/* If there was any data contained within this ACK,
|
||||
* we'd better pass it on to the application as well. */
|
||||
accepted_inseq = tcp_receive(pcb);
|
||||
tcp_receive(pcb);
|
||||
|
||||
/* Prevent ACK for SYN to generate a sent event */
|
||||
if (pcb->acked != 0) {
|
||||
pcb->acked--;
|
||||
}
|
||||
|
||||
pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
|
||||
|
||||
if ((flags & TCP_FIN) && accepted_inseq) {
|
||||
if (recv_flags & TF_GOT_FIN) {
|
||||
tcp_ack_now(pcb);
|
||||
pcb->state = CLOSE_WAIT;
|
||||
}
|
||||
@@ -628,23 +666,26 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
} else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
|
||||
/* Looks like another copy of the SYN - retransmit our SYN-ACK */
|
||||
tcp_rexmit(pcb);
|
||||
}
|
||||
break;
|
||||
case CLOSE_WAIT:
|
||||
/* FALLTHROUGH */
|
||||
case ESTABLISHED:
|
||||
accepted_inseq = tcp_receive(pcb);
|
||||
if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */
|
||||
tcp_receive(pcb);
|
||||
if (recv_flags & TF_GOT_FIN) { /* passive close */
|
||||
tcp_ack_now(pcb);
|
||||
pcb->state = CLOSE_WAIT;
|
||||
}
|
||||
break;
|
||||
case FIN_WAIT_1:
|
||||
tcp_receive(pcb);
|
||||
if (flags & TCP_FIN) {
|
||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
||||
if (recv_flags & TF_GOT_FIN) {
|
||||
if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
|
||||
LWIP_DEBUGF(TCP_DEBUG,
|
||||
("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
tcp_ack_now(pcb);
|
||||
tcp_pcb_purge(pcb);
|
||||
TCP_RMV(&tcp_active_pcbs, pcb);
|
||||
@@ -654,14 +695,14 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
tcp_ack_now(pcb);
|
||||
pcb->state = CLOSING;
|
||||
}
|
||||
} else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
||||
} else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
|
||||
pcb->state = FIN_WAIT_2;
|
||||
}
|
||||
break;
|
||||
case FIN_WAIT_2:
|
||||
tcp_receive(pcb);
|
||||
if (flags & TCP_FIN) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
if (recv_flags & TF_GOT_FIN) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
tcp_ack_now(pcb);
|
||||
tcp_pcb_purge(pcb);
|
||||
TCP_RMV(&tcp_active_pcbs, pcb);
|
||||
@@ -672,8 +713,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
case CLOSING:
|
||||
tcp_receive(pcb);
|
||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
tcp_ack_now(pcb);
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
tcp_pcb_purge(pcb);
|
||||
TCP_RMV(&tcp_active_pcbs, pcb);
|
||||
pcb->state = TIME_WAIT;
|
||||
@@ -683,9 +723,9 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
case LAST_ACK:
|
||||
tcp_receive(pcb);
|
||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
/* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
|
||||
recv_flags = TF_CLOSED;
|
||||
recv_flags |= TF_CLOSED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -694,6 +734,47 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
/**
|
||||
* Insert segment into the list (segments covered with new one will be deleted)
|
||||
*
|
||||
* Called from tcp_receive()
|
||||
*/
|
||||
static void
|
||||
tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
|
||||
{
|
||||
struct tcp_seg *old_seg;
|
||||
|
||||
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
|
||||
/* received segment overlaps all following segments */
|
||||
tcp_segs_free(next);
|
||||
next = NULL;
|
||||
}
|
||||
else {
|
||||
/* delete some following segments
|
||||
oos queue may have segments with FIN flag */
|
||||
while (next &&
|
||||
TCP_SEQ_GEQ((seqno + cseg->len),
|
||||
(next->tcphdr->seqno + next->len))) {
|
||||
/* cseg with FIN already processed */
|
||||
if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
|
||||
TCPH_FLAGS_SET(cseg->tcphdr, TCPH_FLAGS(cseg->tcphdr) | TCP_FIN);
|
||||
}
|
||||
old_seg = next;
|
||||
next = next->next;
|
||||
tcp_seg_free(old_seg);
|
||||
}
|
||||
if (next &&
|
||||
TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
|
||||
/* We need to trim the incoming segment. */
|
||||
cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(cseg->p, cseg->len);
|
||||
}
|
||||
}
|
||||
cseg->next = next;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Called by tcp_process. Checks if the given segment is an ACK for outstanding
|
||||
* data, and if so frees the memory of the buffered data. Next, is places the
|
||||
@@ -705,10 +786,8 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
* estimation, the RTT is estimated here as well.
|
||||
*
|
||||
* Called from tcp_process().
|
||||
*
|
||||
* @return 1 if the incoming segment is the next in sequence, 0 if not
|
||||
*/
|
||||
static u8_t
|
||||
static void
|
||||
tcp_receive(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct tcp_seg *next;
|
||||
@@ -720,10 +799,10 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
s16_t m;
|
||||
u32_t right_wnd_edge;
|
||||
u16_t new_tot_len;
|
||||
u8_t accepted_inseq = 0;
|
||||
int found_dupack = 0;
|
||||
|
||||
if (flags & TCP_ACK) {
|
||||
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;
|
||||
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
|
||||
|
||||
/* Update window. */
|
||||
if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
|
||||
@@ -739,57 +818,70 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
#if TCP_WND_DEBUG
|
||||
} else {
|
||||
if (pcb->snd_wnd != tcphdr->wnd) {
|
||||
LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" snd_max %"U32_F" ackno %"U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
|
||||
pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
|
||||
LWIP_DEBUGF(TCP_WND_DEBUG,
|
||||
("tcp_receive: no window update lastack %"U32_F" ackno %"
|
||||
U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
|
||||
pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
|
||||
}
|
||||
#endif /* TCP_WND_DEBUG */
|
||||
}
|
||||
|
||||
if (pcb->lastack == ackno) {
|
||||
/* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
|
||||
* duplicate ack if:
|
||||
* 1) It doesn't ACK new data
|
||||
* 2) length of received packet is zero (i.e. no payload)
|
||||
* 3) the advertised window hasn't changed
|
||||
* 4) There is outstanding unacknowledged data (retransmission timer running)
|
||||
* 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
|
||||
*
|
||||
* If it passes all five, should process as a dupack:
|
||||
* a) dupacks < 3: do nothing
|
||||
* b) dupacks == 3: fast retransmit
|
||||
* c) dupacks > 3: increase cwnd
|
||||
*
|
||||
* If it only passes 1-3, should reset dupack counter (and add to
|
||||
* stats, which we don't do in lwIP)
|
||||
*
|
||||
* If it only passes 1, should reset dupack counter
|
||||
*
|
||||
*/
|
||||
|
||||
/* Clause 1 */
|
||||
if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
|
||||
pcb->acked = 0;
|
||||
|
||||
if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){
|
||||
++pcb->dupacks;
|
||||
if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
|
||||
if (!(pcb->flags & TF_INFR)) {
|
||||
/* This is fast retransmit. Retransmit the first unacked segment. */
|
||||
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n",
|
||||
(u16_t)pcb->dupacks, pcb->lastack,
|
||||
ntohl(pcb->unacked->tcphdr->seqno)));
|
||||
tcp_rexmit(pcb);
|
||||
/* Set ssthresh to max (FlightSize / 2, 2*SMSS) */
|
||||
/*pcb->ssthresh = LWIP_MAX((pcb->snd_max -
|
||||
pcb->lastack) / 2,
|
||||
2 * pcb->mss);*/
|
||||
/* Set ssthresh to half of the minimum of the current cwnd and the advertised window */
|
||||
if (pcb->cwnd > pcb->snd_wnd)
|
||||
pcb->ssthresh = pcb->snd_wnd / 2;
|
||||
else
|
||||
pcb->ssthresh = pcb->cwnd / 2;
|
||||
|
||||
/* The minimum value for ssthresh should be 2 MSS */
|
||||
if (pcb->ssthresh < 2*pcb->mss) {
|
||||
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: The minimum value for ssthresh %"U16_F" should be min 2 mss %"U16_F"...\n", pcb->ssthresh, 2*pcb->mss));
|
||||
pcb->ssthresh = 2*pcb->mss;
|
||||
}
|
||||
|
||||
pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
|
||||
pcb->flags |= TF_INFR;
|
||||
} else {
|
||||
/* Inflate the congestion window, but not if it means that
|
||||
the value overflows. */
|
||||
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
|
||||
pcb->cwnd += pcb->mss;
|
||||
/* Clause 2 */
|
||||
if (tcplen == 0) {
|
||||
/* Clause 3 */
|
||||
if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
|
||||
/* Clause 4 */
|
||||
if (pcb->rtime >= 0) {
|
||||
/* Clause 5 */
|
||||
if (pcb->lastack == ackno) {
|
||||
found_dupack = 1;
|
||||
if (pcb->dupacks + 1 > pcb->dupacks)
|
||||
++pcb->dupacks;
|
||||
if (pcb->dupacks > 3) {
|
||||
/* Inflate the congestion window, but not if it means that
|
||||
the value overflows. */
|
||||
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
|
||||
pcb->cwnd += pcb->mss;
|
||||
}
|
||||
} else if (pcb->dupacks == 3) {
|
||||
/* Do fast retransmit */
|
||||
tcp_rexmit_fast(pcb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",
|
||||
pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));
|
||||
}
|
||||
} else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){
|
||||
/* If Clause (1) or more is true, but not a duplicate ack, reset
|
||||
* count of consecutive duplicate acks */
|
||||
if (!found_dupack) {
|
||||
pcb->dupacks = 0;
|
||||
}
|
||||
} else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
|
||||
/* We come here when the ACK acknowledges new data. */
|
||||
|
||||
|
||||
/* Reset the "IN Fast Retransmit" flag, since we are no longer
|
||||
in fast retransmit. Also reset the congestion window to the
|
||||
slow start threshold. */
|
||||
@@ -851,6 +943,11 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
|
||||
LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
|
||||
/* Prevent ACK for FIN to generate a sent event */
|
||||
if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
|
||||
pcb->acked--;
|
||||
}
|
||||
|
||||
pcb->snd_queuelen -= pbuf_clen(next->p);
|
||||
tcp_seg_free(next);
|
||||
|
||||
@@ -881,10 +978,8 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
->unsent list after a retransmission, so these segments may
|
||||
in fact have been sent once. */
|
||||
while (pcb->unsent != NULL &&
|
||||
/*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&
|
||||
TCP_SEQ_LEQ(ackno, pcb->snd_max)*/
|
||||
TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)
|
||||
) {
|
||||
TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
|
||||
TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
|
||||
ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
|
||||
TCP_TCPLEN(pcb->unsent)));
|
||||
@@ -893,6 +988,10 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
pcb->unsent = pcb->unsent->next;
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
|
||||
LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
|
||||
/* Prevent ACK for FIN to generate a sent event */
|
||||
if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
|
||||
pcb->acked--;
|
||||
}
|
||||
pcb->snd_queuelen -= pbuf_clen(next->p);
|
||||
tcp_seg_free(next);
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
|
||||
@@ -900,10 +999,6 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
LWIP_ASSERT("tcp_receive: valid queue length",
|
||||
pcb->unacked != NULL || pcb->unsent != NULL);
|
||||
}
|
||||
|
||||
if (pcb->unsent != NULL) {
|
||||
pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
|
||||
}
|
||||
}
|
||||
/* End of ACK for new data processing. */
|
||||
|
||||
@@ -1038,53 +1133,101 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
and below rcv_nxt + rcv_wnd) in order to be further
|
||||
processed. */
|
||||
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
|
||||
pcb->rcv_nxt + pcb->rcv_ann_wnd - 1)){
|
||||
pcb->rcv_nxt + pcb->rcv_wnd - 1)){
|
||||
if (pcb->rcv_nxt == seqno) {
|
||||
accepted_inseq = 1;
|
||||
/* The incoming segment is the next in sequence. We check if
|
||||
we have to trim the end of the segment and update rcv_nxt
|
||||
and pass the data to the application. */
|
||||
tcplen = TCP_TCPLEN(&inseg);
|
||||
|
||||
if (tcplen > pcb->rcv_wnd) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG,
|
||||
("tcp_receive: other end overran receive window"
|
||||
"seqno %"U32_F" len %"U32_F" right edge %"U32_F"\n",
|
||||
seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
|
||||
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
||||
/* Must remove the FIN from the header as we're trimming
|
||||
* that byte of sequence-space from the packet */
|
||||
TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
|
||||
}
|
||||
/* Adjust length of segment to fit in the window. */
|
||||
inseg.len = pcb->rcv_wnd;
|
||||
if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
|
||||
inseg.len -= 1;
|
||||
}
|
||||
pbuf_realloc(inseg.p, inseg.len);
|
||||
tcplen = TCP_TCPLEN(&inseg);
|
||||
LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
|
||||
(seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
|
||||
}
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
if (pcb->ooseq != NULL &&
|
||||
TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
|
||||
if (pcb->ooseq->len > 0) {
|
||||
/* We have to trim the second edge of the incoming
|
||||
segment. */
|
||||
inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(inseg.p, inseg.len);
|
||||
} else {
|
||||
/* does the ooseq segment contain only flags that are in inseg also? */
|
||||
if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) ==
|
||||
(TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {
|
||||
if (pcb->ooseq != NULL) {
|
||||
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG,
|
||||
("tcp_receive: received in-order FIN, binning ooseq queue\n"));
|
||||
/* Received in-order FIN means anything that was received
|
||||
* out of order must now have been received in-order, so
|
||||
* bin the ooseq queue
|
||||
* rcv_nxt
|
||||
* . |--ooseq--|
|
||||
* .==seg============|FIN
|
||||
*/
|
||||
while (pcb->ooseq != NULL) {
|
||||
struct tcp_seg *old_ooseq = pcb->ooseq;
|
||||
pcb->ooseq = pcb->ooseq->next;
|
||||
memp_free(MEMP_TCP_SEG, old_ooseq);
|
||||
tcp_seg_free(old_ooseq);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct tcp_seg* next = pcb->ooseq;
|
||||
struct tcp_seg *old_seg;
|
||||
/* rcv_nxt
|
||||
* . |--ooseq--|
|
||||
* .==seg============|
|
||||
*/
|
||||
while (next &&
|
||||
TCP_SEQ_GEQ(seqno + tcplen,
|
||||
next->tcphdr->seqno + next->len)) {
|
||||
/* inseg doesn't have FIN (already processed) */
|
||||
if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
|
||||
(TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
|
||||
TCPH_FLAGS_SET(inseg.tcphdr,
|
||||
TCPH_FLAGS(inseg.tcphdr) | TCP_FIN);
|
||||
tcplen = TCP_TCPLEN(&inseg);
|
||||
}
|
||||
old_seg = next;
|
||||
next = next->next;
|
||||
tcp_seg_free(old_seg);
|
||||
}
|
||||
/* rcv_nxt
|
||||
* . |--ooseq--|
|
||||
* .==seg============|
|
||||
*/
|
||||
if (next &&
|
||||
TCP_SEQ_GT(seqno + tcplen,
|
||||
next->tcphdr->seqno)) {
|
||||
/* FIN in inseg already handled by dropping whole ooseq queue */
|
||||
inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);
|
||||
if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
|
||||
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);
|
||||
}
|
||||
pcb->ooseq = next;
|
||||
}
|
||||
}
|
||||
#endif /* TCP_QUEUE_OOSEQ */
|
||||
|
||||
tcplen = TCP_TCPLEN(&inseg);
|
||||
|
||||
/* First received FIN will be ACKed +1, on any successive (duplicate)
|
||||
* FINs we are already in CLOSE_WAIT and have already done +1.
|
||||
*/
|
||||
if (pcb->state != CLOSE_WAIT) {
|
||||
pcb->rcv_nxt += tcplen;
|
||||
}
|
||||
pcb->rcv_nxt = seqno + tcplen;
|
||||
|
||||
/* Update the receiver's (our) window. */
|
||||
if (pcb->rcv_wnd < tcplen) {
|
||||
pcb->rcv_wnd = 0;
|
||||
} else {
|
||||
pcb->rcv_wnd -= tcplen;
|
||||
}
|
||||
LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
|
||||
pcb->rcv_wnd -= tcplen;
|
||||
|
||||
if (pcb->rcv_ann_wnd < tcplen) {
|
||||
pcb->rcv_ann_wnd = 0;
|
||||
} else {
|
||||
pcb->rcv_ann_wnd -= tcplen;
|
||||
}
|
||||
tcp_update_rcv_ann_wnd(pcb);
|
||||
|
||||
/* If there is data in the segment, we make preparations to
|
||||
pass this up to the application. The ->recv_data variable
|
||||
@@ -1104,7 +1247,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
}
|
||||
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
|
||||
recv_flags = TF_GOT_FIN;
|
||||
recv_flags |= TF_GOT_FIN;
|
||||
}
|
||||
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
@@ -1117,16 +1260,11 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
seqno = pcb->ooseq->tcphdr->seqno;
|
||||
|
||||
pcb->rcv_nxt += TCP_TCPLEN(cseg);
|
||||
if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
|
||||
pcb->rcv_wnd = 0;
|
||||
} else {
|
||||
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
|
||||
}
|
||||
if (pcb->rcv_ann_wnd < TCP_TCPLEN(cseg)) {
|
||||
pcb->rcv_ann_wnd = 0;
|
||||
} else {
|
||||
pcb->rcv_ann_wnd -= TCP_TCPLEN(cseg);
|
||||
}
|
||||
LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
|
||||
pcb->rcv_wnd >= TCP_TCPLEN(cseg));
|
||||
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
|
||||
|
||||
tcp_update_rcv_ann_wnd(pcb);
|
||||
|
||||
if (cseg->p->tot_len > 0) {
|
||||
/* Chain this pbuf onto the pbuf that we will pass to
|
||||
@@ -1140,13 +1278,12 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
}
|
||||
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
|
||||
recv_flags = TF_GOT_FIN;
|
||||
recv_flags |= TF_GOT_FIN;
|
||||
if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
|
||||
pcb->state = CLOSE_WAIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pcb->ooseq = cseg->next;
|
||||
tcp_seg_free(cseg);
|
||||
}
|
||||
@@ -1158,7 +1295,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
|
||||
} else {
|
||||
/* We get here if the incoming segment is out-of-sequence. */
|
||||
tcp_ack_now(pcb);
|
||||
tcp_send_empty_ack(pcb);
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
/* We queue the segment on the ->ooseq queue. */
|
||||
if (pcb->ooseq == NULL) {
|
||||
@@ -1185,25 +1322,16 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
discard. */
|
||||
if (inseg.len > next->len) {
|
||||
/* The incoming segment is larger than the old
|
||||
segment. We replace the old segment with the new
|
||||
segment. We replace some segments with the new
|
||||
one. */
|
||||
cseg = tcp_seg_copy(&inseg);
|
||||
if (cseg != NULL) {
|
||||
cseg->next = next->next;
|
||||
if (prev != NULL) {
|
||||
prev->next = cseg;
|
||||
} else {
|
||||
pcb->ooseq = cseg;
|
||||
}
|
||||
}
|
||||
tcp_seg_free(next);
|
||||
if (cseg->next != NULL) {
|
||||
next = cseg->next;
|
||||
if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
|
||||
/* We need to trim the incoming segment. */
|
||||
cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(cseg->p, cseg->len);
|
||||
}
|
||||
tcp_oos_insert_segment(cseg, next);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
@@ -1219,51 +1347,44 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
than the sequence number of the first segment on the
|
||||
queue. We put the incoming segment first on the
|
||||
queue. */
|
||||
|
||||
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
||||
/* We need to trim the incoming segment. */
|
||||
inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(inseg.p, inseg.len);
|
||||
}
|
||||
cseg = tcp_seg_copy(&inseg);
|
||||
if (cseg != NULL) {
|
||||
cseg->next = next;
|
||||
pcb->ooseq = cseg;
|
||||
tcp_oos_insert_segment(cseg, next);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
/*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
|
||||
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
|
||||
if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){
|
||||
/* The sequence number of the incoming segment is in
|
||||
between the sequence numbers of the previous and
|
||||
the next segment on ->ooseq. We trim and insert the
|
||||
incoming segment and trim the previous segment, if
|
||||
needed. */
|
||||
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
||||
/* We need to trim the incoming segment. */
|
||||
inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(inseg.p, inseg.len);
|
||||
}
|
||||
|
||||
cseg = tcp_seg_copy(&inseg);
|
||||
if (cseg != NULL) {
|
||||
cseg->next = next;
|
||||
prev->next = cseg;
|
||||
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
|
||||
/* We need to trim the prev segment. */
|
||||
prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
|
||||
pbuf_realloc(prev->p, prev->len);
|
||||
if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
|
||||
/* The sequence number of the incoming segment is in
|
||||
between the sequence numbers of the previous and
|
||||
the next segment on ->ooseq. We trim trim the previous
|
||||
segment, delete next segments that included in received segment
|
||||
and trim received, if needed. */
|
||||
cseg = tcp_seg_copy(&inseg);
|
||||
if (cseg != NULL) {
|
||||
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
|
||||
/* We need to trim the prev segment. */
|
||||
prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
|
||||
pbuf_realloc(prev->p, prev->len);
|
||||
}
|
||||
prev->next = cseg;
|
||||
tcp_oos_insert_segment(cseg, next);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* If the "next" segment is the last segment on the
|
||||
ooseq queue, we add the incoming segment to the end
|
||||
of the list. */
|
||||
if (next->next == NULL &&
|
||||
TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
|
||||
if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
|
||||
/* segment "next" already contains all data */
|
||||
break;
|
||||
}
|
||||
next->next = tcp_seg_copy(&inseg);
|
||||
if (next->next != NULL) {
|
||||
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
|
||||
@@ -1282,10 +1403,8 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
|
||||
}
|
||||
} else {
|
||||
if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
|
||||
pcb->rcv_nxt + pcb->rcv_ann_wnd-1)){
|
||||
tcp_ack_now(pcb);
|
||||
}
|
||||
/* The incoming segment is not withing the window. */
|
||||
tcp_send_empty_ack(pcb);
|
||||
}
|
||||
} else {
|
||||
/* Segments with length 0 is taken care of here. Segments that
|
||||
@@ -1296,12 +1415,10 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
tcp_ack_now(pcb);
|
||||
}
|
||||
}
|
||||
return accepted_inseq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the options contained in the incoming segment. (Code taken
|
||||
* from uIP with only small changes.)
|
||||
* Parses the options contained in the incoming segment.
|
||||
*
|
||||
* Called from tcp_listen_input() and tcp_process().
|
||||
* Currently, only the MSS option is supported!
|
||||
@@ -1311,35 +1428,72 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
static void
|
||||
tcp_parseopt(struct tcp_pcb *pcb)
|
||||
{
|
||||
u8_t c;
|
||||
u8_t *opts, opt;
|
||||
u16_t c, max_c;
|
||||
u16_t mss;
|
||||
u8_t *opts, opt;
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
u32_t tsval;
|
||||
#endif
|
||||
|
||||
opts = (u8_t *)tcphdr + TCP_HLEN;
|
||||
|
||||
/* Parse the TCP MSS option, if present. */
|
||||
if(TCPH_HDRLEN(tcphdr) > 0x5) {
|
||||
for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) {
|
||||
max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
|
||||
for (c = 0; c < max_c; ) {
|
||||
opt = opts[c];
|
||||
if (opt == 0x00) {
|
||||
switch (opt) {
|
||||
case 0x00:
|
||||
/* End of options. */
|
||||
break;
|
||||
} else if (opt == 0x01) {
|
||||
++c;
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
|
||||
return;
|
||||
case 0x01:
|
||||
/* NOP option. */
|
||||
} else if (opt == 0x02 &&
|
||||
opts[c + 1] == 0x04) {
|
||||
++c;
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
|
||||
break;
|
||||
case 0x02:
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
|
||||
if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
|
||||
/* Bad length */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
|
||||
return;
|
||||
}
|
||||
/* An MSS option with the right option length. */
|
||||
mss = (opts[c + 2] << 8) | opts[c + 3];
|
||||
pcb->mss = mss > TCP_MSS? TCP_MSS: mss;
|
||||
|
||||
/* And we are done processing options. */
|
||||
/* Limit the mss to the configured TCP_MSS and prevent division by zero */
|
||||
pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
|
||||
/* Advance to next option */
|
||||
c += 0x04;
|
||||
break;
|
||||
} else {
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
case 0x08:
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
|
||||
if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
|
||||
/* Bad length */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
|
||||
return;
|
||||
}
|
||||
/* TCP timestamp option with valid length */
|
||||
tsval = (opts[c+2]) | (opts[c+3] << 8) |
|
||||
(opts[c+4] << 16) | (opts[c+5] << 24);
|
||||
if (flags & TCP_SYN) {
|
||||
pcb->ts_recent = ntohl(tsval);
|
||||
pcb->flags |= TF_TIMESTAMP;
|
||||
} else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
|
||||
pcb->ts_recent = ntohl(tsval);
|
||||
}
|
||||
/* Advance to next option */
|
||||
c += 0x0A;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
|
||||
if (opts[c + 1] == 0) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
|
||||
/* If the length field is zero, the options are malformed
|
||||
and we don't process them further. */
|
||||
break;
|
||||
return;
|
||||
}
|
||||
/* All other options have a length field, so that we easily
|
||||
can skip past them. */
|
||||
|
||||
@@ -59,6 +59,27 @@
|
||||
/* Forward declarations.*/
|
||||
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
|
||||
|
||||
static struct tcp_hdr *
|
||||
tcp_output_set_header(struct tcp_pcb *pcb, struct pbuf *p, int optlen,
|
||||
u32_t seqno_be /* already in network byte order */)
|
||||
{
|
||||
struct tcp_hdr *tcphdr = p->payload;
|
||||
tcphdr->src = htons(pcb->local_port);
|
||||
tcphdr->dest = htons(pcb->remote_port);
|
||||
tcphdr->seqno = seqno_be;
|
||||
tcphdr->ackno = htonl(pcb->rcv_nxt);
|
||||
TCPH_FLAGS_SET(tcphdr, TCP_ACK);
|
||||
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
||||
tcphdr->urgp = 0;
|
||||
TCPH_HDRLEN_SET(tcphdr, (5 + optlen / 4));
|
||||
tcphdr->chksum = 0;
|
||||
|
||||
/* If we're sending a packet, update the announced right window edge */
|
||||
pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
|
||||
|
||||
return tcphdr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by tcp_close() to send a segment including flags but not data.
|
||||
*
|
||||
@@ -69,8 +90,8 @@ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
|
||||
err_t
|
||||
tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
|
||||
{
|
||||
/* no data, no length, flags, copy=1, no optdata, no optdatalen */
|
||||
return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, NULL, 0);
|
||||
/* no data, no length, flags, copy=1, no optdata */
|
||||
return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,17 +123,22 @@ tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags)
|
||||
pcb->state == SYN_SENT ||
|
||||
pcb->state == SYN_RCVD) {
|
||||
if (len > 0) {
|
||||
return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, NULL, 0);
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
return tcp_enqueue(pcb, (void *)data, len, 0, apiflags,
|
||||
pcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0);
|
||||
#else
|
||||
return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, 0);
|
||||
#endif
|
||||
}
|
||||
return ERR_OK;
|
||||
} else {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | 3, ("tcp_write() called in invalid state\n"));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n"));
|
||||
return ERR_CONN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue either data or TCP options (but not both) for tranmission
|
||||
* Enqueue data and/or TCP options for transmission
|
||||
*
|
||||
* Called by tcp_connect(), tcp_listen_input(), tcp_send_ctrl() and tcp_write().
|
||||
*
|
||||
@@ -123,13 +149,11 @@ tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags)
|
||||
* @param apiflags combination of following flags :
|
||||
* - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
|
||||
* - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,
|
||||
* @param optdata
|
||||
* @param optlen
|
||||
* @param optflags options to include in segment later on (see definition of struct tcp_seg)
|
||||
*/
|
||||
err_t
|
||||
tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
u8_t flags, u8_t apiflags,
|
||||
u8_t *optdata, u8_t optlen)
|
||||
u8_t flags, u8_t apiflags, u8_t optflags)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_seg *seg, *useg, *queue;
|
||||
@@ -137,22 +161,29 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
u16_t left, seglen;
|
||||
void *ptr;
|
||||
u16_t queuelen;
|
||||
u8_t optlen;
|
||||
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
|
||||
("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n",
|
||||
(void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags));
|
||||
LWIP_ERROR("tcp_enqueue: packet needs payload, options, or SYN/FIN (programmer violates API)",
|
||||
((len != 0) || (optflags != 0) || ((flags & (TCP_SYN | TCP_FIN)) != 0)),
|
||||
return ERR_ARG;);
|
||||
LWIP_ERROR("tcp_enqueue: len != 0 || arg == NULL (programmer violates API)",
|
||||
((len != 0) || (arg == NULL)), return ERR_ARG;);
|
||||
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n",
|
||||
(void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags));
|
||||
LWIP_ERROR("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",
|
||||
((len == 0) || (optlen == 0)), return ERR_ARG;);
|
||||
LWIP_ERROR("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",
|
||||
((arg == NULL) || (optdata == NULL)), return ERR_ARG;);
|
||||
/* fail on too much data */
|
||||
if (len > pcb->snd_buf) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_WARNING,
|
||||
("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));
|
||||
pcb->flags |= TF_NAGLEMEMERR;
|
||||
return ERR_MEM;
|
||||
}
|
||||
left = len;
|
||||
ptr = arg;
|
||||
|
||||
optlen = LWIP_TCP_OPT_LENGTH(optflags);
|
||||
|
||||
/* seqno will be the sequence number of the first segment enqueued
|
||||
* by the call to this function. */
|
||||
seqno = pcb->snd_lbb;
|
||||
@@ -164,7 +195,8 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
queuelen = pcb->snd_queuelen;
|
||||
/* check for configured max queuelen and possible overflow */
|
||||
if ((queuelen >= TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_WARNING,
|
||||
("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
|
||||
TCP_STATS_INC(tcp.memerr);
|
||||
pcb->flags |= TF_NAGLEMEMERR;
|
||||
return ERR_MEM;
|
||||
@@ -182,15 +214,14 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
useg = queue = seg = NULL;
|
||||
seglen = 0;
|
||||
while (queue == NULL || left > 0) {
|
||||
|
||||
/* The segment length should be the MSS if the data to be enqueued
|
||||
* is larger than the MSS. */
|
||||
seglen = left > pcb->mss? pcb->mss: left;
|
||||
/* The segment length (including options) should be at most the MSS */
|
||||
seglen = left > (pcb->mss - optlen) ? (pcb->mss - optlen) : left;
|
||||
|
||||
/* Allocate memory for tcp_seg, and fill in fields. */
|
||||
seg = memp_malloc(MEMP_TCP_SEG);
|
||||
if (seg == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("tcp_enqueue: could not allocate memory for tcp_seg\n"));
|
||||
goto memerr;
|
||||
}
|
||||
seg->next = NULL;
|
||||
@@ -211,68 +242,61 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
|
||||
/* If copy is set, memory should be allocated
|
||||
* and data copied into pbuf, otherwise data comes from
|
||||
* ROM or other static memory, and need not be copied. If
|
||||
* optdata is != NULL, we have options instead of data. */
|
||||
|
||||
/* options? */
|
||||
if (optdata != NULL) {
|
||||
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold optlen",
|
||||
(seg->p->len >= optlen));
|
||||
queuelen += pbuf_clen(seg->p);
|
||||
seg->dataptr = seg->p->payload;
|
||||
}
|
||||
/* copy from volatile memory? */
|
||||
else if (apiflags & TCP_WRITE_FLAG_COPY) {
|
||||
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
|
||||
* ROM or other static memory, and need not be copied. */
|
||||
if (apiflags & TCP_WRITE_FLAG_COPY) {
|
||||
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen + optlen, PBUF_RAM)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
|
||||
goto memerr;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold the complete seglen",
|
||||
(seg->p->len >= seglen));
|
||||
(seg->p->len >= seglen + optlen));
|
||||
queuelen += pbuf_clen(seg->p);
|
||||
if (arg != NULL) {
|
||||
MEMCPY(seg->p->payload, ptr, seglen);
|
||||
MEMCPY((char *)seg->p->payload + optlen, ptr, seglen);
|
||||
}
|
||||
seg->dataptr = seg->p->payload;
|
||||
}
|
||||
/* do not copy data */
|
||||
else {
|
||||
/* First, allocate a pbuf for holding the data.
|
||||
* since the referenced data is available at least until it is sent out on the
|
||||
* link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
|
||||
* instead of PBUF_REF here.
|
||||
*/
|
||||
if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));
|
||||
goto memerr;
|
||||
}
|
||||
++queuelen;
|
||||
/* reference the non-volatile payload data */
|
||||
p->payload = ptr;
|
||||
seg->dataptr = ptr;
|
||||
|
||||
/* Second, allocate a pbuf for the headers. */
|
||||
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {
|
||||
/* If allocation fails, we have to deallocate the data pbuf as
|
||||
* well. */
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));
|
||||
/* First, allocate a pbuf for the headers. */
|
||||
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("tcp_enqueue: could not allocate memory for header pbuf\n"));
|
||||
goto memerr;
|
||||
}
|
||||
queuelen += pbuf_clen(seg->p);
|
||||
|
||||
/* Concatenate the headers and data pbufs together. */
|
||||
pbuf_cat(seg->p/*header*/, p/*data*/);
|
||||
p = NULL;
|
||||
/* Second, allocate a pbuf for holding the data.
|
||||
* since the referenced data is available at least until it is sent out on the
|
||||
* link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
|
||||
* instead of PBUF_REF here.
|
||||
*/
|
||||
if (left > 0) {
|
||||
if ((p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
|
||||
/* If allocation fails, we have to deallocate the header pbuf as well. */
|
||||
pbuf_free(seg->p);
|
||||
seg->p = NULL;
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("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
|
||||
length of the queue exceeds the configured maximum or overflows. */
|
||||
if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
|
||||
goto memerr;
|
||||
}
|
||||
|
||||
@@ -280,7 +304,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
|
||||
/* build TCP header */
|
||||
if (pbuf_header(seg->p, TCP_HLEN)) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
|
||||
TCP_STATS_INC(tcp.err);
|
||||
goto memerr;
|
||||
}
|
||||
@@ -292,17 +316,10 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
TCPH_FLAGS_SET(seg->tcphdr, flags);
|
||||
/* don't fill in tcphdr->ackno and tcphdr->wnd until later */
|
||||
|
||||
/* Copy the options into the header, if they are present. */
|
||||
if (optdata == NULL) {
|
||||
TCPH_HDRLEN_SET(seg->tcphdr, 5);
|
||||
}
|
||||
else {
|
||||
TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));
|
||||
/* Copy options into data portion of segment.
|
||||
Options can thus only be sent in non data carrying
|
||||
segments such as SYN|ACK. */
|
||||
SMEMCPY(seg->dataptr, optdata, optlen);
|
||||
}
|
||||
seg->flags = optflags;
|
||||
|
||||
/* Set the length of the header */
|
||||
TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
|
||||
ntohl(seg->tcphdr->seqno),
|
||||
ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
|
||||
@@ -329,23 +346,43 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
if (useg != NULL &&
|
||||
TCP_TCPLEN(useg) != 0 &&
|
||||
!(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
|
||||
!(flags & (TCP_SYN | TCP_FIN)) &&
|
||||
(!(flags & (TCP_SYN | TCP_FIN)) || (flags == TCP_FIN)) &&
|
||||
/* fit within max seg size */
|
||||
useg->len + queue->len <= pcb->mss) {
|
||||
(useg->len + queue->len <= pcb->mss) &&
|
||||
/* only concatenate segments with the same options */
|
||||
(useg->flags == queue->flags) &&
|
||||
/* segments are consecutive */
|
||||
(ntohl(useg->tcphdr->seqno) + useg->len == ntohl(queue->tcphdr->seqno)) ) {
|
||||
/* Remove TCP header from first segment of our to-be-queued list */
|
||||
if(pbuf_header(queue->p, -TCP_HLEN)) {
|
||||
if(pbuf_header(queue->p, -(TCP_HLEN + optlen))) {
|
||||
/* Can we cope with this failing? Just assert for now */
|
||||
LWIP_ASSERT("pbuf_header failed\n", 0);
|
||||
TCP_STATS_INC(tcp.err);
|
||||
goto memerr;
|
||||
}
|
||||
pbuf_cat(useg->p, queue->p);
|
||||
useg->len += queue->len;
|
||||
useg->next = queue->next;
|
||||
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);
|
||||
}
|
||||
if (flags & TCP_FIN) {
|
||||
/* the new segment contains only FIN, no data -> put the FIN into the last segment */
|
||||
LWIP_ASSERT("FIN enqueued together with data", queue->p == NULL && queue->len == 0);
|
||||
TCPH_SET_FLAG(useg->tcphdr, TCP_FIN);
|
||||
} else {
|
||||
LWIP_ASSERT("zero-length pbuf", (queue->p != NULL) && (queue->p->len > 0));
|
||||
pbuf_cat(useg->p, queue->p);
|
||||
useg->len += queue->len;
|
||||
useg->next = queue->next;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len));
|
||||
if (seg == queue) {
|
||||
seg = NULL;
|
||||
seg = useg;
|
||||
seglen = useg->len;
|
||||
}
|
||||
memp_free(MEMP_TCP_SEG, queue);
|
||||
}
|
||||
@@ -400,6 +437,76 @@ memerr:
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
/* Build a timestamp option (12 bytes long) at the specified options pointer)
|
||||
*
|
||||
* @param pcb tcp_pcb
|
||||
* @param opts option pointer where to store the timestamp option
|
||||
*/
|
||||
static void
|
||||
tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
|
||||
{
|
||||
/* Pad with two NOP options to make everything nicely aligned */
|
||||
opts[0] = htonl(0x0101080A);
|
||||
opts[1] = htonl(sys_now());
|
||||
opts[2] = htonl(pcb->ts_recent);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Send an ACK without data.
|
||||
*
|
||||
* @param pcb Protocol control block for the TCP connection to send the ACK
|
||||
*/
|
||||
err_t
|
||||
tcp_send_empty_ack(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
u8_t optlen = 0;
|
||||
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
if (pcb->flags & TF_TIMESTAMP) {
|
||||
optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
|
||||
}
|
||||
#endif
|
||||
p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
|
||||
("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
|
||||
/* remove ACK flags from the PCB, as we send an empty ACK now */
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
|
||||
tcphdr = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt));
|
||||
|
||||
/* NB. MSS option is only sent on SYNs, so ignore it here */
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
pcb->ts_lastacksent = pcb->rcv_nxt;
|
||||
|
||||
if (pcb->flags & TF_TIMESTAMP) {
|
||||
tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
#endif
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
pbuf_free(p);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out what we can send and send it
|
||||
*
|
||||
@@ -410,10 +517,8 @@ memerr:
|
||||
err_t
|
||||
tcp_output(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
struct tcp_seg *seg, *useg;
|
||||
u32_t wnd;
|
||||
u32_t wnd, snd_nxt;
|
||||
#if TCP_CWND_DEBUG
|
||||
s16_t i = 0;
|
||||
#endif /* TCP_CWND_DEBUG */
|
||||
@@ -430,12 +535,6 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
|
||||
seg = pcb->unsent;
|
||||
|
||||
/* useg should point to last segment on unacked queue */
|
||||
useg = pcb->unacked;
|
||||
if (useg != NULL) {
|
||||
for (; useg->next != NULL; useg = useg->next);
|
||||
}
|
||||
|
||||
/* If the TF_ACK_NOW flag is set and no data will be sent (either
|
||||
* because the ->unsent queue is empty or because the window does
|
||||
* not allow it), construct an empty ACK segment and send it.
|
||||
@@ -445,48 +544,13 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
if (pcb->flags & TF_ACK_NOW &&
|
||||
(seg == NULL ||
|
||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
|
||||
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
|
||||
/* remove ACK flags from the PCB, as we send an empty ACK now */
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
return tcp_send_empty_ack(pcb);
|
||||
}
|
||||
|
||||
tcphdr = p->payload;
|
||||
tcphdr->src = htons(pcb->local_port);
|
||||
tcphdr->dest = htons(pcb->remote_port);
|
||||
tcphdr->seqno = htonl(pcb->snd_nxt);
|
||||
tcphdr->ackno = htonl(pcb->rcv_nxt);
|
||||
TCPH_FLAGS_SET(tcphdr, TCP_ACK);
|
||||
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
||||
tcphdr->urgp = 0;
|
||||
TCPH_HDRLEN_SET(tcphdr, 5);
|
||||
|
||||
tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
#endif
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
{
|
||||
struct netif *netif;
|
||||
netif = ip_route(&pcb->remote_ip);
|
||||
if(netif != NULL){
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,
|
||||
pcb->tos, IP_PROTO_TCP, netif);
|
||||
netif->addr_hint = NULL;
|
||||
}
|
||||
}
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
pbuf_free(p);
|
||||
|
||||
return ERR_OK;
|
||||
/* useg should point to last segment on unacked queue */
|
||||
useg = pcb->unacked;
|
||||
if (useg != NULL) {
|
||||
for (; useg->next != NULL; useg = useg->next);
|
||||
}
|
||||
|
||||
#if TCP_OUTPUT_DEBUG
|
||||
@@ -543,9 +607,9 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
}
|
||||
|
||||
tcp_output_segment(seg, pcb);
|
||||
pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
|
||||
if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
|
||||
pcb->snd_max = pcb->snd_nxt;
|
||||
snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
|
||||
if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
|
||||
pcb->snd_nxt = snd_nxt;
|
||||
}
|
||||
/* put segment on unacknowledged list if length > 0 */
|
||||
if (TCP_TCPLEN(seg) > 0) {
|
||||
@@ -557,12 +621,17 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
/* unacked list is not empty? */
|
||||
} else {
|
||||
/* In the case of fast retransmit, the packet should not go to the tail
|
||||
* of the unacked queue, but rather at the head. We need to check for
|
||||
* of the unacked queue, but rather somewhere before it. We need to check for
|
||||
* this case. -STJ Jul 27, 2004 */
|
||||
if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
|
||||
/* add segment to head of unacked list */
|
||||
seg->next = pcb->unacked;
|
||||
pcb->unacked = seg;
|
||||
/* add segment to before tail of unacked list, keeping the list sorted */
|
||||
struct tcp_seg **cur_seg = &(pcb->unacked);
|
||||
while (*cur_seg &&
|
||||
TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
|
||||
cur_seg = &((*cur_seg)->next );
|
||||
}
|
||||
seg->next = (*cur_seg);
|
||||
(*cur_seg) = seg;
|
||||
} else {
|
||||
/* add segment to tail of unacked list */
|
||||
useg->next = seg;
|
||||
@@ -598,6 +667,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
{
|
||||
u16_t len;
|
||||
struct netif *netif;
|
||||
u32_t *opts;
|
||||
|
||||
/** @bug Exclude retransmitted segments from this count. */
|
||||
snmp_inc_tcpoutsegs();
|
||||
@@ -609,6 +679,24 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
/* advertise our receive window size in this TCP segment */
|
||||
seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
||||
|
||||
pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
|
||||
|
||||
/* Add any requested options. NB MSS option is only set on SYN
|
||||
packets, so ignore it here */
|
||||
opts = (u32_t *)(seg->tcphdr + 1);
|
||||
if (seg->flags & TF_SEG_OPTS_MSS) {
|
||||
TCP_BUILD_MSS_OPTION(*opts);
|
||||
opts += 1;
|
||||
}
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
pcb->ts_lastacksent = pcb->rcv_nxt;
|
||||
|
||||
if (seg->flags & TF_SEG_OPTS_TS) {
|
||||
tcp_build_timestamp_option(pcb, opts);
|
||||
opts += 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we don't have a local IP address, we get one by
|
||||
calling ip_route(). */
|
||||
if (ip_addr_isany(&(pcb->local_ip))) {
|
||||
@@ -650,16 +738,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
{
|
||||
struct netif *netif;
|
||||
netif = ip_route(&pcb->remote_ip);
|
||||
if(netif != NULL){
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
ip_output_if(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,
|
||||
pcb->tos, IP_PROTO_TCP, netif);
|
||||
netif->addr_hint = NULL;
|
||||
}
|
||||
}
|
||||
ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
@@ -749,7 +829,6 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
|
||||
/* unacked queue is now empty */
|
||||
pcb->unacked = NULL;
|
||||
|
||||
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
|
||||
/* increment number of retransmissions */
|
||||
++pcb->nrtx;
|
||||
|
||||
@@ -771,18 +850,24 @@ void
|
||||
tcp_rexmit(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct tcp_seg *seg;
|
||||
struct tcp_seg **cur_seg;
|
||||
|
||||
if (pcb->unacked == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move the first unacked segment to the unsent queue */
|
||||
seg = pcb->unacked->next;
|
||||
pcb->unacked->next = pcb->unsent;
|
||||
pcb->unsent = pcb->unacked;
|
||||
pcb->unacked = seg;
|
||||
/* Keep the unsent queue sorted. */
|
||||
seg = pcb->unacked;
|
||||
pcb->unacked = seg->next;
|
||||
|
||||
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
|
||||
cur_seg = &(pcb->unsent);
|
||||
while (*cur_seg &&
|
||||
TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
|
||||
cur_seg = &((*cur_seg)->next );
|
||||
}
|
||||
seg->next = *cur_seg;
|
||||
*cur_seg = seg;
|
||||
|
||||
++pcb->nrtx;
|
||||
|
||||
@@ -791,9 +876,50 @@ tcp_rexmit(struct tcp_pcb *pcb)
|
||||
|
||||
/* Do the actual retransmission. */
|
||||
snmp_inc_tcpretranssegs();
|
||||
tcp_output(pcb);
|
||||
/* No need to call tcp_output: we are always called from tcp_input()
|
||||
and thus tcp_output directly returns. */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle retransmission after three dupacks received
|
||||
*
|
||||
* @param pcb the tcp_pcb for which to retransmit the first unacked segment
|
||||
*/
|
||||
void
|
||||
tcp_rexmit_fast(struct tcp_pcb *pcb)
|
||||
{
|
||||
if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {
|
||||
/* This is fast retransmit. Retransmit the first unacked segment. */
|
||||
LWIP_DEBUGF(TCP_FR_DEBUG,
|
||||
("tcp_receive: dupacks %"U16_F" (%"U32_F
|
||||
"), fast retransmit %"U32_F"\n",
|
||||
(u16_t)pcb->dupacks, pcb->lastack,
|
||||
ntohl(pcb->unacked->tcphdr->seqno)));
|
||||
tcp_rexmit(pcb);
|
||||
|
||||
/* Set ssthresh to half of the minimum of the current
|
||||
* cwnd and the advertised window */
|
||||
if (pcb->cwnd > pcb->snd_wnd)
|
||||
pcb->ssthresh = pcb->snd_wnd / 2;
|
||||
else
|
||||
pcb->ssthresh = pcb->cwnd / 2;
|
||||
|
||||
/* The minimum value for ssthresh should be 2 MSS */
|
||||
if (pcb->ssthresh < 2*pcb->mss) {
|
||||
LWIP_DEBUGF(TCP_FR_DEBUG,
|
||||
("tcp_receive: The minimum value for ssthresh %"U16_F
|
||||
" should be min 2 mss %"U16_F"...\n",
|
||||
pcb->ssthresh, 2*pcb->mss));
|
||||
pcb->ssthresh = 2*pcb->mss;
|
||||
}
|
||||
|
||||
pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
|
||||
pcb->flags |= TF_INFR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send keepalive packets to keep a connection active although
|
||||
* no data is sent over it.
|
||||
@@ -825,17 +951,8 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
||||
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
|
||||
(p->len >= sizeof(struct tcp_hdr)));
|
||||
|
||||
tcphdr = p->payload;
|
||||
tcphdr->src = htons(pcb->local_port);
|
||||
tcphdr->dest = htons(pcb->remote_port);
|
||||
tcphdr->seqno = htonl(pcb->snd_nxt - 1);
|
||||
tcphdr->ackno = htonl(pcb->rcv_nxt);
|
||||
TCPH_FLAGS_SET(tcphdr, 0);
|
||||
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
||||
tcphdr->urgp = 0;
|
||||
TCPH_HDRLEN_SET(tcphdr, 5);
|
||||
tcphdr = tcp_output_set_header(pcb, p, 0, htonl(pcb->snd_nxt - 1));
|
||||
|
||||
tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
@@ -844,16 +961,8 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
||||
|
||||
/* Send output to IP */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
{
|
||||
struct netif *netif;
|
||||
netif = ip_route(&pcb->remote_ip);
|
||||
if(netif != NULL){
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,
|
||||
0, IP_PROTO_TCP, netif);
|
||||
netif->addr_hint = NULL;
|
||||
}
|
||||
}
|
||||
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
|
||||
&(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
@@ -879,6 +988,8 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
struct tcp_seg *seg;
|
||||
u16_t len;
|
||||
u8_t is_fin;
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG,
|
||||
("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
|
||||
@@ -899,8 +1010,10 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
if(seg == NULL)
|
||||
return;
|
||||
|
||||
p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM);
|
||||
|
||||
is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
|
||||
len = is_fin ? TCP_HLEN : TCP_HLEN + 1;
|
||||
|
||||
p = pbuf_alloc(PBUF_IP, len, PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
|
||||
return;
|
||||
@@ -908,20 +1021,16 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
|
||||
(p->len >= sizeof(struct tcp_hdr)));
|
||||
|
||||
tcphdr = p->payload;
|
||||
tcphdr->src = htons(pcb->local_port);
|
||||
tcphdr->dest = htons(pcb->remote_port);
|
||||
tcphdr->seqno = seg->tcphdr->seqno;
|
||||
tcphdr->ackno = htonl(pcb->rcv_nxt);
|
||||
TCPH_FLAGS_SET(tcphdr, 0);
|
||||
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
||||
tcphdr->urgp = 0;
|
||||
TCPH_HDRLEN_SET(tcphdr, 5);
|
||||
tcphdr = tcp_output_set_header(pcb, p, 0, seg->tcphdr->seqno);
|
||||
|
||||
/* Copy in one byte from the head of the unacked queue */
|
||||
*((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;
|
||||
if (is_fin) {
|
||||
/* FIN segment, no data */
|
||||
TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
|
||||
} else {
|
||||
/* Data segment, copy in one byte from the head of the unacked queue */
|
||||
*((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;
|
||||
}
|
||||
|
||||
tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
@@ -930,16 +1039,8 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
|
||||
/* Send output to IP */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
{
|
||||
struct netif *netif;
|
||||
netif = ip_route(&pcb->remote_ip);
|
||||
if(netif != NULL){
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,
|
||||
0, IP_PROTO_TCP, netif);
|
||||
netif->addr_hint = NULL;
|
||||
}
|
||||
}
|
||||
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
|
||||
&(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
|
||||
@@ -90,6 +90,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
struct ip_hdr *iphdr;
|
||||
u16_t src, dest;
|
||||
u8_t local_match;
|
||||
u8_t broadcast;
|
||||
|
||||
PERF_START;
|
||||
|
||||
@@ -112,6 +113,9 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
udphdr = (struct udp_hdr *)p->payload;
|
||||
|
||||
/* is broadcast packet ? */
|
||||
broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp);
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
|
||||
|
||||
/* convert src and dest ports to host byte order */
|
||||
@@ -169,16 +173,20 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
/* compare PCB local addr+port to UDP destination addr+port */
|
||||
if ((pcb->local_port == dest) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
|
||||
((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
|
||||
#if LWIP_IGMP
|
||||
ip_addr_ismulticast(&(iphdr->dest)) ||
|
||||
#endif /* LWIP_IGMP */
|
||||
ip_addr_isbroadcast(&(iphdr->dest), inp))) {
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
(broadcast && (pcb->so_options & SOF_BROADCAST)))) {
|
||||
#else /* IP_SOF_BROADCAST_RECV */
|
||||
(broadcast))) {
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
local_match = 1;
|
||||
if ((uncon_pcb == NULL) &&
|
||||
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
|
||||
/* the first unconnected matching PCB */
|
||||
/* the first unconnected matching PCB */
|
||||
uncon_pcb = pcb;
|
||||
}
|
||||
}
|
||||
@@ -233,8 +241,8 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | 2,
|
||||
("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
|
||||
UDP_STATS_INC(udp.chkerr);
|
||||
UDP_STATS_INC(udp.drop);
|
||||
snmp_inc_udpinerrors();
|
||||
@@ -250,7 +258,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
IP_PROTO_UDP, p->tot_len) != 0) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | 2,
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("udp_input: UDP datagram discarded due to failing checksum\n"));
|
||||
UDP_STATS_INC(udp.chkerr);
|
||||
UDP_STATS_INC(udp.drop);
|
||||
@@ -274,7 +282,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
/* callback */
|
||||
if (pcb->recv != NULL) {
|
||||
/* now the recv function is responsible for freeing p */
|
||||
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
|
||||
pcb->recv(pcb->recv_arg, pcb, p, &iphdr->src, src);
|
||||
} else {
|
||||
/* no recv function registered? then we have to free the pbuf! */
|
||||
pbuf_free(p);
|
||||
@@ -286,7 +294,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
#if LWIP_ICMP
|
||||
/* No match was found, send ICMP destination port unreachable unless
|
||||
destination address was broadcast/multicast. */
|
||||
if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&
|
||||
if (!broadcast &&
|
||||
!ip_addr_ismulticast(&iphdr->dest)) {
|
||||
/* move payload pointer back to ip header */
|
||||
pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
|
||||
@@ -354,7 +362,7 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n"));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
|
||||
|
||||
/* find the outgoing network interface for this packet */
|
||||
#if LWIP_IGMP
|
||||
@@ -365,7 +373,7 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
|
||||
|
||||
/* no outgoing network interface could be found? */
|
||||
if (netif == NULL) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
|
||||
UDP_STATS_INC(udp.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
@@ -400,12 +408,21 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
err_t err;
|
||||
struct pbuf *q; /* q will be sent down the stack */
|
||||
|
||||
#if IP_SOF_BROADCAST
|
||||
/* broadcast filter? */
|
||||
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
|
||||
return ERR_VAL;
|
||||
}
|
||||
#endif /* IP_SOF_BROADCAST */
|
||||
|
||||
/* if the PCB is not yet bound to a port, bind it here */
|
||||
if (pcb->local_port == 0) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n"));
|
||||
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@@ -416,7 +433,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
|
||||
/* new header pbuf could not be allocated? */
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* chain header q in front of given pbuf p */
|
||||
@@ -496,7 +513,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
|
||||
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
@@ -519,7 +536,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
|
||||
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
@@ -564,9 +581,9 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
struct udp_pcb *ipcb;
|
||||
u8_t rebind;
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = "));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
|
||||
ip_addr_debug_print(UDP_DEBUG, ipaddr);
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", port = %"U16_F")\n", port));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
|
||||
|
||||
rebind = 0;
|
||||
/* Check for double bind and rebind of the same pcb */
|
||||
@@ -635,9 +652,9 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
|
||||
(u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),
|
||||
(u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),
|
||||
(u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),
|
||||
(u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff),
|
||||
(u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff),
|
||||
(u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff),
|
||||
(u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
|
||||
return ERR_OK;
|
||||
}
|
||||
@@ -693,9 +710,9 @@ udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
#endif
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
|
||||
(u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),
|
||||
(u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),
|
||||
(u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),
|
||||
(u16_t)((ntohl(pcb->remote_ip.addr) >> 24) & 0xff),
|
||||
(u16_t)((ntohl(pcb->remote_ip.addr) >> 16) & 0xff),
|
||||
(u16_t)((ntohl(pcb->remote_ip.addr) >> 8) & 0xff),
|
||||
(u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
|
||||
|
||||
/* Insert UDP PCB into the list of active UDP PCBs. */
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
#include "lwip/udp.h"
|
||||
#include "netif/etharp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* AutoIP Timing */
|
||||
#define AUTOIP_TMR_INTERVAL 100
|
||||
#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)
|
||||
@@ -100,6 +104,13 @@ void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);
|
||||
/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */
|
||||
void autoip_tmr(void);
|
||||
|
||||
/** Handle a possible change in the network configuration */
|
||||
void autoip_network_changed(struct netif *netif);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
#endif /* __LWIP_AUTOIP_H__ */
|
||||
|
||||
@@ -33,9 +33,6 @@
|
||||
#define __LWIP_ICMP_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
@@ -70,52 +67,45 @@ enum icmp_te_type {
|
||||
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
|
||||
};
|
||||
|
||||
void icmp_input(struct pbuf *p, struct netif *inp);
|
||||
|
||||
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
|
||||
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
/** This is the standard ICMP header only that the u32_t data
|
||||
* is splitted to two u16_t like ICMP echo needs it.
|
||||
* This header is also used for other ICMP types that do not
|
||||
* use the data part.
|
||||
*/
|
||||
PACK_STRUCT_BEGIN
|
||||
struct icmp_echo_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t _type_code);
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u16_t id);
|
||||
PACK_STRUCT_FIELD(u16_t seqno);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
struct icmp_dur_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t _type_code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u32_t unused);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
struct icmp_te_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t _type_code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u32_t unused);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)
|
||||
#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)
|
||||
#define ICMPH_TYPE(hdr) ((hdr)->type)
|
||||
#define ICMPH_CODE(hdr) ((hdr)->code)
|
||||
|
||||
#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))
|
||||
#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))
|
||||
/** Combines type and code to an u16_t */
|
||||
#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
|
||||
#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
|
||||
|
||||
|
||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
void icmp_input(struct pbuf *p, struct netif *inp);
|
||||
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
|
||||
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
#endif /* __LWIP_ICMP_H__ */
|
||||
|
||||
@@ -34,12 +34,20 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For compatibility with BSD code */
|
||||
struct in_addr {
|
||||
u32_t s_addr;
|
||||
};
|
||||
|
||||
#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */
|
||||
#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */
|
||||
#define INADDR_ANY ((u32_t)0x00000000UL) /* 0.0.0.0 */
|
||||
#define INADDR_BROADCAST ((u32_t)0xffffffffUL) /* 255.255.255.255 */
|
||||
|
||||
u32_t inet_addr(const char *cp);
|
||||
int inet_aton(const char *cp, struct in_addr *addr);
|
||||
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
|
||||
|
||||
@@ -46,9 +46,11 @@ u16_t inet_chksum_pbuf(struct pbuf *p);
|
||||
u16_t inet_chksum_pseudo(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u16_t proto_len);
|
||||
#if LWIP_UDPLITE
|
||||
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u16_t proto_len, u16_t chksum_len);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -38,19 +38,14 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ip_init() /* Compatibility define, not init needed. */
|
||||
struct netif *ip_route(struct ip_addr *dest);
|
||||
err_t ip_input(struct pbuf *p, struct netif *inp);
|
||||
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto);
|
||||
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto,
|
||||
struct netif *netif);
|
||||
/** Currently, the function ip_output_if_opt() is only used with IGMP */
|
||||
#define IP_OPTIONS_SEND LWIP_IGMP
|
||||
|
||||
#define IP_HLEN 20
|
||||
|
||||
@@ -103,7 +98,7 @@ struct ip_pcb {
|
||||
#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */
|
||||
#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */
|
||||
#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */
|
||||
#define SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */
|
||||
#define SOF_BROADCAST (u16_t)0x0020U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
|
||||
#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */
|
||||
#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */
|
||||
#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */
|
||||
@@ -158,6 +153,36 @@ PACK_STRUCT_END
|
||||
#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
|
||||
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
|
||||
|
||||
/** The interface that provided the packet for the current callback invocation. */
|
||||
extern struct netif *current_netif;
|
||||
/** Header of the input packet currently being processed. */
|
||||
extern const struct ip_hdr *current_header;
|
||||
|
||||
#define ip_init() /* Compatibility define, not init needed. */
|
||||
struct netif *ip_route(struct ip_addr *dest);
|
||||
err_t ip_input(struct pbuf *p, struct netif *inp);
|
||||
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 */
|
||||
/** Get the interface that received the current packet.
|
||||
* This function must only be called from a receive callback (udp_recv,
|
||||
* raw_recv, tcp_accept). It will return NULL otherwise. */
|
||||
#define ip_current_netif() (current_netif)
|
||||
/** Get the IP header of the current packet.
|
||||
* This function must only be called from a receive callback (udp_recv,
|
||||
* raw_recv, tcp_accept). It will return NULL otherwise. */
|
||||
#define ip_current_header() (current_header)
|
||||
#if IP_DEBUG
|
||||
void ip_debug_print(struct pbuf *p);
|
||||
#else
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/inet.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -66,11 +68,6 @@ PACK_STRUCT_END
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* For compatibility with BSD code */
|
||||
struct in_addr {
|
||||
u32_t s_addr;
|
||||
};
|
||||
|
||||
struct netif;
|
||||
|
||||
extern const struct ip_addr ip_addr_any;
|
||||
@@ -82,9 +79,6 @@ extern const struct ip_addr ip_addr_broadcast;
|
||||
#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any)
|
||||
#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast)
|
||||
|
||||
#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */
|
||||
#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */
|
||||
|
||||
/* Definitions of the bits in an Internet address integer.
|
||||
|
||||
On subnets, host and network parts are found according to
|
||||
@@ -150,11 +144,15 @@ u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
|
||||
#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))
|
||||
|
||||
#define ip_addr_debug_print(debug, ipaddr) \
|
||||
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
|
||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
|
||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \
|
||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \
|
||||
ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0))
|
||||
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
|
||||
ipaddr != NULL ? \
|
||||
(u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
|
||||
ipaddr != NULL ? \
|
||||
(u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \
|
||||
ipaddr != NULL ? \
|
||||
(u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \
|
||||
ipaddr != NULL ? \
|
||||
(u16_t)ntohl((ipaddr)->addr) & 0xff : 0))
|
||||
|
||||
/* These are cast to u16_t, with the intent that they are often arguments
|
||||
* to printf using the U16_F format from cc.h. */
|
||||
@@ -163,6 +161,11 @@ u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
|
||||
#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)
|
||||
#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)
|
||||
|
||||
/**
|
||||
* Same as inet_ntoa() but takes a struct ip_addr*
|
||||
*/
|
||||
#define ip_ntoa(addr) ((addr != NULL) ? inet_ntoa(*((struct in_addr*)(addr))) : "NULL")
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -114,6 +114,9 @@ err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t proto,
|
||||
struct netif *netif);
|
||||
|
||||
#define ip_current_netif() NULL
|
||||
#define ip_current_header() NULL
|
||||
|
||||
#if IP_DEBUG
|
||||
void ip_debug_print(struct pbuf *p);
|
||||
#endif /* IP_DEBUG */
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#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/sys.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
@@ -137,19 +139,21 @@ struct netconn {
|
||||
/** maximum amount of bytes queued in recvmbox */
|
||||
int recv_bufsize;
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
u16_t recv_avail;
|
||||
s16_t recv_avail;
|
||||
#if LWIP_TCP
|
||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||
this temporarily stores the message. */
|
||||
struct api_msg_msg *write_msg;
|
||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||
this temporarily stores how much is already sent. */
|
||||
int write_offset;
|
||||
size_t write_offset;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||
this temporarily stores whether to wake up the original application task
|
||||
if data couldn't be sent in the first try. */
|
||||
u8_t write_delayed;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
#endif /* LWIP_TCP */
|
||||
/** A callback function that is informed about events for this netconn */
|
||||
netconn_callback callback;
|
||||
};
|
||||
@@ -166,7 +170,8 @@ struct
|
||||
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
|
||||
netconn_callback callback);
|
||||
err_t netconn_delete (struct netconn *conn);
|
||||
enum netconn_type netconn_type (struct netconn *conn);
|
||||
/** Get the type of a netconn (as enum netconn_type). */
|
||||
#define netconn_type(conn) (conn->type)
|
||||
|
||||
err_t netconn_getaddr (struct netconn *conn,
|
||||
struct ip_addr *addr,
|
||||
@@ -191,7 +196,7 @@ err_t netconn_sendto (struct netconn *conn,
|
||||
err_t netconn_send (struct netconn *conn,
|
||||
struct netbuf *buf);
|
||||
err_t netconn_write (struct netconn *conn,
|
||||
const void *dataptr, int size,
|
||||
const void *dataptr, size_t size,
|
||||
u8_t apiflags);
|
||||
err_t netconn_close (struct netconn *conn);
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#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/err.h"
|
||||
#include "lwip/sys.h"
|
||||
@@ -78,10 +80,10 @@ struct api_msg_msg {
|
||||
/** used for do_write */
|
||||
struct {
|
||||
const void *dataptr;
|
||||
int len;
|
||||
size_t len;
|
||||
u8_t apiflags;
|
||||
} w;
|
||||
/** used ofr do_recv */
|
||||
/** used for do_recv */
|
||||
struct {
|
||||
u16_t len;
|
||||
} r;
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
|
||||
#include "arch/cc.h"
|
||||
|
||||
/** Temporary: define format string for size_t if not defined in cc.h */
|
||||
#ifndef SZT_F
|
||||
#define SZT_F U32_F
|
||||
#endif /* SZT_F */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -35,12 +35,13 @@
|
||||
#include "lwip/arch.h"
|
||||
|
||||
/** lower two bits indicate debug level
|
||||
* - 0 off
|
||||
* - 0 all
|
||||
* - 1 warning
|
||||
* - 2 serious
|
||||
* - 3 severe
|
||||
*/
|
||||
#define LWIP_DBG_LEVEL_OFF 0x00
|
||||
#define LWIP_DBG_LEVEL_ALL 0x00
|
||||
#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */
|
||||
#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
|
||||
#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
|
||||
#define LWIP_DBG_LEVEL_SEVERE 0x03
|
||||
@@ -61,26 +62,28 @@
|
||||
#define LWIP_DBG_HALT 0x08U
|
||||
|
||||
#ifndef LWIP_NOASSERT
|
||||
#define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0)
|
||||
#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
|
||||
LWIP_PLATFORM_ASSERT(message); } while(0)
|
||||
#else /* LWIP_NOASSERT */
|
||||
#define LWIP_ASSERT(x,y)
|
||||
#define LWIP_ASSERT(message, assertion)
|
||||
#endif /* LWIP_NOASSERT */
|
||||
|
||||
/** print "m" message only if "e" is true, and execute "h" expression */
|
||||
/** if "expression" isn't true, then print "message" and execute "handler" expression */
|
||||
#ifndef LWIP_ERROR
|
||||
#define LWIP_ERROR(m,e,h) do { if (!(e)) { LWIP_PLATFORM_ASSERT(m); h;}} while(0)
|
||||
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
|
||||
LWIP_PLATFORM_ASSERT(message); handler;}} while(0)
|
||||
#endif /* LWIP_ERROR */
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
/** print debug message only if debug message type is enabled...
|
||||
* AND is of correct type AND is at least LWIP_DBG_LEVEL
|
||||
*/
|
||||
#define LWIP_DEBUGF(debug,x) do { \
|
||||
#define LWIP_DEBUGF(debug, message) do { \
|
||||
if ( \
|
||||
((debug) & LWIP_DBG_ON) && \
|
||||
((debug) & LWIP_DBG_TYPES_ON) && \
|
||||
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
|
||||
LWIP_PLATFORM_DIAG(x); \
|
||||
LWIP_PLATFORM_DIAG(message); \
|
||||
if ((debug) & LWIP_DBG_HALT) { \
|
||||
while(1); \
|
||||
} \
|
||||
@@ -88,7 +91,7 @@
|
||||
} while(0)
|
||||
|
||||
#else /* LWIP_DEBUG */
|
||||
#define LWIP_DEBUGF(debug,x)
|
||||
#define LWIP_DEBUGF(debug, message)
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
#endif /* __LWIP_DEBUG_H__ */
|
||||
|
||||
@@ -18,28 +18,26 @@ extern "C" {
|
||||
/** period (in seconds) of the application calling dhcp_coarse_tmr() */
|
||||
#define DHCP_COARSE_TIMER_SECS 60
|
||||
/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */
|
||||
#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS*1000)
|
||||
#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL)
|
||||
/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
|
||||
#define DHCP_FINE_TIMER_MSECS 500
|
||||
|
||||
struct dhcp
|
||||
{
|
||||
/** current DHCP state machine state */
|
||||
u8_t state;
|
||||
/** retries of current request */
|
||||
u8_t tries;
|
||||
/** transaction identifier of last sent request */
|
||||
u32_t xid;
|
||||
/** our connection to the DHCP server */
|
||||
struct udp_pcb *pcb;
|
||||
/** (first) pbuf of incoming msg */
|
||||
struct pbuf *p;
|
||||
/** incoming msg */
|
||||
struct dhcp_msg *msg_in;
|
||||
/** incoming msg options */
|
||||
struct dhcp_msg *options_in;
|
||||
void *options_in;
|
||||
/** ingoing msg options length */
|
||||
u16_t options_in_len;
|
||||
/** current DHCP state machine state */
|
||||
u8_t state;
|
||||
/** retries of current request */
|
||||
u8_t tries;
|
||||
|
||||
struct pbuf *p_out; /* pbuf of outcoming msg */
|
||||
struct dhcp_msg *msg_out; /* outgoing msg */
|
||||
@@ -124,6 +122,8 @@ err_t dhcp_release(struct netif *netif);
|
||||
void dhcp_stop(struct netif *netif);
|
||||
/** inform server of our manual IP address */
|
||||
void dhcp_inform(struct netif *netif);
|
||||
/** Handle a possible change in the network configuration */
|
||||
void dhcp_network_changed(struct netif *netif);
|
||||
|
||||
/** if enabled, check whether the offered IP address is not in use, using ARP */
|
||||
#if DHCP_DOES_ARP_CHECK
|
||||
|
||||
@@ -87,6 +87,11 @@ struct ip_addr dns_getserver(u8_t numdns);
|
||||
err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr,
|
||||
dns_found_callback found, void *callback_arg);
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
int dns_local_removehost(const char *hostname, const struct ip_addr *addr);
|
||||
err_t dns_local_addhost(const char *hostname, const struct ip_addr *addr);
|
||||
#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
#endif /* __LWIP_DNS_H__ */
|
||||
|
||||
@@ -33,37 +33,43 @@
|
||||
#define __LWIP_ERR_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/arch.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef s8_t err_t;
|
||||
/** Define LWIP_ERR_T in cc.h if you want to use
|
||||
* a different type for your platform (must be signed). */
|
||||
#ifdef LWIP_ERR_T
|
||||
typedef LWIP_ERR_T err_t;
|
||||
#else /* LWIP_ERR_T */
|
||||
typedef s8_t err_t;
|
||||
#endif /* LWIP_ERR_T*/
|
||||
|
||||
/* Definitions for error constants. */
|
||||
|
||||
#define ERR_OK 0 /* No error, everything OK. */
|
||||
#define ERR_MEM -1 /* Out of memory error. */
|
||||
#define ERR_BUF -2 /* Buffer error. */
|
||||
#define ERR_RTE -3 /* Routing problem. */
|
||||
#define ERR_TIMEOUT -3 /* Timeout. */
|
||||
#define ERR_RTE -4 /* Routing problem. */
|
||||
|
||||
#define ERR_IS_FATAL(e) ((e) < ERR_RTE)
|
||||
|
||||
#define ERR_ABRT -4 /* Connection aborted. */
|
||||
#define ERR_RST -5 /* Connection reset. */
|
||||
#define ERR_CLSD -6 /* Connection closed. */
|
||||
#define ERR_CONN -7 /* Not connected. */
|
||||
#define ERR_ABRT -5 /* Connection aborted. */
|
||||
#define ERR_RST -6 /* Connection reset. */
|
||||
#define ERR_CLSD -7 /* Connection closed. */
|
||||
#define ERR_CONN -8 /* Not connected. */
|
||||
|
||||
#define ERR_VAL -8 /* Illegal value. */
|
||||
#define ERR_VAL -9 /* Illegal value. */
|
||||
|
||||
#define ERR_ARG -9 /* Illegal argument. */
|
||||
#define ERR_ARG -10 /* Illegal argument. */
|
||||
|
||||
#define ERR_USE -10 /* Address in use. */
|
||||
#define ERR_USE -11 /* Address in use. */
|
||||
|
||||
#define ERR_IF -11 /* Low-level netif error */
|
||||
#define ERR_ISCONN -12 /* Already connected. */
|
||||
|
||||
#define ERR_TIMEOUT -13 /* Timeout. */
|
||||
#define ERR_IF -12 /* Low-level netif error */
|
||||
#define ERR_ISCONN -13 /* Already connected. */
|
||||
|
||||
#define ERR_INPROGRESS -14 /* Operation in progress */
|
||||
|
||||
|
||||
@@ -38,6 +38,30 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** X.x.x: Major version of the stack */
|
||||
#define LWIP_VERSION_MAJOR 1U
|
||||
/** x.X.x: Minor version of the stack */
|
||||
#define LWIP_VERSION_MINOR 3U
|
||||
/** x.x.X: Revision of the stack */
|
||||
#define LWIP_VERSION_REVISION 2U
|
||||
/** For release candidates, this is set to 1..254
|
||||
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
|
||||
* For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
|
||||
#define LWIP_VERSION_RC 255U
|
||||
|
||||
/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
|
||||
#define LWIP_RC_RELEASE 255U
|
||||
/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */
|
||||
#define LWIP_RC_DEVELOPMENT 0U
|
||||
|
||||
#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE)
|
||||
#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT)
|
||||
#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT))
|
||||
|
||||
/** Provides the version of the stack */
|
||||
#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \
|
||||
LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
|
||||
|
||||
/* Modules initialization */
|
||||
void lwip_init(void);
|
||||
|
||||
|
||||
@@ -50,16 +50,20 @@ typedef size_t mem_size_t;
|
||||
* allow these defines to be overridden.
|
||||
*/
|
||||
#ifndef mem_free
|
||||
#define mem_free(x) free(x)
|
||||
#define mem_free free
|
||||
#endif
|
||||
#ifndef mem_malloc
|
||||
#define mem_malloc(x) malloc(x)
|
||||
#define mem_malloc malloc
|
||||
#endif
|
||||
#ifndef mem_calloc
|
||||
#define mem_calloc(x, y) calloc(x, y)
|
||||
#define mem_calloc calloc
|
||||
#endif
|
||||
#ifndef mem_realloc
|
||||
#define mem_realloc(x, size) (x)
|
||||
static void *mem_realloc(void *mem, mem_size_t size)
|
||||
{
|
||||
LWIP_UNUSED_ARG(size);
|
||||
return mem;
|
||||
}
|
||||
#endif
|
||||
#else /* MEM_LIBC_MALLOC */
|
||||
|
||||
|
||||
@@ -73,8 +73,28 @@ typedef enum {
|
||||
We use this helper type and these defines so we can avoid using const memp_t values */
|
||||
#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)
|
||||
#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST)
|
||||
#endif /* MEM_USE_POOLS */
|
||||
|
||||
#if MEMP_MEM_MALLOC || MEM_USE_POOLS
|
||||
extern const u16_t memp_sizes[MEMP_MAX];
|
||||
#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
|
||||
|
||||
#if MEMP_MEM_MALLOC
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
#define memp_init()
|
||||
#define memp_malloc(type) mem_malloc(memp_sizes[type])
|
||||
#define memp_free(type, mem) mem_free(mem)
|
||||
|
||||
#else /* MEMP_MEM_MALLOC */
|
||||
|
||||
#if MEM_USE_POOLS
|
||||
/** This structure is used to save the pool one element came from. */
|
||||
struct memp_malloc_helper
|
||||
{
|
||||
memp_t poolnr;
|
||||
};
|
||||
#endif /* MEM_USE_POOLS */
|
||||
|
||||
void memp_init(void);
|
||||
@@ -87,6 +107,8 @@ void *memp_malloc(memp_t type);
|
||||
#endif
|
||||
void memp_free(memp_t type, void *mem);
|
||||
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
* above, then will declare #2 & #3 to be just standard mempools.
|
||||
*/
|
||||
#ifndef LWIP_MALLOC_MEMPOOL
|
||||
/* This treats "malloc pools" just like any other pool */
|
||||
#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, size, "MALLOC_"#size)
|
||||
/* This treats "malloc pools" just like any other pool.
|
||||
The pools are a little bigger to provide 'size' as the amount of user data. */
|
||||
#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size)
|
||||
#define LWIP_MALLOC_MEMPOOL_START
|
||||
#define LWIP_MALLOC_MEMPOOL_END
|
||||
#endif /* LWIP_MALLOC_MEMPOOL */
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -43,6 +44,10 @@ struct netbuf {
|
||||
struct pbuf *p, *ptr;
|
||||
struct ip_addr *addr;
|
||||
u16_t port;
|
||||
#if LWIP_NETBUF_RECVINFO
|
||||
struct ip_addr *toaddr;
|
||||
u16_t toport;
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
};
|
||||
|
||||
/* Network buffer functions: */
|
||||
@@ -65,9 +70,14 @@ void netbuf_first (struct netbuf *buf);
|
||||
#define netbuf_copy_partial(buf, dataptr, len, offset) \
|
||||
pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))
|
||||
#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
|
||||
#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
|
||||
#define netbuf_len(buf) ((buf)->p->tot_len)
|
||||
#define netbuf_fromaddr(buf) ((buf)->addr)
|
||||
#define netbuf_fromport(buf) ((buf)->port)
|
||||
#if LWIP_NETBUF_RECVINFO
|
||||
#define netbuf_destaddr(buf) ((buf)->toaddr)
|
||||
#define netbuf_destport(buf) ((buf)->toport)
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#if LWIP_DNS && LWIP_SOCKET
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
/* some rarely used options */
|
||||
@@ -101,7 +103,7 @@ int lwip_getaddrinfo(const char *nodename,
|
||||
#define gethostbyname(name) lwip_gethostbyname(name)
|
||||
#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
|
||||
lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
|
||||
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a)
|
||||
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
|
||||
#define getaddrinfo(nodname, servname, hints, res) \
|
||||
lwip_getaddrinfo(nodname, servname, hints, res)
|
||||
#endif /* LWIP_COMPAT_SOCKETS */
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
@@ -129,12 +131,12 @@ struct netif {
|
||||
/* the hostname for this netif, NULL is a valid value */
|
||||
char* hostname;
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
/** maximum transfer unit (in bytes) */
|
||||
u16_t mtu;
|
||||
/** number of bytes used in hwaddr */
|
||||
u8_t hwaddr_len;
|
||||
/** link level hardware address of this interface */
|
||||
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
||||
/** maximum transfer unit (in bytes) */
|
||||
u16_t mtu;
|
||||
/** flags (see NETIF_FLAG_ above) */
|
||||
u8_t flags;
|
||||
/** descriptive abbreviation */
|
||||
@@ -165,6 +167,14 @@ struct netif {
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
u8_t *addr_hint;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
#if ENABLE_LOOPBACK
|
||||
/* List of packets to be queued for ourselves. */
|
||||
struct pbuf *loop_first;
|
||||
struct pbuf *loop_last;
|
||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||
u16_t loop_cnt_current;
|
||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
};
|
||||
|
||||
#if LWIP_SNMP
|
||||
@@ -242,4 +252,12 @@ void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_LOOPBACK
|
||||
err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip);
|
||||
void netif_poll(struct netif *netif);
|
||||
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
void netif_poll_all(void);
|
||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
#endif /* __LWIP_NETIF_H__ */
|
||||
|
||||
@@ -78,6 +78,11 @@ err_t netifapi_netif_add ( struct netif *netif,
|
||||
err_t (* init)(struct netif *netif),
|
||||
err_t (* input)(struct pbuf *p, struct netif *netif) );
|
||||
|
||||
err_t netifapi_netif_set_addr ( struct netif *netif,
|
||||
struct ip_addr *ipaddr,
|
||||
struct ip_addr *netmask,
|
||||
struct ip_addr *gw );
|
||||
|
||||
err_t netifapi_netif_common ( struct netif *netif,
|
||||
void (* voidfunc)(struct netif *netif),
|
||||
err_t (* errtfunc)(struct netif *netif) );
|
||||
|
||||
@@ -98,6 +98,15 @@
|
||||
#define MEM_LIBC_MALLOC 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator.
|
||||
* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution
|
||||
* speed and usage from interrupts!
|
||||
*/
|
||||
#ifndef MEMP_MEM_MALLOC
|
||||
#define MEMP_MEM_MALLOC 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MEM_ALIGNMENT: should be set to the alignment of the CPU
|
||||
* 4 byte alignment -> #define MEM_ALIGNMENT 4
|
||||
@@ -139,12 +148,21 @@
|
||||
/**
|
||||
* MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set
|
||||
* of memory pools of various sizes. When mem_malloc is called, an element of
|
||||
* the smallest pool that can provide the lenght needed is returned.
|
||||
* the smallest pool that can provide the length needed is returned.
|
||||
* To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled.
|
||||
*/
|
||||
#ifndef MEM_USE_POOLS
|
||||
#define MEM_USE_POOLS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next
|
||||
* bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more
|
||||
* reliable. */
|
||||
#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||
#define MEM_USE_POOLS_TRY_BIGGER_POOL 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h
|
||||
* that defines additional pools beyond the "standard" ones required
|
||||
@@ -155,6 +173,27 @@
|
||||
#define MEMP_USE_CUSTOM_POOLS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from
|
||||
* interrupt context (or another context that doesn't allow waiting for a
|
||||
* semaphore).
|
||||
* If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT,
|
||||
* while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs
|
||||
* with each loop so that mem_free can run.
|
||||
*
|
||||
* ATTENTION: As you can see from the above description, this leads to dis-/
|
||||
* enabling interrupts often, which can be slow! Also, on low memory, mem_malloc
|
||||
* can need longer.
|
||||
*
|
||||
* If you don't want that, at least for NO_SYS=0, you can still use the following
|
||||
* functions to enqueue a deallocation call which then runs in the tcpip_thread
|
||||
* context:
|
||||
* - pbuf_free_callback(p);
|
||||
* - mem_free_callback(m);
|
||||
*/
|
||||
#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------
|
||||
@@ -327,6 +366,16 @@
|
||||
#define ETHARP_TRUST_IP_MAC 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header.
|
||||
* Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check.
|
||||
* If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted.
|
||||
* If ETHARP_VLAN_CHECK is not defined, all traffic is accepted.
|
||||
*/
|
||||
#ifndef ETHARP_SUPPORT_VLAN
|
||||
#define ETHARP_SUPPORT_VLAN 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
--------------------------------
|
||||
---------- IP options ----------
|
||||
@@ -411,6 +460,23 @@
|
||||
#define IP_DEFAULT_TTL 255
|
||||
#endif
|
||||
|
||||
/**
|
||||
* IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast
|
||||
* filter per pcb on udp and raw send operations. To enable broadcast filter
|
||||
* on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1.
|
||||
*/
|
||||
#ifndef IP_SOF_BROADCAST
|
||||
#define IP_SOF_BROADCAST 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast
|
||||
* filter on recv operations.
|
||||
*/
|
||||
#ifndef IP_SOF_BROADCAST_RECV
|
||||
#define IP_SOF_BROADCAST_RECV 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
----------------------------------
|
||||
---------- ICMP options ----------
|
||||
@@ -431,6 +497,20 @@
|
||||
#define ICMP_TTL (IP_DEFAULT_TTL)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only)
|
||||
*/
|
||||
#ifndef LWIP_BROADCAST_PING
|
||||
#define LWIP_BROADCAST_PING 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only)
|
||||
*/
|
||||
#ifndef LWIP_MULTICAST_PING
|
||||
#define LWIP_MULTICAST_PING 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
---------------------------------
|
||||
---------- RAW options ----------
|
||||
@@ -489,6 +569,17 @@
|
||||
#define LWIP_DHCP_AUTOIP_COOP 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes
|
||||
* that should be sent before falling back on AUTOIP. This can be set
|
||||
* as low as 1 to get an AutoIP address very quickly, but you should
|
||||
* be prepared to handle a changing IP address when DHCP overrides
|
||||
* AutoIP.
|
||||
*/
|
||||
#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES
|
||||
#define LWIP_DHCP_AUTOIP_COOP_TRIES 9
|
||||
#endif
|
||||
|
||||
/*
|
||||
----------------------------------
|
||||
---------- SNMP options ----------
|
||||
@@ -591,6 +682,26 @@
|
||||
#define DNS_MSG_SIZE 512
|
||||
#endif
|
||||
|
||||
/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled,
|
||||
* you have to define
|
||||
* #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}}
|
||||
* (an array of structs name/address, where address is an u32_t in network
|
||||
* byte order).
|
||||
*
|
||||
* Instead, you can also use an external function:
|
||||
* #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name)
|
||||
* that returns the IP address or INADDR_NONE if not found.
|
||||
*/
|
||||
#ifndef DNS_LOCAL_HOSTLIST
|
||||
#define DNS_LOCAL_HOSTLIST 0
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
|
||||
/** If this is turned on, the local host-list can be dynamically changed
|
||||
* at runtime. */
|
||||
#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
|
||||
/*
|
||||
---------------------------------
|
||||
---------- UDP options ----------
|
||||
@@ -617,6 +728,13 @@
|
||||
#define UDP_TTL (IP_DEFAULT_TTL)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf.
|
||||
*/
|
||||
#ifndef LWIP_NETBUF_RECVINFO
|
||||
#define LWIP_NETBUF_RECVINFO 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
---------------------------------
|
||||
---------- TCP options ----------
|
||||
@@ -637,10 +755,11 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TCP_WND: The size of a TCP window.
|
||||
* TCP_WND: The size of a TCP window. This must be at least
|
||||
* (2 * TCP_MSS) for things to work well
|
||||
*/
|
||||
#ifndef TCP_WND
|
||||
#define TCP_WND 2048
|
||||
#define TCP_WND (4 * TCP_MSS)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -662,18 +781,18 @@
|
||||
* Define to 0 if your device is low on memory.
|
||||
*/
|
||||
#ifndef TCP_QUEUE_OOSEQ
|
||||
#define TCP_QUEUE_OOSEQ 1
|
||||
#define TCP_QUEUE_OOSEQ (LWIP_TCP)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TCP_MSS: TCP Maximum segment size. (default is 128, a *very*
|
||||
* conservative default.)
|
||||
* TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,
|
||||
* you might want to increase this.)
|
||||
* For the receive side, this MSS is advertised to the remote side
|
||||
* when opening a connection. For the transmit size, this MSS sets
|
||||
* an upper limit on the MSS advertised by the remote host.
|
||||
*/
|
||||
#ifndef TCP_MSS
|
||||
#define TCP_MSS 128
|
||||
#define TCP_MSS 536
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -701,7 +820,7 @@
|
||||
* as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.
|
||||
*/
|
||||
#ifndef TCP_SND_QUEUELEN
|
||||
#define TCP_SND_QUEUELEN (4 * (TCP_SND_BUF/TCP_MSS))
|
||||
#define TCP_SND_QUEUELEN (4 * (TCP_SND_BUF)/(TCP_MSS))
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -710,7 +829,7 @@
|
||||
* TCP snd_buf for select to return writable.
|
||||
*/
|
||||
#ifndef TCP_SNDLOWAT
|
||||
#define TCP_SNDLOWAT (TCP_SND_BUF/2)
|
||||
#define TCP_SNDLOWAT ((TCP_SND_BUF)/2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -729,6 +848,21 @@
|
||||
#define TCP_DEFAULT_LISTEN_BACKLOG 0xff
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option.
|
||||
*/
|
||||
#ifndef LWIP_TCP_TIMESTAMPS
|
||||
#define LWIP_TCP_TIMESTAMPS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an
|
||||
* explicit window update
|
||||
*/
|
||||
#ifndef TCP_WND_UPDATE_THRESHOLD
|
||||
#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1.
|
||||
* LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all
|
||||
@@ -815,6 +949,52 @@
|
||||
#define LWIP_NETIF_HWADDRHINT 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP
|
||||
* address equal to the netif IP address, looping them back up the stack.
|
||||
*/
|
||||
#ifndef LWIP_NETIF_LOOPBACK
|
||||
#define LWIP_NETIF_LOOPBACK 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback
|
||||
* sending for each netif (0 = disabled)
|
||||
*/
|
||||
#ifndef LWIP_LOOPBACK_MAX_PBUFS
|
||||
#define LWIP_LOOPBACK_MAX_PBUFS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in
|
||||
* the system, as netifs must change how they behave depending on this setting
|
||||
* for the LWIP_NETIF_LOOPBACK option to work.
|
||||
* Setting this is needed to avoid reentering non-reentrant functions like
|
||||
* tcp_input().
|
||||
* LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a
|
||||
* multithreaded environment like tcpip.c. In this case, netif->input()
|
||||
* is called directly.
|
||||
* LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.
|
||||
* The packets are put on a list and netif_poll() must be called in
|
||||
* the main application loop.
|
||||
*/
|
||||
#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data
|
||||
* to be sent into one single pbuf. This is for compatibility with DMA-enabled
|
||||
* MACs that do not support scatter-gather.
|
||||
* Beware that this might involve CPU-memcpy before transmitting that would not
|
||||
* be needed without this flag! Use this only if you need to!
|
||||
*
|
||||
* @todo: TCP and IP-frag do not work with this, yet:
|
||||
*/
|
||||
#ifndef LWIP_NETIF_TX_SINGLE_PBUF
|
||||
#define LWIP_NETIF_TX_SINGLE_PBUF 0
|
||||
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
|
||||
/*
|
||||
------------------------------------
|
||||
---------- LOOPIF options ----------
|
||||
@@ -827,20 +1007,16 @@
|
||||
#define LWIP_HAVE_LOOPIF 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------
|
||||
---------- SLIPIF options ----------
|
||||
------------------------------------
|
||||
*/
|
||||
/**
|
||||
* LWIP_LOOPIF_MULTITHREADING: Indicates whether threading is enabled in
|
||||
* the system, as LOOPIF must change how it behaves depending on this setting.
|
||||
* Setting this is needed to avoid reentering non-reentrant functions like
|
||||
* tcp_input().
|
||||
* LWIP_LOOPIF_MULTITHREADING==1: Indicates that the user is using a
|
||||
* multithreaded environment like tcpip.c. In this case, netif->input()
|
||||
* is called directly.
|
||||
* LWIP_LOOPIF_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.
|
||||
* The packets are put on a list and loopif_poll() must be called in
|
||||
* the main application loop.
|
||||
* LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c
|
||||
*/
|
||||
#ifndef LWIP_LOOPIF_MULTITHREADING
|
||||
#define LWIP_LOOPIF_MULTITHREADING 1
|
||||
#ifndef LWIP_HAVE_SLIPIF
|
||||
#define LWIP_HAVE_SLIPIF 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1065,6 +1241,13 @@
|
||||
#define LWIP_SO_RCVBUF 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.
|
||||
*/
|
||||
#ifndef RECV_BUFSIZE_DEFAULT
|
||||
#define RECV_BUFSIZE_DEFAULT INT_MAX
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE!
|
||||
*/
|
||||
@@ -1156,21 +1339,21 @@
|
||||
* MEM_STATS==1: Enable mem.c stats.
|
||||
*/
|
||||
#ifndef MEM_STATS
|
||||
#define MEM_STATS 1
|
||||
#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MEMP_STATS==1: Enable memp.c pool stats.
|
||||
*/
|
||||
#ifndef MEMP_STATS
|
||||
#define MEMP_STATS 1
|
||||
#define MEMP_STATS (MEMP_MEM_MALLOC == 0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SYS_STATS==1: Enable system stats (sem and mbox counts, etc).
|
||||
*/
|
||||
#ifndef SYS_STATS
|
||||
#define SYS_STATS 1
|
||||
#define SYS_STATS (NO_SYS == 0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
@@ -1344,9 +1527,12 @@
|
||||
#endif
|
||||
#define PPP_MINMRU 128 /* No MRUs below this */
|
||||
|
||||
|
||||
#ifndef MAXNAMELEN
|
||||
#define MAXNAMELEN 256 /* max length of hostname or name for auth */
|
||||
#endif
|
||||
#ifndef MAXSECRETLEN
|
||||
#define MAXSECRETLEN 256 /* max length of password or secret */
|
||||
#endif
|
||||
|
||||
#endif /* PPP_SUPPORT */
|
||||
|
||||
@@ -1408,7 +1594,7 @@
|
||||
* messages are written.
|
||||
*/
|
||||
#ifndef LWIP_DBG_MIN_LEVEL
|
||||
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_OFF
|
||||
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
@@ -110,6 +110,8 @@ void pbuf_chain(struct pbuf *head, struct pbuf *tail);
|
||||
struct pbuf *pbuf_dechain(struct pbuf *p);
|
||||
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
|
||||
u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
|
||||
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
|
||||
struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -32,40 +32,110 @@
|
||||
* It needs to be implemented by those platforms which need SLIP or PPP
|
||||
*/
|
||||
|
||||
#ifndef __SIO_H__
|
||||
#define __SIO_H__
|
||||
|
||||
#include "lwip/arch.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* If you want to define sio_fd_t elsewhere or differently,
|
||||
define this in your cc.h file. */
|
||||
#ifndef __sio_fd_t_defined
|
||||
typedef void * sio_fd_t;
|
||||
#endif
|
||||
|
||||
/* The following functions can be defined to something else in your cc.h file
|
||||
or be implemented in your custom sio.c file. */
|
||||
|
||||
#ifndef sio_open
|
||||
sio_fd_t sio_open(u8_t);
|
||||
/**
|
||||
* Opens a serial device for communication.
|
||||
*
|
||||
* @param devnum device number
|
||||
* @return handle to serial device if successful, NULL otherwise
|
||||
*/
|
||||
sio_fd_t sio_open(u8_t devnum);
|
||||
#endif
|
||||
|
||||
#ifndef sio_send
|
||||
void sio_send(u8_t, sio_fd_t);
|
||||
/**
|
||||
* Sends a single character to the serial device.
|
||||
*
|
||||
* @param c character to send
|
||||
* @param fd serial device handle
|
||||
*
|
||||
* @note This function will block until the character can be sent.
|
||||
*/
|
||||
void sio_send(u8_t c, sio_fd_t fd);
|
||||
#endif
|
||||
|
||||
#ifndef sio_recv
|
||||
u8_t sio_recv(sio_fd_t);
|
||||
/**
|
||||
* Receives a single character from the serial device.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
*
|
||||
* @note This function will block until a character is received.
|
||||
*/
|
||||
u8_t sio_recv(sio_fd_t fd);
|
||||
#endif
|
||||
|
||||
#ifndef sio_read
|
||||
u32_t sio_read(sio_fd_t, u8_t *, u32_t);
|
||||
/**
|
||||
* Reads from the serial device.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data buffer for receiving
|
||||
* @param len maximum length (in bytes) of data to receive
|
||||
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
|
||||
*
|
||||
* @note This function will block until data can be received. The blocking
|
||||
* can be cancelled by calling sio_read_abort().
|
||||
*/
|
||||
u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
|
||||
#endif
|
||||
|
||||
#ifndef sio_tryread
|
||||
/**
|
||||
* Tries to read from the serial device. Same as sio_read but returns
|
||||
* immediately if no data is available and never blocks.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data buffer for receiving
|
||||
* @param len maximum length (in bytes) of data to receive
|
||||
* @return number of bytes actually received
|
||||
*/
|
||||
u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len);
|
||||
#endif
|
||||
|
||||
#ifndef sio_write
|
||||
u32_t sio_write(sio_fd_t, u8_t *, u32_t);
|
||||
/**
|
||||
* Writes to the serial device.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data to send
|
||||
* @param len length (in bytes) of data to send
|
||||
* @return number of bytes actually sent
|
||||
*
|
||||
* @note This function will block until all data can be sent.
|
||||
*/
|
||||
u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
|
||||
#endif
|
||||
|
||||
#ifndef sio_read_abort
|
||||
void sio_read_abort(sio_fd_t);
|
||||
/**
|
||||
* Aborts a blocking sio_read() call.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
*/
|
||||
void sio_read_abort(sio_fd_t fd);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SIO_H__ */
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/snmp.h"
|
||||
|
||||
#if LWIP_SNMP
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -94,4 +96,6 @@ err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* __LWIP_SNMP_ASN1_H__ */
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/snmp_structs.h"
|
||||
|
||||
#if LWIP_SNMP
|
||||
|
||||
#if SNMP_PRIVATE_MIB
|
||||
#include "private_mib.h"
|
||||
#endif
|
||||
@@ -304,4 +306,6 @@ void snmp_authfail_trap(void);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* __LWIP_SNMP_MSG_H__ */
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
#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/inet.h"
|
||||
|
||||
@@ -77,7 +79,7 @@ struct sockaddr {
|
||||
#define SO_REUSEADDR 0x0004 /* Unimplemented: allow local address reuse */
|
||||
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
|
||||
#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */
|
||||
#define SO_BROADCAST 0x0020 /* Unimplemented: permit sending of broadcast msgs */
|
||||
#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
|
||||
#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */
|
||||
#define SO_LINGER 0x0080 /* linger on close if data present */
|
||||
#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */
|
||||
@@ -124,9 +126,6 @@ struct linger {
|
||||
#define IPPROTO_UDP 17
|
||||
#define IPPROTO_UDPLITE 136
|
||||
|
||||
#define INADDR_ANY 0
|
||||
#define INADDR_BROADCAST 0xffffffff
|
||||
|
||||
/* Flags we can use with send and recv. */
|
||||
#define MSG_PEEK 0x01 /* Peeks at an incoming message */
|
||||
#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */
|
||||
@@ -177,7 +176,22 @@ typedef struct ip_mreq {
|
||||
} ip_mreq;
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
/* Unimplemented for now... */
|
||||
/*
|
||||
* The Type of Service provides an indication of the abstract
|
||||
* parameters of the quality of service desired. These parameters are
|
||||
* to be used to guide the selection of the actual service parameters
|
||||
* when transmitting a datagram through a particular network. Several
|
||||
* networks offer service precedence, which somehow treats high
|
||||
* precedence traffic as more important than other traffic (generally
|
||||
* by accepting only traffic above a certain precedence at time of high
|
||||
* load). The major choice is a three way tradeoff between low-delay,
|
||||
* high-reliability, and high-throughput.
|
||||
* The use of the Delay, Throughput, and Reliability indications may
|
||||
* increase the cost (in some sense) of the service. In many networks
|
||||
* better performance for one of these parameters is coupled with worse
|
||||
* performance on another. Except for very unusual cases at most two
|
||||
* of these three indications should be set.
|
||||
*/
|
||||
#define IPTOS_TOS_MASK 0x1E
|
||||
#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
|
||||
#define IPTOS_LOWDELAY 0x10
|
||||
@@ -187,7 +201,13 @@ typedef struct ip_mreq {
|
||||
#define IPTOS_MINCOST IPTOS_LOWCOST
|
||||
|
||||
/*
|
||||
* Definitions for IP precedence (also in ip_tos) (Unimplemented)
|
||||
* The Network Control precedence designation is intended to be used
|
||||
* within a network only. The actual use and control of that
|
||||
* designation is up to each network. The Internetwork Control
|
||||
* designation is intended for use by gateway control originators only.
|
||||
* If the actual use of these precedence designations is of concern to
|
||||
* a particular network, it is the responsibility of that network to
|
||||
* control the access to, and use of, those precedence designations.
|
||||
*/
|
||||
#define IPTOS_PREC_MASK 0xe0
|
||||
#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK)
|
||||
@@ -279,7 +299,7 @@ struct timeval {
|
||||
void lwip_socket_init(void);
|
||||
|
||||
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
int lwip_bind(int s, struct sockaddr *name, socklen_t namelen);
|
||||
int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen);
|
||||
int lwip_shutdown(int s, int how);
|
||||
int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);
|
||||
int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen);
|
||||
@@ -288,15 +308,15 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_
|
||||
int lwip_close(int s);
|
||||
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen);
|
||||
int lwip_listen(int s, int backlog);
|
||||
int lwip_recv(int s, void *mem, int len, unsigned int flags);
|
||||
int lwip_read(int s, void *mem, int len);
|
||||
int lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||
int lwip_recv(int s, void *mem, size_t len, int flags);
|
||||
int lwip_read(int s, void *mem, size_t len);
|
||||
int lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen);
|
||||
int lwip_send(int s, const void *dataptr, int size, unsigned int flags);
|
||||
int lwip_sendto(int s, const void *dataptr, int size, unsigned int flags,
|
||||
struct sockaddr *to, socklen_t tolen);
|
||||
int lwip_send(int s, const void *dataptr, size_t size, int flags);
|
||||
int lwip_sendto(int s, const void *dataptr, size_t size, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen);
|
||||
int lwip_socket(int domain, int type, int protocol);
|
||||
int lwip_write(int s, const void *dataptr, int size);
|
||||
int lwip_write(int s, const void *dataptr, size_t size);
|
||||
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
||||
struct timeval *timeout);
|
||||
int lwip_ioctl(int s, long cmd, void *argp);
|
||||
|
||||
@@ -57,7 +57,6 @@ extern "C" {
|
||||
|
||||
struct stats_proto {
|
||||
STAT_COUNTER xmit; /* Transmitted packets. */
|
||||
STAT_COUNTER rexmit; /* Retransmitted packets. */
|
||||
STAT_COUNTER recv; /* Received packets. */
|
||||
STAT_COUNTER fw; /* Forwarded packets. */
|
||||
STAT_COUNTER drop; /* Dropped packets. */
|
||||
@@ -87,7 +86,8 @@ struct stats_mem {
|
||||
mem_size_t avail;
|
||||
mem_size_t used;
|
||||
mem_size_t max;
|
||||
mem_size_t err;
|
||||
STAT_COUNTER err;
|
||||
STAT_COUNTER illegal;
|
||||
};
|
||||
|
||||
struct stats_syselem {
|
||||
@@ -142,64 +142,138 @@ extern struct stats_ lwip_stats;
|
||||
#define stats_init() /* Compatibility define, not init needed. */
|
||||
|
||||
#define STATS_INC(x) ++lwip_stats.x
|
||||
#define STATS_DEC(x) --lwip_stats.x
|
||||
#else
|
||||
#define stats_init()
|
||||
#define STATS_INC(x)
|
||||
#define STATS_DEC(x)
|
||||
#endif /* LWIP_STATS */
|
||||
|
||||
#if TCP_STATS
|
||||
#define TCP_STATS_INC(x) STATS_INC(x)
|
||||
#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP")
|
||||
#else
|
||||
#define TCP_STATS_INC(x)
|
||||
#define TCP_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if UDP_STATS
|
||||
#define UDP_STATS_INC(x) STATS_INC(x)
|
||||
#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP")
|
||||
#else
|
||||
#define UDP_STATS_INC(x)
|
||||
#define UDP_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if ICMP_STATS
|
||||
#define ICMP_STATS_INC(x) STATS_INC(x)
|
||||
#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP")
|
||||
#else
|
||||
#define ICMP_STATS_INC(x)
|
||||
#define ICMP_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if IGMP_STATS
|
||||
#define IGMP_STATS_INC(x) STATS_INC(x)
|
||||
#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp)
|
||||
#else
|
||||
#define IGMP_STATS_INC(x)
|
||||
#define IGMP_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if IP_STATS
|
||||
#define IP_STATS_INC(x) STATS_INC(x)
|
||||
#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP")
|
||||
#else
|
||||
#define IP_STATS_INC(x)
|
||||
#define IP_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if IPFRAG_STATS
|
||||
#define IPFRAG_STATS_INC(x) STATS_INC(x)
|
||||
#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG")
|
||||
#else
|
||||
#define IPFRAG_STATS_INC(x)
|
||||
#define IPFRAG_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if ETHARP_STATS
|
||||
#define ETHARP_STATS_INC(x) STATS_INC(x)
|
||||
#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP")
|
||||
#else
|
||||
#define ETHARP_STATS_INC(x)
|
||||
#define ETHARP_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if LINK_STATS
|
||||
#define LINK_STATS_INC(x) STATS_INC(x)
|
||||
#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK")
|
||||
#else
|
||||
#define LINK_STATS_INC(x)
|
||||
#define LINK_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if MEM_STATS
|
||||
#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y
|
||||
#define MEM_STATS_INC(x) STATS_INC(mem.x)
|
||||
#define MEM_STATS_INC_USED(x, y) do { lwip_stats.mem.used += y; \
|
||||
if (lwip_stats.mem.max < lwip_stats.mem.used) { \
|
||||
lwip_stats.mem.max = lwip_stats.mem.used; \
|
||||
} \
|
||||
} while(0)
|
||||
#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y
|
||||
#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP")
|
||||
#else
|
||||
#define MEM_STATS_AVAIL(x, y)
|
||||
#define MEM_STATS_INC(x)
|
||||
#define MEM_STATS_INC_USED(x, y)
|
||||
#define MEM_STATS_DEC_USED(x, y)
|
||||
#define MEM_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
#if MEMP_STATS
|
||||
#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y
|
||||
#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x)
|
||||
#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x)
|
||||
#define MEMP_STATS_INC_USED(x, i) do { ++lwip_stats.memp[i].used; \
|
||||
if (lwip_stats.memp[i].max < lwip_stats.memp[i].used) { \
|
||||
lwip_stats.memp[i].max = lwip_stats.memp[i].used; \
|
||||
} \
|
||||
} while(0)
|
||||
#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i)
|
||||
#else
|
||||
#define MEMP_STATS_AVAIL(x, i, y)
|
||||
#define MEMP_STATS_INC(x, i)
|
||||
#define MEMP_STATS_DEC(x, i)
|
||||
#define MEMP_STATS_INC_USED(x, i)
|
||||
#define MEMP_STATS_DISPLAY(i)
|
||||
#endif
|
||||
|
||||
#if SYS_STATS
|
||||
#define SYS_STATS_INC(x) STATS_INC(sys.x)
|
||||
#define SYS_STATS_DEC(x) STATS_DEC(sys.x)
|
||||
#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys)
|
||||
#else
|
||||
#define SYS_STATS_INC(x)
|
||||
#define SYS_STATS_DEC(x)
|
||||
#define SYS_STATS_DISPLAY()
|
||||
#endif
|
||||
|
||||
/* Display of statistics */
|
||||
#if LWIP_STATS_DISPLAY
|
||||
void stats_display(void);
|
||||
void stats_display_proto(struct stats_proto *proto, char *name);
|
||||
void stats_display_igmp(struct stats_igmp *igmp);
|
||||
void stats_display_mem(struct stats_mem *mem, char *name);
|
||||
void stats_display_memp(struct stats_mem *mem, int index);
|
||||
void stats_display_sys(struct stats_sys *sys);
|
||||
#else
|
||||
#define stats_display()
|
||||
#define stats_display_proto(proto, name)
|
||||
#define stats_display_igmp(igmp)
|
||||
#define stats_display_mem(mem, name)
|
||||
#define stats_display_memp(mem, index)
|
||||
#define stats_display_sys(sys)
|
||||
#endif /* LWIP_STATS_DISPLAY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -44,7 +44,6 @@ extern "C" {
|
||||
definitions of the sys_ functions. */
|
||||
typedef u8_t sys_sem_t;
|
||||
typedef u8_t sys_mbox_t;
|
||||
typedef u8_t sys_prot_t;
|
||||
struct sys_timeo {u8_t dummy;};
|
||||
|
||||
#define sys_init()
|
||||
@@ -139,13 +138,11 @@ void sys_mbox_fetch(sys_mbox_t mbox, void **msg);
|
||||
/* Thread functions. */
|
||||
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio);
|
||||
|
||||
/* The following functions are used only in Unix code, and
|
||||
can be omitted when porting the stack. */
|
||||
/* Returns the current time in microseconds. */
|
||||
unsigned long sys_now(void);
|
||||
|
||||
#endif /* NO_SYS */
|
||||
|
||||
/** Returns the current time in milliseconds. */
|
||||
u32_t sys_now(void);
|
||||
|
||||
/* Critical Region Protection */
|
||||
/* These functions must be implemented in the sys_arch.c file.
|
||||
In some implementations they can provide a more light-weight protection
|
||||
|
||||
@@ -78,6 +78,9 @@ void tcp_err (struct tcp_pcb *pcb,
|
||||
|
||||
#define tcp_mss(pcb) ((pcb)->mss)
|
||||
#define tcp_sndbuf(pcb) ((pcb)->snd_buf)
|
||||
#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY)
|
||||
#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY)
|
||||
#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0)
|
||||
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
#define tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--)
|
||||
@@ -96,7 +99,8 @@ err_t tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
|
||||
#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
|
||||
|
||||
void tcp_abort (struct tcp_pcb *pcb);
|
||||
void tcp_abandon (struct tcp_pcb *pcb, int reset);
|
||||
#define tcp_abort(pcb) tcp_abandon((pcb), 1)
|
||||
err_t tcp_close (struct tcp_pcb *pcb);
|
||||
|
||||
/* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */
|
||||
@@ -121,29 +125,30 @@ void tcp_fasttmr (void);
|
||||
/* Only used by IP to pass a TCP segment to TCP: */
|
||||
void tcp_input (struct pbuf *p, struct netif *inp);
|
||||
/* Used within the TCP code only: */
|
||||
err_t tcp_send_empty_ack(struct tcp_pcb *pcb);
|
||||
err_t tcp_output (struct tcp_pcb *pcb);
|
||||
void tcp_rexmit (struct tcp_pcb *pcb);
|
||||
void tcp_rexmit_rto (struct tcp_pcb *pcb);
|
||||
void tcp_rexmit_fast (struct tcp_pcb *pcb);
|
||||
u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
|
||||
|
||||
/**
|
||||
* This is the Nagle algorithm: inhibit the sending of new TCP
|
||||
* segments when new outgoing data arrives from the user if any
|
||||
* previously transmitted data on the connection remains
|
||||
* unacknowledged.
|
||||
* This is the Nagle algorithm: try to combine user data to send as few TCP
|
||||
* segments as possible. Only send if
|
||||
* - no previously transmitted data on the connection remains unacknowledged or
|
||||
* - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or
|
||||
* - the only unsent segment is at least pcb->mss bytes long (or there is more
|
||||
* than one unsent segment - with lwIP, this can happen although unsent->len < mss)
|
||||
* - or if we are in fast-retransmit (TF_INFR)
|
||||
*/
|
||||
#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
|
||||
((tpcb)->flags & TF_NODELAY) || \
|
||||
(((tpcb)->unsent != NULL) && ((tpcb)->unsent->next != NULL))) ? \
|
||||
1 : 0)
|
||||
((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \
|
||||
(((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
|
||||
((tpcb)->unsent->len >= (tpcb)->mss))) \
|
||||
) ? 1 : 0)
|
||||
#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)
|
||||
|
||||
|
||||
/** This returns a TCP header option for MSS in an u32_t */
|
||||
#define TCP_BUILD_MSS_OPTION() htonl(((u32_t)2 << 24) | \
|
||||
((u32_t)4 << 16) | \
|
||||
(((u32_t)TCP_MSS / 256) << 8) | \
|
||||
(TCP_MSS & 255))
|
||||
|
||||
#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0)
|
||||
#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
|
||||
#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
|
||||
@@ -185,7 +190,7 @@ void tcp_rexmit_rto (struct tcp_pcb *pcb);
|
||||
#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */
|
||||
|
||||
#ifndef TCP_MSL
|
||||
#define TCP_MSL 60000U /* The maximum segment lifetime in milliseconds */
|
||||
#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */
|
||||
#endif
|
||||
|
||||
/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */
|
||||
@@ -231,12 +236,11 @@ PACK_STRUCT_END
|
||||
|
||||
#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))
|
||||
#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))
|
||||
#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags))
|
||||
#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags))
|
||||
#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & htons((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags))
|
||||
#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags))
|
||||
#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )
|
||||
|
||||
#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \
|
||||
TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0))
|
||||
#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0))
|
||||
|
||||
enum tcp_state {
|
||||
CLOSED = 0,
|
||||
@@ -258,6 +262,20 @@ enum tcp_state {
|
||||
#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */
|
||||
#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
|
||||
|
||||
|
||||
#if LWIP_CALLBACK_API
|
||||
/* Function to call when a listener has been connected.
|
||||
* @param arg user-supplied argument (tcp_pcb.callback_arg)
|
||||
* @param pcb a new tcp_pcb that now is connected
|
||||
* @param err an error argument (TODO: that is current always ERR_OK?)
|
||||
* @return ERR_OK: accept the new connection,
|
||||
* any other err_t abortsthe new connection
|
||||
*/
|
||||
#define DEF_ACCEPT_CALLBACK err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
#else /* LWIP_CALLBACK_API */
|
||||
#define DEF_ACCEPT_CALLBACK
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
|
||||
/**
|
||||
* members common to struct tcp_pcb and struct tcp_listen_pcb
|
||||
*/
|
||||
@@ -267,7 +285,10 @@ enum tcp_state {
|
||||
u8_t prio; \
|
||||
void *callback_arg; \
|
||||
/* ports are in host byte order */ \
|
||||
u16_t local_port
|
||||
u16_t local_port; \
|
||||
/* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \
|
||||
DEF_ACCEPT_CALLBACK
|
||||
|
||||
|
||||
/* the TCP protocol control block */
|
||||
struct tcp_pcb {
|
||||
@@ -280,19 +301,21 @@ struct tcp_pcb {
|
||||
u16_t remote_port;
|
||||
|
||||
u8_t flags;
|
||||
#define TF_ACK_DELAY (u8_t)0x01U /* Delayed ACK. */
|
||||
#define TF_ACK_NOW (u8_t)0x02U /* Immediate ACK. */
|
||||
#define TF_INFR (u8_t)0x04U /* In fast recovery. */
|
||||
#define TF_FIN (u8_t)0x20U /* Connection was closed locally (FIN segment enqueued). */
|
||||
#define TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */
|
||||
#define TF_NAGLEMEMERR (u8_t)0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
|
||||
#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */
|
||||
#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */
|
||||
#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */
|
||||
#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */
|
||||
#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */
|
||||
#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */
|
||||
#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
|
||||
|
||||
/* the rest of the fields are in host byte order
|
||||
as we have to do some math with them */
|
||||
/* receiver variables */
|
||||
u32_t rcv_nxt; /* next seqno expected */
|
||||
u16_t rcv_wnd; /* receiver window */
|
||||
u16_t rcv_ann_wnd; /* announced receive window */
|
||||
u16_t rcv_wnd; /* receiver window available */
|
||||
u16_t rcv_ann_wnd; /* receiver window to announce */
|
||||
u32_t rcv_ann_right_edge; /* announced right edge of window */
|
||||
|
||||
/* Timers */
|
||||
u32_t tmr;
|
||||
@@ -320,12 +343,11 @@ struct tcp_pcb {
|
||||
u16_t ssthresh;
|
||||
|
||||
/* sender variables */
|
||||
u32_t snd_nxt, /* next seqno to be sent */
|
||||
snd_max; /* Highest seqno sent. */
|
||||
u32_t snd_nxt; /* next new seqno to be sent */
|
||||
u16_t snd_wnd; /* sender window */
|
||||
u32_t snd_wl1, snd_wl2, /* Sequence and acknowledgement numbers of last
|
||||
u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last
|
||||
window update. */
|
||||
snd_lbb; /* Sequence number of next byte to be buffered. */
|
||||
u32_t snd_lbb; /* Sequence number of next byte to be buffered. */
|
||||
|
||||
u16_t acked;
|
||||
|
||||
@@ -369,15 +391,6 @@ struct tcp_pcb {
|
||||
*/
|
||||
err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);
|
||||
|
||||
/* Function to call when a listener has been connected.
|
||||
* @param arg user-supplied argument (tcp_pcb.callback_arg)
|
||||
* @param pcb a new tcp_pcb that now is connected
|
||||
* @param err an error argument (TODO: that is current always ERR_OK?)
|
||||
* @return ERR_OK: accept the new connection,
|
||||
* any other err_t abortsthe new connection
|
||||
*/
|
||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
|
||||
|
||||
/* Function which is called periodically.
|
||||
* The period can be adjusted in multiples of the TCP slow timer interval
|
||||
* by changing tcp_pcb.polltmr.
|
||||
@@ -398,6 +411,11 @@ struct tcp_pcb {
|
||||
void (* errf)(void *arg, err_t err);
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
u32_t ts_lastacksent;
|
||||
u32_t ts_recent;
|
||||
#endif /* LWIP_TCP_TIMESTAMPS */
|
||||
|
||||
/* idle time before KEEPALIVE is sent */
|
||||
u32_t keep_idle;
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
@@ -420,16 +438,6 @@ struct tcp_pcb_listen {
|
||||
/* Protocol specific PCB members */
|
||||
TCP_PCB_COMMON(struct tcp_pcb_listen);
|
||||
|
||||
#if LWIP_CALLBACK_API
|
||||
/* Function to call when a listener has been connected.
|
||||
* @param arg user-supplied argument (tcp_pcb.callback_arg)
|
||||
* @param pcb a new tcp_pcb that now is connected
|
||||
* @param err an error argument (TODO: that is current always ERR_OK?)
|
||||
* @return ERR_OK: accept the new connection,
|
||||
* any other err_t abortsthe new connection
|
||||
*/
|
||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
u8_t backlog;
|
||||
u8_t accepts_pending;
|
||||
@@ -466,26 +474,50 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
|
||||
#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \
|
||||
LWIP_EVENT_ERR, NULL, 0, (err))
|
||||
#else /* LWIP_EVENT_API */
|
||||
#define TCP_EVENT_ACCEPT(pcb,err,ret) \
|
||||
if((pcb)->accept != NULL) \
|
||||
(ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err)))
|
||||
#define TCP_EVENT_SENT(pcb,space,ret) \
|
||||
if((pcb)->sent != NULL) \
|
||||
(ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space)))
|
||||
#define TCP_EVENT_RECV(pcb,p,err,ret) \
|
||||
if((pcb)->recv != NULL) \
|
||||
{ ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \
|
||||
ret = ERR_OK; \
|
||||
if (p) pbuf_free(p); }
|
||||
#define TCP_EVENT_CONNECTED(pcb,err,ret) \
|
||||
if((pcb)->connected != NULL) \
|
||||
(ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))
|
||||
#define TCP_EVENT_POLL(pcb,ret) \
|
||||
if((pcb)->poll != NULL) \
|
||||
(ret = (pcb)->poll((pcb)->callback_arg,(pcb)))
|
||||
#define TCP_EVENT_ERR(errf,arg,err) \
|
||||
if((errf) != NULL) \
|
||||
(errf)((arg),(err))
|
||||
|
||||
#define TCP_EVENT_ACCEPT(pcb,err,ret) \
|
||||
do { \
|
||||
if((pcb)->accept != NULL) \
|
||||
(ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \
|
||||
else (ret) = ERR_OK; \
|
||||
} while (0)
|
||||
|
||||
#define TCP_EVENT_SENT(pcb,space,ret) \
|
||||
do { \
|
||||
if((pcb)->sent != NULL) \
|
||||
(ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \
|
||||
else (ret) = ERR_OK; \
|
||||
} while (0)
|
||||
|
||||
#define TCP_EVENT_RECV(pcb,p,err,ret) \
|
||||
do { \
|
||||
if((pcb)->recv != NULL) { \
|
||||
(ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \
|
||||
} else { \
|
||||
(ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TCP_EVENT_CONNECTED(pcb,err,ret) \
|
||||
do { \
|
||||
if((pcb)->connected != NULL) \
|
||||
(ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \
|
||||
else (ret) = ERR_OK; \
|
||||
} while (0)
|
||||
|
||||
#define TCP_EVENT_POLL(pcb,ret) \
|
||||
do { \
|
||||
if((pcb)->poll != NULL) \
|
||||
(ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \
|
||||
else (ret) = ERR_OK; \
|
||||
} while (0)
|
||||
|
||||
#define TCP_EVENT_ERR(errf,arg,err) \
|
||||
do { \
|
||||
if((errf) != NULL) \
|
||||
(errf)((arg),(err)); \
|
||||
} while (0)
|
||||
|
||||
#endif /* LWIP_EVENT_API */
|
||||
|
||||
/* This structure represents a TCP segment on the unsent and unacked queues */
|
||||
@@ -494,9 +526,22 @@ struct tcp_seg {
|
||||
struct pbuf *p; /* buffer containing data + TCP header */
|
||||
void *dataptr; /* pointer to the TCP data in the pbuf */
|
||||
u16_t len; /* the TCP length of this segment */
|
||||
u8_t flags;
|
||||
#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */
|
||||
#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */
|
||||
struct tcp_hdr *tcphdr; /* the TCP header */
|
||||
};
|
||||
|
||||
#define LWIP_TCP_OPT_LENGTH(flags) \
|
||||
(flags & TF_SEG_OPTS_MSS ? 4 : 0) + \
|
||||
(flags & TF_SEG_OPTS_TS ? 12 : 0)
|
||||
|
||||
/** This returns a TCP header option for MSS in an u32_t */
|
||||
#define TCP_BUILD_MSS_OPTION(x) (x) = htonl(((u32_t)2 << 24) | \
|
||||
((u32_t)4 << 16) | \
|
||||
(((u32_t)TCP_MSS / 256) << 8) | \
|
||||
(TCP_MSS & 255))
|
||||
|
||||
/* Internal functions and global variables: */
|
||||
struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
|
||||
void tcp_pcb_purge(struct tcp_pcb *pcb);
|
||||
@@ -506,21 +551,27 @@ u8_t tcp_segs_free(struct tcp_seg *seg);
|
||||
u8_t tcp_seg_free(struct tcp_seg *seg);
|
||||
struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
|
||||
|
||||
#define tcp_ack(pcb) if((pcb)->flags & TF_ACK_DELAY) { \
|
||||
(pcb)->flags &= ~TF_ACK_DELAY; \
|
||||
(pcb)->flags |= TF_ACK_NOW; \
|
||||
tcp_output(pcb); \
|
||||
} else { \
|
||||
(pcb)->flags |= TF_ACK_DELAY; \
|
||||
}
|
||||
#define tcp_ack(pcb) \
|
||||
do { \
|
||||
if((pcb)->flags & TF_ACK_DELAY) { \
|
||||
(pcb)->flags &= ~TF_ACK_DELAY; \
|
||||
(pcb)->flags |= TF_ACK_NOW; \
|
||||
tcp_output(pcb); \
|
||||
} \
|
||||
else { \
|
||||
(pcb)->flags |= TF_ACK_DELAY; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \
|
||||
tcp_output(pcb)
|
||||
#define tcp_ack_now(pcb) \
|
||||
do { \
|
||||
(pcb)->flags |= TF_ACK_NOW; \
|
||||
tcp_output(pcb); \
|
||||
} while (0)
|
||||
|
||||
err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags);
|
||||
err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,
|
||||
u8_t flags, u8_t apiflags,
|
||||
u8_t *optdata, u8_t optlen);
|
||||
u8_t flags, u8_t apiflags, u8_t optflags);
|
||||
|
||||
void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
|
||||
|
||||
@@ -537,9 +588,14 @@ void tcp_zero_window_probe(struct tcp_pcb *pcb);
|
||||
u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr);
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
#if LWIP_CALLBACK_API
|
||||
err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
|
||||
extern struct tcp_pcb *tcp_input_pcb;
|
||||
extern u32_t tcp_ticks;
|
||||
|
||||
const char* tcp_debug_state_str(enum tcp_state s);
|
||||
#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
|
||||
void tcp_debug_print(struct tcp_hdr *tcphdr);
|
||||
void tcp_debug_print_flags(u8_t flags);
|
||||
@@ -603,7 +659,7 @@ extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
|
||||
if(*pcbs == npcb) { \
|
||||
*pcbs = (*pcbs)->next; \
|
||||
} else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
|
||||
if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \
|
||||
if(tcp_tmp_pcb->next == npcb) { \
|
||||
tcp_tmp_pcb->next = npcb->next; \
|
||||
break; \
|
||||
} \
|
||||
@@ -614,22 +670,32 @@ extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
|
||||
} while(0)
|
||||
|
||||
#else /* LWIP_DEBUG */
|
||||
#define TCP_REG(pcbs, npcb) do { \
|
||||
npcb->next = *pcbs; \
|
||||
*(pcbs) = npcb; \
|
||||
tcp_timer_needed(); \
|
||||
} while(0)
|
||||
#define TCP_RMV(pcbs, npcb) do { \
|
||||
if(*(pcbs) == npcb) { \
|
||||
(*(pcbs)) = (*pcbs)->next; \
|
||||
} else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
|
||||
if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \
|
||||
tcp_tmp_pcb->next = npcb->next; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
npcb->next = NULL; \
|
||||
} while(0)
|
||||
|
||||
#define TCP_REG(pcbs, npcb) \
|
||||
do { \
|
||||
npcb->next = *pcbs; \
|
||||
*(pcbs) = npcb; \
|
||||
tcp_timer_needed(); \
|
||||
} while (0)
|
||||
|
||||
#define TCP_RMV(pcbs, npcb) \
|
||||
do { \
|
||||
if(*(pcbs) == npcb) { \
|
||||
(*(pcbs)) = (*pcbs)->next; \
|
||||
} \
|
||||
else { \
|
||||
for(tcp_tmp_pcb = *pcbs; \
|
||||
tcp_tmp_pcb != NULL; \
|
||||
tcp_tmp_pcb = tcp_tmp_pcb->next) { \
|
||||
if(tcp_tmp_pcb->next == npcb) { \
|
||||
tcp_tmp_pcb->next = npcb->next; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
npcb->next = NULL; \
|
||||
} while(0)
|
||||
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -83,10 +84,14 @@ err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block);
|
||||
#define tcpip_callback(f,ctx) tcpip_callback_with_block(f,ctx,1)
|
||||
#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1)
|
||||
|
||||
/* free pbufs or heap memory from another context without blocking */
|
||||
err_t pbuf_free_callback(struct pbuf *p);
|
||||
err_t mem_free_callback(void *m);
|
||||
|
||||
err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
|
||||
#define tcpip_untimeout(h, arg) tcpip_timeout(0xffffffff, h, arg)
|
||||
err_t tcpip_untimeout(sys_timeout_handler h, void *arg);
|
||||
|
||||
enum tcpip_msg_type {
|
||||
#if LWIP_NETCONN
|
||||
@@ -97,7 +102,8 @@ enum tcpip_msg_type {
|
||||
TCPIP_MSG_NETIFAPI,
|
||||
#endif /* LWIP_NETIF_API */
|
||||
TCPIP_MSG_CALLBACK,
|
||||
TCPIP_MSG_TIMEOUT
|
||||
TCPIP_MSG_TIMEOUT,
|
||||
TCPIP_MSG_UNTIMEOUT
|
||||
};
|
||||
|
||||
struct tcpip_msg {
|
||||
|
||||
@@ -94,6 +94,9 @@ struct udp_pcb {
|
||||
* The callback is responsible for freeing the pbuf
|
||||
* if it's not used any more.
|
||||
*
|
||||
* ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf
|
||||
* makes 'addr' invalid, too.
|
||||
*
|
||||
* @param arg user supplied argument (udp_pcb.recv_arg)
|
||||
* @param pcb the udp_pcb which received data
|
||||
* @param p the packet buffer that was received
|
||||
|
||||
@@ -85,13 +85,34 @@ PACK_STRUCT_END
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
|
||||
|
||||
#if ETHARP_SUPPORT_VLAN
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct eth_vlan_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t tpid);
|
||||
PACK_STRUCT_FIELD(u16_t prio_vid);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define SIZEOF_VLAN_HDR 4
|
||||
#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF)
|
||||
|
||||
#endif /* ETHARP_SUPPORT_VLAN */
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
/** the ARP message */
|
||||
struct etharp_hdr {
|
||||
PACK_STRUCT_FIELD(struct eth_hdr ethhdr);
|
||||
PACK_STRUCT_FIELD(u16_t hwtype);
|
||||
PACK_STRUCT_FIELD(u16_t proto);
|
||||
PACK_STRUCT_FIELD(u16_t _hwlen_protolen);
|
||||
@@ -106,24 +127,15 @@ PACK_STRUCT_END
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ethip_hdr {
|
||||
PACK_STRUCT_FIELD(struct eth_hdr eth);
|
||||
PACK_STRUCT_FIELD(struct ip_hdr ip);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
#define SIZEOF_ETHARP_HDR 28
|
||||
#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR)
|
||||
|
||||
/** 5 seconds period */
|
||||
#define ARP_TMR_INTERVAL 5000
|
||||
|
||||
#define ETHTYPE_ARP 0x0806
|
||||
#define ETHTYPE_IP 0x0800
|
||||
#define ETHTYPE_VLAN 0x8100
|
||||
#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */
|
||||
#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */
|
||||
|
||||
@@ -151,6 +163,11 @@ void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
|
||||
err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr);
|
||||
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);
|
||||
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);
|
||||
/** For Ethernet network interfaces, we might want to send "gratuitous ARP";
|
||||
* this is an ARP packet sent by a node in order to spontaneously cause other
|
||||
* nodes to update an entry in their ARP cache.
|
||||
* From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
|
||||
#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
|
||||
|
||||
err_t ethernet_input(struct pbuf *p, struct netif *netif);
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#ifndef __NETIF_LOOPIF_H__
|
||||
#define __NETIF_LOOPIF_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/err.h"
|
||||
|
||||
@@ -39,9 +40,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !LWIP_LOOPIF_MULTITHREADING
|
||||
void loopif_poll(struct netif *netif);
|
||||
#endif
|
||||
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
#define loopif_poll netif_poll
|
||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
|
||||
err_t loopif_init(struct netif *netif);
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
err_t slipif_init(struct netif * netif);
|
||||
void slipif_poll(struct netif *netif);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -23,3 +23,7 @@ slipif.c
|
||||
protocol. It requires a sio (serial I/O) module to work.
|
||||
|
||||
ppp/ Point-to-Point Protocol stack
|
||||
The PPP stack has been ported from ucip (http://ucip.sourceforge.net).
|
||||
It matches quite well to pppd 2.3.1 (http://ppp.samba.org), although
|
||||
compared to that, it has some modifications for embedded systems and
|
||||
the source code has been reordered a bit.
|
||||
@@ -8,8 +8,7 @@
|
||||
*
|
||||
* This implementation complies with RFC 826 (Ethernet ARP). It supports
|
||||
* Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
|
||||
* if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon
|
||||
* address change.
|
||||
* if an interface calls etharp_gratuitous(our_netif) upon address change.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -353,7 +352,7 @@ find_entry(struct ip_addr *ipaddr, u8_t flags)
|
||||
* 1) empty entry
|
||||
* 2) oldest stable entry
|
||||
* 3) oldest pending entry without queued packets
|
||||
* 4) oldest pending entry without queued packets
|
||||
* 4) oldest pending entry with queued packets
|
||||
*
|
||||
* { ETHARP_TRY_HARD is set at this point }
|
||||
*/
|
||||
@@ -469,7 +468,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
||||
{
|
||||
s8_t i;
|
||||
u8_t k;
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 3, ("update_arp_entry()\n"));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry()\n"));
|
||||
LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
|
||||
ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),
|
||||
@@ -580,13 +579,21 @@ etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,
|
||||
void
|
||||
etharp_ip_input(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
struct ethip_hdr *hdr;
|
||||
struct eth_hdr *ethhdr;
|
||||
struct ip_hdr *iphdr;
|
||||
LWIP_ERROR("netif != NULL", (netif != NULL), return;);
|
||||
/* Only insert an entry if the source IP address of the
|
||||
incoming IP packet comes from a host on the local network. */
|
||||
hdr = p->payload;
|
||||
ethhdr = p->payload;
|
||||
iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
|
||||
#if ETHARP_SUPPORT_VLAN
|
||||
if (ethhdr->type == ETHTYPE_VLAN) {
|
||||
iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
|
||||
}
|
||||
#endif /* ETHARP_SUPPORT_VLAN */
|
||||
|
||||
/* source is not on the local network? */
|
||||
if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
|
||||
if (!ip_addr_netcmp(&(iphdr->src), &(netif->ip_addr), &(netif->netmask))) {
|
||||
/* do nothing */
|
||||
return;
|
||||
}
|
||||
@@ -595,7 +602,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
|
||||
/* update ARP table */
|
||||
/* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
|
||||
* back soon (for example, if the destination IP address is ours. */
|
||||
update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);
|
||||
update_arp_entry(netif, &(iphdr->src), &(ethhdr->src), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -618,6 +625,7 @@ void
|
||||
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
{
|
||||
struct etharp_hdr *hdr;
|
||||
struct eth_hdr *ethhdr;
|
||||
/* these are aligned properly, whereas the ARP header fields might not be */
|
||||
struct ip_addr sipaddr, dipaddr;
|
||||
u8_t i;
|
||||
@@ -630,24 +638,32 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
|
||||
/* drop short ARP packets: we have to check for p->len instead of p->tot_len here
|
||||
since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
|
||||
if (p->len < sizeof(struct etharp_hdr)) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)sizeof(struct etharp_hdr)));
|
||||
if (p->len < SIZEOF_ETHARP_PACKET) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
|
||||
("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len,
|
||||
(s16_t)SIZEOF_ETHARP_PACKET));
|
||||
ETHARP_STATS_INC(etharp.lenerr);
|
||||
ETHARP_STATS_INC(etharp.drop);
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
hdr = p->payload;
|
||||
ethhdr = p->payload;
|
||||
hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
|
||||
#if ETHARP_SUPPORT_VLAN
|
||||
if (ethhdr->type == ETHTYPE_VLAN) {
|
||||
hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
|
||||
}
|
||||
#endif /* ETHARP_SUPPORT_VLAN */
|
||||
|
||||
/* RFC 826 "Packet Reception": */
|
||||
if ((hdr->hwtype != htons(HWTYPE_ETHERNET)) ||
|
||||
(hdr->_hwlen_protolen != htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr))) ||
|
||||
(hdr->proto != htons(ETHTYPE_IP)) ||
|
||||
(hdr->ethhdr.type != htons(ETHTYPE_ARP))) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1,
|
||||
(ethhdr->type != htons(ETHTYPE_ARP))) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
|
||||
("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
|
||||
hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), hdr->ethhdr.type));
|
||||
hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), ethhdr->type));
|
||||
ETHARP_STATS_INC(etharp.proterr);
|
||||
ETHARP_STATS_INC(etharp.drop);
|
||||
pbuf_free(p);
|
||||
@@ -705,7 +721,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
hdr->opcode = htons(ARP_REPLY);
|
||||
|
||||
hdr->dipaddr = hdr->sipaddr;
|
||||
hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
|
||||
SMEMCPY(&hdr->sipaddr, &netif->ip_addr, sizeof(hdr->sipaddr));
|
||||
|
||||
LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
|
||||
(netif->hwaddr_len == ETHARP_HWADDR_LEN));
|
||||
@@ -720,12 +736,12 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
i--;
|
||||
hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
|
||||
#if LWIP_AUTOIP
|
||||
hdr->ethhdr.dest.addr[i] = ethdst_hwaddr[i];
|
||||
ethhdr->dest.addr[i] = ethdst_hwaddr[i];
|
||||
#else /* LWIP_AUTOIP */
|
||||
hdr->ethhdr.dest.addr[i] = hdr->shwaddr.addr[i];
|
||||
ethhdr->dest.addr[i] = hdr->shwaddr.addr[i];
|
||||
#endif /* LWIP_AUTOIP */
|
||||
hdr->shwaddr.addr[i] = ethaddr->addr[i];
|
||||
hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
|
||||
ethhdr->src.addr[i] = ethaddr->addr[i];
|
||||
}
|
||||
|
||||
/* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header
|
||||
@@ -789,7 +805,8 @@ etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr)
|
||||
/* make room for Ethernet header - should not fail */
|
||||
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
|
||||
/* bail out */
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("etharp_output: could not allocate room for header.\n"));
|
||||
LINK_STATS_INC(link.lenerr);
|
||||
return ERR_BUF;
|
||||
}
|
||||
@@ -1035,23 +1052,26 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
||||
struct pbuf *p;
|
||||
err_t result = ERR_OK;
|
||||
u8_t k; /* ARP entry index */
|
||||
struct eth_hdr *ethhdr;
|
||||
struct etharp_hdr *hdr;
|
||||
#if LWIP_AUTOIP
|
||||
const u8_t * ethdst_hwaddr;
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
/* allocate a pbuf for the outgoing ARP request packet */
|
||||
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
|
||||
p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);
|
||||
/* could allocate a pbuf for an ARP request? */
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n"));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("etharp_raw: could not allocate pbuf for ARP request.\n"));
|
||||
ETHARP_STATS_INC(etharp.memerr);
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",
|
||||
(p->len >= sizeof(struct etharp_hdr)));
|
||||
(p->len >= SIZEOF_ETHARP_PACKET));
|
||||
|
||||
hdr = p->payload;
|
||||
ethhdr = p->payload;
|
||||
hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));
|
||||
hdr->opcode = htons(opcode);
|
||||
|
||||
@@ -1071,11 +1091,11 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
||||
hdr->dhwaddr.addr[k] = hwdst_addr->addr[k];
|
||||
/* Write the Ethernet MAC-Addresses */
|
||||
#if LWIP_AUTOIP
|
||||
hdr->ethhdr.dest.addr[k] = ethdst_hwaddr[k];
|
||||
ethhdr->dest.addr[k] = ethdst_hwaddr[k];
|
||||
#else /* LWIP_AUTOIP */
|
||||
hdr->ethhdr.dest.addr[k] = ethdst_addr->addr[k];
|
||||
ethhdr->dest.addr[k] = ethdst_addr->addr[k];
|
||||
#endif /* LWIP_AUTOIP */
|
||||
hdr->ethhdr.src.addr[k] = ethsrc_addr->addr[k];
|
||||
ethhdr->src.addr[k] = ethsrc_addr->addr[k];
|
||||
}
|
||||
hdr->sipaddr = *(struct ip_addr2 *)ipsrc_addr;
|
||||
hdr->dipaddr = *(struct ip_addr2 *)ipdst_addr;
|
||||
@@ -1085,7 +1105,7 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
||||
/* set hwlen and protolen together */
|
||||
hdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr));
|
||||
|
||||
hdr->ethhdr.type = htons(ETHTYPE_ARP);
|
||||
ethhdr->type = htons(ETHTYPE_ARP);
|
||||
/* send ARP query */
|
||||
result = netif->linkoutput(netif, p);
|
||||
ETHARP_STATS_INC(etharp.xmit);
|
||||
@@ -1127,11 +1147,34 @@ err_t
|
||||
ethernet_input(struct pbuf *p, struct netif *netif)
|
||||
{
|
||||
struct eth_hdr* ethhdr;
|
||||
u16_t type;
|
||||
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = p->payload;
|
||||
|
||||
switch (htons(ethhdr->type)) {
|
||||
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)));
|
||||
|
||||
type = htons(ethhdr->type);
|
||||
#if ETHARP_SUPPORT_VLAN
|
||||
if (type == ETHTYPE_VLAN) {
|
||||
struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
|
||||
#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */
|
||||
if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
|
||||
/* silently ignore this packet: not for our VLAN */
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* ETHARP_VLAN_CHECK */
|
||||
type = htons(vlan->tpid);
|
||||
}
|
||||
#endif /* ETHARP_SUPPORT_VLAN */
|
||||
|
||||
switch (type) {
|
||||
/* IP packet? */
|
||||
case ETHTYPE_IP:
|
||||
#if ETHARP_TRUST_IP_MAC
|
||||
@@ -1139,7 +1182,7 @@ ethernet_input(struct pbuf *p, struct netif *netif)
|
||||
etharp_ip_input(netif, p);
|
||||
#endif /* ETHARP_TRUST_IP_MAC */
|
||||
/* skip Ethernet header */
|
||||
if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) {
|
||||
if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) {
|
||||
LWIP_ASSERT("Can't move over header in packet", 0);
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
@@ -1165,6 +1208,8 @@ ethernet_input(struct pbuf *p, struct netif *netif)
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
|
||||
default:
|
||||
ETHARP_STATS_INC(etharp.proterr);
|
||||
ETHARP_STATS_INC(etharp.drop);
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
break;
|
||||
|
||||
@@ -187,7 +187,12 @@ low_level_input(struct netif *netif)
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
/* Read enough bytes to fill this pbuf in the chain. The
|
||||
* available data in the pbuf is given by the q->len
|
||||
* variable. */
|
||||
* variable.
|
||||
* This does not necessarily have to be a memcpy, you can also preallocate
|
||||
* pbufs for a DMA-enabled MAC and after receiving truncate it to the
|
||||
* actually received size. In this case, ensure the tot_len member of the
|
||||
* pbuf is the sum of the chained pbuf len members.
|
||||
*/
|
||||
read data into(q->payload, q->len);
|
||||
}
|
||||
acknowledge that packet has been read();
|
||||
@@ -290,7 +295,7 @@ ethernetif_init(struct netif *netif)
|
||||
* The last argument should be replaced with your link speed, in units
|
||||
* of bits per second.
|
||||
*/
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, ???);
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
|
||||
|
||||
netif->state = ethernetif;
|
||||
netif->name[0] = IFNAME0;
|
||||
|
||||
@@ -40,149 +40,8 @@
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
|
||||
#include "netif/loopif.h"
|
||||
#include "lwip/pbuf.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
|
||||
*
|
||||
@@ -193,16 +52,6 @@ loopif_output(struct netif *netif, struct pbuf *p,
|
||||
err_t
|
||||
loopif_init(struct netif *netif)
|
||||
{
|
||||
#if !LWIP_LOOPIF_MULTITHREADING
|
||||
struct loopif_private *priv;
|
||||
|
||||
priv = (struct loopif_private*)mem_malloc(sizeof(struct loopif_private));
|
||||
if(priv == NULL)
|
||||
return ERR_MEM;
|
||||
priv->first = priv->last = NULL;
|
||||
netif->state = priv;
|
||||
#endif /* LWIP_LOOPIF_MULTITHREADING */
|
||||
|
||||
/* initialize the snmp variables and counters inside the struct netif
|
||||
* ifSpeed: no assumption can be made!
|
||||
*/
|
||||
@@ -210,7 +59,7 @@ loopif_init(struct netif *netif)
|
||||
|
||||
netif->name[0] = 'l';
|
||||
netif->name[1] = 'o';
|
||||
netif->output = loopif_output;
|
||||
netif->output = netif_loop_output;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
#include "cbcp.h"
|
||||
#endif /* CBCP_SUPPORT */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*************************/
|
||||
/*** LOCAL DEFINITIONS ***/
|
||||
/*************************/
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
#include "chap.h"
|
||||
#include "chpms.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*************************/
|
||||
/*** LOCAL DEFINITIONS ***/
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
|
||||
/*** The original PPPD code is written in a way to require either the UNIX DES
|
||||
encryption functions encrypt(3) and setkey(3) or the DES library libdes.
|
||||
Since both is not included in lwIP, MSCHAP currently does not work! */
|
||||
/*****************************************************************************
|
||||
* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
|
||||
*
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
|
||||
#include "fsm.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*************************/
|
||||
/*** LOCAL DEFINITIONS ***/
|
||||
@@ -551,7 +553,7 @@ fsm_timeout(void *arg)
|
||||
break;
|
||||
|
||||
default:
|
||||
FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d (%s)!\n",
|
||||
FSMDEBUG((LOG_INFO, "%s: UNHANDLED timeout event in state %d (%s)!\n",
|
||||
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,20 +183,7 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
|
||||
/*** LOCAL FUNCTION DEFINITIONS ***/
|
||||
/**********************************/
|
||||
|
||||
/*
|
||||
* Non-standard inet_ntoa left here for compat with original ppp
|
||||
* sources. Assumes u32_t instead of struct in_addr.
|
||||
*/
|
||||
|
||||
char *
|
||||
_inet_ntoa(u32_t n)
|
||||
{
|
||||
struct in_addr ia;
|
||||
ia.s_addr = n;
|
||||
return inet_ntoa(ia);
|
||||
}
|
||||
|
||||
#define inet_ntoa _inet_ntoa
|
||||
#define inet_ntoa(addr) ip_ntoa(((struct ip_addr*)&(addr)))
|
||||
|
||||
/*
|
||||
* ipcp_init - Initialize IPCP.
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
** Message-digest routines: **
|
||||
|
||||
@@ -61,6 +61,8 @@
|
||||
#include "auth.h"
|
||||
#include "pap.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/***********************************/
|
||||
/*** LOCAL FUNCTION DECLARATIONS ***/
|
||||
/***********************************/
|
||||
@@ -490,6 +492,7 @@ upap_rauthack(upap_state *u, u_char *inp, int id, int len)
|
||||
msg = (char *) inp;
|
||||
PRINTMSG(msg, msglen);
|
||||
|
||||
UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
|
||||
u->us_clientstate = UPAPCS_OPEN;
|
||||
|
||||
auth_withpeer_success(u->us_unit, PPP_PAP);
|
||||
@@ -518,16 +521,18 @@ upap_rauthnak(upap_state *u, u_char *inp, int id, int len)
|
||||
*/
|
||||
if (len < sizeof (u_char)) {
|
||||
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
|
||||
return;
|
||||
} else {
|
||||
GETCHAR(msglen, inp);
|
||||
if(msglen > 0) {
|
||||
len -= sizeof (u_char);
|
||||
if (len < msglen) {
|
||||
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
|
||||
return;
|
||||
}
|
||||
msg = (char *) inp;
|
||||
PRINTMSG(msg, msglen);
|
||||
}
|
||||
}
|
||||
GETCHAR(msglen, inp);
|
||||
len -= sizeof (u_char);
|
||||
if (len < msglen) {
|
||||
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
|
||||
return;
|
||||
}
|
||||
msg = (char *) inp;
|
||||
PRINTMSG(msg, msglen);
|
||||
|
||||
u->us_clientstate = UPAPCS_BADAUTH;
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ typedef struct PPPControl_s {
|
||||
ext_accm outACCM; /* Async-Ctl-Char-Map for output. */
|
||||
#if PPPOS_SUPPORT && VJ_SUPPORT
|
||||
int vjEnabled; /* Flag indicating VJ compression enabled. */
|
||||
struct vjcompress vjComp; /* Van Jabobsen compression header. */
|
||||
struct vjcompress vjComp; /* Van Jacobson compression header. */
|
||||
#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
|
||||
|
||||
struct netif netif;
|
||||
@@ -235,7 +235,7 @@ struct protent *ppp_protocols[] = {
|
||||
* Buffers for outgoing packets. This must be accessed only from the appropriate
|
||||
* PPP task so that it doesn't need to be protected to avoid collisions.
|
||||
*/
|
||||
u_char *outpacket_buf[NUM_PPP];
|
||||
u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
|
||||
|
||||
|
||||
/*****************************/
|
||||
@@ -306,13 +306,11 @@ pppMainWakeup(int pd)
|
||||
void
|
||||
pppLinkTerminated(int pd)
|
||||
{
|
||||
PPPControl *pc = &pppControl[pd];
|
||||
|
||||
PPPDEBUG((LOG_DEBUG, "pppLinkTerminated: unit %d\n", pd));
|
||||
|
||||
#if PPPOE_SUPPORT
|
||||
if(pc->ethif) {
|
||||
pppoe_disconnect(pc->pppoe_sc);
|
||||
if(pppControl[pd].ethif) {
|
||||
pppoe_disconnect(pppControl[pd].pppoe_sc);
|
||||
} else
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
{
|
||||
@@ -325,13 +323,11 @@ pppLinkTerminated(int pd)
|
||||
void
|
||||
pppLinkDown(int pd)
|
||||
{
|
||||
PPPControl *pc = &pppControl[pd];
|
||||
|
||||
PPPDEBUG((LOG_DEBUG, "pppLinkDown: unit %d\n", pd));
|
||||
|
||||
#if PPPOE_SUPPORT
|
||||
if(pc->ethif) {
|
||||
pppoe_disconnect(pc->pppoe_sc);
|
||||
if(pppControl[pd].ethif) {
|
||||
pppoe_disconnect(pppControl[pd].pppoe_sc);
|
||||
} else
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
{
|
||||
@@ -383,7 +379,7 @@ pppHupCB(void *arg)
|
||||
|
||||
struct ppp_settings ppp_settings;
|
||||
|
||||
err_t
|
||||
void
|
||||
pppInit(void)
|
||||
{
|
||||
struct protent *protp;
|
||||
@@ -395,16 +391,11 @@ pppInit(void)
|
||||
|
||||
magicInit();
|
||||
|
||||
subnetMask = htonl(0xffffff00);
|
||||
|
||||
for (i = 0; i < NUM_PPP; i++) {
|
||||
pppControl[i].openFlag = 0;
|
||||
|
||||
subnetMask = htonl(0xffffff00);
|
||||
|
||||
outpacket_buf[i] = (u_char *)mem_malloc(PPP_MRU+PPP_HDRLEN);
|
||||
if(!outpacket_buf[i]) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize to the standard option set.
|
||||
*/
|
||||
@@ -413,17 +404,9 @@ pppInit(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if LINK_STATS
|
||||
/** @todo already done in stats_init (in fact, zeroed at boot). So, remove it? */
|
||||
/* Clear the statistics. */
|
||||
memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));
|
||||
#endif /* LINK_STATS */
|
||||
|
||||
#if PPPOE_SUPPORT
|
||||
pppoe_init();
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -601,7 +584,7 @@ int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const cha
|
||||
pppControl[pd].openFlag = !0;
|
||||
}
|
||||
|
||||
/* Launch a deamon thread. */
|
||||
/* PPP session descriptor found, start PPPoE */
|
||||
if (pd >= 0) {
|
||||
|
||||
pppControl[pd].openFlag = 1;
|
||||
@@ -824,9 +807,9 @@ static err_t
|
||||
pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
|
||||
{
|
||||
int pd = (int)netif->state;
|
||||
u_short protocol = PPP_IP;
|
||||
PPPControl *pc = &pppControl[pd];
|
||||
#if PPPOS_SUPPORT
|
||||
u_short protocol = PPP_IP;
|
||||
u_int fcsOut = PPP_INITFCS;
|
||||
struct pbuf *headMB = NULL, *tailMB = NULL, *p;
|
||||
u_char c;
|
||||
@@ -839,7 +822,7 @@ pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
|
||||
* and the peer will just drop it if it's not accepting it. */
|
||||
if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
|
||||
PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",
|
||||
pd, protocol, pb));
|
||||
pd, PPP_IP, pb));
|
||||
LINK_STATS_INC(link.opterr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
return ERR_ARG;
|
||||
@@ -1056,7 +1039,7 @@ pppWriteOverEthernet(int pd, const u_char *s, int n)
|
||||
|
||||
pc->lastXMit = sys_jiffies();
|
||||
|
||||
SMEMCPY(pb->payload, s, n);
|
||||
MEMCPY(pb->payload, s, n);
|
||||
|
||||
if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
|
||||
LINK_STATS_INC(link.err);
|
||||
@@ -1294,7 +1277,7 @@ GetMask(u32_t addr)
|
||||
* sifvjcomp - config tcp header compression
|
||||
*/
|
||||
int
|
||||
sifvjcomp( int pd, int vjcomp, int cidcomp, int maxcid)
|
||||
sifvjcomp(int pd, int vjcomp, int cidcomp, int maxcid)
|
||||
{
|
||||
#if PPPOS_SUPPORT && VJ_SUPPORT
|
||||
PPPControl *pc = &pppControl[pd];
|
||||
@@ -1304,6 +1287,11 @@ sifvjcomp( int pd, int vjcomp, int cidcomp, int maxcid)
|
||||
pc->vjComp.maxSlotIndex = maxcid;
|
||||
PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
|
||||
vjcomp, cidcomp, maxcid));
|
||||
#else /* PPPOS_SUPPORT && VJ_SUPPORT */
|
||||
LWIP_UNUSED_ARG(pd);
|
||||
LWIP_UNUSED_ARG(vjcomp);
|
||||
LWIP_UNUSED_ARG(cidcomp);
|
||||
LWIP_UNUSED_ARG(maxcid);
|
||||
#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
|
||||
|
||||
return 0;
|
||||
@@ -1339,10 +1327,6 @@ sifup(int pd)
|
||||
netif_remove(&pc->netif);
|
||||
if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) {
|
||||
netif_set_up(&pc->netif);
|
||||
#if LWIP_DHCP
|
||||
/* ugly workaround for storing a reference to the ppp related info*/
|
||||
pc->netif.dhcp = (struct dhcp *) &pc->addrs;
|
||||
#endif /* LWIP_DHCP */
|
||||
pc->if_up = 1;
|
||||
pc->errCode = PPPERR_NONE;
|
||||
|
||||
@@ -1385,6 +1369,8 @@ sifdown(int pd)
|
||||
PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));
|
||||
} else {
|
||||
pc->if_up = 0;
|
||||
/* make sure the netif status callback is called */
|
||||
netif_set_down(&pc->netif);
|
||||
netif_remove(&pc->netif);
|
||||
PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
|
||||
if(pc->linkStatusCB) {
|
||||
@@ -1541,8 +1527,8 @@ pppMain(void *arg)
|
||||
if(c > 0) {
|
||||
pppInProc(pd, p->payload, c);
|
||||
} else {
|
||||
PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
|
||||
sys_msleep(1); /* give other tasks a chance to run */
|
||||
/* nothing received, give other tasks a chance to run */
|
||||
sys_msleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1662,7 +1648,7 @@ pppInput(void *arg)
|
||||
|
||||
switch(protocol) {
|
||||
case PPP_VJC_COMP: /* VJ compressed TCP */
|
||||
#if VJ_SUPPORT
|
||||
#if PPPOS_SUPPORT && VJ_SUPPORT
|
||||
PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
|
||||
/*
|
||||
* Clip off the VJ header and prepend the rebuilt TCP/IP header and
|
||||
@@ -1674,14 +1660,14 @@ pppInput(void *arg)
|
||||
}
|
||||
/* Something's wrong so drop it. */
|
||||
PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));
|
||||
#else /* VJ_SUPPORT */
|
||||
#else /* PPPOS_SUPPORT && VJ_SUPPORT */
|
||||
/* No handler for this protocol so drop the packet. */
|
||||
PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
|
||||
#endif /* VJ_SUPPORT */
|
||||
#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
|
||||
break;
|
||||
|
||||
case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */
|
||||
#if VJ_SUPPORT
|
||||
#if PPPOS_SUPPORT && VJ_SUPPORT
|
||||
PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
|
||||
/*
|
||||
* Process the TCP/IP header for VJ header compression and then pass
|
||||
@@ -1693,12 +1679,12 @@ pppInput(void *arg)
|
||||
}
|
||||
/* Something's wrong so drop it. */
|
||||
PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));
|
||||
#else /* VJ_SUPPORT */
|
||||
#else /* PPPOS_SUPPORT && VJ_SUPPORT */
|
||||
/* No handler for this protocol so drop the packet. */
|
||||
PPPDEBUG((LOG_INFO,
|
||||
"pppInput[%d]: drop VJ UnComp in %d:.*H\n",
|
||||
pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
|
||||
#endif /* VJ_SUPPORT */
|
||||
#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
|
||||
break;
|
||||
|
||||
case PPP_IP: /* Internet Protocol */
|
||||
|
||||
@@ -333,7 +333,7 @@ struct ppp_addrs {
|
||||
*****************************/
|
||||
|
||||
/* Buffers for outgoing packets. */
|
||||
extern u_char *outpacket_buf[NUM_PPP];
|
||||
extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
|
||||
|
||||
extern struct ppp_settings ppp_settings;
|
||||
|
||||
@@ -345,7 +345,7 @@ extern struct protent *ppp_protocols[]; /* Table of pointers to supported protoc
|
||||
***********************/
|
||||
|
||||
/* Initialize the PPP subsystem. */
|
||||
err_t pppInit(void);
|
||||
void pppInit(void);
|
||||
|
||||
/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
|
||||
* RFC 1994 says:
|
||||
|
||||
@@ -398,7 +398,7 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)
|
||||
#endif
|
||||
struct pppoehdr *ph;
|
||||
struct pppoetag pt;
|
||||
int off = 0, err, errortag;
|
||||
int off, err, errortag;
|
||||
struct eth_hdr *ethhdr;
|
||||
|
||||
pb = pppSingleBuf(pb);
|
||||
@@ -410,7 +410,7 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)
|
||||
goto done;
|
||||
}
|
||||
ethhdr = (struct eth_hdr *)pb->payload;
|
||||
off += sizeof(*ethhdr);
|
||||
off = sizeof(*ethhdr);
|
||||
|
||||
ac_cookie = NULL;
|
||||
ac_cookie_len = 0;
|
||||
@@ -419,7 +419,7 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)
|
||||
hunique_len = 0;
|
||||
#endif
|
||||
session = 0;
|
||||
if (pb->len - off <= PPPOE_HEADERLEN) {
|
||||
if (pb->len - off < PPPOE_HEADERLEN) {
|
||||
printf("pppoe: packet too short: %d\n", pb->len);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "ppp.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if MD5_SUPPORT /* this module depends on MD5 */
|
||||
#define RANDPOOLSZ 16 /* Bytes stored in the pool of randomness. */
|
||||
|
||||
@@ -136,7 +136,7 @@ vj_compress_init(struct vjcompress *comp)
|
||||
}
|
||||
|
||||
/*
|
||||
* vj_compress_tcp - Attempt to do Van Jacobsen header compression on a
|
||||
* vj_compress_tcp - Attempt to do Van Jacobson header compression on a
|
||||
* packet. This assumes that nb and comp are not null and that the first
|
||||
* buffer of the chain contains a valid IP header.
|
||||
* Return the VJ type code indicating whether or not the packet was
|
||||
|
||||
@@ -39,11 +39,14 @@
|
||||
|
||||
/*
|
||||
* This is an arch independent SLIP netif. The specific serial hooks must be
|
||||
* provided by another file. They are sio_open, sio_recv and sio_send
|
||||
* provided by another file. They are sio_open, sio_read/sio_tryread and sio_send
|
||||
*/
|
||||
|
||||
#include "netif/slipif.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_HAVE_SLIPIF
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
@@ -51,12 +54,28 @@
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/sio.h"
|
||||
|
||||
#define SLIP_BLOCK 1
|
||||
#define SLIP_DONTBLOCK 0
|
||||
|
||||
#define SLIP_END 0300 /* 0xC0 */
|
||||
#define SLIP_ESC 0333 /* 0xDB */
|
||||
#define SLIP_ESC_END 0334 /* 0xDC */
|
||||
#define SLIP_ESC_ESC 0335 /* 0xDD */
|
||||
|
||||
#define MAX_SIZE 1500
|
||||
#define SLIP_MAX_SIZE 1500
|
||||
|
||||
enum slipif_recv_state {
|
||||
SLIP_RECV_NORMAL,
|
||||
SLIP_RECV_ESCAPE,
|
||||
};
|
||||
|
||||
struct slipif_priv {
|
||||
sio_fd_t sd;
|
||||
/* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
|
||||
struct pbuf *p, *q;
|
||||
enum slipif_recv_state state;
|
||||
u16_t i, recved;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a pbuf doing the necessary SLIP encapsulation
|
||||
@@ -71,6 +90,7 @@
|
||||
err_t
|
||||
slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
{
|
||||
struct slipif_priv *priv;
|
||||
struct pbuf *q;
|
||||
u16_t i;
|
||||
u8_t c;
|
||||
@@ -81,73 +101,101 @@ slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
|
||||
priv = netif->state;
|
||||
|
||||
/* Send pbuf out on the serial I/O device. */
|
||||
sio_send(SLIP_END, netif->state);
|
||||
sio_send(SLIP_END, priv->sd);
|
||||
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
for (i = 0; i < q->len; i++) {
|
||||
c = ((u8_t *)q->payload)[i];
|
||||
switch (c) {
|
||||
case SLIP_END:
|
||||
sio_send(SLIP_ESC, netif->state);
|
||||
sio_send(SLIP_ESC_END, netif->state);
|
||||
sio_send(SLIP_ESC, priv->sd);
|
||||
sio_send(SLIP_ESC_END, priv->sd);
|
||||
break;
|
||||
case SLIP_ESC:
|
||||
sio_send(SLIP_ESC, netif->state);
|
||||
sio_send(SLIP_ESC_ESC, netif->state);
|
||||
sio_send(SLIP_ESC, priv->sd);
|
||||
sio_send(SLIP_ESC_ESC, priv->sd);
|
||||
break;
|
||||
default:
|
||||
sio_send(c, netif->state);
|
||||
sio_send(c, priv->sd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
sio_send(SLIP_END, netif->state);
|
||||
sio_send(SLIP_END, priv->sd);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function for easy use of blockig or non-blocking
|
||||
* sio_read
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data buffer for receiving
|
||||
* @param len maximum length (in bytes) of data to receive
|
||||
* @param block if 1, call sio_read; if 0, call sio_tryread
|
||||
* @return return value of sio_read of sio_tryread
|
||||
*/
|
||||
static u32_t
|
||||
slip_sio_read(sio_fd_t fd, u8_t* data, u32_t len, u8_t block)
|
||||
{
|
||||
if (block) {
|
||||
return sio_read(fd, data, len);
|
||||
} else {
|
||||
return sio_tryread(fd, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the incoming SLIP stream character by character
|
||||
*
|
||||
* Poll the serial layer by calling sio_recv()
|
||||
* Poll the serial layer by calling sio_read() or sio_tryread().
|
||||
*
|
||||
* @param netif the lwip network interface structure for this slipif
|
||||
* @return The IP packet when SLIP_END is received
|
||||
* @param block if 1, block until data is received; if 0, return when all data
|
||||
* from the buffer is received (multiple calls to this function will
|
||||
* return a complete packet, NULL is returned before - used for polling)
|
||||
* @return The IP packet when SLIP_END is received
|
||||
*/
|
||||
static struct pbuf *
|
||||
slipif_input(struct netif *netif)
|
||||
slipif_input(struct netif *netif, u8_t block)
|
||||
{
|
||||
struct slipif_priv *priv;
|
||||
u8_t c;
|
||||
/* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
|
||||
struct pbuf *p, *q;
|
||||
u16_t recved;
|
||||
u16_t i;
|
||||
struct pbuf *t;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||
|
||||
q = p = NULL;
|
||||
recved = i = 0;
|
||||
c = 0;
|
||||
priv = netif->state;
|
||||
|
||||
while (1) {
|
||||
c = sio_recv(netif->state);
|
||||
switch (c) {
|
||||
case SLIP_END:
|
||||
if (recved > 0) {
|
||||
/* Received whole packet. */
|
||||
/* Trim the pbuf to the size of the received packet. */
|
||||
pbuf_realloc(q, recved);
|
||||
|
||||
LINK_STATS_INC(link.recv);
|
||||
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
|
||||
return q;
|
||||
while (slip_sio_read(priv->sd, &c, 1, block) > 0) {
|
||||
switch (priv->state) {
|
||||
case SLIP_RECV_NORMAL:
|
||||
switch (c) {
|
||||
case SLIP_END:
|
||||
if (priv->recved > 0) {
|
||||
/* Received whole packet. */
|
||||
/* Trim the pbuf to the size of the received packet. */
|
||||
pbuf_realloc(priv->q, priv->recved);
|
||||
|
||||
LINK_STATS_INC(link.recv);
|
||||
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
|
||||
t = priv->q;
|
||||
priv->p = priv->q = NULL;
|
||||
priv->i = priv->recved = 0;
|
||||
return t;
|
||||
}
|
||||
continue;
|
||||
case SLIP_ESC:
|
||||
priv->state = SLIP_RECV_ESCAPE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SLIP_ESC:
|
||||
c = sio_recv(netif->state);
|
||||
case SLIP_RECV_ESCAPE:
|
||||
switch (c) {
|
||||
case SLIP_ESC_END:
|
||||
c = SLIP_END;
|
||||
@@ -156,52 +204,52 @@ slipif_input(struct netif *netif)
|
||||
c = SLIP_ESC;
|
||||
break;
|
||||
}
|
||||
priv->state = SLIP_RECV_NORMAL;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
default:
|
||||
/* byte received, packet not yet completely received */
|
||||
if (p == NULL) {
|
||||
/* allocate a new pbuf */
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
|
||||
p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL);
|
||||
/* byte received, packet not yet completely received */
|
||||
if (priv->p == NULL) {
|
||||
/* allocate a new pbuf */
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
|
||||
priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL);
|
||||
|
||||
if (p == NULL) {
|
||||
LINK_STATS_INC(link.drop);
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
|
||||
/* don't process any further since we got no pbuf to receive to */
|
||||
break;
|
||||
}
|
||||
if (priv->p == NULL) {
|
||||
LINK_STATS_INC(link.drop);
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
|
||||
/* don't process any further since we got no pbuf to receive to */
|
||||
break;
|
||||
}
|
||||
|
||||
if (q != NULL) {
|
||||
/* 'chain' the pbuf to the existing chain */
|
||||
pbuf_cat(q, p);
|
||||
if (priv->q != NULL) {
|
||||
/* 'chain' the pbuf to the existing chain */
|
||||
pbuf_cat(priv->q, priv->p);
|
||||
} else {
|
||||
/* p is the first pbuf in the chain */
|
||||
priv->q = priv->p;
|
||||
}
|
||||
}
|
||||
|
||||
/* this automatically drops bytes if > SLIP_MAX_SIZE */
|
||||
if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
|
||||
((u8_t *)priv->p->payload)[priv->i] = c;
|
||||
priv->recved++;
|
||||
priv->i++;
|
||||
if (priv->i >= priv->p->len) {
|
||||
/* on to the next pbuf */
|
||||
priv->i = 0;
|
||||
if (priv->p->next != NULL && priv->p->next->len > 0) {
|
||||
/* p is a chain, on to the next in the chain */
|
||||
priv->p = priv->p->next;
|
||||
} else {
|
||||
/* p is the first pbuf in the chain */
|
||||
q = p;
|
||||
/* p is a single pbuf, set it to NULL so next time a new
|
||||
* pbuf is allocated */
|
||||
priv->p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* this automatically drops bytes if > MAX_SIZE */
|
||||
if ((p != NULL) && (recved <= MAX_SIZE)) {
|
||||
((u8_t *)p->payload)[i] = c;
|
||||
recved++;
|
||||
i++;
|
||||
if (i >= p->len) {
|
||||
/* on to the next pbuf */
|
||||
i = 0;
|
||||
if (p->next != NULL && p->next->len > 0) {
|
||||
/* p is a chain, on to the next in the chain */
|
||||
p = p->next;
|
||||
} else {
|
||||
/* p is a single pbuf, set it to NULL so next time a new
|
||||
* pbuf is allocated */
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -214,13 +262,13 @@ slipif_input(struct netif *netif)
|
||||
* @param nf the lwip network interface structure for this slipif
|
||||
*/
|
||||
static void
|
||||
slipif_loop(void *nf)
|
||||
slipif_loop_thread(void *nf)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct netif *netif = (struct netif *)nf;
|
||||
|
||||
while (1) {
|
||||
p = slipif_input(netif);
|
||||
p = slipif_input(netif, SLIP_BLOCK);
|
||||
if (p != NULL) {
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
@@ -239,6 +287,7 @@ slipif_loop(void *nf)
|
||||
*
|
||||
* @param netif the lwip network interface structure for this slipif
|
||||
* @return ERR_OK if serial line could be opened,
|
||||
* ERR_MEM if no memory could be allocated,
|
||||
* ERR_IF is serial line couldn't be opened
|
||||
*
|
||||
* @note netif->num must contain the number of the serial port to open
|
||||
@@ -247,22 +296,39 @@ slipif_loop(void *nf)
|
||||
err_t
|
||||
slipif_init(struct netif *netif)
|
||||
{
|
||||
struct slipif_priv *priv;
|
||||
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));
|
||||
|
||||
/* Allocate private data */
|
||||
priv = mem_malloc(sizeof(struct slipif_priv));
|
||||
if (!priv) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
netif->name[0] = 's';
|
||||
netif->name[1] = 'l';
|
||||
netif->output = slipif_output;
|
||||
netif->mtu = MAX_SIZE;
|
||||
netif->flags = NETIF_FLAG_POINTTOPOINT;
|
||||
netif->mtu = SLIP_MAX_SIZE;
|
||||
netif->flags |= NETIF_FLAG_POINTTOPOINT;
|
||||
|
||||
/* Try to open the serial port (netif->num contains the port number). */
|
||||
netif->state = sio_open(netif->num);
|
||||
if (!netif->state) {
|
||||
priv->sd = sio_open(netif->num);
|
||||
if (!priv->sd) {
|
||||
/* Opening the serial port failed. */
|
||||
mem_free(priv);
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
/* Initialize private data */
|
||||
priv->p = NULL;
|
||||
priv->q = NULL;
|
||||
priv->state = SLIP_RECV_NORMAL;
|
||||
priv->i = 0;
|
||||
priv->recved = 0;
|
||||
|
||||
netif->state = priv;
|
||||
|
||||
/* initialize the snmp variables and counters inside the struct netif
|
||||
* ifSpeed: no assumption can be made without knowing more about the
|
||||
* serial line!
|
||||
@@ -270,6 +336,32 @@ slipif_init(struct netif *netif)
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0);
|
||||
|
||||
/* Create a thread to poll the serial line. */
|
||||
sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
|
||||
sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
|
||||
SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls the serial device and feeds the IP layer with incoming packets.
|
||||
*
|
||||
* @param netif The lwip network interface structure for this slipif
|
||||
*/
|
||||
void
|
||||
slipif_poll(struct netif *netif)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct slipif_priv *priv;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||
|
||||
priv = netif->state;
|
||||
|
||||
while ((p = slipif_input(netif, SLIP_DONTBLOCK)) != NULL) {
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_HAVE_SLIPIF */
|
||||
|
||||
37
test/unit/lwip_check.h
Normal file
37
test/unit/lwip_check.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef __LWIP_CHECK_H__
|
||||
#define __LWIP_CHECK_H__
|
||||
|
||||
/* Common header file for lwIP unit tests using the check framework */
|
||||
|
||||
#include <config.h>
|
||||
#include <check.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FAIL_RET() do { fail(); return; } while(0)
|
||||
#define EXPECT(x) fail_unless(x)
|
||||
#define EXPECT_RET(x) do { fail_unless(x); if(!(x)) { return; }} while(0)
|
||||
#define EXPECT_RETX(x, y) do { fail_unless(x); if(!(x)) { return y; }} while(0)
|
||||
#define EXPECT_RETNULL(x) EXPECT_RETX(x, NULL)
|
||||
|
||||
/** typedef for a function returning a test suite */
|
||||
typedef Suite* (suite_getter_fn)(void);
|
||||
|
||||
/** Create a test suite */
|
||||
static Suite* create_suite(const char* name, TFun *tests, size_t num_tests, SFun setup, SFun teardown)
|
||||
{
|
||||
size_t i;
|
||||
Suite *s = suite_create(name);
|
||||
|
||||
for(i = 0; i < num_tests; i++) {
|
||||
// Core test case
|
||||
TCase *tc_core = tcase_create("Core");
|
||||
if ((setup != NULL) || (teardown != NULL)) {
|
||||
tcase_add_checked_fixture(tc_core, setup, teardown);
|
||||
}
|
||||
tcase_add_test(tc_core, tests[i]);
|
||||
suite_add_tcase(s, tc_core);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif /* __LWIP_CHECK_H__ */
|
||||
42
test/unit/lwip_unittests.c
Normal file
42
test/unit/lwip_unittests.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "lwip_check.h"
|
||||
|
||||
#include "udp/test_udp.h"
|
||||
#include "tcp/test_tcp.h"
|
||||
#include "tcp/test_tcp_oos.h"
|
||||
|
||||
#include "lwip/init.h"
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int number_failed;
|
||||
SRunner *sr;
|
||||
size_t i;
|
||||
suite_getter_fn* suites[] = {
|
||||
udp_suite,
|
||||
tcp_suite,
|
||||
tcp_oos_suite,
|
||||
};
|
||||
size_t num = sizeof(suites)/sizeof(void*);
|
||||
LWIP_ASSERT("No suites defined", num > 0);
|
||||
|
||||
lwip_init();
|
||||
|
||||
sr = srunner_create((suites[0])());
|
||||
for(i = 1; i < num; i++) {
|
||||
srunner_add_suite(sr, ((suite_getter_fn*)suites[i])());
|
||||
}
|
||||
|
||||
#ifdef LWIP_UNITTESTS_NOFORK
|
||||
srunner_set_fork_status(sr, CK_NOFORK);
|
||||
#endif
|
||||
#ifdef LWIP_UNITTESTS_FORK
|
||||
srunner_set_fork_status(sr, CK_FORK);
|
||||
#endif
|
||||
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
196
test/unit/tcp/tcp_helper.c
Normal file
196
test/unit/tcp/tcp_helper.c
Normal file
@@ -0,0 +1,196 @@
|
||||
#include "tcp_helper.h"
|
||||
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
|
||||
#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
|
||||
#error "This tests needs TCP- and MEMP-statistics enabled"
|
||||
#endif
|
||||
|
||||
/** Remove all pcbs on the given list. */
|
||||
static void
|
||||
tcp_remove(struct tcp_pcb* pcb_list)
|
||||
{
|
||||
struct tcp_pcb *pcb = pcb_list;
|
||||
struct tcp_pcb *pcb2;
|
||||
|
||||
while(pcb != NULL) {
|
||||
pcb2 = pcb;
|
||||
pcb = pcb->next;
|
||||
tcp_abort(pcb2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */
|
||||
void
|
||||
tcp_remove_all(void)
|
||||
{
|
||||
//tcp_remove(tcp_bound_pcbs);
|
||||
tcp_remove(tcp_listen_pcbs.pcbs);
|
||||
tcp_remove(tcp_active_pcbs);
|
||||
tcp_remove(tcp_tw_pcbs);
|
||||
fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
fail_unless(lwip_stats.memp[MEMP_TCP_PCB_LISTEN].used == 0);
|
||||
fail_unless(lwip_stats.memp[MEMP_TCP_SEG].used == 0);
|
||||
fail_unless(lwip_stats.memp[MEMP_PBUF_POOL].used == 0);
|
||||
}
|
||||
|
||||
/** Create a TCP segment usable for passing to tcp_input
|
||||
* - IP-addresses, ports, seqno and ackno are taken from pcb
|
||||
* - seqno and ackno can be altered with an offset
|
||||
*/
|
||||
struct pbuf*
|
||||
tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset,
|
||||
u32_t ackno_offset, u8_t headerflags)
|
||||
{
|
||||
return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
|
||||
data, data_len, pcb->rcv_nxt + seqno_offset, pcb->snd_nxt + ackno_offset, headerflags);
|
||||
}
|
||||
|
||||
/** Create a TCP segment usable for passing to tcp_input */
|
||||
struct pbuf*
|
||||
tcp_create_segment(struct ip_addr* src_ip, struct ip_addr* dst_ip,
|
||||
u16_t src_port, u16_t dst_port, void* data, size_t data_len,
|
||||
u32_t seqno, u32_t ackno, u8_t headerflags)
|
||||
{
|
||||
struct pbuf* p;
|
||||
struct ip_hdr* iphdr;
|
||||
struct tcp_hdr* tcphdr;
|
||||
u16_t pbuf_len = sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len;
|
||||
|
||||
p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
|
||||
EXPECT_RETNULL(p != NULL);
|
||||
EXPECT_RETNULL(p->next == NULL);
|
||||
|
||||
memset(p->payload, 0, p->len);
|
||||
|
||||
iphdr = p->payload;
|
||||
/* fill IP header */
|
||||
iphdr->dest.addr = dst_ip->addr;
|
||||
iphdr->src.addr = src_ip->addr;
|
||||
IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0);
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
|
||||
pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
|
||||
|
||||
tcphdr = p->payload;
|
||||
tcphdr->src = htons(src_port);
|
||||
tcphdr->dest = htons(dst_port);
|
||||
tcphdr->seqno = htonl(seqno);
|
||||
tcphdr->ackno = htonl(ackno);
|
||||
TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
|
||||
TCPH_FLAGS_SET(tcphdr, headerflags);
|
||||
tcphdr->wnd = htonl(TCP_WND);
|
||||
|
||||
/* copy data */
|
||||
memcpy((char*)tcphdr + sizeof(struct tcp_hdr), data, data_len);
|
||||
|
||||
/* calculate checksum */
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
|
||||
pbuf_header(p, sizeof(struct ip_hdr));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/** Safely bring a tcp_pcb into the requested state */
|
||||
void
|
||||
tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, struct ip_addr* local_ip,
|
||||
struct ip_addr* remote_ip, u16_t local_port, u16_t remote_port)
|
||||
{
|
||||
/* @todo: are these all states? */
|
||||
/* @todo: remove from previous list */
|
||||
pcb->state = state;
|
||||
if (state == ESTABLISHED) {
|
||||
TCP_REG(&tcp_active_pcbs, pcb);
|
||||
pcb->local_ip.addr = local_ip->addr;
|
||||
pcb->local_port = local_port;
|
||||
pcb->remote_ip.addr = remote_ip->addr;
|
||||
pcb->remote_port = remote_port;
|
||||
} else if(state == LISTEN) {
|
||||
TCP_REG(&tcp_listen_pcbs.pcbs, pcb);
|
||||
pcb->local_ip.addr = local_ip->addr;
|
||||
pcb->local_port = local_port;
|
||||
} else if(state == TIME_WAIT) {
|
||||
TCP_REG(&tcp_tw_pcbs, pcb);
|
||||
pcb->local_ip.addr = local_ip->addr;
|
||||
pcb->local_port = local_port;
|
||||
pcb->remote_ip.addr = remote_ip->addr;
|
||||
pcb->remote_port = remote_port;
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_tcp_counters_err(void* arg, err_t err)
|
||||
{
|
||||
struct test_tcp_counters* counters = arg;
|
||||
EXPECT_RET(arg != NULL);
|
||||
counters->err_calls++;
|
||||
counters->last_err = err;
|
||||
}
|
||||
|
||||
static void
|
||||
test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p)
|
||||
{
|
||||
struct pbuf* q;
|
||||
u32_t i, received;
|
||||
if(counters->expected_data == NULL) {
|
||||
/* no data to compare */
|
||||
return;
|
||||
}
|
||||
EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len);
|
||||
received = counters->recved_bytes;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
char *data = q->payload;
|
||||
for(i = 0; i < q->len; i++) {
|
||||
EXPECT_RET(data[i] == counters->expected_data[received]);
|
||||
received++;
|
||||
}
|
||||
}
|
||||
EXPECT(received == counters->recved_bytes + p->tot_len);
|
||||
}
|
||||
|
||||
err_t
|
||||
test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err)
|
||||
{
|
||||
struct test_tcp_counters* counters = arg;
|
||||
EXPECT_RETX(arg != NULL, ERR_OK);
|
||||
EXPECT_RETX(pcb != NULL, ERR_OK);
|
||||
EXPECT_RETX(err == ERR_OK, ERR_OK);
|
||||
|
||||
if (p != NULL) {
|
||||
if (counters->close_calls == 0) {
|
||||
counters->recv_calls++;
|
||||
test_tcp_counters_check_rxdata(counters, p);
|
||||
counters->recved_bytes += p->tot_len;
|
||||
} else {
|
||||
counters->recv_calls_after_close++;
|
||||
counters->recved_bytes_after_close += p->tot_len;
|
||||
}
|
||||
pbuf_free(p);
|
||||
} else {
|
||||
counters->close_calls++;
|
||||
}
|
||||
EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Allocate a pcb and set up the test_tcp_counters_* callbacks */
|
||||
struct tcp_pcb*
|
||||
test_tcp_new_counters_pcb(struct test_tcp_counters* counters)
|
||||
{
|
||||
struct tcp_pcb* pcb = tcp_new();
|
||||
if (pcb != NULL) {
|
||||
/* set up args and callbacks */
|
||||
tcp_arg(pcb, counters);
|
||||
tcp_recv(pcb, test_tcp_counters_recv);
|
||||
tcp_err(pcb, test_tcp_counters_err);
|
||||
}
|
||||
return pcb;
|
||||
}
|
||||
36
test/unit/tcp/tcp_helper.h
Normal file
36
test/unit/tcp/tcp_helper.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef __TCP_HELPER_H__
|
||||
#define __TCP_HELPER_H__
|
||||
|
||||
#include "../lwip_check.h"
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
/* counters used for test_tcp_counters_* callback functions */
|
||||
struct test_tcp_counters {
|
||||
u32_t recv_calls;
|
||||
u32_t recved_bytes;
|
||||
u32_t recv_calls_after_close;
|
||||
u32_t recved_bytes_after_close;
|
||||
u32_t close_calls;
|
||||
u32_t err_calls;
|
||||
err_t last_err;
|
||||
char* expected_data;
|
||||
u32_t expected_data_len;
|
||||
};
|
||||
|
||||
/* Helper functions */
|
||||
void tcp_remove_all(void);
|
||||
|
||||
struct pbuf* tcp_create_segment(struct ip_addr* src_ip, struct ip_addr* dst_ip,
|
||||
u16_t src_port, u16_t dst_port, void* data, size_t data_len,
|
||||
u32_t seqno, u32_t ackno, u8_t headerflags);
|
||||
struct pbuf* tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len,
|
||||
u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags);
|
||||
void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, struct ip_addr* local_ip,
|
||||
struct ip_addr* remote_ip, u16_t local_port, u16_t remote_port);
|
||||
void test_tcp_counters_err(void* arg, err_t err);
|
||||
err_t test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err);
|
||||
|
||||
struct tcp_pcb* test_tcp_new_counters_pcb(struct test_tcp_counters* counters);
|
||||
|
||||
#endif
|
||||
104
test/unit/tcp/test_tcp.c
Normal file
104
test/unit/tcp/test_tcp.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "test_tcp.h"
|
||||
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "tcp_helper.h"
|
||||
|
||||
#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
|
||||
#error "This tests needs TCP- and MEMP-statistics enabled"
|
||||
#endif
|
||||
|
||||
/* Setups/teardown functions */
|
||||
|
||||
static void
|
||||
tcp_setup(void)
|
||||
{
|
||||
tcp_remove_all();
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_teardown(void)
|
||||
{
|
||||
tcp_remove_all();
|
||||
}
|
||||
|
||||
|
||||
/* Test functions */
|
||||
|
||||
/** Call tcp_new() and tcp_abort() and test memp stats */
|
||||
START_TEST(test_tcp_new_abort)
|
||||
{
|
||||
struct tcp_pcb* pcb;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
|
||||
pcb = tcp_new();
|
||||
fail_unless(pcb != NULL);
|
||||
if (pcb != NULL) {
|
||||
fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
|
||||
tcp_abort(pcb);
|
||||
fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/** Create an ESTABLISHED pcb and check if receive callback is called */
|
||||
START_TEST(test_tcp_recv_inseq)
|
||||
{
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf* p;
|
||||
char data[] = {1, 2, 3, 4};
|
||||
struct ip_addr remote_ip, local_ip;
|
||||
u16_t data_len;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
struct netif netif;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
/* initialize local vars */
|
||||
memset(&netif, 0, sizeof(netif));
|
||||
IP4_ADDR(&local_ip, 192, 168, 1, 1);
|
||||
IP4_ADDR(&remote_ip, 192, 168, 1, 2);
|
||||
data_len = sizeof(data);
|
||||
/* initialize counter struct */
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
counters.expected_data_len = data_len;
|
||||
counters.expected_data = data;
|
||||
|
||||
/* create and initialize the pcb */
|
||||
pcb = test_tcp_new_counters_pcb(&counters);
|
||||
EXPECT_RET(pcb != NULL);
|
||||
tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
|
||||
|
||||
/* create a segment */
|
||||
p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);
|
||||
EXPECT(p != NULL);
|
||||
if (p != NULL) {
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
EXPECT(counters.recved_bytes == data_len);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
}
|
||||
|
||||
/* make sure the pcb is freed */
|
||||
EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
|
||||
tcp_abort(pcb);
|
||||
EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
/** Create the suite including all tests for this module */
|
||||
Suite *
|
||||
tcp_suite(void)
|
||||
{
|
||||
TFun tests[] = {
|
||||
test_tcp_new_abort,
|
||||
test_tcp_recv_inseq,
|
||||
};
|
||||
return create_suite("TCP", tests, sizeof(tests)/sizeof(TFun), tcp_setup, tcp_teardown);
|
||||
}
|
||||
8
test/unit/tcp/test_tcp.h
Normal file
8
test/unit/tcp/test_tcp.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef __TEST_TCP_H__
|
||||
#define __TEST_TCP_H__
|
||||
|
||||
#include "../lwip_check.h"
|
||||
|
||||
Suite *tcp_suite(void);
|
||||
|
||||
#endif
|
||||
433
test/unit/tcp/test_tcp_oos.c
Normal file
433
test/unit/tcp/test_tcp_oos.c
Normal file
@@ -0,0 +1,433 @@
|
||||
#include "test_tcp_oos.h"
|
||||
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "tcp_helper.h"
|
||||
|
||||
#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
|
||||
#error "This tests needs TCP- and MEMP-statistics enabled"
|
||||
#endif
|
||||
#if !TCP_QUEUE_OOSEQ
|
||||
#error "This tests needs TCP_QUEUE_OOSEQ enabled"
|
||||
#endif
|
||||
|
||||
/** CHECK_SEGMENTS_ON_OOSEQ:
|
||||
* 1: check count, seqno and len of segments on pcb->ooseq (strict)
|
||||
* 0: only check that bytes are received in correct order (less strict) */
|
||||
#define CHECK_SEGMENTS_ON_OOSEQ 1
|
||||
|
||||
#if CHECK_SEGMENTS_ON_OOSEQ
|
||||
#define EXPECT_OOSEQ(x) EXPECT(x)
|
||||
#else
|
||||
#define EXPECT_OOSEQ(x)
|
||||
#endif
|
||||
|
||||
/* helper functions */
|
||||
|
||||
/** Get the numbers of segments on the ooseq list */
|
||||
static int tcp_oos_count(struct tcp_pcb* pcb)
|
||||
{
|
||||
int num = 0;
|
||||
struct tcp_seg* seg = pcb->ooseq;
|
||||
while(seg != NULL) {
|
||||
num++;
|
||||
seg = seg->next;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/** Get the seqno of a segment (by index) on the ooseq list
|
||||
*
|
||||
* @param pcb the pcb to check for ooseq segments
|
||||
* @param seg_index index of the segment on the ooseq list
|
||||
* @return seqno of the segment
|
||||
*/
|
||||
static u32_t
|
||||
tcp_oos_seg_seqno(struct tcp_pcb* pcb, int seg_index)
|
||||
{
|
||||
int num = 0;
|
||||
struct tcp_seg* seg = pcb->ooseq;
|
||||
|
||||
/* then check the actual segment */
|
||||
while(seg != NULL) {
|
||||
if(num == seg_index) {
|
||||
return seg->tcphdr->seqno;
|
||||
}
|
||||
num++;
|
||||
seg = seg->next;
|
||||
}
|
||||
fail();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Get the tcplen of a segment (by index) on the ooseq list
|
||||
*
|
||||
* @param pcb the pcb to check for ooseq segments
|
||||
* @param seg_index index of the segment on the ooseq list
|
||||
* @return tcplen of the segment
|
||||
*/
|
||||
static int
|
||||
tcp_oos_seg_tcplen(struct tcp_pcb* pcb, int seg_index)
|
||||
{
|
||||
int num = 0;
|
||||
struct tcp_seg* seg = pcb->ooseq;
|
||||
|
||||
/* then check the actual segment */
|
||||
while(seg != NULL) {
|
||||
if(num == seg_index) {
|
||||
return TCP_TCPLEN(seg);
|
||||
}
|
||||
num++;
|
||||
seg = seg->next;
|
||||
}
|
||||
fail();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Setup/teardown functions */
|
||||
|
||||
static void
|
||||
tcp_oos_setup(void)
|
||||
{
|
||||
tcp_remove_all();
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_oos_teardown(void)
|
||||
{
|
||||
tcp_remove_all();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Test functions */
|
||||
|
||||
/** create multiple segments and pass them to tcp_input in a wrong
|
||||
* order to see if ooseq-caching works correctly
|
||||
* FIN is received in out-of-sequence segments only */
|
||||
START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ)
|
||||
{
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf *p_8_9, *p_4_8, *p_4_10, *p_2_14, *p_fin, *pinseq;
|
||||
char data[] = {
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16};
|
||||
struct ip_addr remote_ip, local_ip;
|
||||
u16_t data_len;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
struct netif netif;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
/* initialize local vars */
|
||||
memset(&netif, 0, sizeof(netif));
|
||||
IP4_ADDR(&local_ip, 192, 168, 1, 1);
|
||||
IP4_ADDR(&remote_ip, 192, 168, 1, 2);
|
||||
data_len = sizeof(data);
|
||||
/* initialize counter struct */
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
counters.expected_data_len = data_len;
|
||||
counters.expected_data = data;
|
||||
|
||||
/* create and initialize the pcb */
|
||||
pcb = test_tcp_new_counters_pcb(&counters);
|
||||
EXPECT_RET(pcb != NULL);
|
||||
tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
|
||||
|
||||
/* create segments */
|
||||
/* pinseq is sent as last segment! */
|
||||
pinseq = tcp_create_rx_segment(pcb, &data[0], 4, 0, 0, TCP_ACK);
|
||||
/* p1: 8 bytes before FIN */
|
||||
/* seqno: 8..16 */
|
||||
p_8_9 = tcp_create_rx_segment(pcb, &data[8], 8, 8, 0, TCP_ACK|TCP_FIN);
|
||||
/* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */
|
||||
/* seqno: 4..11 */
|
||||
p_4_8 = tcp_create_rx_segment(pcb, &data[4], 8, 4, 0, TCP_ACK);
|
||||
/* p3: same as p2 but 2 bytes longer */
|
||||
/* seqno: 4..13 */
|
||||
p_4_10 = tcp_create_rx_segment(pcb, &data[4], 10, 4, 0, TCP_ACK);
|
||||
/* p4: 14 bytes before FIN, includes data from p1 and p2, plus partly from pinseq */
|
||||
/* seqno: 2..15 */
|
||||
p_2_14 = tcp_create_rx_segment(pcb, &data[2], 14, 2, 0, TCP_ACK);
|
||||
/* FIN, seqno 16 */
|
||||
p_fin = tcp_create_rx_segment(pcb, NULL, 0,16, 0, TCP_ACK|TCP_FIN);
|
||||
EXPECT(pinseq != NULL);
|
||||
EXPECT(p_8_9 != NULL);
|
||||
EXPECT(p_4_8 != NULL);
|
||||
EXPECT(p_4_10 != NULL);
|
||||
EXPECT(p_2_14 != NULL);
|
||||
EXPECT(p_fin != NULL);
|
||||
if ((pinseq != NULL) && (p_8_9 != NULL) && (p_4_8 != NULL) && (p_4_10 != NULL) && (p_2_14 != NULL) && (p_fin != NULL)) {
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_8_9, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 8);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 9); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_4_8, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_4_10, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* ooseq queue: unchanged */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_2_14, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 6);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_fin, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* ooseq queue: unchanged */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 6);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(pinseq, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 1);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
EXPECT(counters.recved_bytes == data_len);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
EXPECT(pcb->ooseq == NULL);
|
||||
}
|
||||
|
||||
/* make sure the pcb is freed */
|
||||
EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
|
||||
tcp_abort(pcb);
|
||||
EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
/** create multiple segments and pass them to tcp_input in a wrong
|
||||
* order to see if ooseq-caching works correctly
|
||||
* FIN is received IN-SEQUENCE at the end */
|
||||
START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
{
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf *p_1_2, *p_4_8, *p_3_11, *p_2_12, *p_15_1, *p_15_1a, *pinseq, *pinseqFIN;
|
||||
char data[] = {
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16};
|
||||
struct ip_addr remote_ip, local_ip;
|
||||
u16_t data_len;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
struct netif netif;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
/* initialize local vars */
|
||||
memset(&netif, 0, sizeof(netif));
|
||||
IP4_ADDR(&local_ip, 192, 168, 1, 1);
|
||||
IP4_ADDR(&remote_ip, 192, 168, 1, 2);
|
||||
data_len = sizeof(data);
|
||||
/* initialize counter struct */
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
counters.expected_data_len = data_len;
|
||||
counters.expected_data = data;
|
||||
|
||||
/* create and initialize the pcb */
|
||||
pcb = test_tcp_new_counters_pcb(&counters);
|
||||
EXPECT_RET(pcb != NULL);
|
||||
tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
|
||||
|
||||
/* create segments */
|
||||
/* p1: 7 bytes - 2 before FIN */
|
||||
/* seqno: 1..2 */
|
||||
p_1_2 = tcp_create_rx_segment(pcb, &data[1], 2, 1, 0, TCP_ACK);
|
||||
/* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */
|
||||
/* seqno: 4..11 */
|
||||
p_4_8 = tcp_create_rx_segment(pcb, &data[4], 8, 4, 0, TCP_ACK);
|
||||
/* p3: same as p2 but 2 bytes longer and one byte more at the front */
|
||||
/* seqno: 3..13 */
|
||||
p_3_11 = tcp_create_rx_segment(pcb, &data[3], 11, 3, 0, TCP_ACK);
|
||||
/* p4: 13 bytes - 2 before FIN - should be ignored as contained in p1 and p3 */
|
||||
/* seqno: 2..13 */
|
||||
p_2_12 = tcp_create_rx_segment(pcb, &data[2], 12, 2, 0, TCP_ACK);
|
||||
/* pinseq is the first segment that is held back to create ooseq! */
|
||||
/* seqno: 0..3 */
|
||||
pinseq = tcp_create_rx_segment(pcb, &data[0], 4, 0, 0, TCP_ACK);
|
||||
/* p5: last byte before FIN */
|
||||
/* seqno: 15 */
|
||||
p_15_1 = tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK);
|
||||
/* p6: same as p5, should be ignored */
|
||||
p_15_1a= tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK);
|
||||
/* pinseqFIN: last 2 bytes plus FIN */
|
||||
/* only segment containing seqno 14 and FIN */
|
||||
pinseqFIN = tcp_create_rx_segment(pcb, &data[14], 2, 14, 0, TCP_ACK|TCP_FIN);
|
||||
EXPECT(pinseq != NULL);
|
||||
EXPECT(p_1_2 != NULL);
|
||||
EXPECT(p_4_8 != NULL);
|
||||
EXPECT(p_3_11 != NULL);
|
||||
EXPECT(p_2_12 != NULL);
|
||||
EXPECT(p_15_1 != NULL);
|
||||
EXPECT(p_15_1a != NULL);
|
||||
EXPECT(pinseqFIN != NULL);
|
||||
if ((pinseq != NULL) && (p_1_2 != NULL) && (p_4_8 != NULL) && (p_3_11 != NULL) && (p_2_12 != NULL)
|
||||
&& (p_15_1 != NULL) && (p_15_1a != NULL) && (pinseqFIN != NULL)) {
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_1_2, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_4_8, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 4);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 8);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_3_11, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
|
||||
/* p_3_11 has removed p_4_8 from ooseq */
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 3);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 11);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_2_12, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
EXPECT(counters.recved_bytes == 0);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 3);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 2);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 2) == 3);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 2) == 11);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(pinseq, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
EXPECT(counters.recved_bytes == 14);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
EXPECT(pcb->ooseq == NULL);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_15_1, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
EXPECT(counters.recved_bytes == 14);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_15_1a, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
EXPECT(counters.recved_bytes == 14);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
/* check ooseq queue: unchanged */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15);
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(pinseqFIN, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 1);
|
||||
EXPECT(counters.recv_calls == 2);
|
||||
EXPECT(counters.recved_bytes == data_len);
|
||||
EXPECT(counters.err_calls == 0);
|
||||
EXPECT(pcb->ooseq == NULL);
|
||||
}
|
||||
|
||||
/* make sure the pcb is freed */
|
||||
EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
|
||||
tcp_abort(pcb);
|
||||
EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/** Create the suite including all tests for this module */
|
||||
Suite *
|
||||
tcp_oos_suite(void)
|
||||
{
|
||||
TFun tests[] = {
|
||||
test_tcp_recv_ooseq_FIN_OOSEQ,
|
||||
test_tcp_recv_ooseq_FIN_INSEQ,
|
||||
};
|
||||
return create_suite("TCP_OOS", tests, sizeof(tests)/sizeof(TFun), tcp_oos_setup, tcp_oos_teardown);
|
||||
}
|
||||
8
test/unit/tcp/test_tcp_oos.h
Normal file
8
test/unit/tcp/test_tcp_oos.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef __TEST_TCP_OOS_H__
|
||||
#define __TEST_TCP_OOS_H__
|
||||
|
||||
#include "../lwip_check.h"
|
||||
|
||||
Suite *tcp_oos_suite(void);
|
||||
|
||||
#endif
|
||||
80
test/unit/udp/test_udp.c
Normal file
80
test/unit/udp/test_udp.c
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "test_udp.h"
|
||||
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS
|
||||
#error "This tests needs UDP- and MEMP-statistics enabled"
|
||||
#endif
|
||||
|
||||
/* Helper functions */
|
||||
static void
|
||||
udp_remove_all(void)
|
||||
{
|
||||
struct udp_pcb *pcb = udp_pcbs;
|
||||
struct udp_pcb *pcb2;
|
||||
|
||||
while(pcb != NULL) {
|
||||
pcb2 = pcb;
|
||||
pcb = pcb->next;
|
||||
udp_remove(pcb2);
|
||||
}
|
||||
fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0);
|
||||
}
|
||||
|
||||
/* Setups/teardown functions */
|
||||
|
||||
static void
|
||||
udp_setup(void)
|
||||
{
|
||||
udp_remove_all();
|
||||
}
|
||||
|
||||
static void
|
||||
udp_teardown(void)
|
||||
{
|
||||
udp_remove_all();
|
||||
}
|
||||
|
||||
|
||||
/* Test functions */
|
||||
|
||||
START_TEST(test_udp_new_remove)
|
||||
{
|
||||
struct udp_pcb* pcb;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0);
|
||||
|
||||
pcb = udp_new();
|
||||
fail_unless(pcb != NULL);
|
||||
if (pcb != NULL) {
|
||||
fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 1);
|
||||
udp_remove(pcb);
|
||||
fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_udp_remove)
|
||||
{
|
||||
struct udp_pcb* pcb;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
pcb = NULL;
|
||||
//pcb = udp_new();
|
||||
//fail_unless(pcb != NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
/** Create the suite including all tests for this module */
|
||||
Suite *
|
||||
udp_suite(void)
|
||||
{
|
||||
TFun tests[] = {
|
||||
test_udp_new_remove,
|
||||
test_udp_remove
|
||||
};
|
||||
return create_suite("UDP", tests, sizeof(tests)/sizeof(TFun), udp_setup, udp_teardown);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user