Compare commits
308 Commits
STABLE-1_4
...
STABLE-1_4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21a1cf9c80 | ||
|
|
6486c4b1d7 | ||
|
|
5deeaa652a | ||
|
|
3db3811054 | ||
|
|
f8bafcb298 | ||
|
|
eb658da462 | ||
|
|
d8b2bc2788 | ||
|
|
07af231f2b | ||
|
|
8d04da8c6e | ||
|
|
6b37e7ec74 | ||
|
|
8c5edcf564 | ||
|
|
162432fe24 | ||
|
|
13791ccff3 | ||
|
|
aecc5db1be | ||
|
|
d4b169a6de | ||
|
|
61588f9d90 | ||
|
|
63dbd8faed | ||
|
|
4d71f7270b | ||
|
|
593f75fc3b | ||
|
|
bec8cf9f38 | ||
|
|
b163197340 | ||
|
|
be1dccd15e | ||
|
|
83b46811f9 | ||
|
|
1d96195f47 | ||
|
|
5546e46c60 | ||
|
|
4bcb7accb8 | ||
|
|
5f4f07c193 | ||
|
|
f76488a841 | ||
|
|
ef0a44c62d | ||
|
|
d3ee77e7b1 | ||
|
|
a91d8e7395 | ||
|
|
8114627d6a | ||
|
|
3306641708 | ||
|
|
1ebd914cdc | ||
|
|
56207f2505 | ||
|
|
4c8e4fa003 | ||
|
|
c4f3b8818a | ||
|
|
f0b0a3760c | ||
|
|
b361533584 | ||
|
|
40a16289f7 | ||
|
|
ec565c8a19 | ||
|
|
0b382a0d53 | ||
|
|
386a4b7079 | ||
|
|
3585cc1a70 | ||
|
|
4790ebf282 | ||
|
|
4ffbcbf62e | ||
|
|
76e74b6635 | ||
|
|
77f0305ef0 | ||
|
|
935144b3a3 | ||
|
|
a148e33c42 | ||
|
|
d96703bba3 | ||
|
|
9621ccb712 | ||
|
|
21f39082b7 | ||
|
|
0da2bd7f62 | ||
|
|
d8f090a759 | ||
|
|
bd0a664446 | ||
|
|
aafa00f3aa | ||
|
|
dbbd161219 | ||
|
|
26f69123fd | ||
|
|
de4a51e96e | ||
|
|
a0bd27053d | ||
|
|
56cee6b4d8 | ||
|
|
277c7aa518 | ||
|
|
5cfef5bf48 | ||
|
|
ca6fd6015c | ||
|
|
eff10f6458 | ||
|
|
9c3a6b828f | ||
|
|
ba3567ea40 | ||
|
|
513522d7c4 | ||
|
|
5715469d26 | ||
|
|
140eb22cf0 | ||
|
|
ac7c061406 | ||
|
|
45a3f198e8 | ||
|
|
d5eb52868e | ||
|
|
3d48abb98d | ||
|
|
223307fa38 | ||
|
|
c951ab8cee | ||
|
|
81a49a437a | ||
|
|
5460900b14 | ||
|
|
2576a2e565 | ||
|
|
49369cc9ce | ||
|
|
fe66fa6540 | ||
|
|
72e2d16f14 | ||
|
|
378bed8a03 | ||
|
|
9a1eeeea67 | ||
|
|
68f8966f74 | ||
|
|
e6a179ea32 | ||
|
|
adb2aeb10f | ||
|
|
a030b741a5 | ||
|
|
6145af516b | ||
|
|
b1359f1c80 | ||
|
|
7d254a542c | ||
|
|
422e7963de | ||
|
|
e2cdf0d39d | ||
|
|
2fe1af0d05 | ||
|
|
ff85feb22d | ||
|
|
be191148e0 | ||
|
|
626131fb28 | ||
|
|
d154f5c653 | ||
|
|
38f619dd6f | ||
|
|
5b899dd85b | ||
|
|
e7b9849a1a | ||
|
|
b1980b36b8 | ||
|
|
20833fdcc4 | ||
|
|
1ac0c90ec4 | ||
|
|
e931086c3e | ||
|
|
b65af6c572 | ||
|
|
5983c1c5ff | ||
|
|
be412dc042 | ||
|
|
23dfcf7b8c | ||
|
|
e8b80b8ae9 | ||
|
|
a7f7762302 | ||
|
|
859fd87600 | ||
|
|
211b8be07d | ||
|
|
22ee104a04 | ||
|
|
5048a30fc7 | ||
|
|
49e16fcbe9 | ||
|
|
1b79ac1160 | ||
|
|
f9e286ff67 | ||
|
|
d798abcb91 | ||
|
|
5c05d427b0 | ||
|
|
a45b1bad35 | ||
|
|
88bf9b2380 | ||
|
|
717b2dab59 | ||
|
|
8d74559f72 | ||
|
|
59513b41e5 | ||
|
|
fe2003124a | ||
|
|
8b06c61a70 | ||
|
|
ce6fb83ef4 | ||
|
|
85f8a59d7f | ||
|
|
dd8729063c | ||
|
|
14c766e750 | ||
|
|
988815579a | ||
|
|
08b497faea | ||
|
|
96d332e234 | ||
|
|
440f31a4d3 | ||
|
|
cb91705e03 | ||
|
|
d12e742373 | ||
|
|
7aa7c0f481 | ||
|
|
b3ffa16315 | ||
|
|
09d1f55bce | ||
|
|
21333d0f18 | ||
|
|
edcc859b58 | ||
|
|
2ce17a724a | ||
|
|
0fb07ba328 | ||
|
|
78f0307246 | ||
|
|
c5203ab5ea | ||
|
|
3d1a306518 | ||
|
|
2750d61e92 | ||
|
|
43ac5ad70d | ||
|
|
309e936ad9 | ||
|
|
d00fa906cf | ||
|
|
01839b9c14 | ||
|
|
1f396946e5 | ||
|
|
2f58ef781c | ||
|
|
8b9f70ac08 | ||
|
|
e039d4103f | ||
|
|
0333e81616 | ||
|
|
cf1be4ae2d | ||
|
|
dc34636598 | ||
|
|
c74d881d3d | ||
|
|
ab51f3bec0 | ||
|
|
b4c4fae3f5 | ||
|
|
ce98df59f1 | ||
|
|
f29bdd21a7 | ||
|
|
9d31401d47 | ||
|
|
5c68bbe16f | ||
|
|
07c610e068 | ||
|
|
998f109fc8 | ||
|
|
cfb70bccc1 | ||
|
|
7524f9006e | ||
|
|
bcfe3dacc6 | ||
|
|
6c56151d27 | ||
|
|
98274d2145 | ||
|
|
1d125f55ba | ||
|
|
918470affc | ||
|
|
797f26e45b | ||
|
|
e145c1d31c | ||
|
|
bb5d0c5c4a | ||
|
|
0aea1b608a | ||
|
|
a2aa43a426 | ||
|
|
8d5514603e | ||
|
|
b9a2feff5e | ||
|
|
f13615d97a | ||
|
|
d6227aece6 | ||
|
|
6058389974 | ||
|
|
dccad08508 | ||
|
|
112158b056 | ||
|
|
5be300736e | ||
|
|
1b98a64e90 | ||
|
|
4849eb4c54 | ||
|
|
5e8ee7e006 | ||
|
|
e27d34d118 | ||
|
|
a0bf8d5740 | ||
|
|
17a5ba08e4 | ||
|
|
d0877153bf | ||
|
|
55011e5308 | ||
|
|
2697b3c7da | ||
|
|
b9c17dd1f0 | ||
|
|
aea17bfae2 | ||
|
|
0a5755145c | ||
|
|
249e19769b | ||
|
|
f64808c385 | ||
|
|
2e69b54a4f | ||
|
|
cd5d1ceadf | ||
|
|
c55f6b40ec | ||
|
|
bf4ec9be22 | ||
|
|
ed0626afeb | ||
|
|
b5305d5a8c | ||
|
|
17efa04ea6 | ||
|
|
b3f5c8f6b2 | ||
|
|
4507083148 | ||
|
|
f4c0018d7a | ||
|
|
c9e1d6cca8 | ||
|
|
242dc34115 | ||
|
|
41c785d77a | ||
|
|
a745528b40 | ||
|
|
7465be91d0 | ||
|
|
d79c5baa1b | ||
|
|
46af0d38fa | ||
|
|
6323e09a0a | ||
|
|
d94bdb75c8 | ||
|
|
cc3b4dff20 | ||
|
|
78ac382fdf | ||
|
|
860072aaaf | ||
|
|
2694a409c6 | ||
|
|
206b1f4631 | ||
|
|
ef9891e8ff | ||
|
|
bd69890ccd | ||
|
|
fc280c7cd6 | ||
|
|
435ac2a650 | ||
|
|
fb0ad2f9ea | ||
|
|
7385449f33 | ||
|
|
1f4b814d0b | ||
|
|
a93d9c4310 | ||
|
|
1813d11b9d | ||
|
|
09ac68c196 | ||
|
|
c2fd905e32 | ||
|
|
cc84f28d1b | ||
|
|
2bd498524d | ||
|
|
4b934945f3 | ||
|
|
b666ab0673 | ||
|
|
6a4c30fe5d | ||
|
|
4002aef594 | ||
|
|
ba28d36e67 | ||
|
|
4444db2990 | ||
|
|
d0026793bf | ||
|
|
93b5cd5ddd | ||
|
|
12c2d7e4cf | ||
|
|
4eb5acd9e2 | ||
|
|
0f56d838ec | ||
|
|
12a948dacb | ||
|
|
137953605e | ||
|
|
629fad6f5f | ||
|
|
2911c84a69 | ||
|
|
89a1420609 | ||
|
|
e584557afe | ||
|
|
2ed5413e24 | ||
|
|
91532b2d5c | ||
|
|
732cac1c0e | ||
|
|
5b04860b8b | ||
|
|
5a674f419d | ||
|
|
d30246dc05 | ||
|
|
af5a913019 | ||
|
|
604e69c7ae | ||
|
|
d765c9de37 | ||
|
|
98b6e2bcce | ||
|
|
d80be7961c | ||
|
|
2aec3a9789 | ||
|
|
ccd7dbe0e4 | ||
|
|
92fcfd7a6f | ||
|
|
1b2b054139 | ||
|
|
853d1eac96 | ||
|
|
2ef29d6839 | ||
|
|
6865806b55 | ||
|
|
9546e65617 | ||
|
|
5852993243 | ||
|
|
90a03a77ad | ||
|
|
4bfbe7ebeb | ||
|
|
f3c1686a40 | ||
|
|
33a587d97e | ||
|
|
a444ec5111 | ||
|
|
5ead1bf5c8 | ||
|
|
3a267586f4 | ||
|
|
52271e0366 | ||
|
|
e4739da961 | ||
|
|
80b344e9fc | ||
|
|
036cb26fa3 | ||
|
|
33d6dcec5b | ||
|
|
791505ab6e | ||
|
|
88e1719d8e | ||
|
|
0885555521 | ||
|
|
36c1750b8f | ||
|
|
11b1c9f19f | ||
|
|
b5dd87b184 | ||
|
|
b54c7bedfd | ||
|
|
783404d8d4 | ||
|
|
3bad9f013e | ||
|
|
4495516497 | ||
|
|
3f849848a4 | ||
|
|
7203680146 | ||
|
|
d793ed3b9b | ||
|
|
c6de17d1e5 | ||
|
|
5b084f4b95 | ||
|
|
4e3b2b9f6b | ||
|
|
856ccb5bb7 | ||
|
|
dbf5659cd9 | ||
|
|
fee0c6afe9 |
333
CHANGELOG
333
CHANGELOG
@@ -1,18 +1,281 @@
|
||||
FUTURE
|
||||
|
||||
* TODO: The lwIP source code makes some invalid assumptions on processor
|
||||
word-length, storage sizes and alignment. See the mailing lists for
|
||||
problems with exoteric (/DSP) architectures showing these problems.
|
||||
We still have to fix some of these issues neatly.
|
||||
|
||||
HISTORY
|
||||
|
||||
(CVS HEAD)
|
||||
|
||||
* [Enter new changes just after this line - do not remove this line]
|
||||
|
||||
++ New features:
|
||||
|
||||
2012-01-16: Simon Goldschmidt
|
||||
* opt.h, icmp.c: Added option CHECKSUM_GEN_ICMP
|
||||
|
||||
2011-12-17: Simon Goldschmidt
|
||||
* ip.h: implemented API functions to access so_options of IP pcbs (UDP, TCP, RAW)
|
||||
(fixes bug #35061)
|
||||
|
||||
2011-09-27: Simon Goldschmidt
|
||||
* opt.h, tcp.c, tcp_in.c: Implemented limiting data on ooseq queue (task #9989)
|
||||
(define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h)
|
||||
|
||||
2011-09-21: Simon Goldschmidt
|
||||
* opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on
|
||||
send (TCP only, bug #33820)
|
||||
|
||||
2011-09-21: Simon Goldschmidt
|
||||
* init.c: Converted runtime-sanity-checks into compile-time checks that can
|
||||
be disabled (since runtime checks can often not be seen on embedded targets)
|
||||
|
||||
2011-09-11: Simon Goldschmidt
|
||||
* ppp.h, ppp_impl.h: splitted ppp.h to an internal and external header file
|
||||
to get a clear separation of which functions an application or port may use
|
||||
(task #11281)
|
||||
|
||||
2011-09-11: Simon Goldschmidt
|
||||
* opt.h, tcp_impl.h, tcp.c, udp.h/.c: Added a config option to randomize
|
||||
initial local TCP/UDP ports (so that different port ranges are used after
|
||||
a reboot; bug #33818; this one added tcp_init/udp_init functions again)
|
||||
|
||||
2011-09-03: Simon Goldschmidt
|
||||
* dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302)
|
||||
|
||||
2011-08-24: Simon Goldschmidt
|
||||
* opt.h, netif.h/.c: added netif remove callback (bug #32397)
|
||||
|
||||
2011-07-26: Simon Goldschmidt
|
||||
* etharp.c: ETHARP_SUPPORT_VLAN: add support for an external VLAN filter
|
||||
function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN)
|
||||
|
||||
2011-07-21: Simon Goldschmidt (patch by hanhui)
|
||||
* ip4.c, etharp.c, pbuf.h: bug #33634 ip_forward() have a faulty behaviour:
|
||||
Added pbuf flags to mark incoming packets as link-layer broadcast/multicast.
|
||||
Also added code to allow ip_forward() to forward non-broadcast packets to
|
||||
the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1).
|
||||
|
||||
2011-06-26: Simon Goldschmidt (patch by Cameron Gutman)
|
||||
* tcp.c, tcp_out.c: bug #33604: added some more asserts to check that
|
||||
pcb->state != LISTEN
|
||||
|
||||
2011-05-14: Simon Goldschmidt (patch by St<53>phane Lesage)
|
||||
* tcpip.c/.h: patch #7449 allow tcpip callback from interrupt with static
|
||||
memory message
|
||||
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2012-03-12: Simon Goldschmidt (patch by Bostjan Meglic)
|
||||
* ppp.c: fixed bug #35809: PPP GetMask(): Compiler warning on big endian,
|
||||
possible bug on little endian system
|
||||
|
||||
2012-02-23: Simon Goldschmidt
|
||||
* etharp.c: fixed bug #35595: Impossible to send broadcast without a gateway
|
||||
(introduced when fixing bug# 33551)
|
||||
|
||||
2012-02-16: Simon Goldschmidt
|
||||
* ppp.c: fixed pbuf leak when PPP session is aborted through pppSigHUP()
|
||||
(bug #35541: PPP Memory Leak)
|
||||
|
||||
2012-02-16: Simon Goldschmidt
|
||||
* etharp.c: fixed bug #35531: Impossible to send multicast without a gateway
|
||||
(introduced when fixing bug# 33551)
|
||||
|
||||
2012-02-16: Simon Goldschmidt (patch by St<53>phane Lesage)
|
||||
* msg_in.c, msg_out.c: fixed bug #35536 SNMP: error too big response is malformed
|
||||
|
||||
2012-02-15: Simon Goldschmidt
|
||||
* init.c: fixed bug #35537: MEMP_NUM_* sanity checks should be disabled with
|
||||
MEMP_MEM_MALLOC==1
|
||||
|
||||
2012-02-12: Simon Goldschmidt
|
||||
* tcp.h, tcp_in.c, tcp_out.c: partly fixed bug #25882: TCP hangs on
|
||||
MSS > pcb->snd_wnd (by not creating segments bigger than half the window)
|
||||
|
||||
2012-02-11: Simon Goldschmidt
|
||||
* tcp.c: fixed bug #35435: No pcb state check before adding it to time-wait
|
||||
queue while closing
|
||||
|
||||
2012-01-22: Simon Goldschmidt
|
||||
* tcp.c, tcp_in.c: fixed bug #35305: pcb may be freed too early on shutdown(WR)
|
||||
|
||||
2012-01-21: Simon Goldschmidt
|
||||
* tcp.c: fixed bug #34636: FIN_WAIT_2 - Incorrect shutdown of TCP pcb
|
||||
|
||||
2012-01-20: Simon Goldschmidt
|
||||
* dhcp.c: fixed bug #35151: DHCP asserts on incoming option lengths
|
||||
|
||||
2012-01-20: Simon Goldschmidt
|
||||
* pbuf.c: fixed bug #35291: NULL pointer in pbuf_copy
|
||||
|
||||
2011-11-25: Simon Goldschmidt
|
||||
* tcp.h/.c, tcp_impl.h, tcp_in.c: fixed bug #31177: tcp timers can corrupt
|
||||
tcp_active_pcbs in some cases
|
||||
|
||||
2011-11-23: Simon Goldschmidt
|
||||
* sys.c: fixed bug #34884: sys_msleep() body needs to be surrounded with
|
||||
'#ifndef sys_msleep'
|
||||
|
||||
2011-11-22: Simon Goldschmidt
|
||||
* netif.c, etharp.h/.c: fixed bug #34684: Clear the arp table cache when
|
||||
netif is brought down
|
||||
|
||||
2011-10-28: Simon Goldschmidt
|
||||
* tcp_in.c: fixed bug #34638: Dead code in tcp_receive - pcb->dupacks
|
||||
|
||||
2011-10-23: Simon Goldschmidt
|
||||
* mem.c: fixed bug #34429: possible memory corruption with
|
||||
LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1
|
||||
|
||||
2011-10-18: Simon Goldschmidt
|
||||
* arch.h, netdb.c: fixed bug #34592: lwip_gethostbyname_r uses nonstandard
|
||||
error value
|
||||
|
||||
2011-10-18: Simon Goldschmidt
|
||||
* opt.h: fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small
|
||||
windows (bug #34176 select after non-blocking send times out)
|
||||
|
||||
2011-10-18: Simon Goldschmidt
|
||||
* tcp_impl.h, tcp_out.c: fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't
|
||||
consider netif->mtu, causes slow network
|
||||
|
||||
2011-10-18: Simon Goldschmidt
|
||||
* sockets.c: fixed bug #34581 missing parentheses in udplite sockets code
|
||||
|
||||
2011-10-18: Simon Goldschmidt
|
||||
* sockets.h: fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS
|
||||
|
||||
2011-10-17: Simon Goldschmidt
|
||||
* api_msg.c: fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api
|
||||
|
||||
2011-10-13: Simon Goldschmidt
|
||||
* tcp_in.c, tcp_out.c: fixed bug #34517 (persist timer is started although no
|
||||
zero window is received) by starting the persist timer when a zero window is
|
||||
received, not when we have more data queued for sending than fits into the
|
||||
window
|
||||
|
||||
2011-10-13: Simon Goldschmidt
|
||||
* def.h, timers.c: fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex
|
||||
|
||||
2011-10-13: Simon Goldschmidt
|
||||
* sockets.c, api_lib.c: fixed bug #34540: compiler error when CORE_LOCKING is
|
||||
used and not all protocols are enabled
|
||||
|
||||
2011-10-12: Simon Goldschmidt
|
||||
* pbuf.c: fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4
|
||||
|
||||
2011-10-09: Simon Goldschmidt
|
||||
* tcp_out.c: fixed bug #34426: tcp_zero_window_probe() transmits incorrect
|
||||
byte value when pcb->unacked != NULL
|
||||
|
||||
2011-10-09: Simon Goldschmidt
|
||||
* ip4.c: fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong
|
||||
|
||||
2011-09-27: Simon Goldschmidt
|
||||
* tcp_in.c, tcp_out.c: Reset pcb->unsent_oversize in 2 more places...
|
||||
|
||||
2011-09-27: Simon Goldschmidt
|
||||
* tcp_in.c: fixed bug #28288: Data after FIN in oos queue
|
||||
|
||||
2011-09-27: Simon Goldschmidt
|
||||
* dhcp.c: fixed bug #34406 dhcp_option_hostname() can overflow the pbuf
|
||||
|
||||
2011-09-24: Simon Goldschmidt
|
||||
* mem.h: fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1
|
||||
|
||||
2011-09-23: Simon Goldschmidt
|
||||
* pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for
|
||||
the last packet including FIN can lose data
|
||||
|
||||
2011-09-22: Simon Goldschmidt
|
||||
* tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into
|
||||
account
|
||||
|
||||
2011-09-21: Simon Goldschmidt
|
||||
* opt.h: fixed default value of TCP_SND_BUF to not violate the sanity checks
|
||||
in init.c
|
||||
|
||||
2011-09-20: Simon Goldschmidt
|
||||
* timers.c: fixed bug #34337 (possible NULL pointer in sys_check_timeouts)
|
||||
|
||||
2011-09-11: Simon Goldschmidt
|
||||
* tcp_out.c: use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs
|
||||
(bug #34019)
|
||||
|
||||
2011-09-09: Simon Goldschmidt
|
||||
* udp.c: fixed bug #34072: UDP broadcast is received from wrong UDP pcb if
|
||||
udp port matches
|
||||
|
||||
2011-09-03: Simon Goldschmidt
|
||||
* tcp_in.c: fixed bug #33952 PUSH flag in incoming packet is lost when packet
|
||||
is aggregated and sent to application
|
||||
|
||||
2011-09-01: Simon Goldschmidt
|
||||
* opt.h: fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared
|
||||
to other options
|
||||
|
||||
2011-09-01: Simon Goldschmidt
|
||||
* tcp_in.c: fixed bug #34111 RST for ACK to listening pcb has wrong seqno
|
||||
|
||||
2011-08-24: Simon Goldschmidt
|
||||
* api_msg.c, sockets.c: fixed bug #33956 Wrong error returned when calling
|
||||
accept() on UDP connections
|
||||
|
||||
2011-08-24: Simon Goldschmidt
|
||||
* sockets.h: fixed bug #34057 socklen_t should be a typedef
|
||||
|
||||
2011-08-24: Simon Goldschmidt
|
||||
* pbuf.c: fixed bug #34112 Odd check in pbuf_alloced_custom (typo)
|
||||
|
||||
2011-08-24: Simon Goldschmidt
|
||||
* dhcp.c: fixed bug #34122 dhcp: hostname can overflow
|
||||
|
||||
2011-08-24: Simon Goldschmidt
|
||||
* netif.c: fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr
|
||||
|
||||
2011-08-22: Simon Goldschmidt
|
||||
* tcp_out.c: fixed bug #33962 TF_FIN not always set after FIN is sent. (This
|
||||
merely prevents nagle from not transmitting fast after closing.)
|
||||
|
||||
2011-07-22: Simon Goldschmidt
|
||||
* api_lib.c, api_msg.c, sockets.c, api.h: fixed bug #31084 (socket API returns
|
||||
always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now
|
||||
lwip_send() sends as much as possible for non-blocking sockets
|
||||
|
||||
2011-07-22: Simon Goldschmidt
|
||||
* pbuf.c/.h, timers.c: freeing ooseq pbufs when the pbuf pool is empty implemented
|
||||
for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ()
|
||||
at regular intervals from main level.
|
||||
|
||||
2011-07-21: Simon Goldschmidt
|
||||
* etharp.c: fixed bug #33551 (ARP entries may time out although in use) by
|
||||
sending an ARP request when an ARP entry is used in the last minute before
|
||||
it would time out.
|
||||
|
||||
2011-07-04: Simon Goldschmidt
|
||||
* sys_arch.txt: Fixed documentation after changing sys arch prototypes for 1.4.0.
|
||||
|
||||
2011-06-26: Simon Goldschmidt
|
||||
* tcp.c: fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by
|
||||
updating its documentation only.
|
||||
|
||||
2011-06-26: Simon Goldschmidt
|
||||
* mem.c: fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an
|
||||
unaligned pointer.
|
||||
|
||||
2011-06-26: Simon Goldschmidt
|
||||
* mem.c: fixed bug #33544 "warning in mem.c in lwip 1.4.0 with NO_SYS=1"
|
||||
|
||||
2011-05-25: Simon Goldschmidt
|
||||
* tcp.c: fixed bug #33398 (pointless conversion when checking TCP port range)
|
||||
|
||||
|
||||
|
||||
(STABLE-1.4.0)
|
||||
|
||||
++ New features:
|
||||
|
||||
2011-03-27: Simon Goldschmidt
|
||||
* tcp_impl.h, tcp_in.c, tcp_out.c: Removed 'dataptr' from 'struct tcp_seg' and
|
||||
calculate it in tcp_zero_window_probe (the only place where it was used).
|
||||
|
||||
2010-11-21: Simon Goldschmidt
|
||||
* dhcp.c/.h: Added a function to deallocate the struct dhcp from a netif
|
||||
(fixes bug #31525).
|
||||
@@ -233,6 +496,62 @@ HISTORY
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2011-04-20: Simon Goldschmidt
|
||||
* sys_arch.txt: sys_arch_timeouts() is not needed any more.
|
||||
|
||||
2011-04-13: Simon Goldschmidt
|
||||
* tcp.c, udp.c: Fixed bug #33048 (Bad range for IP source port numbers) by
|
||||
using ports in the IANA private/dynamic range (49152 through 65535).
|
||||
|
||||
2011-03-29: Simon Goldschmidt, patch by Emil Lhungdahl:
|
||||
* etharp.h/.c: Fixed broken VLAN support.
|
||||
|
||||
2011-03-27: Simon Goldschmidt
|
||||
* tcp.c: Fixed bug #32926 (TCP_RMV(&tcp_bound_pcbs) is called on unbound tcp
|
||||
pcbs) by checking if the pcb was bound (local_port != 0).
|
||||
|
||||
2011-03-27: Simon Goldschmidt
|
||||
* ppp.c: Fixed bug #32280 (ppp: a pbuf is freed twice)
|
||||
|
||||
2011-03-27: Simon Goldschmidt
|
||||
* sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and
|
||||
raw pcbs with LWIP_TCPIP_CORE_LOCKING==1.
|
||||
|
||||
2011-03-27: Simon Goldschmidt
|
||||
* tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route
|
||||
is present never times out) by starting retransmission timer before checking
|
||||
route.
|
||||
|
||||
2011-03-22: Simon Goldschmidt
|
||||
* ppp.c: Fixed bug #32648 (PPP code crashes when terminating a link) by only
|
||||
calling sio_read_abort() if the file descriptor is valid.
|
||||
|
||||
2011-03-14: Simon Goldschmidt
|
||||
* err.h/.c, sockets.c, api_msg.c: fixed bug #31748 (Calling non-blocking connect
|
||||
more than once can render a socket useless) since it mainly involves changing
|
||||
"FATAL" classification of error codes: ERR_USE and ERR_ISCONN just aren't fatal.
|
||||
|
||||
2011-03-13: Simon Goldschmidt
|
||||
* sockets.c: fixed bug #32769 (ESHUTDOWN is linux-specific) by fixing
|
||||
err_to_errno_table (ERR_CLSD: ENOTCONN instead of ESHUTDOWN), ERR_ISCONN:
|
||||
use EALRADY instead of -1
|
||||
|
||||
2011-03-13: Simon Goldschmidt
|
||||
* api_lib.c: netconn_accept: return ERR_ABRT instead of ERR_CLSD if the
|
||||
connection has been aborted by err_tcp (since this is not a normal closing
|
||||
procedure).
|
||||
|
||||
2011-03-13: Simon Goldschmidt
|
||||
* tcp.c: tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind
|
||||
with pcb->state != CLOSED
|
||||
|
||||
2011-02-17: Simon Goldschmidt
|
||||
* rawapi.txt: Fixed bug #32561 tcp_poll argument definition out-of-order in
|
||||
documentation
|
||||
|
||||
2011-02-17: Simon Goldschmidt
|
||||
* many files: Added missing U/UL modifiers to fix 16-bit-arch portability.
|
||||
|
||||
2011-01-24: Simon Goldschmidt
|
||||
* sockets.c: Fixed bug #31741: lwip_select seems to have threading problems
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ incoming connections or be explicitly connected to another host.
|
||||
Creates a new connection identifier (PCB). If memory is not
|
||||
available for creating the new pcb, NULL is returned.
|
||||
|
||||
- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Binds the pcb to a local IP address and port number. The IP address
|
||||
@@ -147,6 +147,8 @@ incoming connections or be explicitly connected to another host.
|
||||
usually be called from the accept callback. This allows lwIP to perform
|
||||
housekeeping tasks, such as allowing further incoming connections to be
|
||||
queued in the listen backlog.
|
||||
ATTENTION: the PCB passed in must be the listening pcb, not the pcb passed
|
||||
into the accept callback!
|
||||
|
||||
- void tcp_accept(struct tcp_pcb *pcb,
|
||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
|
||||
@@ -154,8 +156,8 @@ incoming connections or be explicitly connected to another host.
|
||||
|
||||
Specified the callback function that should be called when a new
|
||||
connection arrives on a listening connection.
|
||||
|
||||
- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
|
||||
- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port, err_t (* connected)(void *arg,
|
||||
struct tcp_pcb *tpcb,
|
||||
err_t err));
|
||||
@@ -176,7 +178,7 @@ incoming connections or be explicitly connected to another host.
|
||||
available for enqueueing the SYN segment. If the SYN indeed was
|
||||
enqueued successfully, the tcp_connect() function returns ERR_OK.
|
||||
|
||||
|
||||
|
||||
--- Sending TCP data
|
||||
|
||||
TCP data is sent by enqueueing the data with a call to
|
||||
@@ -184,15 +186,19 @@ tcp_write(). When the data is successfully transmitted to the remote
|
||||
host, the application will be notified with a call to a specified
|
||||
callback function.
|
||||
|
||||
- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,
|
||||
u8_t copy)
|
||||
- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len,
|
||||
u8_t apiflags)
|
||||
|
||||
Enqueues the data pointed to by the argument dataptr. The length of
|
||||
the data is passed as the len parameter. The copy argument is either
|
||||
0 or 1 and indicates whether the new memory should be allocated for
|
||||
the data to be copied into. If the argument is 0, no new memory
|
||||
should be allocated and the data should only be referenced by
|
||||
pointer.
|
||||
the data is passed as the len parameter. The apiflags can be one or more of:
|
||||
- TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated
|
||||
for the data to be copied into. If this flag is not given, no new memory
|
||||
should be allocated and the data should only be referenced by pointer. This
|
||||
also means that the memory behind dataptr must not change until the data is
|
||||
ACKed by the remote host
|
||||
- TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is given,
|
||||
the PSH flag is set in the last segment created by this call to tcp_write.
|
||||
If this flag is given, the PSH flag is not set.
|
||||
|
||||
The tcp_write() function will fail and return ERR_MEM if the length
|
||||
of the data exceeds the current send buffer size or if the length of
|
||||
@@ -238,7 +244,7 @@ window.
|
||||
|
||||
Must be called when the application has received the data. The len
|
||||
argument indicates the length of the received data.
|
||||
|
||||
|
||||
|
||||
--- Application polling
|
||||
|
||||
@@ -251,8 +257,9 @@ if a call to tcp_write() has failed because memory wasn't available,
|
||||
the application may use the polling functionality to call tcp_write()
|
||||
again when the connection has been idle for a while.
|
||||
|
||||
- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,
|
||||
err_t (* poll)(void *arg, struct tcp_pcb *tpcb))
|
||||
- void tcp_poll(struct tcp_pcb *pcb,
|
||||
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
|
||||
u8_t interval)
|
||||
|
||||
Specifies the polling interval and the callback function that should
|
||||
be called to poll the application. The interval is specified in
|
||||
@@ -321,14 +328,14 @@ level of complexity of UDP, the interface is significantly simpler.
|
||||
|
||||
Removes and deallocates the pcb.
|
||||
|
||||
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Binds the pcb to a local address. The IP-address argument "ipaddr"
|
||||
can be IP_ADDR_ANY to indicate that it should listen to any local IP
|
||||
address. The function currently always return ERR_OK.
|
||||
|
||||
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Sets the remote end of the pcb. This function does not generate any
|
||||
@@ -346,7 +353,7 @@ level of complexity of UDP, the interface is significantly simpler.
|
||||
- void udp_recv(struct udp_pcb *pcb,
|
||||
void (* recv)(void *arg, struct udp_pcb *upcb,
|
||||
struct pbuf *p,
|
||||
struct ip_addr *addr,
|
||||
ip_addr_t *addr,
|
||||
u16_t port),
|
||||
void *recv_arg)
|
||||
|
||||
@@ -407,8 +414,8 @@ Call these functions in the order of appearance:
|
||||
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
|
||||
predefined regular intervals after this initialization.
|
||||
|
||||
- netif_add(struct netif *netif, struct ip_addr *ipaddr,
|
||||
struct ip_addr *netmask, struct ip_addr *gw,
|
||||
- netif_add(struct netif *netif, ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask, ip_addr_t *gw,
|
||||
void *state, err_t (* init)(struct netif *netif),
|
||||
err_t (* input)(struct pbuf *p, struct netif *netif))
|
||||
|
||||
|
||||
@@ -34,26 +34,36 @@ in the sys_arch.h file. Mailboxes are equivalently represented by the
|
||||
type "sys_mbox_t". lwIP does not place any restrictions on how
|
||||
sys_sem_t or sys_mbox_t are represented internally.
|
||||
|
||||
Since lwIP 1.4.0, semaphore and mailbox functions are prototyped in a way that
|
||||
allows both using pointers or actual OS structures to be used. This way, memory
|
||||
required for such types can be either allocated in place (globally or on the
|
||||
stack) or on the heap (allocated internally in the "*_new()" functions).
|
||||
|
||||
The following functions must be implemented by the sys_arch:
|
||||
|
||||
- void sys_init(void)
|
||||
|
||||
Is called to initialize the sys_arch layer.
|
||||
|
||||
- sys_sem_t sys_sem_new(u8_t count)
|
||||
- err_t sys_sem_new(sys_sem_t *sem, u8_t count)
|
||||
|
||||
Creates and returns a new semaphore. The "count" argument specifies
|
||||
the initial state of the semaphore.
|
||||
Creates a new semaphore. The semaphore is allocated to the memory that 'sem'
|
||||
points to (which can be both a pointer or the actual OS structure).
|
||||
The "count" argument specifies the initial state of the semaphore (which is
|
||||
either 0 or 1).
|
||||
If the semaphore has been created, ERR_OK should be returned. Returning any
|
||||
other error will provide a hint what went wrong, but except for assertions,
|
||||
no real error handling is implemented.
|
||||
|
||||
- void sys_sem_free(sys_sem_t sem)
|
||||
- void sys_sem_free(sys_sem_t *sem)
|
||||
|
||||
Deallocates a semaphore.
|
||||
|
||||
- void sys_sem_signal(sys_sem_t sem)
|
||||
- void sys_sem_signal(sys_sem_t *sem)
|
||||
|
||||
Signals a semaphore.
|
||||
|
||||
- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
|
||||
- u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
|
||||
|
||||
Blocks the thread while waiting for the semaphore to be
|
||||
signaled. If the "timeout" argument is non-zero, the thread should
|
||||
@@ -70,30 +80,47 @@ The following functions must be implemented by the sys_arch:
|
||||
Notice that lwIP implements a function with a similar name,
|
||||
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
|
||||
|
||||
- sys_mbox_t sys_mbox_new(int size)
|
||||
- int sys_sem_valid(sys_sem_t *sem)
|
||||
|
||||
Returns 1 if the semaphore is valid, 0 if it is not valid.
|
||||
When using pointers, a simple way is to check the pointer for != NULL.
|
||||
When directly using OS structures, implementing this may be more complex.
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_sem_set_invalid(sys_sem_t *sem)
|
||||
|
||||
Invalidate a semaphore so that sys_sem_valid() returns 0.
|
||||
ATTENTION: This does NOT mean that the semaphore shall be deallocated:
|
||||
sys_sem_free() is always called before calling this function!
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- err_t sys_mbox_new(sys_mbox_t *mbox, int size)
|
||||
|
||||
Creates an empty mailbox for maximum "size" elements. Elements stored
|
||||
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
|
||||
in your lwipopts.h, or ignore this parameter in your implementation
|
||||
and use a default size.
|
||||
If the mailbox has been created, ERR_OK should be returned. Returning any
|
||||
other error will provide a hint what went wrong, but except for assertions,
|
||||
no real error handling is implemented.
|
||||
|
||||
- void sys_mbox_free(sys_mbox_t mbox)
|
||||
- void sys_mbox_free(sys_mbox_t *mbox)
|
||||
|
||||
Deallocates a mailbox. If there are messages still present in the
|
||||
mailbox when the mailbox is deallocated, it is an indication of a
|
||||
programming error in lwIP and the developer should be notified.
|
||||
|
||||
- void sys_mbox_post(sys_mbox_t mbox, void *msg)
|
||||
- void sys_mbox_post(sys_mbox_t *mbox, void *msg)
|
||||
|
||||
Posts the "msg" to the mailbox. This function have to block until
|
||||
the "msg" is really posted.
|
||||
|
||||
- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
|
||||
- err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
|
||||
|
||||
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
|
||||
is full, else, ERR_OK if the "msg" is posted.
|
||||
|
||||
- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
|
||||
- u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
|
||||
|
||||
Blocks the thread until a message arrives in the mailbox, but does
|
||||
not block the thread longer than "timeout" milliseconds (similar to
|
||||
@@ -110,7 +137,7 @@ The following functions must be implemented by the sys_arch:
|
||||
Note that a function with a similar name, sys_mbox_fetch(), is
|
||||
implemented by lwIP.
|
||||
|
||||
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
|
||||
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
|
||||
|
||||
This is similar to sys_arch_mbox_fetch, however if a message is not
|
||||
present in the mailbox, it immediately returns with the code
|
||||
@@ -122,19 +149,21 @@ The following functions must be implemented by the sys_arch:
|
||||
#define sys_arch_mbox_tryfetch(mbox,msg) \
|
||||
sys_arch_mbox_fetch(mbox,msg,1)
|
||||
although this would introduce unnecessary delays.
|
||||
|
||||
- struct sys_timeouts *sys_arch_timeouts(void)
|
||||
|
||||
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
|
||||
each thread has a list of timeouts which is repressented as a linked
|
||||
list of sys_timeout structures. The sys_timeouts structure holds a
|
||||
pointer to a linked list of timeouts. This function is called by
|
||||
the lwIP timeout scheduler and must not return a NULL value.
|
||||
- int sys_mbox_valid(sys_mbox_t *mbox)
|
||||
|
||||
Returns 1 if the mailbox is valid, 0 if it is not valid.
|
||||
When using pointers, a simple way is to check the pointer for != NULL.
|
||||
When directly using OS structures, implementing this may be more complex.
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_mbox_set_invalid(sys_mbox_t *mbox)
|
||||
|
||||
Invalidate a mailbox so that sys_mbox_valid() returns 0.
|
||||
ATTENTION: This does NOT mean that the mailbox shall be deallocated:
|
||||
sys_mbox_free() is always called before calling this function!
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
In a single thread sys_arch implementation, this function will
|
||||
simply return a pointer to a global sys_timeouts variable stored in
|
||||
the sys_arch module.
|
||||
|
||||
If threads are supported by the underlying operating system and if
|
||||
such functionality is needed in lwIP, the following function will have
|
||||
to be implemented as well:
|
||||
@@ -168,6 +197,16 @@ to be implemented as well:
|
||||
more information. This function is only required if your port is supporting
|
||||
an operating system.
|
||||
|
||||
For some configurations, you also need:
|
||||
|
||||
- u32_t sys_now(void)
|
||||
|
||||
This optional function returns the current time in milliseconds (don't care
|
||||
for wraparound, this is only used for time diffs).
|
||||
Not implementing this function means you cannot use some modules (e.g. TCP
|
||||
timestamps, internal timeouts for NO_SYS==1).
|
||||
|
||||
|
||||
Note:
|
||||
|
||||
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
|
||||
|
||||
@@ -307,9 +307,9 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
||||
|
||||
if (newconn == NULL) {
|
||||
/* connection has been closed */
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
|
||||
return ERR_CLSD;
|
||||
/* connection has been aborted */
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
/* Let the stack know that we have accepted the connection. */
|
||||
@@ -372,7 +372,10 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
|
||||
#if LWIP_TCP
|
||||
if (conn->type == NETCONN_TCP) {
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
if (conn->type == NETCONN_TCP)
|
||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||
{
|
||||
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
|
||||
/* Let the stack know that we have taken the data. */
|
||||
/* TODO: Speedup: Don't block and wait for the answer here
|
||||
@@ -461,7 +464,10 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
||||
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
|
||||
|
||||
#if LWIP_TCP
|
||||
if (conn->type == NETCONN_TCP) {
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
if (conn->type == NETCONN_TCP)
|
||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||
{
|
||||
struct pbuf *p = NULL;
|
||||
/* This is not a listening netconn, since recvmbox is set */
|
||||
|
||||
@@ -485,8 +491,11 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
||||
*new_buf = buf;
|
||||
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||
return ERR_OK;
|
||||
} else
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
|
||||
else
|
||||
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
|
||||
{
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
return netconn_recv_data(conn, (void **)new_buf);
|
||||
@@ -582,31 +591,62 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
|
||||
* - NETCONN_COPY: data will be copied into memory belonging to the stack
|
||||
* - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
|
||||
* - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
|
||||
* @param bytes_written pointer to a location that receives the number of written bytes
|
||||
* @return ERR_OK if data was sent, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
|
||||
netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
|
||||
u8_t apiflags, size_t *bytes_written)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
u8_t dontblock;
|
||||
|
||||
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
|
||||
if (size == 0) {
|
||||
return ERR_OK;
|
||||
}
|
||||
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
|
||||
if (dontblock && !bytes_written) {
|
||||
/* This implies netconn_write() cannot be used for non-blocking send, since
|
||||
it has no way to return the number of bytes written. */
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/* @todo: for non-blocking write, check if 'size' would ever fit into
|
||||
snd_queue or snd_buf */
|
||||
/* non-blocking write sends as much */
|
||||
msg.function = do_write;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.w.dataptr = dataptr;
|
||||
msg.msg.msg.w.apiflags = apiflags;
|
||||
msg.msg.msg.w.len = size;
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
if (conn->send_timeout != 0) {
|
||||
/* get the time we started, which is later compared to
|
||||
sys_now() + conn->send_timeout */
|
||||
msg.msg.msg.w.time_started = sys_now();
|
||||
} else {
|
||||
msg.msg.msg.w.time_started = 0;
|
||||
}
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
|
||||
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
|
||||
but if it is, this is done inside api_msg.c:do_write(), so we can use the
|
||||
non-blocking version here. */
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
if ((err == ERR_OK) && (bytes_written != NULL)) {
|
||||
if (dontblock
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
|| (conn->send_timeout != 0)
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
) {
|
||||
/* nonblocking write: maybe the data has been sent partly */
|
||||
*bytes_written = msg.msg.msg.w.len;
|
||||
} else {
|
||||
/* blocking call succeeded: all data has been sent if it */
|
||||
*bytes_written = size;
|
||||
}
|
||||
}
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
|
||||
@@ -597,18 +597,16 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
|
||||
#endif /* LWIP_TCP */
|
||||
default:
|
||||
LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
|
||||
break;
|
||||
goto free_and_return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
|
||||
memp_free(MEMP_NETCONN, conn);
|
||||
return NULL;
|
||||
goto free_and_return;
|
||||
}
|
||||
if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
|
||||
sys_sem_free(&conn->op_completed);
|
||||
memp_free(MEMP_NETCONN, conn);
|
||||
return NULL;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
#if LWIP_TCP
|
||||
@@ -624,6 +622,9 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
|
||||
conn->current_msg = NULL;
|
||||
conn->write_offset = 0;
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
conn->send_timeout = 0;
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
conn->recv_timeout = 0;
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
@@ -633,6 +634,9 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
conn->flags = 0;
|
||||
return conn;
|
||||
free_and_return:
|
||||
memp_free(MEMP_NETCONN, conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -770,21 +774,21 @@ do_close_internal(struct netconn *conn)
|
||||
}
|
||||
}
|
||||
/* Try to close the connection */
|
||||
if (shut == NETCONN_SHUT_RDWR) {
|
||||
if (close) {
|
||||
err = tcp_close(conn->pcb.tcp);
|
||||
} else {
|
||||
err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);
|
||||
err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx);
|
||||
}
|
||||
if (err == ERR_OK) {
|
||||
/* Closing succeeded */
|
||||
conn->current_msg->err = ERR_OK;
|
||||
conn->current_msg = NULL;
|
||||
conn->state = NETCONN_NONE;
|
||||
/* Set back some callback pointers as conn is going away */
|
||||
conn->pcb.tcp = NULL;
|
||||
/* Trigger select() in socket layer. Make sure everybody notices activity
|
||||
on the connection, error first! */
|
||||
if (close) {
|
||||
/* Set back some callback pointers as conn is going away */
|
||||
conn->pcb.tcp = NULL;
|
||||
/* Trigger select() in socket layer. Make sure everybody notices activity
|
||||
on the connection, error first! */
|
||||
API_EVENT(conn, NETCONN_EVT_ERROR, 0);
|
||||
}
|
||||
if (shut_rx) {
|
||||
@@ -950,12 +954,7 @@ do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
|
||||
conn->current_msg = NULL;
|
||||
conn->state = NETCONN_NONE;
|
||||
if (!was_blocking) {
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
if (conn->last_err == ERR_INPROGRESS) {
|
||||
conn->last_err = ERR_OK;
|
||||
}
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_OK);
|
||||
}
|
||||
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
|
||||
|
||||
@@ -1094,6 +1093,8 @@ do_listen(struct api_msg_msg *msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
msg->err = ERR_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1198,7 +1199,7 @@ do_recv(struct api_msg_msg *msg)
|
||||
static err_t
|
||||
do_writemore(struct netconn *conn)
|
||||
{
|
||||
err_t err = ERR_OK;
|
||||
err_t err;
|
||||
void *dataptr;
|
||||
u16_t len, available;
|
||||
u8_t write_finished = 0;
|
||||
@@ -1214,62 +1215,78 @@ do_writemore(struct netconn *conn)
|
||||
LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
|
||||
conn->write_offset < conn->current_msg->msg.w.len);
|
||||
|
||||
dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
|
||||
diff = conn->current_msg->msg.w.len - conn->write_offset;
|
||||
if (diff > 0xffffUL) { /* max_u16_t */
|
||||
len = 0xffff;
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
if ((conn->send_timeout != 0) &&
|
||||
((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
|
||||
write_finished = 1;
|
||||
if (conn->write_offset == 0) {
|
||||
/* nothing has been written */
|
||||
err = ERR_WOULDBLOCK;
|
||||
conn->current_msg->msg.w.len = 0;
|
||||
} else {
|
||||
/* partial write */
|
||||
err = ERR_OK;
|
||||
conn->current_msg->msg.w.len = conn->write_offset;
|
||||
}
|
||||
} else
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
{
|
||||
dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
|
||||
diff = conn->current_msg->msg.w.len - conn->write_offset;
|
||||
if (diff > 0xffffUL) { /* max_u16_t */
|
||||
len = 0xffff;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
#endif
|
||||
apiflags |= TCP_WRITE_FLAG_MORE;
|
||||
} else {
|
||||
len = (u16_t)diff;
|
||||
}
|
||||
available = tcp_sndbuf(conn->pcb.tcp);
|
||||
if (available < len) {
|
||||
/* don't try to write more than sendbuf */
|
||||
len = available;
|
||||
apiflags |= TCP_WRITE_FLAG_MORE;
|
||||
} else {
|
||||
len = (u16_t)diff;
|
||||
}
|
||||
available = tcp_sndbuf(conn->pcb.tcp);
|
||||
if (available < len) {
|
||||
/* don't try to write more than sendbuf */
|
||||
len = available;
|
||||
if (dontblock){
|
||||
if (!len) {
|
||||
err = ERR_WOULDBLOCK;
|
||||
goto err_mem;
|
||||
}
|
||||
} else {
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
#endif
|
||||
apiflags |= TCP_WRITE_FLAG_MORE;
|
||||
}
|
||||
if (dontblock && (len < conn->current_msg->msg.w.len)) {
|
||||
/* failed to send all data at once -> nonblocking write not possible */
|
||||
err = ERR_MEM;
|
||||
}
|
||||
if (err == ERR_OK) {
|
||||
apiflags |= TCP_WRITE_FLAG_MORE;
|
||||
}
|
||||
}
|
||||
LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
|
||||
err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
|
||||
}
|
||||
if (dontblock && (err == ERR_MEM)) {
|
||||
/* nonblocking write failed */
|
||||
write_finished = 1;
|
||||
err = ERR_WOULDBLOCK;
|
||||
/* let poll_tcp check writable space to mark the pcb
|
||||
writable again */
|
||||
conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
|
||||
/* let select mark this pcb as non-writable. */
|
||||
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
|
||||
} else {
|
||||
/* if OK or memory error, check available space */
|
||||
if (((err == ERR_OK) || (err == ERR_MEM)) &&
|
||||
((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
|
||||
(tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) {
|
||||
/* The queued byte- or pbuf-count exceeds the configured low-water limit,
|
||||
let select mark this pcb as non-writable. */
|
||||
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
|
||||
if ((err == ERR_OK) || (err == ERR_MEM)) {
|
||||
err_mem:
|
||||
if (dontblock && (len < conn->current_msg->msg.w.len)) {
|
||||
/* non-blocking write did not write everything: mark the pcb non-writable
|
||||
and let poll_tcp check writable space to mark the pcb writable again */
|
||||
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
|
||||
conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
|
||||
} else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
|
||||
(tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
|
||||
/* The queued byte- or pbuf-count exceeds the configured low-water limit,
|
||||
let select mark this pcb as non-writable. */
|
||||
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ERR_OK) {
|
||||
conn->write_offset += len;
|
||||
if (conn->write_offset == conn->current_msg->msg.w.len) {
|
||||
if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
|
||||
/* return sent length */
|
||||
conn->current_msg->msg.w.len = conn->write_offset;
|
||||
/* everything was written */
|
||||
write_finished = 1;
|
||||
conn->write_offset = 0;
|
||||
}
|
||||
tcp_output(conn->pcb.tcp);
|
||||
} else if (err == ERR_MEM) {
|
||||
} else if ((err == ERR_MEM) && !dontblock) {
|
||||
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
|
||||
we do NOT return to the application thread, since ERR_MEM is
|
||||
only a temporary error! */
|
||||
@@ -1277,16 +1294,16 @@ do_writemore(struct netconn *conn)
|
||||
/* tcp_write returned ERR_MEM, try tcp_output anyway */
|
||||
tcp_output(conn->pcb.tcp);
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
/* On errors != ERR_MEM, we don't try writing any more but return
|
||||
the error to the application thread. */
|
||||
write_finished = 1;
|
||||
conn->current_msg->msg.w.len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (write_finished) {
|
||||
/* everything was written: set back connection state
|
||||
and back to application task */
|
||||
|
||||
@@ -49,14 +49,14 @@ static const char *err_strerr[] = {
|
||||
"Operation in progress.", /* ERR_INPROGRESS -5 */
|
||||
"Illegal value.", /* ERR_VAL -6 */
|
||||
"Operation would block.", /* ERR_WOULDBLOCK -7 */
|
||||
"Connection aborted.", /* ERR_ABRT -8 */
|
||||
"Connection reset.", /* ERR_RST -9 */
|
||||
"Connection closed.", /* ERR_CLSD -10 */
|
||||
"Not connected.", /* ERR_CONN -11 */
|
||||
"Illegal argument.", /* ERR_ARG -12 */
|
||||
"Address in use.", /* ERR_USE -13 */
|
||||
"Low-level netif error.", /* ERR_IF -14 */
|
||||
"Already connected.", /* ERR_ISCONN -15 */
|
||||
"Address in use.", /* ERR_USE -8 */
|
||||
"Already connected.", /* ERR_ISCONN -9 */
|
||||
"Connection aborted.", /* ERR_ABRT -10 */
|
||||
"Connection reset.", /* ERR_RST -11 */
|
||||
"Connection closed.", /* ERR_CLSD -12 */
|
||||
"Not connected.", /* ERR_CONN -13 */
|
||||
"Illegal argument.", /* ERR_ARG -14 */
|
||||
"Low-level netif error.", /* ERR_IF -15 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -200,7 +200,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
err = netconn_gethostbyname(name, &(h->addr));
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
|
||||
*h_errnop = ENSRNOTFOUND;
|
||||
*h_errnop = HOST_NOT_FOUND;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,14 +141,14 @@ static const int err_to_errno_table[] = {
|
||||
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
|
||||
EINVAL, /* ERR_VAL -6 Illegal value. */
|
||||
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
|
||||
ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */
|
||||
ECONNRESET, /* ERR_RST -9 Connection reset. */
|
||||
ESHUTDOWN, /* ERR_CLSD -10 Connection closed. */
|
||||
ENOTCONN, /* ERR_CONN -11 Not connected. */
|
||||
EIO, /* ERR_ARG -12 Illegal argument. */
|
||||
EADDRINUSE, /* ERR_USE -13 Address in use. */
|
||||
-1, /* ERR_IF -14 Low-level netif error */
|
||||
-1, /* ERR_ISCONN -15 Already connected. */
|
||||
EADDRINUSE, /* ERR_USE -8 Address in use. */
|
||||
EALREADY, /* ERR_ISCONN -9 Already connected. */
|
||||
ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
|
||||
ECONNRESET, /* ERR_RST -11 Connection reset. */
|
||||
ENOTCONN, /* ERR_CLSD -12 Connection closed. */
|
||||
ENOTCONN, /* ERR_CONN -13 Not connected. */
|
||||
EIO, /* ERR_ARG -14 Illegal argument. */
|
||||
-1, /* ERR_IF -15 Low-level netif error */
|
||||
};
|
||||
|
||||
#define ERR_TO_ERRNO_TABLE_SIZE \
|
||||
@@ -336,6 +336,10 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
err = netconn_accept(sock->conn, &newconn);
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
|
||||
if (netconn_type(sock->conn) != NETCONN_TCP) {
|
||||
sock_set_errno(sock, EOPNOTSUPP);
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
return -1;
|
||||
}
|
||||
@@ -537,6 +541,10 @@ lwip_listen(int s, int backlog)
|
||||
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
|
||||
if (netconn_type(sock->conn) != NETCONN_TCP) {
|
||||
sock_set_errno(sock, EOPNOTSUPP);
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
return -1;
|
||||
}
|
||||
@@ -748,6 +756,7 @@ lwip_send(int s, const void *data, size_t size, int flags)
|
||||
struct lwip_sock *sock;
|
||||
err_t err;
|
||||
u8_t write_flags;
|
||||
size_t written;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
|
||||
s, data, size, flags));
|
||||
@@ -766,22 +775,15 @@ lwip_send(int s, const void *data, size_t size, int flags)
|
||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||
}
|
||||
|
||||
if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
|
||||
if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
|
||||
/* too much data to ever send nonblocking! */
|
||||
sock_set_errno(sock, EMSGSIZE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
write_flags = NETCONN_COPY |
|
||||
((flags & MSG_MORE) ? NETCONN_MORE : 0) |
|
||||
((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
|
||||
err = netconn_write(sock->conn, data, size, write_flags);
|
||||
written = 0;
|
||||
err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
return (err == ERR_OK ? (int)size : -1);
|
||||
return (err == ERR_OK ? (int)written : -1);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -847,14 +849,29 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
|
||||
inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
|
||||
remote_port = ntohs(to_in->sin_port);
|
||||
} else {
|
||||
remote_addr = IP_ADDR_ANY;
|
||||
remote_port = 0;
|
||||
remote_addr = &sock->conn->pcb.ip->remote_ip;
|
||||
#if LWIP_UDP
|
||||
if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) {
|
||||
remote_port = sock->conn->pcb.udp->remote_port;
|
||||
} else
|
||||
#endif /* LWIP_UDP */
|
||||
{
|
||||
remote_port = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LOCK_TCPIP_CORE();
|
||||
if (sock->conn->type == NETCONN_RAW) {
|
||||
if (netconn_type(sock->conn) == NETCONN_RAW) {
|
||||
#if LWIP_RAW
|
||||
err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
|
||||
} else {
|
||||
#else /* LWIP_RAW */
|
||||
err = ERR_ARG;
|
||||
#endif /* LWIP_RAW */
|
||||
}
|
||||
#if LWIP_UDP && LWIP_RAW
|
||||
else
|
||||
#endif /* LWIP_UDP && LWIP_RAW */
|
||||
{
|
||||
#if LWIP_UDP
|
||||
#if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
|
||||
err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
|
||||
@@ -890,7 +907,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
|
||||
netbuf_fromport(&buf) = 0;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=",
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
|
||||
s, data, short_size, flags));
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
|
||||
@@ -1464,7 +1481,9 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
|
||||
case SO_ERROR:
|
||||
case SO_KEEPALIVE:
|
||||
/* UNIMPL case SO_CONTIMEO: */
|
||||
/* UNIMPL case SO_SNDTIMEO: */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
case SO_SNDTIMEO:
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case SO_RCVTIMEO:
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
@@ -1672,7 +1691,7 @@ lwip_getsockopt_internal(void *arg)
|
||||
case SO_REUSEPORT:
|
||||
#endif /* SO_REUSE */
|
||||
/*case SO_USELOOPBACK: UNIMPL */
|
||||
*(int*)optval = sock->conn->pcb.ip->so_options & optname;
|
||||
*(int*)optval = ip_get_option(sock->conn->pcb.ip, optname);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
|
||||
s, optname, (*(int*)optval?"on":"off")));
|
||||
break;
|
||||
@@ -1709,6 +1728,11 @@ lwip_getsockopt_internal(void *arg)
|
||||
s, *(int *)optval));
|
||||
break;
|
||||
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
case SO_SNDTIMEO:
|
||||
*(int *)optval = netconn_get_sendtimeout(sock->conn);
|
||||
break;
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case SO_RCVTIMEO:
|
||||
*(int *)optval = netconn_get_recvtimeout(sock->conn);
|
||||
@@ -1863,7 +1887,9 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
|
||||
/* UNIMPL case SO_DONTROUTE: */
|
||||
case SO_KEEPALIVE:
|
||||
/* UNIMPL case case SO_CONTIMEO: */
|
||||
/* UNIMPL case case SO_SNDTIMEO: */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
case SO_SNDTIMEO:
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case SO_RCVTIMEO:
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
@@ -2082,13 +2108,18 @@ lwip_setsockopt_internal(void *arg)
|
||||
#endif /* SO_REUSE */
|
||||
/* UNIMPL case SO_USELOOPBACK: */
|
||||
if (*(int*)optval) {
|
||||
sock->conn->pcb.ip->so_options |= optname;
|
||||
ip_set_option(sock->conn->pcb.ip, optname);
|
||||
} else {
|
||||
sock->conn->pcb.ip->so_options &= ~optname;
|
||||
ip_reset_option(sock->conn->pcb.ip, optname);
|
||||
}
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
|
||||
s, optname, (*(int*)optval?"on":"off")));
|
||||
break;
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
case SO_SNDTIMEO:
|
||||
netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval);
|
||||
break;
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case SO_RCVTIMEO:
|
||||
netconn_set_recvtimeout(sock->conn, *(int*)optval);
|
||||
@@ -2214,7 +2245,7 @@ lwip_setsockopt_internal(void *arg)
|
||||
case IPPROTO_UDPLITE:
|
||||
switch (optname) {
|
||||
case UDPLITE_SEND_CSCOV:
|
||||
if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
|
||||
if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) {
|
||||
/* don't allow illegal values! */
|
||||
sock->conn->pcb.udp->chksum_len_tx = 8;
|
||||
} else {
|
||||
@@ -2224,7 +2255,7 @@ lwip_setsockopt_internal(void *arg)
|
||||
s, (*(int*)optval)) );
|
||||
break;
|
||||
case UDPLITE_RECV_CSCOV:
|
||||
if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
|
||||
if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) {
|
||||
/* don't allow illegal values! */
|
||||
sock->conn->pcb.udp->chksum_len_rx = 8;
|
||||
} else {
|
||||
|
||||
@@ -117,12 +117,6 @@ tcpip_thread(void *arg)
|
||||
break;
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
case TCPIP_MSG_CALLBACK:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT
|
||||
case TCPIP_MSG_TIMEOUT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
||||
@@ -136,6 +130,17 @@ tcpip_thread(void *arg)
|
||||
break;
|
||||
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||
|
||||
case TCPIP_MSG_CALLBACK:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
|
||||
case TCPIP_MSG_CALLBACK_STATIC:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
break;
|
||||
|
||||
default:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
|
||||
LWIP_ASSERT("tcpip_thread: invalid message", 0);
|
||||
@@ -172,22 +177,22 @@ tcpip_input(struct pbuf *p, struct netif *inp)
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_INPKT;
|
||||
msg->msg.inp.p = p;
|
||||
msg->msg.inp.netif = inp;
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_OK;
|
||||
if (!sys_mbox_valid(&mbox)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
return ERR_VAL;
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_INPKT;
|
||||
msg->msg.inp.p = p;
|
||||
msg->msg.inp.netif = inp;
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_OK;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
}
|
||||
|
||||
@@ -392,6 +397,52 @@ tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
|
||||
#endif /* !LWIP_TCPIP_CORE_LOCKING */
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
/**
|
||||
* Allocate a structure for a static callback message and initialize it.
|
||||
* This is intended to be used to send "static" messages from interrupt context.
|
||||
*
|
||||
* @param function the function to call
|
||||
* @param ctx parameter passed to function
|
||||
* @return a struct pointer to pass to tcpip_trycallback().
|
||||
*/
|
||||
struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
|
||||
{
|
||||
struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
msg->type = TCPIP_MSG_CALLBACK_STATIC;
|
||||
msg->msg.cb.function = function;
|
||||
msg->msg.cb.ctx = ctx;
|
||||
return (struct tcpip_callback_msg*)msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a callback message allocated by tcpip_callbackmsg_new().
|
||||
*
|
||||
* @param msg the message to free
|
||||
*/
|
||||
void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
|
||||
{
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to post a callback-message to the tcpip_thread mbox
|
||||
* This is intended to be used to send "static" messages from interrupt context.
|
||||
*
|
||||
* @param msg pointer to the message to post
|
||||
* @return sys_mbox_trypost() return code
|
||||
*/
|
||||
err_t
|
||||
tcpip_trycallback(struct tcpip_callback_msg* msg)
|
||||
{
|
||||
if (!sys_mbox_valid(&mbox)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
return sys_mbox_trypost(&mbox, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this module:
|
||||
* - initialize all sub modules
|
||||
|
||||
172
src/core/dhcp.c
172
src/core/dhcp.c
@@ -76,7 +76,6 @@
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/dhcp.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/dns.h"
|
||||
@@ -84,6 +83,13 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using
|
||||
* LWIP_RAND() (this overrides DHCP_GLOBAL_XID)
|
||||
*/
|
||||
#ifndef DHCP_CREATE_RAND_XID
|
||||
#define DHCP_CREATE_RAND_XID 1
|
||||
#endif
|
||||
|
||||
/** 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"
|
||||
@@ -115,7 +121,7 @@
|
||||
#define DHCP_OPTION_IDX_T2 5
|
||||
#define DHCP_OPTION_IDX_SUBNET_MASK 6
|
||||
#define DHCP_OPTION_IDX_ROUTER 7
|
||||
#define DHCP_OPTION_IDX_DNS_SERVER 8
|
||||
#define DHCP_OPTION_IDX_DNS_SERVER 8
|
||||
#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
|
||||
|
||||
/** Holds the decoded option values, only valid while in dhcp_recv.
|
||||
@@ -126,6 +132,11 @@ u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX];
|
||||
@todo: move this into struct dhcp? */
|
||||
u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];
|
||||
|
||||
#ifdef DHCP_GLOBAL_XID
|
||||
static u32_t xid;
|
||||
static u8_t xid_initialised;
|
||||
#endif /* DHCP_GLOBAL_XID */
|
||||
|
||||
#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0)
|
||||
#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1)
|
||||
#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0)
|
||||
@@ -164,6 +175,9 @@ static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
|
||||
static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
|
||||
static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
|
||||
static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif);
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
/* always add the DHCP options trailer to end and pad */
|
||||
static void dhcp_option_trailer(struct dhcp *dhcp);
|
||||
|
||||
@@ -295,17 +309,7 @@ dhcp_select(struct netif *netif)
|
||||
dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
if (netif->hostname != NULL) {
|
||||
const char *p = (const char*)netif->hostname;
|
||||
u8_t namelen = (u8_t)strlen(p);
|
||||
if (namelen > 0) {
|
||||
LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
|
||||
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
|
||||
while (*p) {
|
||||
dhcp_option_byte(dhcp, *p++);
|
||||
}
|
||||
}
|
||||
}
|
||||
dhcp_option_hostname(dhcp, netif);
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
dhcp_option_trailer(dhcp);
|
||||
@@ -676,7 +680,7 @@ dhcp_start(struct netif *netif)
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
dhcp->pcb->so_options |= SOF_BROADCAST;
|
||||
ip_set_option(dhcp->pcb, 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);
|
||||
@@ -726,7 +730,7 @@ dhcp_inform(struct netif *netif)
|
||||
return;
|
||||
}
|
||||
dhcp.pcb = pcb;
|
||||
dhcp.pcb->so_options |= SOF_BROADCAST;
|
||||
ip_set_option(dhcp.pcb, SOF_BROADCAST);
|
||||
udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
|
||||
}
|
||||
@@ -965,11 +969,11 @@ dhcp_bind(struct netif *netif)
|
||||
/* subnet mask not given, choose a safe subnet mask given the network class */
|
||||
u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr);
|
||||
if (first_octet <= 127) {
|
||||
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000));
|
||||
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL));
|
||||
} else if (first_octet >= 192) {
|
||||
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00));
|
||||
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL));
|
||||
} else {
|
||||
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000));
|
||||
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -979,7 +983,7 @@ dhcp_bind(struct netif *netif)
|
||||
/* copy network address */
|
||||
ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask);
|
||||
/* use first host address on network as gateway */
|
||||
ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001));
|
||||
ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL));
|
||||
}
|
||||
|
||||
#if LWIP_DHCP_AUTOIP_COOP
|
||||
@@ -1024,20 +1028,6 @@ dhcp_renew(struct netif *netif)
|
||||
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
||||
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
if (netif->hostname != NULL) {
|
||||
const char *p = (const char*)netif->hostname;
|
||||
u8_t namelen = (u8_t)strlen(p);
|
||||
if (namelen > 0) {
|
||||
LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
|
||||
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
|
||||
while (*p) {
|
||||
dhcp_option_byte(dhcp, *p++);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
#if 0
|
||||
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
|
||||
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
|
||||
@@ -1047,6 +1037,11 @@ dhcp_renew(struct netif *netif)
|
||||
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
|
||||
dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
|
||||
#endif
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
dhcp_option_hostname(dhcp, netif);
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
/* append DHCP message trailer */
|
||||
dhcp_option_trailer(dhcp);
|
||||
|
||||
@@ -1088,17 +1083,7 @@ dhcp_rebind(struct netif *netif)
|
||||
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
if (netif->hostname != NULL) {
|
||||
const char *p = (const char*)netif->hostname;
|
||||
u8_t namelen = (u8_t)strlen(p);
|
||||
if (namelen > 0) {
|
||||
LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
|
||||
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
|
||||
while (*p) {
|
||||
dhcp_option_byte(dhcp, *p++);
|
||||
}
|
||||
}
|
||||
}
|
||||
dhcp_option_hostname(dhcp, netif);
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
#if 0
|
||||
@@ -1310,6 +1295,29 @@ dhcp_option_long(struct dhcp *dhcp, u32_t value)
|
||||
dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
static void
|
||||
dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif)
|
||||
{
|
||||
if (netif->hostname != NULL) {
|
||||
size_t namelen = strlen(netif->hostname);
|
||||
if (namelen > 0) {
|
||||
u8_t len;
|
||||
const char *p = netif->hostname;
|
||||
/* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME
|
||||
and 1 byte for trailer) */
|
||||
size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3;
|
||||
LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available);
|
||||
len = LWIP_MIN(namelen, available);
|
||||
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len);
|
||||
while (len--) {
|
||||
dhcp_option_byte(dhcp, *p++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
/**
|
||||
* Extract the DHCP message and the DHCP options.
|
||||
*
|
||||
@@ -1387,44 +1395,44 @@ again:
|
||||
offset--;
|
||||
break;
|
||||
case(DHCP_OPTION_SUBNET_MASK):
|
||||
LWIP_ASSERT("len == 4", len == 4);
|
||||
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;
|
||||
break;
|
||||
case(DHCP_OPTION_ROUTER):
|
||||
decode_len = 4; /* only copy the first given router */
|
||||
LWIP_ASSERT("len >= decode_len", len >= decode_len);
|
||||
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_ROUTER;
|
||||
break;
|
||||
case(DHCP_OPTION_DNS_SERVER):
|
||||
/* special case: there might be more than one server */
|
||||
LWIP_ASSERT("len % 4 == 0", len % 4 == 0);
|
||||
LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;);
|
||||
/* limit number of DNS servers */
|
||||
decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
|
||||
LWIP_ASSERT("len >= decode_len", len >= decode_len);
|
||||
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
|
||||
break;
|
||||
case(DHCP_OPTION_LEASE_TIME):
|
||||
LWIP_ASSERT("len == 4", len == 4);
|
||||
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
|
||||
break;
|
||||
case(DHCP_OPTION_OVERLOAD):
|
||||
LWIP_ASSERT("len == 1", len == 1);
|
||||
LWIP_ERROR("len == 1", len == 1, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_OVERLOAD;
|
||||
break;
|
||||
case(DHCP_OPTION_MESSAGE_TYPE):
|
||||
LWIP_ASSERT("len == 1", len == 1);
|
||||
LWIP_ERROR("len == 1", len == 1, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
|
||||
break;
|
||||
case(DHCP_OPTION_SERVER_ID):
|
||||
LWIP_ASSERT("len == 4", len == 4);
|
||||
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_SERVER_ID;
|
||||
break;
|
||||
case(DHCP_OPTION_T1):
|
||||
LWIP_ASSERT("len == 4", len == 4);
|
||||
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_T1;
|
||||
break;
|
||||
case(DHCP_OPTION_T2):
|
||||
LWIP_ASSERT("len == 4", len == 4);
|
||||
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
||||
decode_idx = DHCP_OPTION_IDX_T2;
|
||||
break;
|
||||
default:
|
||||
@@ -1438,26 +1446,27 @@ again:
|
||||
u16_t copy_len;
|
||||
decode_next:
|
||||
LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
|
||||
LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx));
|
||||
copy_len = LWIP_MIN(decode_len, 4);
|
||||
pbuf_copy_partial(q, &value, copy_len, val_offset);
|
||||
if (decode_len > 4) {
|
||||
/* decode more than one u32_t */
|
||||
LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0);
|
||||
if (!dhcp_option_given(dhcp, decode_idx)) {
|
||||
copy_len = LWIP_MIN(decode_len, 4);
|
||||
pbuf_copy_partial(q, &value, copy_len, val_offset);
|
||||
if (decode_len > 4) {
|
||||
/* decode more than one u32_t */
|
||||
LWIP_ERROR("decode_len % 4 == 0", decode_len % 4 == 0, return ERR_VAL;);
|
||||
dhcp_got_option(dhcp, decode_idx);
|
||||
dhcp_set_option_value(dhcp, decode_idx, htonl(value));
|
||||
decode_len -= 4;
|
||||
val_offset += 4;
|
||||
decode_idx++;
|
||||
goto decode_next;
|
||||
} else if (decode_len == 4) {
|
||||
value = ntohl(value);
|
||||
} else {
|
||||
LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;);
|
||||
value = ((u8_t*)&value)[0];
|
||||
}
|
||||
dhcp_got_option(dhcp, decode_idx);
|
||||
dhcp_set_option_value(dhcp, decode_idx, htonl(value));
|
||||
decode_len -= 4;
|
||||
val_offset += 4;
|
||||
decode_idx++;
|
||||
goto decode_next;
|
||||
} else if (decode_len == 4) {
|
||||
value = ntohl(value);
|
||||
} else {
|
||||
LWIP_ASSERT("invalid decode_len", decode_len == 1);
|
||||
value = ((u8_t*)&value)[0];
|
||||
dhcp_set_option_value(dhcp, decode_idx, value);
|
||||
}
|
||||
dhcp_got_option(dhcp, decode_idx);
|
||||
dhcp_set_option_value(dhcp, decode_idx, value);
|
||||
}
|
||||
if (offset >= q->len) {
|
||||
offset -= q->len;
|
||||
@@ -1626,10 +1635,12 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
|
||||
* 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
|
||||
#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
|
||||
static u32_t xid;
|
||||
static u8_t xid_initialised = 0;
|
||||
#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
|
||||
static u32_t xid = 0xABCD0000;
|
||||
#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
|
||||
#else
|
||||
if (!xid_initialised) {
|
||||
xid = DHCP_GLOBAL_XID;
|
||||
xid_initialised = !xid_initialised;
|
||||
@@ -1650,7 +1661,11 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
|
||||
|
||||
/* reuse transaction identifier in retransmissions */
|
||||
if (dhcp->tries == 0) {
|
||||
xid++;
|
||||
#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
|
||||
xid = LWIP_RAND();
|
||||
#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
|
||||
xid++;
|
||||
#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
|
||||
}
|
||||
dhcp->xid = xid;
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
|
||||
@@ -1734,9 +1749,8 @@ dhcp_option_trailer(struct dhcp *dhcp)
|
||||
LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
|
||||
dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
|
||||
/* packet is too small, or not 4 byte aligned? */
|
||||
while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
|
||||
/* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
|
||||
LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
|
||||
while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) &&
|
||||
(dhcp->options_out_len < DHCP_OPTIONS_LEN)) {
|
||||
/* add a fill/padding byte */
|
||||
dhcp->msg_out->options[dhcp->options_out_len++] = 0;
|
||||
}
|
||||
|
||||
146
src/core/init.c
146
src/core/init.c
@@ -56,6 +56,7 @@
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/timers.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
/* Compile-time sanity checks for configuration errors.
|
||||
* These can be done independently of LWIP_DEBUG, without penalty.
|
||||
@@ -66,9 +67,6 @@
|
||||
#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
|
||||
#if (!LWIP_UDP && LWIP_UDPLITE)
|
||||
#error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
@@ -87,6 +85,7 @@
|
||||
#if (!LWIP_UDP && LWIP_DNS)
|
||||
#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */
|
||||
#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
|
||||
#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
|
||||
#endif
|
||||
@@ -99,6 +98,20 @@
|
||||
#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
|
||||
#error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
|
||||
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
|
||||
#endif
|
||||
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
|
||||
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
|
||||
#endif
|
||||
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
|
||||
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
|
||||
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
|
||||
#endif
|
||||
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
|
||||
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
|
||||
#endif
|
||||
#endif /* !MEMP_MEM_MALLOC */
|
||||
#if (LWIP_TCP && (TCP_WND > 0xffff))
|
||||
#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
|
||||
#endif
|
||||
@@ -114,18 +127,12 @@
|
||||
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
|
||||
#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
|
||||
#endif
|
||||
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
|
||||
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_NETIF_API && (NO_SYS==1))
|
||||
#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
|
||||
#endif
|
||||
#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
|
||||
#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
|
||||
#endif
|
||||
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
|
||||
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_NETCONN && LWIP_SOCKET)
|
||||
#error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
|
||||
#endif
|
||||
@@ -147,13 +154,6 @@
|
||||
#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
|
||||
#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
|
||||
#endif
|
||||
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
|
||||
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
|
||||
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
|
||||
#endif
|
||||
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
|
||||
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
|
||||
#endif
|
||||
#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)
|
||||
#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"
|
||||
#endif
|
||||
@@ -163,9 +163,6 @@
|
||||
#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
|
||||
@@ -187,6 +184,32 @@
|
||||
#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
|
||||
#error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
|
||||
#endif
|
||||
#if LWIP_NETCONN && LWIP_TCP
|
||||
#if NETCONN_COPY != TCP_WRITE_FLAG_COPY
|
||||
#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY"
|
||||
#endif
|
||||
#if NETCONN_MORE != TCP_WRITE_FLAG_MORE
|
||||
#error "NETCONN_MORE != TCP_WRITE_FLAG_MORE"
|
||||
#endif
|
||||
#endif /* LWIP_NETCONN && LWIP_TCP */
|
||||
#if LWIP_SOCKET
|
||||
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
|
||||
#if SO_ACCEPTCONN != SOF_ACCEPTCONN
|
||||
#error "SO_ACCEPTCONN != SOF_ACCEPTCONN"
|
||||
#endif
|
||||
#if SO_REUSEADDR != SOF_REUSEADDR
|
||||
#error "WARNING: SO_REUSEADDR != SOF_REUSEADDR"
|
||||
#endif
|
||||
#if SO_KEEPALIVE != SOF_KEEPALIVE
|
||||
#error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE"
|
||||
#endif
|
||||
#if SO_BROADCAST != SOF_BROADCAST
|
||||
#error "WARNING: SO_BROADCAST != SOF_BROADCAST"
|
||||
#endif
|
||||
#if SO_LINGER != SOF_LINGER
|
||||
#error "WARNING: SO_LINGER != SOF_LINGER"
|
||||
#endif
|
||||
#endif /* LWIP_SOCKET */
|
||||
|
||||
|
||||
/* Compile-time checks for deprecated options.
|
||||
@@ -210,48 +233,54 @@
|
||||
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
|
||||
#endif
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
static void
|
||||
lwip_sanity_check(void)
|
||||
{
|
||||
/* Warnings */
|
||||
#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS
|
||||
#define LWIP_DISABLE_TCP_SANITY_CHECKS 0
|
||||
#endif
|
||||
#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS
|
||||
#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0
|
||||
#endif
|
||||
|
||||
/* MEMP sanity checks */
|
||||
#if !LWIP_DISABLE_MEMP_SANITY_CHECKS
|
||||
#if LWIP_NETCONN
|
||||
if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));
|
||||
#if MEMP_MEM_MALLOC
|
||||
#if !MEMP_NUM_NETCONN && LWIP_SOCKET
|
||||
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!"
|
||||
#endif
|
||||
#else /* MEMP_MEM_MALLOC */
|
||||
#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)
|
||||
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
#endif /* LWIP_NETCONN */
|
||||
#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */
|
||||
|
||||
/* TCP sanity checks */
|
||||
#if !LWIP_DISABLE_TCP_SANITY_CHECKS
|
||||
#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)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n"));
|
||||
if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n"));
|
||||
if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
|
||||
if (TCP_WND < TCP_MSS)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
|
||||
#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
|
||||
#error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_SND_BUF < (2 * TCP_MSS)
|
||||
#error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS))
|
||||
#error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_SNDLOWAT >= TCP_SND_BUF
|
||||
#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN
|
||||
#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))))
|
||||
#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_WND < TCP_MSS
|
||||
#error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_SOCKET
|
||||
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
|
||||
if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
|
||||
if (SO_REUSEADDR != SOF_REUSEADDR)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
|
||||
if (SO_KEEPALIVE != SOF_KEEPALIVE)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
|
||||
if (SO_BROADCAST != SOF_BROADCAST)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
|
||||
if (SO_LINGER != SOF_LINGER)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
|
||||
#endif /* LWIP_SOCKET */
|
||||
}
|
||||
#else /* LWIP_DEBUG */
|
||||
#define lwip_sanity_check()
|
||||
#endif /* LWIP_DEBUG */
|
||||
#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */
|
||||
|
||||
/**
|
||||
* Perform Sanity check of user-configurable values, and initialize all modules.
|
||||
@@ -259,9 +288,6 @@ lwip_sanity_check(void)
|
||||
void
|
||||
lwip_init(void)
|
||||
{
|
||||
/* Sanity check user-configurable values */
|
||||
lwip_sanity_check();
|
||||
|
||||
/* Modules initialization */
|
||||
stats_init();
|
||||
#if !NO_SYS
|
||||
|
||||
@@ -122,14 +122,6 @@ 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, ("autoip_init()\n"));
|
||||
}
|
||||
|
||||
/** Set a statically allocated struct autoip to work with.
|
||||
* Using this prevents autoip_start to allocate it using mem_malloc.
|
||||
@@ -170,8 +162,8 @@ autoip_handle_arp_conflict(struct netif *netif)
|
||||
/* Somehow detect if we are defending or retreating */
|
||||
unsigned char defend = 1; /* tbd */
|
||||
|
||||
if(defend) {
|
||||
if(netif->autoip->lastconflict > 0) {
|
||||
if (defend) {
|
||||
if (netif->autoip->lastconflict > 0) {
|
||||
/* retreat, there was a conflicting ARP in the last
|
||||
* DEFEND_INTERVAL seconds
|
||||
*/
|
||||
@@ -295,7 +287,7 @@ autoip_start(struct netif *netif)
|
||||
struct autoip *autoip = netif->autoip;
|
||||
err_t result = ERR_OK;
|
||||
|
||||
if(netif_is_up(netif)) {
|
||||
if (netif_is_up(netif)) {
|
||||
netif_set_down(netif);
|
||||
}
|
||||
|
||||
@@ -309,12 +301,12 @@ autoip_start(struct netif *netif)
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
|
||||
netif->name[1], (u16_t)netif->num));
|
||||
if(autoip == NULL) {
|
||||
if (autoip == NULL) {
|
||||
/* no AutoIP client attached yet? */
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_start(): starting new AUTOIP client\n"));
|
||||
autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
|
||||
if(autoip == NULL) {
|
||||
if (autoip == NULL) {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_start(): could not allocate autoip\n"));
|
||||
return ERR_MEM;
|
||||
@@ -360,7 +352,7 @@ autoip_start_probing(struct netif *netif)
|
||||
* accquiring and probing address
|
||||
* compliant to RFC 3927 Section 2.2.1
|
||||
*/
|
||||
if(autoip->tried_llipaddr > MAX_CONFLICTS) {
|
||||
if (autoip->tried_llipaddr > MAX_CONFLICTS) {
|
||||
autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
@@ -404,7 +396,7 @@ autoip_tmr()
|
||||
while (netif != NULL) {
|
||||
/* only act on AutoIP configured interfaces */
|
||||
if (netif->autoip != NULL) {
|
||||
if(netif->autoip->lastconflict > 0) {
|
||||
if (netif->autoip->lastconflict > 0) {
|
||||
netif->autoip->lastconflict--;
|
||||
}
|
||||
|
||||
@@ -414,10 +406,10 @@ autoip_tmr()
|
||||
|
||||
switch(netif->autoip->state) {
|
||||
case AUTOIP_STATE_PROBING:
|
||||
if(netif->autoip->ttw > 0) {
|
||||
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;
|
||||
@@ -439,10 +431,10 @@ autoip_tmr()
|
||||
break;
|
||||
|
||||
case AUTOIP_STATE_ANNOUNCING:
|
||||
if(netif->autoip->ttw > 0) {
|
||||
if (netif->autoip->ttw > 0) {
|
||||
netif->autoip->ttw--;
|
||||
} else {
|
||||
if(netif->autoip->sent_num == 0) {
|
||||
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.
|
||||
*
|
||||
@@ -458,7 +450,7 @@ autoip_tmr()
|
||||
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
netif->autoip->sent_num++;
|
||||
|
||||
if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
|
||||
if (netif->autoip->sent_num >= ANNOUNCE_NUM) {
|
||||
netif->autoip->state = AUTOIP_STATE_BOUND;
|
||||
netif->autoip->sent_num = 0;
|
||||
netif->autoip->ttw = 0;
|
||||
|
||||
@@ -190,12 +190,16 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
ip_addr_copy(iphdr->src, *ip_current_dest_addr());
|
||||
ip_addr_copy(iphdr->dest, *ip_current_src_addr());
|
||||
ICMPH_TYPE_SET(iecho, ICMP_ER);
|
||||
#if CHECKSUM_GEN_ICMP
|
||||
/* adjust the checksum */
|
||||
if (iecho->chksum >= PP_HTONS(0xffff - (ICMP_ECHO << 8))) {
|
||||
if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
|
||||
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
|
||||
} else {
|
||||
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
|
||||
}
|
||||
#else /* CHECKSUM_GEN_ICMP */
|
||||
iecho->chksum = 0;
|
||||
#endif /* CHECKSUM_GEN_ICMP */
|
||||
|
||||
/* Set the correct TTL and recalculate the header checksum. */
|
||||
IPH_TTL_SET(iphdr, ICMP_TTL);
|
||||
|
||||
@@ -100,7 +100,7 @@ Steve Reynolds
|
||||
*/
|
||||
#define IGMP_TTL 1
|
||||
#define IGMP_MINLEN 8
|
||||
#define ROUTER_ALERT 0x9404
|
||||
#define ROUTER_ALERT 0x9404U
|
||||
#define ROUTER_ALERTLEN 4
|
||||
|
||||
/*
|
||||
@@ -139,7 +139,6 @@ static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
|
||||
static err_t igmp_remove_group(struct igmp_group *group);
|
||||
static void igmp_timeout( struct igmp_group *group);
|
||||
static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
|
||||
static void igmp_stop_timer(struct igmp_group *group);
|
||||
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
|
||||
static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
|
||||
static void igmp_send(struct igmp_group *group, u8_t type);
|
||||
@@ -706,17 +705,6 @@ igmp_start_timer(struct igmp_group *group, u8_t max_time)
|
||||
group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a timer for an igmp_group
|
||||
*
|
||||
* @param group the igmp_group for which to stop the timer
|
||||
*/
|
||||
static void
|
||||
igmp_stop_timer(struct igmp_group *group)
|
||||
{
|
||||
group->timer = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delaying membership report for a group if necessary
|
||||
*
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
|| (LWIP_IP_ACCEPT_UDP_PORT(port)))
|
||||
#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
|
||||
/* accept custom port only */
|
||||
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
|
||||
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port))
|
||||
#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
|
||||
/* accept DHCP client port only */
|
||||
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
|
||||
@@ -125,8 +125,15 @@ ip_route(ip_addr_t *dest)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
#ifdef LWIP_HOOK_IP4_ROUTE
|
||||
netif = LWIP_HOOK_IP4_ROUTE(dest);
|
||||
if (netif != NULL) {
|
||||
return netif;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* iterate through netifs */
|
||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
/* network mask matches? */
|
||||
if (netif_is_up(netif)) {
|
||||
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||
@@ -147,6 +154,41 @@ ip_route(ip_addr_t *dest)
|
||||
}
|
||||
|
||||
#if IP_FORWARD
|
||||
/**
|
||||
* Determine whether an IP address is in a reserved set of addresses
|
||||
* that may not be forwarded, or whether datagrams to that destination
|
||||
* may be forwarded.
|
||||
* @param p the packet to forward
|
||||
* @param dest the destination IP address
|
||||
* @return 1: can forward 0: discard
|
||||
*/
|
||||
static int
|
||||
ip_canforward(struct pbuf *p)
|
||||
{
|
||||
u32_t addr = ip4_addr_get_u32(ip_current_dest_addr());
|
||||
|
||||
if (p->flags & PBUF_FLAG_LLBCAST) {
|
||||
/* don't route link-layer broadcasts */
|
||||
return 0;
|
||||
}
|
||||
if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) {
|
||||
/* don't route link-layer multicasts unless the destination address is an IP
|
||||
multicast address */
|
||||
return 0;
|
||||
}
|
||||
if (IP_EXPERIMENTAL(addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (IP_CLASSA(addr)) {
|
||||
u32_t net = addr & IP_CLASSA_NET;
|
||||
if ((net == 0) || (net == (IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) {
|
||||
/* don't route loopback packets */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards an IP packet. It finds an appropriate route for the
|
||||
* packet, decrements the TTL value of the packet, adjusts the
|
||||
@@ -163,6 +205,10 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||
|
||||
PERF_START;
|
||||
|
||||
if (!ip_canforward(p)) {
|
||||
goto return_noroute;
|
||||
}
|
||||
|
||||
/* RFC3927 2.7: do not forward link-local addresses */
|
||||
if (ip_addr_islinklocal(¤t_iphdr_dest)) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
@@ -179,12 +225,14 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||
ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest)));
|
||||
goto return_noroute;
|
||||
}
|
||||
#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF
|
||||
/* Do not forward packets onto the same network interface on which
|
||||
* they arrived. */
|
||||
if (netif == inp) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
|
||||
goto return_noroute;
|
||||
}
|
||||
#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */
|
||||
|
||||
/* decrement TTL */
|
||||
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
|
||||
@@ -201,7 +249,7 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||
}
|
||||
|
||||
/* Incrementally update the IP checksum. */
|
||||
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) {
|
||||
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
|
||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
|
||||
} else {
|
||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
|
||||
@@ -264,6 +312,13 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#ifdef LWIP_HOOK_IP4_INPUT
|
||||
if (LWIP_HOOK_IP4_INPUT(p, inp)) {
|
||||
/* the packet has been eaten */
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* obtain IP header length in number of 32-bit words */
|
||||
iphdr_hlen = IPH_HL(iphdr);
|
||||
/* calculate IP header length in bytes */
|
||||
@@ -488,7 +543,6 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
if (raw_input(p, inp) == 0)
|
||||
#endif /* LWIP_RAW */
|
||||
{
|
||||
|
||||
switch (IPH_PROTO(iphdr)) {
|
||||
#if LWIP_UDP
|
||||
case IP_PROTO_UDP:
|
||||
@@ -657,9 +711,10 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
|
||||
IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
|
||||
IPH_VHL_SET(iphdr, 4, ip_hlen / 4);
|
||||
IPH_TOS_SET(iphdr, tos);
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
chk_sum += iphdr->_v_hl_tos;
|
||||
chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl);
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
@@ -801,9 +856,9 @@ ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
netif->addr_hint = addr_hint;
|
||||
NETIF_SET_HWADDRHINT(netif, addr_hint);
|
||||
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||
netif->addr_hint = NULL;
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -817,9 +872,6 @@ void
|
||||
ip_debug_print(struct pbuf *p)
|
||||
{
|
||||
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
|
||||
u8_t *payload;
|
||||
|
||||
payload = (u8_t *)iphdr + IP_HLEN;
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
|
||||
@@ -93,7 +93,7 @@ ip4_addr_netmask_valid(u32_t netmask)
|
||||
u32_t nm_hostorder = lwip_htonl(netmask);
|
||||
|
||||
/* first, check for the first zero */
|
||||
for (mask = 1U << 31 ; mask != 0; mask >>= 1) {
|
||||
for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
|
||||
if ((nm_hostorder & mask) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -341,9 +341,9 @@ ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
netif->addr_hint = addr_hint;
|
||||
LWIP_NETIF_HWADDRHINT(netif, addr_hint);
|
||||
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||
netif->addr_hint = NULL;
|
||||
LWIP_NETIF_HWADDRHINT(netif, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -78,9 +78,10 @@
|
||||
void *
|
||||
mem_malloc(mem_size_t size)
|
||||
{
|
||||
void *ret;
|
||||
struct memp_malloc_helper *element;
|
||||
memp_t poolnr;
|
||||
mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
|
||||
mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
|
||||
|
||||
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
|
||||
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||
@@ -113,9 +114,9 @@ again:
|
||||
/* save the pool number this element came from */
|
||||
element->poolnr = poolnr;
|
||||
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
|
||||
element++;
|
||||
ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
|
||||
|
||||
return element;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,13 +129,13 @@ again:
|
||||
void
|
||||
mem_free(void *rmem)
|
||||
{
|
||||
struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
|
||||
struct memp_malloc_helper *hmem;
|
||||
|
||||
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
|
||||
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
|
||||
|
||||
/* get the original struct memp_malloc_helper */
|
||||
hmem--;
|
||||
hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)));
|
||||
|
||||
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
|
||||
LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
|
||||
@@ -190,7 +191,9 @@ static struct mem *ram_end;
|
||||
static struct mem *lfree;
|
||||
|
||||
/** concurrent access protection */
|
||||
#if !NO_SYS
|
||||
static sys_mutex_t mem_mutex;
|
||||
#endif
|
||||
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
|
||||
@@ -518,7 +521,7 @@ mem_malloc(mem_size_t size)
|
||||
sys_mutex_lock(&mem_mutex);
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
/* run as long as a mem_free disturbed mem_malloc */
|
||||
/* run as long as a mem_free disturbed mem_malloc or mem_trim */
|
||||
do {
|
||||
local_mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
@@ -532,12 +535,14 @@ mem_malloc(mem_size_t size)
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 0;
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
/* allow mem_free to run */
|
||||
/* allow mem_free or mem_trim to run */
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
if (mem_free_count != 0) {
|
||||
local_mem_free_count = mem_free_count;
|
||||
/* If mem_free or mem_trim have run, we have to restart since they
|
||||
could have altered our current struct mem. */
|
||||
local_mem_free_count = 1;
|
||||
break;
|
||||
}
|
||||
mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
if ((!mem->used) &&
|
||||
@@ -581,15 +586,27 @@ mem_malloc(mem_size_t size)
|
||||
mem->used = 1;
|
||||
MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
|
||||
}
|
||||
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_malloc_adjust_lfree:
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
if (mem == lfree) {
|
||||
struct mem *cur = lfree;
|
||||
/* Find next free block after mem and update lowest free pointer */
|
||||
while (lfree->used && lfree != ram_end) {
|
||||
while (cur->used && cur != ram_end) {
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 0;
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
/* prevent high interrupt latency... */
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
lfree = (struct mem *)(void *)&ram[lfree->next];
|
||||
if (mem_free_count != 0) {
|
||||
/* If mem_free or mem_trim have run, we have to restart since they
|
||||
could have altered our current struct mem or lfree. */
|
||||
goto mem_malloc_adjust_lfree;
|
||||
}
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
cur = (struct mem *)(void *)&ram[cur->next];
|
||||
}
|
||||
lfree = cur;
|
||||
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
|
||||
}
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
struct netif *netif_list;
|
||||
struct netif *netif_default;
|
||||
|
||||
static u8_t netif_num;
|
||||
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
static struct netif loop_netif;
|
||||
|
||||
@@ -137,7 +139,6 @@ struct netif *
|
||||
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
|
||||
{
|
||||
static u8_t netifnum = 0;
|
||||
|
||||
LWIP_ASSERT("No init function given", init != NULL);
|
||||
|
||||
@@ -170,11 +171,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
|
||||
/* remember netif specific state information data */
|
||||
netif->state = state;
|
||||
netif->num = netifnum++;
|
||||
netif->num = netif_num++;
|
||||
netif->input = input;
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
|
||||
netif->loop_cnt_current = 0;
|
||||
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
|
||||
@@ -273,6 +272,11 @@ netif_remove(struct netif *netif)
|
||||
/* reset default netif */
|
||||
netif_set_default(NULL);
|
||||
}
|
||||
#if LWIP_NETIF_REMOVE_CALLBACK
|
||||
if (netif->remove_callback) {
|
||||
netif->remove_callback(netif);
|
||||
}
|
||||
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
|
||||
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
|
||||
}
|
||||
|
||||
@@ -325,7 +329,7 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
|
||||
struct tcp_pcb_listen *lpcb;
|
||||
|
||||
/* address is actually being changed? */
|
||||
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
|
||||
if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
|
||||
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
|
||||
pcb = tcp_active_pcbs;
|
||||
@@ -491,6 +495,11 @@ void netif_set_down(struct netif *netif)
|
||||
snmp_get_sysuptime(&netif->ts);
|
||||
#endif
|
||||
|
||||
#if LWIP_ARP
|
||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||
etharp_cleanup_netif(netif);
|
||||
}
|
||||
#endif /* LWIP_ARP */
|
||||
NETIF_STATUS_CALLBACK(netif);
|
||||
}
|
||||
}
|
||||
@@ -507,6 +516,19 @@ void netif_set_status_callback(struct netif *netif, netif_status_callback_fn sta
|
||||
}
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
|
||||
#if LWIP_NETIF_REMOVE_CALLBACK
|
||||
/**
|
||||
* Set callback to be called when the interface has been removed
|
||||
*/
|
||||
void
|
||||
netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback)
|
||||
{
|
||||
if (netif) {
|
||||
netif->remove_callback = remove_callback;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
|
||||
|
||||
/**
|
||||
* Called by a driver when its link goes up
|
||||
*/
|
||||
|
||||
111
src/core/pbuf.c
111
src/core/pbuf.c
@@ -70,7 +70,7 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "arch/perf.h"
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
#if LWIP_TCP && TCP_QUEUE_OOSEQ
|
||||
#include "lwip/tcp_impl.h"
|
||||
#endif
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
@@ -84,18 +84,25 @@
|
||||
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
|
||||
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
|
||||
|
||||
#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
|
||||
#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ
|
||||
#define PBUF_POOL_IS_EMPTY()
|
||||
#else /* !LWIP_TCP || !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 */
|
||||
#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
|
||||
|
||||
#if PBUF_POOL_FREE_OOSEQ
|
||||
#if !NO_SYS
|
||||
#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
|
||||
#include "lwip/tcpip.h"
|
||||
#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \
|
||||
if(tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \
|
||||
SYS_ARCH_PROTECT(old_level); \
|
||||
pbuf_free_ooseq_pending = 0; \
|
||||
SYS_ARCH_UNPROTECT(old_level); \
|
||||
} } while(0)
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
volatile u8_t pbuf_free_ooseq_pending;
|
||||
#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
|
||||
@@ -104,15 +111,17 @@ static u8_t pbuf_free_ooseq_queued;
|
||||
* 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)
|
||||
#if !NO_SYS
|
||||
static
|
||||
#endif /* !NO_SYS */
|
||||
void
|
||||
pbuf_free_ooseq(void)
|
||||
{
|
||||
struct tcp_pcb* pcb;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
pbuf_free_ooseq_queued = 0;
|
||||
pbuf_free_ooseq_pending = 0;
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
|
||||
for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
|
||||
@@ -126,29 +135,42 @@ pbuf_free_ooseq(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
#if !NO_SYS
|
||||
/**
|
||||
* Just a callback function for tcpip_timeout() that calls pbuf_free_ooseq().
|
||||
*/
|
||||
static void
|
||||
pbuf_free_ooseq_callback(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
pbuf_free_ooseq();
|
||||
}
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
/** Queue a call to pbuf_free_ooseq if not already queued. */
|
||||
static void
|
||||
pbuf_pool_is_empty(void)
|
||||
{
|
||||
#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
pbuf_free_ooseq_pending = 1;
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
|
||||
u8_t queued;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
queued = pbuf_free_ooseq_queued;
|
||||
pbuf_free_ooseq_queued = 1;
|
||||
queued = pbuf_free_ooseq_pending;
|
||||
pbuf_free_ooseq_pending = 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);
|
||||
}
|
||||
PBUF_POOL_FREE_OOSEQ_QUEUE_CALL();
|
||||
}
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
|
||||
}
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||
#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
|
||||
#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
|
||||
|
||||
/**
|
||||
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
|
||||
@@ -190,21 +212,21 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
|
||||
|
||||
/* determine header offset */
|
||||
offset = 0;
|
||||
switch (layer) {
|
||||
case PBUF_TRANSPORT:
|
||||
/* add room for transport (often TCP) layer header */
|
||||
offset += PBUF_TRANSPORT_HLEN;
|
||||
/* FALLTHROUGH */
|
||||
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
|
||||
break;
|
||||
case PBUF_IP:
|
||||
/* add room for IP layer header */
|
||||
offset += PBUF_IP_HLEN;
|
||||
/* FALLTHROUGH */
|
||||
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
|
||||
break;
|
||||
case PBUF_LINK:
|
||||
/* add room for link layer header */
|
||||
offset += PBUF_LINK_HLEN;
|
||||
offset = PBUF_LINK_HLEN;
|
||||
break;
|
||||
case PBUF_RAW:
|
||||
offset = 0;
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
|
||||
@@ -336,7 +358,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
* @param p pointer to the custom pbuf to initialize (already allocated)
|
||||
* @param payload_mem pointer to the buffer that is used for payload and headers,
|
||||
* must be at least big enough to hold 'length' plus the header size,
|
||||
* may be NULL if set later
|
||||
* may be NULL if set later.
|
||||
* ATTENTION: The caller is responsible for correct alignment of this buffer!!
|
||||
* @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
|
||||
* big enough to hold 'length' plus the header size
|
||||
*/
|
||||
@@ -348,35 +371,35 @@ pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_cust
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
|
||||
|
||||
/* determine header offset */
|
||||
offset = 0;
|
||||
switch (l) {
|
||||
case PBUF_TRANSPORT:
|
||||
/* add room for transport (often TCP) layer header */
|
||||
offset += PBUF_TRANSPORT_HLEN;
|
||||
/* FALLTHROUGH */
|
||||
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
|
||||
break;
|
||||
case PBUF_IP:
|
||||
/* add room for IP layer header */
|
||||
offset += PBUF_IP_HLEN;
|
||||
/* FALLTHROUGH */
|
||||
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
|
||||
break;
|
||||
case PBUF_LINK:
|
||||
/* add room for link layer header */
|
||||
offset += PBUF_LINK_HLEN;
|
||||
offset = PBUF_LINK_HLEN;
|
||||
break;
|
||||
case PBUF_RAW:
|
||||
offset = 0;
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
|
||||
if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) {
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p->pbuf.next = NULL;
|
||||
if (payload_mem != NULL) {
|
||||
p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
|
||||
p->pbuf.payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset);
|
||||
} else {
|
||||
p->pbuf.payload = NULL;
|
||||
}
|
||||
@@ -840,7 +863,6 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
||||
/* iterate through pbuf chain */
|
||||
do
|
||||
{
|
||||
LWIP_ASSERT("p_to != NULL", p_to != NULL);
|
||||
/* copy one part of the original chain */
|
||||
if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
|
||||
/* complete current p_from fits into current p_to */
|
||||
@@ -853,17 +875,18 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
||||
offset_to += len;
|
||||
offset_from += len;
|
||||
LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
|
||||
if (offset_to == p_to->len) {
|
||||
/* on to next p_to (if any) */
|
||||
offset_to = 0;
|
||||
p_to = p_to->next;
|
||||
}
|
||||
LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
|
||||
if (offset_from >= p_from->len) {
|
||||
/* on to next p_from (if any) */
|
||||
offset_from = 0;
|
||||
p_from = p_from->next;
|
||||
}
|
||||
if (offset_to == p_to->len) {
|
||||
/* on to next p_to (if any) */
|
||||
offset_to = 0;
|
||||
p_to = p_to->next;
|
||||
LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL) , return ERR_ARG;);
|
||||
}
|
||||
|
||||
if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
|
||||
/* don't copy more than one packet! */
|
||||
|
||||
@@ -95,7 +95,7 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||
ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest))) {
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
/* broadcast filter? */
|
||||
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp))
|
||||
if (ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp))
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
{
|
||||
/* receive callback function available? */
|
||||
@@ -245,7 +245,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
|
||||
#if IP_SOF_BROADCAST
|
||||
/* broadcast filter? */
|
||||
if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
|
||||
if (!ip_get_option(pcb, SOF_BROADCAST) && 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) {
|
||||
@@ -263,13 +263,9 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
src_ip = &(pcb->local_ip);
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
|
||||
err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
|
||||
/* did we chain a header earlier? */
|
||||
if (q != p) {
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef SNMP_GET_SYSUPTIME
|
||||
#define SNMP_GET_SYSUPTIME(sysuptime)
|
||||
#define SNMP_GET_SYSUPTIME(sysuptime) (sysuptime = (sys_now() / 10))
|
||||
#endif
|
||||
|
||||
static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
|
||||
|
||||
@@ -90,7 +90,7 @@ snmp_init(void)
|
||||
trap_msg.pcb = snmp1_pcb;
|
||||
|
||||
#ifdef SNMP_PRIVATE_MIB_INIT
|
||||
/* If defined, rhis must be a function-like define to initialize the
|
||||
/* If defined, this must be a function-like define to initialize the
|
||||
* private MIB after the stack has been initialized.
|
||||
* The private MIB can also be initialized in tcpip_callback (or after
|
||||
* the stack is initialized), this define is only for convenience. */
|
||||
@@ -105,13 +105,28 @@ snmp_init(void)
|
||||
static void
|
||||
snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
|
||||
{
|
||||
/* move names back from outvb to invb */
|
||||
int v;
|
||||
struct snmp_varbind *vbi = msg_ps->invb.head;
|
||||
struct snmp_varbind *vbo = msg_ps->outvb.head;
|
||||
for (v=0; v<msg_ps->vb_idx; v++) {
|
||||
vbi->ident_len = vbo->ident_len;
|
||||
vbo->ident_len = 0;
|
||||
vbi->ident = vbo->ident;
|
||||
vbo->ident = NULL;
|
||||
vbi = vbi->next;
|
||||
vbo = vbo->next;
|
||||
}
|
||||
/* free outvb */
|
||||
snmp_varbind_list_free(&msg_ps->outvb);
|
||||
/* we send invb back */
|
||||
msg_ps->outvb = msg_ps->invb;
|
||||
msg_ps->invb.head = NULL;
|
||||
msg_ps->invb.tail = NULL;
|
||||
msg_ps->invb.count = 0;
|
||||
msg_ps->error_status = error;
|
||||
msg_ps->error_index = 1 + msg_ps->vb_idx;
|
||||
/* error index must be 0 for error too big */
|
||||
msg_ps->error_index = (error != SNMP_ES_TOOBIG) ? (1 + msg_ps->vb_idx) : 0;
|
||||
snmp_send_response(msg_ps);
|
||||
snmp_varbind_list_free(&msg_ps->outvb);
|
||||
msg_ps->state = SNMP_MSG_EMPTY;
|
||||
@@ -182,7 +197,6 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
|
||||
/* allocate output varbind */
|
||||
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
|
||||
LWIP_ASSERT("vb != NULL",vb != NULL);
|
||||
if (vb != NULL)
|
||||
{
|
||||
vb->next = NULL;
|
||||
@@ -202,7 +216,6 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
{
|
||||
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
|
||||
vb->value = memp_malloc(MEMP_SNMP_VALUE);
|
||||
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
|
||||
if (vb->value != NULL)
|
||||
{
|
||||
en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
|
||||
@@ -297,7 +310,6 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
|
||||
/* allocate output varbind */
|
||||
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
|
||||
LWIP_ASSERT("vb != NULL",vb != NULL);
|
||||
if (vb != NULL)
|
||||
{
|
||||
vb->next = NULL;
|
||||
@@ -318,7 +330,6 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low",
|
||||
vb->value_len <= SNMP_MAX_VALUE_SIZE);
|
||||
vb->value = memp_malloc(MEMP_SNMP_VALUE);
|
||||
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
|
||||
if (vb->value != NULL)
|
||||
{
|
||||
mn->get_value(&object_def, vb->value_len, vb->value);
|
||||
@@ -331,6 +342,8 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
|
||||
msg_ps->vb_ptr->ident = vb->ident;
|
||||
msg_ps->vb_ptr->ident_len = vb->ident_len;
|
||||
vb->ident = NULL;
|
||||
vb->ident_len = 0;
|
||||
memp_free(MEMP_SNMP_VARBIND, vb);
|
||||
snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
|
||||
}
|
||||
@@ -1305,7 +1318,6 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
|
||||
struct snmp_varbind *vb;
|
||||
|
||||
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
|
||||
LWIP_ASSERT("vb != NULL",vb != NULL);
|
||||
if (vb != NULL)
|
||||
{
|
||||
u8_t i;
|
||||
@@ -1319,9 +1331,9 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
|
||||
LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH);
|
||||
/* allocate array of s32_t for our object identifier */
|
||||
vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE);
|
||||
LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
|
||||
if (vb->ident == NULL)
|
||||
{
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate ident value space\n"));
|
||||
memp_free(MEMP_SNMP_VARBIND, vb);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1343,9 +1355,9 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
|
||||
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
|
||||
/* allocate raw bytes for our object value */
|
||||
vb->value = memp_malloc(MEMP_SNMP_VALUE);
|
||||
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
|
||||
if (vb->value == NULL)
|
||||
{
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate value space\n"));
|
||||
if (vb->ident != NULL)
|
||||
{
|
||||
memp_free(MEMP_SNMP_VALUE, vb->ident);
|
||||
@@ -1360,6 +1372,10 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
|
||||
vb->value = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate varbind space\n"));
|
||||
}
|
||||
return vb;
|
||||
}
|
||||
|
||||
|
||||
@@ -145,14 +145,7 @@ snmp_send_response(struct snmp_msg_pstat *m_stat)
|
||||
|
||||
/* pass 1, size error, encode packet ino the pbuf(s) */
|
||||
ofs = snmp_resp_header_enc(m_stat, p);
|
||||
if (m_stat->error_status == SNMP_ES_TOOBIG)
|
||||
{
|
||||
snmp_varbind_list_enc(&emptyvb, p, ofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
|
||||
}
|
||||
snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
|
||||
|
||||
switch (m_stat->error_status)
|
||||
{
|
||||
|
||||
@@ -69,7 +69,7 @@ void stats_init(void)
|
||||
|
||||
#if LWIP_STATS_DISPLAY
|
||||
void
|
||||
stats_display_proto(struct stats_proto *proto, char *name)
|
||||
stats_display_proto(struct stats_proto *proto, const char *name)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
|
||||
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
|
||||
@@ -110,7 +110,7 @@ stats_display_igmp(struct stats_igmp *igmp)
|
||||
|
||||
#if MEM_STATS || MEMP_STATS
|
||||
void
|
||||
stats_display_mem(struct stats_mem *mem, char *name)
|
||||
stats_display_mem(struct stats_mem *mem, const char *name)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
|
||||
LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
#if !NO_SYS
|
||||
|
||||
#ifndef sys_msleep
|
||||
/**
|
||||
* Sleep for some ms. Timeouts are NOT processed while sleeping.
|
||||
*
|
||||
@@ -62,5 +63,6 @@ sys_msleep(u32_t ms)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* sys_msleep */
|
||||
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
330
src/core/tcp.c
330
src/core/tcp.c
@@ -55,6 +55,22 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef TCP_LOCAL_PORT_RANGE_START
|
||||
/* From http://www.iana.org/assignments/port-numbers:
|
||||
"The Dynamic and/or Private Ports are those from 49152 through 65535" */
|
||||
#define TCP_LOCAL_PORT_RANGE_START 0xc000
|
||||
#define TCP_LOCAL_PORT_RANGE_END 0xffff
|
||||
#define TCP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START)
|
||||
#endif
|
||||
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
#define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl)
|
||||
#define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl)
|
||||
#else /* LWIP_TCP_KEEPALIVE */
|
||||
#define TCP_KEEP_DUR(pcb) TCP_MAXIDLE
|
||||
#define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT
|
||||
#endif /* LWIP_TCP_KEEPALIVE */
|
||||
|
||||
const char * const tcp_state_str[] = {
|
||||
"CLOSED",
|
||||
"LISTEN",
|
||||
@@ -69,6 +85,9 @@ const char * const tcp_state_str[] = {
|
||||
"TIME_WAIT"
|
||||
};
|
||||
|
||||
/* last local TCP port */
|
||||
static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START;
|
||||
|
||||
/* Incremented every coarse grained timer shot (typically every 500 ms). */
|
||||
u32_t tcp_ticks;
|
||||
const u8_t tcp_backoff[13] =
|
||||
@@ -91,19 +110,32 @@ struct tcp_pcb *tcp_tw_pcbs;
|
||||
#define NUM_TCP_PCB_LISTS 4
|
||||
#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3
|
||||
/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */
|
||||
struct tcp_pcb **tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
|
||||
struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
|
||||
&tcp_active_pcbs, &tcp_tw_pcbs};
|
||||
|
||||
/** Only used for temporary storage. */
|
||||
struct tcp_pcb *tcp_tmp_pcb;
|
||||
|
||||
u8_t tcp_active_pcbs_changed;
|
||||
|
||||
/** Timer counter to handle calling slow-timer from tcp_tmr() */
|
||||
static u8_t tcp_timer;
|
||||
static u8_t tcp_timer_ctr;
|
||||
static u16_t tcp_new_port(void);
|
||||
|
||||
/**
|
||||
* Initialize this module.
|
||||
*/
|
||||
void
|
||||
tcp_init(void)
|
||||
{
|
||||
#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND)
|
||||
tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
|
||||
#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Called periodically to dispatch TCP timers.
|
||||
*
|
||||
*/
|
||||
void
|
||||
tcp_tmr(void)
|
||||
@@ -139,7 +171,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
if (rst_on_unacked_data && (pcb->state != LISTEN)) {
|
||||
if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {
|
||||
if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) {
|
||||
/* Not all data received by application, send RST to tell the remote
|
||||
side about this. */
|
||||
@@ -151,14 +183,15 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
|
||||
pcb->local_port, pcb->remote_port);
|
||||
|
||||
tcp_pcb_purge(pcb);
|
||||
|
||||
/* TODO: to which state do we move now? */
|
||||
|
||||
/* move to TIME_WAIT since we close actively */
|
||||
TCP_RMV(&tcp_active_pcbs, pcb);
|
||||
pcb->state = TIME_WAIT;
|
||||
TCP_REG(&tcp_tw_pcbs, pcb);
|
||||
|
||||
TCP_RMV_ACTIVE(pcb);
|
||||
if (pcb->state == ESTABLISHED) {
|
||||
/* move to TIME_WAIT since we close actively */
|
||||
pcb->state = TIME_WAIT;
|
||||
TCP_REG(&tcp_tw_pcbs, pcb);
|
||||
} else {
|
||||
/* CLOSE_WAIT: deallocate the pcb since we already sent a RST for it */
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
@@ -173,7 +206,9 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
|
||||
* is erroneous, but this should never happen as the pcb has in those cases
|
||||
* been freed, and so any remaining handles are bogus. */
|
||||
err = ERR_OK;
|
||||
TCP_RMV(&tcp_bound_pcbs, pcb);
|
||||
if (pcb->local_port != 0) {
|
||||
TCP_RMV(&tcp_bound_pcbs, pcb);
|
||||
}
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
pcb = NULL;
|
||||
break;
|
||||
@@ -185,7 +220,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
|
||||
break;
|
||||
case SYN_SENT:
|
||||
err = ERR_OK;
|
||||
tcp_pcb_remove(&tcp_active_pcbs, pcb);
|
||||
TCP_PCB_REMOVE_ACTIVE(pcb);
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
pcb = NULL;
|
||||
snmp_inc_tcpattemptfails();
|
||||
@@ -264,7 +299,9 @@ tcp_close(struct tcp_pcb *pcb)
|
||||
|
||||
/**
|
||||
* Causes all or part of a full-duplex connection of this PCB to be shut down.
|
||||
* This doesn't deallocate the PCB!
|
||||
* This doesn't deallocate the PCB unless shutting down both sides!
|
||||
* Shutting down both sides is the same as calling tcp_close, so if it succeds,
|
||||
* the PCB should not be referenced any more.
|
||||
*
|
||||
* @param pcb PCB to shutdown
|
||||
* @param shut_rx shut down receive side if this is != 0
|
||||
@@ -279,28 +316,32 @@ tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)
|
||||
return ERR_CONN;
|
||||
}
|
||||
if (shut_rx) {
|
||||
/* shut down the receive side: free buffered data... */
|
||||
/* shut down the receive side: set a flag not to receive any more data... */
|
||||
pcb->flags |= TF_RXCLOSED;
|
||||
if (shut_tx) {
|
||||
/* shutting down the tx AND rx side is the same as closing for the raw API */
|
||||
return tcp_close_shutdown(pcb, 1);
|
||||
}
|
||||
/* ... and free buffered data */
|
||||
if (pcb->refused_data != NULL) {
|
||||
pbuf_free(pcb->refused_data);
|
||||
pcb->refused_data = NULL;
|
||||
}
|
||||
/* ... and set a flag not to receive any more data */
|
||||
pcb->flags |= TF_RXCLOSED;
|
||||
}
|
||||
if (shut_tx) {
|
||||
/* This can't happen twice since if it succeeds, the pcb's state is changed.
|
||||
Only close in these states as the others directly deallocate the PCB */
|
||||
switch (pcb->state) {
|
||||
case SYN_RCVD:
|
||||
case ESTABLISHED:
|
||||
case CLOSE_WAIT:
|
||||
return tcp_close_shutdown(pcb, 0);
|
||||
default:
|
||||
/* don't shut down other states */
|
||||
break;
|
||||
case SYN_RCVD:
|
||||
case ESTABLISHED:
|
||||
case CLOSE_WAIT:
|
||||
return tcp_close_shutdown(pcb, shut_rx);
|
||||
default:
|
||||
/* Not (yet?) connected, cannot shutdown the TX side as that would bring us
|
||||
into CLOSED state, where the PCB is deallocated. */
|
||||
return ERR_CONN;
|
||||
}
|
||||
}
|
||||
/* @todo: return another err_t if not in correct state or already shut? */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -316,8 +357,6 @@ void
|
||||
tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||
{
|
||||
u32_t seqno, ackno;
|
||||
u16_t remote_port, local_port;
|
||||
ip_addr_t remote_ip, local_ip;
|
||||
#if LWIP_CALLBACK_API
|
||||
tcp_err_fn errf;
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
@@ -335,15 +374,11 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||
} else {
|
||||
seqno = pcb->snd_nxt;
|
||||
ackno = pcb->rcv_nxt;
|
||||
ip_addr_copy(local_ip, pcb->local_ip);
|
||||
ip_addr_copy(remote_ip, pcb->remote_ip);
|
||||
local_port = pcb->local_port;
|
||||
remote_port = pcb->remote_port;
|
||||
#if LWIP_CALLBACK_API
|
||||
errf = pcb->errf;
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
errf_arg = pcb->callback_arg;
|
||||
tcp_pcb_remove(&tcp_active_pcbs, pcb);
|
||||
TCP_PCB_REMOVE_ACTIVE(pcb);
|
||||
if (pcb->unacked != NULL) {
|
||||
tcp_segs_free(pcb->unacked);
|
||||
}
|
||||
@@ -355,12 +390,12 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||
tcp_segs_free(pcb->ooseq);
|
||||
}
|
||||
#endif /* TCP_QUEUE_OOSEQ */
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
|
||||
if (reset) {
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
|
||||
tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
|
||||
tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port);
|
||||
}
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,6 +426,7 @@ tcp_abort(struct tcp_pcb *pcb)
|
||||
* to any local address
|
||||
* @param port the local port to bind to
|
||||
* @return ERR_USE if the port is already in use
|
||||
* ERR_VAL if bind failed because the PCB is not in a valid state
|
||||
* ERR_OK if bound
|
||||
*/
|
||||
err_t
|
||||
@@ -400,7 +436,7 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
int max_pcb_list = NUM_TCP_PCB_LISTS;
|
||||
struct tcp_pcb *cpcb;
|
||||
|
||||
LWIP_ERROR("tcp_bind: 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_VAL);
|
||||
|
||||
#if SO_REUSE
|
||||
/* Unless the REUSEADDR flag is set,
|
||||
@@ -408,13 +444,16 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
We do not dump TIME_WAIT pcb's; they can still be matched by incoming
|
||||
packets using both local and remote IP addresses and ports to distinguish.
|
||||
*/
|
||||
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
|
||||
if (ip_get_option(pcb, SOF_REUSEADDR)) {
|
||||
max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;
|
||||
}
|
||||
#endif /* SO_REUSE */
|
||||
|
||||
if (port == 0) {
|
||||
port = tcp_new_port();
|
||||
if (port == 0) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the address already is in use (on all lists) */
|
||||
@@ -425,8 +464,8 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
/* Omit checking for the same port if both pcbs have REUSEADDR set.
|
||||
For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in
|
||||
tcp_connect. */
|
||||
if (((pcb->so_options & SOF_REUSEADDR) == 0) ||
|
||||
((cpcb->so_options & SOF_REUSEADDR) == 0))
|
||||
if (!ip_get_option(pcb, SOF_REUSEADDR) ||
|
||||
!ip_get_option(cpcb, SOF_REUSEADDR))
|
||||
#endif /* SO_REUSE */
|
||||
{
|
||||
if (ip_addr_isany(&(cpcb->local_ip)) ||
|
||||
@@ -489,7 +528,7 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||
return pcb;
|
||||
}
|
||||
#if SO_REUSE
|
||||
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
|
||||
if (ip_get_option(pcb, SOF_REUSEADDR)) {
|
||||
/* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage
|
||||
is declared (listen-/connection-pcb), we have to make sure now that
|
||||
this port is only used once for every local IP. */
|
||||
@@ -512,11 +551,13 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||
lpcb->state = LISTEN;
|
||||
lpcb->prio = pcb->prio;
|
||||
lpcb->so_options = pcb->so_options;
|
||||
lpcb->so_options |= SOF_ACCEPTCONN;
|
||||
ip_set_option(lpcb, SOF_ACCEPTCONN);
|
||||
lpcb->ttl = pcb->ttl;
|
||||
lpcb->tos = pcb->tos;
|
||||
ip_addr_copy(lpcb->local_ip, pcb->local_ip);
|
||||
TCP_RMV(&tcp_bound_pcbs, pcb);
|
||||
if (pcb->local_port != 0) {
|
||||
TCP_RMV(&tcp_bound_pcbs, pcb);
|
||||
}
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
#if LWIP_CALLBACK_API
|
||||
lpcb->accept = tcp_accept_null;
|
||||
@@ -571,6 +612,9 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||
{
|
||||
int wnd_inflation;
|
||||
|
||||
/* pcb->state LISTEN not allowed here */
|
||||
LWIP_ASSERT("don't call tcp_recved for listen-pcbs",
|
||||
pcb->state != LISTEN);
|
||||
LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
|
||||
len <= 0xffff - pcb->rcv_wnd );
|
||||
|
||||
@@ -595,35 +639,33 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||
}
|
||||
|
||||
/**
|
||||
* A nastly hack featuring 'goto' statements that allocates a
|
||||
* new TCP local port.
|
||||
* Allocate a new local TCP port.
|
||||
*
|
||||
* @return a new (free) local TCP port number
|
||||
*/
|
||||
static u16_t
|
||||
tcp_new_port(void)
|
||||
{
|
||||
int i;
|
||||
u8_t i;
|
||||
u16_t n = 0;
|
||||
struct tcp_pcb *pcb;
|
||||
#ifndef TCP_LOCAL_PORT_RANGE_START
|
||||
#define TCP_LOCAL_PORT_RANGE_START 4096
|
||||
#define TCP_LOCAL_PORT_RANGE_END 0x7fff
|
||||
#endif
|
||||
static u16_t port = TCP_LOCAL_PORT_RANGE_START;
|
||||
|
||||
again:
|
||||
if (++port > TCP_LOCAL_PORT_RANGE_END) {
|
||||
port = TCP_LOCAL_PORT_RANGE_START;
|
||||
again:
|
||||
if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) {
|
||||
tcp_port = TCP_LOCAL_PORT_RANGE_START;
|
||||
}
|
||||
/* Check all PCB lists. */
|
||||
for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
|
||||
for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
|
||||
for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {
|
||||
if (pcb->local_port == port) {
|
||||
if (pcb->local_port == tcp_port) {
|
||||
if (++n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) {
|
||||
return 0;
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
return port;
|
||||
return tcp_port;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,8 +686,9 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
|
||||
{
|
||||
err_t ret;
|
||||
u32_t iss;
|
||||
u16_t old_local_port;
|
||||
|
||||
LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
|
||||
LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
|
||||
if (ipaddr != NULL) {
|
||||
@@ -668,11 +711,15 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
|
||||
ip_addr_copy(pcb->local_ip, netif->ip_addr);
|
||||
}
|
||||
|
||||
old_local_port = pcb->local_port;
|
||||
if (pcb->local_port == 0) {
|
||||
pcb->local_port = tcp_new_port();
|
||||
if (pcb->local_port == 0) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
}
|
||||
#if SO_REUSE
|
||||
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
|
||||
if (ip_get_option(pcb, SOF_REUSEADDR)) {
|
||||
/* Since SOF_REUSEADDR allows reusing a local address, we have to make sure
|
||||
now that the 5-tuple is unique. */
|
||||
struct tcp_pcb *cpcb;
|
||||
@@ -719,8 +766,10 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
|
||||
if (ret == ERR_OK) {
|
||||
/* SYN segment was enqueued, changed the pcbs state now */
|
||||
pcb->state = SYN_SENT;
|
||||
TCP_RMV(&tcp_bound_pcbs, pcb);
|
||||
TCP_REG(&tcp_active_pcbs, pcb);
|
||||
if (old_local_port != 0) {
|
||||
TCP_RMV(&tcp_bound_pcbs, pcb);
|
||||
}
|
||||
TCP_REG_ACTIVE(pcb);
|
||||
snmp_inc_tcpactiveopens();
|
||||
|
||||
tcp_output(pcb);
|
||||
@@ -747,7 +796,9 @@ tcp_slowtmr(void)
|
||||
err = ERR_OK;
|
||||
|
||||
++tcp_ticks;
|
||||
++tcp_timer_ctr;
|
||||
|
||||
tcp_slowtmr_start:
|
||||
/* Steps through all of the active PCBs. */
|
||||
prev = NULL;
|
||||
pcb = tcp_active_pcbs;
|
||||
@@ -759,6 +810,12 @@ tcp_slowtmr(void)
|
||||
LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
|
||||
LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
|
||||
LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
|
||||
if (pcb->last_timer == tcp_timer_ctr) {
|
||||
/* skip this pcb, we have already processed it */
|
||||
pcb = pcb->next;
|
||||
continue;
|
||||
}
|
||||
pcb->last_timer = tcp_timer_ctr;
|
||||
|
||||
pcb_remove = 0;
|
||||
pcb_reset = 0;
|
||||
@@ -784,8 +841,9 @@ tcp_slowtmr(void)
|
||||
}
|
||||
} else {
|
||||
/* Increase the retransmission timer if it is running */
|
||||
if(pcb->rtime >= 0)
|
||||
if(pcb->rtime >= 0) {
|
||||
++pcb->rtime;
|
||||
}
|
||||
|
||||
if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
|
||||
/* Time for a retransmission. */
|
||||
@@ -821,25 +879,24 @@ tcp_slowtmr(void)
|
||||
}
|
||||
/* Check if this PCB has stayed too long in FIN-WAIT-2 */
|
||||
if (pcb->state == FIN_WAIT_2) {
|
||||
if ((u32_t)(tcp_ticks - pcb->tmr) >
|
||||
TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
|
||||
++pcb_remove;
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
|
||||
/* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */
|
||||
if (pcb->flags & TF_RXCLOSED) {
|
||||
/* PCB was fully closed (either through close() or SHUT_RDWR):
|
||||
normal FIN-WAIT timeout handling. */
|
||||
if ((u32_t)(tcp_ticks - pcb->tmr) >
|
||||
TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
|
||||
++pcb_remove;
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if KEEPALIVE should be sent */
|
||||
if((pcb->so_options & SOF_KEEPALIVE) &&
|
||||
if(ip_get_option(pcb, SOF_KEEPALIVE) &&
|
||||
((pcb->state == ESTABLISHED) ||
|
||||
(pcb->state == CLOSE_WAIT))) {
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
if((u32_t)(tcp_ticks - pcb->tmr) >
|
||||
(pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
|
||||
/ TCP_SLOW_INTERVAL)
|
||||
#else
|
||||
if((u32_t)(tcp_ticks - pcb->tmr) >
|
||||
(pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
|
||||
#endif /* LWIP_TCP_KEEPALIVE */
|
||||
(pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL)
|
||||
{
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
|
||||
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
|
||||
@@ -848,15 +905,9 @@ tcp_slowtmr(void)
|
||||
++pcb_remove;
|
||||
++pcb_reset;
|
||||
}
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
else if((u32_t)(tcp_ticks - pcb->tmr) >
|
||||
(pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)
|
||||
(pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb))
|
||||
/ TCP_SLOW_INTERVAL)
|
||||
#else
|
||||
else if((u32_t)(tcp_ticks - pcb->tmr) >
|
||||
(pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)
|
||||
/ TCP_SLOW_INTERVAL)
|
||||
#endif /* LWIP_TCP_KEEPALIVE */
|
||||
{
|
||||
tcp_keepalive(pcb);
|
||||
pcb->keep_cnt_sent++;
|
||||
@@ -895,6 +946,8 @@ tcp_slowtmr(void)
|
||||
/* If the PCB should be removed, do it. */
|
||||
if (pcb_remove) {
|
||||
struct tcp_pcb *pcb2;
|
||||
tcp_err_fn err_fn;
|
||||
void *err_arg;
|
||||
tcp_pcb_purge(pcb);
|
||||
/* Remove PCB from tcp_active_pcbs list. */
|
||||
if (prev != NULL) {
|
||||
@@ -906,15 +959,22 @@ tcp_slowtmr(void)
|
||||
tcp_active_pcbs = pcb->next;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
err_fn = pcb->errf;
|
||||
err_arg = pcb->callback_arg;
|
||||
pcb2 = pcb;
|
||||
pcb = pcb->next;
|
||||
memp_free(MEMP_TCP_PCB, pcb2);
|
||||
|
||||
tcp_active_pcbs_changed = 0;
|
||||
TCP_EVENT_ERR(err_fn, err_arg, ERR_ABRT);
|
||||
if (tcp_active_pcbs_changed) {
|
||||
goto tcp_slowtmr_start;
|
||||
}
|
||||
} else {
|
||||
/* get the 'next' element now and work with 'prev' below (in case of abort) */
|
||||
prev = pcb;
|
||||
@@ -925,7 +985,11 @@ tcp_slowtmr(void)
|
||||
if (prev->polltmr >= prev->pollinterval) {
|
||||
prev->polltmr = 0;
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
|
||||
tcp_active_pcbs_changed = 0;
|
||||
TCP_EVENT_POLL(prev, err);
|
||||
if (tcp_active_pcbs_changed) {
|
||||
goto tcp_slowtmr_start;
|
||||
}
|
||||
/* if err == ERR_ABRT, 'prev' is already deallocated */
|
||||
if (err == ERR_OK) {
|
||||
tcp_output(prev);
|
||||
@@ -981,34 +1045,78 @@ tcp_slowtmr(void)
|
||||
void
|
||||
tcp_fasttmr(void)
|
||||
{
|
||||
struct tcp_pcb *pcb = tcp_active_pcbs;
|
||||
struct tcp_pcb *pcb;
|
||||
|
||||
++tcp_timer_ctr;
|
||||
|
||||
tcp_fasttmr_start:
|
||||
pcb = tcp_active_pcbs;
|
||||
|
||||
while(pcb != NULL) {
|
||||
struct tcp_pcb *next = pcb->next;
|
||||
/* If there is data which was previously "refused" by upper layer */
|
||||
if (pcb->refused_data != NULL) {
|
||||
/* Notify again application with data previously received. */
|
||||
err_t err;
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
|
||||
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
|
||||
if (err == ERR_OK) {
|
||||
pcb->refused_data = NULL;
|
||||
} else if (err == ERR_ABRT) {
|
||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||
pcb = NULL;
|
||||
if (pcb->last_timer != tcp_timer_ctr) {
|
||||
struct tcp_pcb *next;
|
||||
pcb->last_timer = tcp_timer_ctr;
|
||||
/* send delayed ACKs */
|
||||
if (pcb->flags & TF_ACK_DELAY) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
|
||||
tcp_ack_now(pcb);
|
||||
tcp_output(pcb);
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
}
|
||||
|
||||
next = pcb->next;
|
||||
|
||||
/* If there is data which was previously "refused" by upper layer */
|
||||
if (pcb->refused_data != NULL) {
|
||||
tcp_active_pcbs_changed = 0;
|
||||
tcp_process_refused_data(pcb);
|
||||
if (tcp_active_pcbs_changed) {
|
||||
/* application callback has changed the pcb list: restart the loop */
|
||||
goto tcp_fasttmr_start;
|
||||
}
|
||||
}
|
||||
pcb = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Pass pcb->refused_data to the recv callback */
|
||||
err_t
|
||||
tcp_process_refused_data(struct tcp_pcb *pcb)
|
||||
{
|
||||
err_t err;
|
||||
u8_t refused_flags = pcb->refused_data->flags;
|
||||
/* set pcb->refused_data to NULL in case the callback frees it and then
|
||||
closes the pcb */
|
||||
struct pbuf *refused_data = pcb->refused_data;
|
||||
pcb->refused_data = NULL;
|
||||
/* Notify again application with data previously received. */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
|
||||
TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err);
|
||||
if (err == ERR_OK) {
|
||||
/* did refused_data include a FIN? */
|
||||
if (refused_flags & PBUF_FLAG_TCP_FIN) {
|
||||
/* correct rcv_wnd as the application won't call tcp_recved()
|
||||
for the FIN's seqno */
|
||||
if (pcb->rcv_wnd != TCP_WND) {
|
||||
pcb->rcv_wnd++;
|
||||
}
|
||||
TCP_EVENT_CLOSED(pcb, err);
|
||||
if (err == ERR_ABRT) {
|
||||
return ERR_ABRT;
|
||||
}
|
||||
}
|
||||
|
||||
/* send delayed ACKs */
|
||||
if (pcb && (pcb->flags & TF_ACK_DELAY)) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
|
||||
tcp_ack_now(pcb);
|
||||
tcp_output(pcb);
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
}
|
||||
|
||||
pcb = next;
|
||||
} else if (err == ERR_ABRT) {
|
||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||
/* Drop incoming packets because pcb is "full" (only if the incoming
|
||||
segment contains data). */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
|
||||
return ERR_ABRT;
|
||||
} else {
|
||||
/* data is still refused, pbuf is still valid (go on for ACK-only packets) */
|
||||
pcb->refused_data = refused_data;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1100,7 +1208,8 @@ tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
|
||||
/**
|
||||
* Kills the oldest active connection that has lower priority than prio.
|
||||
* Kills the oldest active connection that has the same or lower priority than
|
||||
* 'prio'.
|
||||
*
|
||||
* @param prio minimum priority
|
||||
*/
|
||||
@@ -1217,6 +1326,7 @@ tcp_alloc(u8_t prio)
|
||||
pcb->lastack = iss;
|
||||
pcb->snd_lbb = iss;
|
||||
pcb->tmr = tcp_ticks;
|
||||
pcb->last_timer = tcp_timer_ctr;
|
||||
|
||||
pcb->polltmr = 0;
|
||||
|
||||
@@ -1264,7 +1374,9 @@ tcp_new(void)
|
||||
*/
|
||||
void
|
||||
tcp_arg(struct tcp_pcb *pcb, void *arg)
|
||||
{
|
||||
{
|
||||
/* This function is allowed to be called for both listen pcbs and
|
||||
connection pcbs. */
|
||||
pcb->callback_arg = arg;
|
||||
}
|
||||
#if LWIP_CALLBACK_API
|
||||
@@ -1279,6 +1391,7 @@ tcp_arg(struct tcp_pcb *pcb, void *arg)
|
||||
void
|
||||
tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
|
||||
{
|
||||
LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN);
|
||||
pcb->recv = recv;
|
||||
}
|
||||
|
||||
@@ -1292,6 +1405,7 @@ tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
|
||||
void
|
||||
tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
|
||||
{
|
||||
LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN);
|
||||
pcb->sent = sent;
|
||||
}
|
||||
|
||||
@@ -1306,6 +1420,7 @@ tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
|
||||
void
|
||||
tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
|
||||
{
|
||||
LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN);
|
||||
pcb->errf = err;
|
||||
}
|
||||
|
||||
@@ -1320,6 +1435,8 @@ tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
|
||||
void
|
||||
tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
|
||||
{
|
||||
/* This function is allowed to be called for both listen pcbs and
|
||||
connection pcbs. */
|
||||
pcb->accept = accept;
|
||||
}
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
@@ -1334,6 +1451,7 @@ tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
|
||||
void
|
||||
tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)
|
||||
{
|
||||
LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN);
|
||||
#if LWIP_CALLBACK_API
|
||||
pcb->poll = poll;
|
||||
#else /* LWIP_CALLBACK_API */
|
||||
|
||||
@@ -117,20 +117,14 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
/* drop short packets */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
|
||||
TCP_STATS_INC(tcp.lenerr);
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
snmp_inc_tcpinerrs();
|
||||
pbuf_free(p);
|
||||
return;
|
||||
goto dropped;
|
||||
}
|
||||
|
||||
/* Don't even process incoming broadcasts/multicasts. */
|
||||
if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) ||
|
||||
ip_addr_ismulticast(¤t_iphdr_dest)) {
|
||||
TCP_STATS_INC(tcp.proterr);
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
snmp_inc_tcpinerrs();
|
||||
pbuf_free(p);
|
||||
return;
|
||||
goto dropped;
|
||||
}
|
||||
|
||||
#if CHECKSUM_CHECK_TCP
|
||||
@@ -144,10 +138,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
tcp_debug_print(tcphdr);
|
||||
#endif /* TCP_DEBUG */
|
||||
TCP_STATS_INC(tcp.chkerr);
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
snmp_inc_tcpinerrs();
|
||||
pbuf_free(p);
|
||||
return;
|
||||
goto dropped;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -158,10 +149,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
/* drop short packets */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
|
||||
TCP_STATS_INC(tcp.lenerr);
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
snmp_inc_tcpinerrs();
|
||||
pbuf_free(p);
|
||||
return;
|
||||
goto dropped;
|
||||
}
|
||||
|
||||
/* Convert fields in TCP header to host byte order. */
|
||||
@@ -291,29 +279,25 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
/* Set up a tcp_seg structure. */
|
||||
inseg.next = NULL;
|
||||
inseg.len = p->tot_len;
|
||||
inseg.dataptr = p->payload;
|
||||
inseg.p = p;
|
||||
inseg.tcphdr = tcphdr;
|
||||
|
||||
recv_data = NULL;
|
||||
recv_flags = 0;
|
||||
|
||||
if (flags & TCP_PSH) {
|
||||
p->flags |= PBUF_FLAG_PUSH;
|
||||
}
|
||||
|
||||
/* If there is data which was previously "refused" by upper layer */
|
||||
if (pcb->refused_data != NULL) {
|
||||
/* Notify again application with data previously received. */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
|
||||
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
|
||||
if (err == ERR_OK) {
|
||||
pcb->refused_data = NULL;
|
||||
} else if ((err == ERR_ABRT) || (tcplen > 0)) {
|
||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||
/* Drop incoming packets because pcb is "full" (only if the incoming
|
||||
segment contains data). */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
|
||||
if ((tcp_process_refused_data(pcb) == ERR_ABRT) ||
|
||||
((pcb->refused_data != NULL) && (tcplen > 0))) {
|
||||
/* pcb has been aborted or refused data is still refused and the new
|
||||
segment contains data */
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
snmp_inc_tcpinerrs();
|
||||
pbuf_free(p);
|
||||
return;
|
||||
goto aborted;
|
||||
}
|
||||
}
|
||||
tcp_input_pcb = pcb;
|
||||
@@ -332,6 +316,12 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
} else if (recv_flags & TF_CLOSED) {
|
||||
/* The connection has been closed and we will deallocate the
|
||||
PCB. */
|
||||
if (!(pcb->flags & TF_RXCLOSED)) {
|
||||
/* Connection closed although the application has only shut down the
|
||||
tx side: call the PCB's err callback and indicate the closure to
|
||||
ensure the application doesn't continue using the PCB. */
|
||||
TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD);
|
||||
}
|
||||
tcp_pcb_remove(&tcp_active_pcbs, pcb);
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
} else {
|
||||
@@ -355,9 +345,6 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
tcp_abort(pcb);
|
||||
goto aborted;
|
||||
}
|
||||
if (flags & TCP_PSH) {
|
||||
recv_data->flags |= PBUF_FLAG_PUSH;
|
||||
}
|
||||
|
||||
/* Notify application that data has been received. */
|
||||
TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
|
||||
@@ -375,14 +362,19 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
/* If a FIN segment was received, we call the callback
|
||||
function with a NULL buffer to indicate EOF. */
|
||||
if (recv_flags & TF_GOT_FIN) {
|
||||
/* correct rcv_wnd as the application won't call tcp_recved()
|
||||
for the FIN's seqno */
|
||||
if (pcb->rcv_wnd != TCP_WND) {
|
||||
pcb->rcv_wnd++;
|
||||
}
|
||||
TCP_EVENT_CLOSED(pcb, err);
|
||||
if (err == ERR_ABRT) {
|
||||
goto aborted;
|
||||
if (pcb->refused_data != NULL) {
|
||||
/* Delay this if we have refused data. */
|
||||
pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN;
|
||||
} else {
|
||||
/* correct rcv_wnd as the application won't call tcp_recved()
|
||||
for the FIN's seqno */
|
||||
if (pcb->rcv_wnd != TCP_WND) {
|
||||
pcb->rcv_wnd++;
|
||||
}
|
||||
TCP_EVENT_CLOSED(pcb, err);
|
||||
if (err == ERR_ABRT) {
|
||||
goto aborted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,6 +417,11 @@ aborted:
|
||||
|
||||
LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
|
||||
PERF_STOP("tcp_input");
|
||||
return;
|
||||
dropped:
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
snmp_inc_tcpinerrs();
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -445,15 +442,19 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
struct tcp_pcb *npcb;
|
||||
err_t rc;
|
||||
|
||||
if (flags & TCP_RST) {
|
||||
/* An incoming RST should be ignored. Return. */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* In the LISTEN state, we check for incoming SYN segments,
|
||||
creates a new PCB, and responds with a SYN|ACK. */
|
||||
if (flags & TCP_ACK) {
|
||||
/* For incoming segments with the ACK flag set, respond with a
|
||||
RST. */
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
|
||||
tcp_rst(ackno + 1, seqno + tcplen,
|
||||
ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(),
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src);
|
||||
} else if (flags & TCP_SYN) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
@@ -483,6 +484,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
npcb->rcv_nxt = seqno + 1;
|
||||
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
|
||||
npcb->snd_wnd = tcphdr->wnd;
|
||||
npcb->snd_wnd_max = tcphdr->wnd;
|
||||
npcb->ssthresh = npcb->snd_wnd;
|
||||
npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
|
||||
npcb->callback_arg = pcb->callback_arg;
|
||||
@@ -493,7 +495,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
npcb->so_options = pcb->so_options & SOF_INHERITED;
|
||||
/* Register the new PCB so that we can begin receiving segments
|
||||
for it. */
|
||||
TCP_REG(&tcp_active_pcbs, npcb);
|
||||
TCP_REG_ACTIVE(npcb);
|
||||
|
||||
/* Parse any options in the SYN. */
|
||||
tcp_parseopt(npcb);
|
||||
@@ -634,6 +636,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
|
||||
pcb->lastack = ackno;
|
||||
pcb->snd_wnd = tcphdr->wnd;
|
||||
pcb->snd_wnd_max = tcphdr->wnd;
|
||||
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
|
||||
pcb->state = ESTABLISHED;
|
||||
|
||||
@@ -651,6 +654,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
|
||||
rseg = pcb->unacked;
|
||||
pcb->unacked = rseg->next;
|
||||
tcp_seg_free(rseg);
|
||||
|
||||
/* If there's nothing left to acknowledge, stop the retransmit
|
||||
timer, otherwise reset it to start again */
|
||||
@@ -661,8 +665,6 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
pcb->nrtx = 0;
|
||||
}
|
||||
|
||||
tcp_seg_free(rseg);
|
||||
|
||||
/* Call the user specified function to call when sucessfully
|
||||
* connected. */
|
||||
TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
|
||||
@@ -742,7 +744,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
("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);
|
||||
TCP_RMV_ACTIVE(pcb);
|
||||
pcb->state = TIME_WAIT;
|
||||
TCP_REG(&tcp_tw_pcbs, pcb);
|
||||
} else {
|
||||
@@ -759,7 +761,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
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);
|
||||
TCP_RMV_ACTIVE(pcb);
|
||||
pcb->state = TIME_WAIT;
|
||||
TCP_REG(&tcp_tw_pcbs, pcb);
|
||||
}
|
||||
@@ -769,7 +771,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
||||
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);
|
||||
TCP_RMV_ACTIVE(pcb);
|
||||
pcb->state = TIME_WAIT;
|
||||
TCP_REG(&tcp_tw_pcbs, pcb);
|
||||
}
|
||||
@@ -834,7 +836,7 @@ tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
|
||||
* data, and if so frees the memory of the buffered data. Next, is places the
|
||||
* segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
|
||||
* is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
|
||||
* i it has been removed from the buffer.
|
||||
* it has been removed from the buffer.
|
||||
*
|
||||
* If the incoming segment constitutes an ACK for a segment that was used for RTT
|
||||
* estimation, the RTT is estimated here as well.
|
||||
@@ -854,6 +856,12 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
u32_t right_wnd_edge;
|
||||
u16_t new_tot_len;
|
||||
int found_dupack = 0;
|
||||
#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
|
||||
u32_t ooseq_blen;
|
||||
u16_t ooseq_qlen;
|
||||
#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
|
||||
|
||||
LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED);
|
||||
|
||||
if (flags & TCP_ACK) {
|
||||
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
|
||||
@@ -863,9 +871,21 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
(pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
|
||||
(pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
|
||||
pcb->snd_wnd = tcphdr->wnd;
|
||||
/* keep track of the biggest window announced by the remote host to calculate
|
||||
the maximum segment size */
|
||||
if (pcb->snd_wnd_max < tcphdr->wnd) {
|
||||
pcb->snd_wnd_max = tcphdr->wnd;
|
||||
}
|
||||
pcb->snd_wl1 = seqno;
|
||||
pcb->snd_wl2 = ackno;
|
||||
if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
|
||||
if (pcb->snd_wnd == 0) {
|
||||
if (pcb->persist_backoff == 0) {
|
||||
/* start persist timer */
|
||||
pcb->persist_cnt = 0;
|
||||
pcb->persist_backoff = 1;
|
||||
}
|
||||
} else if (pcb->persist_backoff > 0) {
|
||||
/* stop persist timer */
|
||||
pcb->persist_backoff = 0;
|
||||
}
|
||||
LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
|
||||
@@ -912,8 +932,9 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
/* Clause 5 */
|
||||
if (pcb->lastack == ackno) {
|
||||
found_dupack = 1;
|
||||
if (pcb->dupacks + 1 > pcb->dupacks)
|
||||
if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) {
|
||||
++pcb->dupacks;
|
||||
}
|
||||
if (pcb->dupacks > 3) {
|
||||
/* Inflate the congestion window, but not if it means that
|
||||
the value overflows. */
|
||||
@@ -1040,6 +1061,11 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
|
||||
next = pcb->unsent;
|
||||
pcb->unsent = pcb->unsent->next;
|
||||
#if TCP_OVERSIZE
|
||||
if (pcb->unsent == NULL) {
|
||||
pcb->unsent_oversize = 0;
|
||||
}
|
||||
#endif /* TCP_OVERSIZE */
|
||||
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 */
|
||||
@@ -1088,8 +1114,10 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
}
|
||||
|
||||
/* If the incoming segment contains data, we must process it
|
||||
further. */
|
||||
if (tcplen > 0) {
|
||||
further unless the pcb already received a FIN.
|
||||
(RFC 793, chapeter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING,
|
||||
LAST-ACK and TIME-WAIT: "Ignore the segment text.") */
|
||||
if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) {
|
||||
/* This code basically does three things:
|
||||
|
||||
+) If the incoming segment contains data that is the next
|
||||
@@ -1167,9 +1195,6 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
LWIP_ASSERT("pbuf_header failed", 0);
|
||||
}
|
||||
}
|
||||
/* KJM following line changed to use p->payload rather than inseg->p->payload
|
||||
to fix bug #9076 */
|
||||
inseg.dataptr = p->payload;
|
||||
inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
|
||||
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
|
||||
}
|
||||
@@ -1230,8 +1255,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
pcb->ooseq = pcb->ooseq->next;
|
||||
tcp_seg_free(old_ooseq);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
next = pcb->ooseq;
|
||||
/* Remove all segments on ooseq that are covered by inseg already.
|
||||
* FIN is copied from ooseq to inseg if present. */
|
||||
@@ -1464,8 +1488,32 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
prev = next;
|
||||
}
|
||||
}
|
||||
#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
|
||||
/* Check that the data on ooseq doesn't exceed one of the limits
|
||||
and throw away everything above that limit. */
|
||||
ooseq_blen = 0;
|
||||
ooseq_qlen = 0;
|
||||
prev = NULL;
|
||||
for(next = pcb->ooseq; next != NULL; prev = next, next = next->next) {
|
||||
struct pbuf *p = next->p;
|
||||
ooseq_blen += p->tot_len;
|
||||
ooseq_qlen += pbuf_clen(p);
|
||||
if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) ||
|
||||
(ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) {
|
||||
/* too much ooseq data, dump this and everything after it */
|
||||
tcp_segs_free(next);
|
||||
if (prev == NULL) {
|
||||
/* first ooseq segment is too much, dump the whole queue */
|
||||
pcb->ooseq = NULL;
|
||||
} else {
|
||||
/* just dump 'next' and everything after it */
|
||||
prev->next = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
|
||||
#endif /* TCP_QUEUE_OOSEQ */
|
||||
|
||||
}
|
||||
} else {
|
||||
/* The incoming segment is not withing the window. */
|
||||
|
||||
@@ -46,12 +46,14 @@
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
#include "lwip/sys.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -131,6 +133,7 @@ tcp_send_fin(struct tcp_pcb *pcb)
|
||||
if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
|
||||
/* no SYN/FIN/RST flag in the header, we can add the FIN flag */
|
||||
TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
|
||||
pcb->flags |= TF_FIN;
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
@@ -166,7 +169,6 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
|
||||
seg->flags = optflags;
|
||||
seg->next = NULL;
|
||||
seg->p = p;
|
||||
seg->dataptr = p->payload;
|
||||
seg->len = p->tot_len - optlen;
|
||||
#if TCP_OVERSIZE_DBGCHECK
|
||||
seg->oversize_left = 0;
|
||||
@@ -227,7 +229,7 @@ tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
|
||||
LWIP_UNUSED_ARG(apiflags);
|
||||
LWIP_UNUSED_ARG(first_seg);
|
||||
/* always create MSS-sized pbufs */
|
||||
alloc = TCP_MSS;
|
||||
alloc = max_length;
|
||||
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
if (length < max_length) {
|
||||
/* Should we allocate an oversized pbuf, or just the minimum
|
||||
@@ -367,6 +369,8 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
u16_t concat_chksummed = 0;
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
err_t err;
|
||||
/* don't allocate segments bigger than half the maximum window we ever received */
|
||||
u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2);
|
||||
|
||||
#if LWIP_NETIF_TX_SINGLE_PBUF
|
||||
/* Always copy to try to create single pbufs for TX */
|
||||
@@ -425,7 +429,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
|
||||
/* Usable space at the end of the last unsent segment */
|
||||
unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
|
||||
space = pcb->mss - (last_unsent->len + unsent_optlen);
|
||||
space = mss_local - (last_unsent->len + unsent_optlen);
|
||||
|
||||
/*
|
||||
* Phase 1: Copy data directly into an oversized pbuf.
|
||||
@@ -518,7 +522,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
while (pos < len) {
|
||||
struct pbuf *p;
|
||||
u16_t left = len - pos;
|
||||
u16_t max_len = pcb->mss - optlen;
|
||||
u16_t max_len = mss_local - optlen;
|
||||
u16_t seglen = left > max_len ? max_len : left;
|
||||
#if TCP_CHECKSUM_ON_COPY
|
||||
u16_t chksum = 0;
|
||||
@@ -528,7 +532,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
if (apiflags & TCP_WRITE_FLAG_COPY) {
|
||||
/* If copy is set, memory should be allocated and data copied
|
||||
* into pbuf */
|
||||
if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
|
||||
if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
|
||||
goto memerr;
|
||||
}
|
||||
@@ -590,10 +594,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
seg->chksum_swapped = chksum_swapped;
|
||||
seg->flags |= TF_SEG_DATA_CHECKSUMMED;
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
/* Fix dataptr for the nocopy case */
|
||||
if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) {
|
||||
seg->dataptr = (u8_t*)arg + pos;
|
||||
}
|
||||
|
||||
/* first segment of to-be-queued data? */
|
||||
if (queue == NULL) {
|
||||
@@ -815,7 +815,6 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
/* Build a timestamp option (12 bytes long) at the specified options pointer)
|
||||
@@ -902,6 +901,10 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
s16_t i = 0;
|
||||
#endif /* TCP_CWND_DEBUG */
|
||||
|
||||
/* pcb->state LISTEN not allowed here */
|
||||
LWIP_ASSERT("don't call tcp_output for listen-pcbs",
|
||||
pcb->state != LISTEN);
|
||||
|
||||
/* First, check if we are invoked by the TCP input processing
|
||||
code. If so, we do not output anything. Instead, we rely on the
|
||||
input processing code to call us when input processing is done
|
||||
@@ -1030,13 +1033,6 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
}
|
||||
#endif /* TCP_OVERSIZE */
|
||||
|
||||
if (seg != NULL && pcb->persist_backoff == 0 &&
|
||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
|
||||
/* prepare for persist timer */
|
||||
pcb->persist_cnt = 0;
|
||||
pcb->persist_backoff = 1;
|
||||
}
|
||||
|
||||
pcb->flags &= ~TF_NAGLEMEMERR;
|
||||
return ERR_OK;
|
||||
}
|
||||
@@ -1068,10 +1064,9 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
|
||||
/* Add any requested options. NB MSS option is only set on SYN
|
||||
packets, so ignore it here */
|
||||
LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
|
||||
opts = (u32_t *)(void *)(seg->tcphdr + 1);
|
||||
if (seg->flags & TF_SEG_OPTS_MSS) {
|
||||
TCP_BUILD_MSS_OPTION(*opts);
|
||||
*opts = TCP_BUILD_MSS_OPTION(pcb->mss);
|
||||
opts += 1;
|
||||
}
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
@@ -1083,6 +1078,12 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set retransmission timer running if it is not currently enabled
|
||||
This must be set before checking the route. */
|
||||
if (pcb->rtime == -1) {
|
||||
pcb->rtime = 0;
|
||||
}
|
||||
|
||||
/* If we don't have a local IP address, we get one by
|
||||
calling ip_route(). */
|
||||
if (ip_addr_isany(&(pcb->local_ip))) {
|
||||
@@ -1093,11 +1094,6 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
ip_addr_copy(pcb->local_ip, netif->ip_addr);
|
||||
}
|
||||
|
||||
/* Set retransmission timer running if it is not currently enabled */
|
||||
if(pcb->rtime == -1) {
|
||||
pcb->rtime = 0;
|
||||
}
|
||||
|
||||
if (pcb->rttest == 0) {
|
||||
pcb->rttest = tcp_ticks;
|
||||
pcb->rtseq = ntohl(seg->tcphdr->seqno);
|
||||
@@ -1248,6 +1244,7 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
|
||||
pcb->unsent = pcb->unacked;
|
||||
/* unacked queue is now empty */
|
||||
pcb->unacked = NULL;
|
||||
/* last unsent hasn't changed, no need to reset unsent_oversize */
|
||||
|
||||
/* increment number of retransmissions */
|
||||
++pcb->nrtx;
|
||||
@@ -1288,6 +1285,12 @@ tcp_rexmit(struct tcp_pcb *pcb)
|
||||
}
|
||||
seg->next = *cur_seg;
|
||||
*cur_seg = seg;
|
||||
#if TCP_OVERSIZE
|
||||
if (seg->next == NULL) {
|
||||
/* the retransmitted segment is last in unsent, so reset unsent_oversize */
|
||||
pcb->unsent_oversize = 0;
|
||||
}
|
||||
#endif /* TCP_OVERSIZE */
|
||||
|
||||
++pcb->nrtx;
|
||||
|
||||
@@ -1444,7 +1447,11 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
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 + TCP_HLEN) = *(char *)seg->dataptr;
|
||||
char *d = ((char *)p->payload + TCP_HLEN);
|
||||
/* Depending on whether the segment has already been sent (unacked) or not
|
||||
(unsent), seg->p->payload points to the IP header or TCP header.
|
||||
Ensure we copy the first TCP data byte: */
|
||||
pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len);
|
||||
}
|
||||
|
||||
#if CHECKSUM_GEN_TCP
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
|
||||
/** The one and only timeout list */
|
||||
@@ -355,22 +357,25 @@ sys_untimeout(sys_timeout_handler handler, void *arg)
|
||||
void
|
||||
sys_check_timeouts(void)
|
||||
{
|
||||
struct sys_timeo *tmptimeout;
|
||||
u32_t diff;
|
||||
sys_timeout_handler handler;
|
||||
void *arg;
|
||||
int had_one;
|
||||
u32_t now;
|
||||
|
||||
now = sys_now();
|
||||
if (next_timeout) {
|
||||
struct sys_timeo *tmptimeout;
|
||||
u32_t diff;
|
||||
sys_timeout_handler handler;
|
||||
void *arg;
|
||||
u8_t had_one;
|
||||
u32_t now;
|
||||
|
||||
now = sys_now();
|
||||
/* this cares for wraparounds */
|
||||
diff = LWIP_U32_DIFF(now, timeouts_last_time);
|
||||
diff = now - timeouts_last_time;
|
||||
do
|
||||
{
|
||||
#if PBUF_POOL_FREE_OOSEQ
|
||||
PBUF_CHECK_FREE_OOSEQ();
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||
had_one = 0;
|
||||
tmptimeout = next_timeout;
|
||||
if (tmptimeout->time <= diff) {
|
||||
if (tmptimeout && (tmptimeout->time <= diff)) {
|
||||
/* timeout has expired */
|
||||
had_one = 1;
|
||||
timeouts_last_time = now;
|
||||
|
||||
141
src/core/udp.c
141
src/core/udp.c
@@ -64,10 +64,77 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef UDP_LOCAL_PORT_RANGE_START
|
||||
/* From http://www.iana.org/assignments/port-numbers:
|
||||
"The Dynamic and/or Private Ports are those from 49152 through 65535" */
|
||||
#define UDP_LOCAL_PORT_RANGE_START 0xc000
|
||||
#define UDP_LOCAL_PORT_RANGE_END 0xffff
|
||||
#define UDP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START)
|
||||
#endif
|
||||
|
||||
/* last local UDP port */
|
||||
static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START;
|
||||
|
||||
/* The list of UDP PCBs */
|
||||
/* exported in udp.h (was static) */
|
||||
struct udp_pcb *udp_pcbs;
|
||||
|
||||
/**
|
||||
* Initialize this module.
|
||||
*/
|
||||
void
|
||||
udp_init(void)
|
||||
{
|
||||
#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND)
|
||||
udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
|
||||
#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new local UDP port.
|
||||
*
|
||||
* @return a new (free) local UDP port number
|
||||
*/
|
||||
static u16_t
|
||||
udp_new_port(void)
|
||||
{
|
||||
u16_t n = 0;
|
||||
struct udp_pcb *pcb;
|
||||
|
||||
again:
|
||||
if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) {
|
||||
udp_port = UDP_LOCAL_PORT_RANGE_START;
|
||||
}
|
||||
/* Check all PCBs. */
|
||||
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
if (pcb->local_port == udp_port) {
|
||||
if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) {
|
||||
return 0;
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
return udp_port;
|
||||
#if 0
|
||||
struct udp_pcb *ipcb = udp_pcbs;
|
||||
while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) {
|
||||
if (ipcb->local_port == udp_port) {
|
||||
/* port is already used by another udp_pcb */
|
||||
udp_port++;
|
||||
/* restart scanning all udp pcbs */
|
||||
ipcb = udp_pcbs;
|
||||
} else {
|
||||
/* go on with next udp pcb */
|
||||
ipcb = ipcb->next;
|
||||
}
|
||||
}
|
||||
if (ipcb != NULL) {
|
||||
return 0;
|
||||
}
|
||||
return udp_port;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an incoming UDP datagram.
|
||||
*
|
||||
@@ -171,22 +238,28 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));
|
||||
|
||||
/* compare PCB local addr+port to UDP destination addr+port */
|
||||
if ((pcb->local_port == dest) &&
|
||||
((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
|
||||
if (pcb->local_port == dest) {
|
||||
if (
|
||||
(!broadcast && ip_addr_isany(&pcb->local_ip)) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) ||
|
||||
#if LWIP_IGMP
|
||||
ip_addr_ismulticast(¤t_iphdr_dest) ||
|
||||
#endif /* LWIP_IGMP */
|
||||
#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 */
|
||||
uncon_pcb = pcb;
|
||||
(broadcast && ip_get_option(pcb, SOF_BROADCAST) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) {
|
||||
#else /* IP_SOF_BROADCAST_RECV */
|
||||
(broadcast &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) {
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
local_match = 1;
|
||||
if ((uncon_pcb == NULL) &&
|
||||
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
|
||||
/* the first unconnected matching PCB */
|
||||
uncon_pcb = pcb;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* compare PCB remote addr+port to UDP source addr+port */
|
||||
@@ -278,7 +351,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
snmp_inc_udpindatagrams();
|
||||
#if SO_REUSE && SO_REUSE_RXTOALL
|
||||
if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) &&
|
||||
((pcb->so_options & SOF_REUSEADDR) != 0)) {
|
||||
ip_get_option(pcb, SOF_REUSEADDR)) {
|
||||
/* pass broadcast- or multicast packets to all multicast pcbs
|
||||
if SOF_REUSEADDR is set on the first match */
|
||||
struct udp_pcb *mpcb;
|
||||
@@ -293,7 +366,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
ip_addr_ismulticast(¤t_iphdr_dest) ||
|
||||
#endif /* LWIP_IGMP */
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
(broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
|
||||
(broadcast && ip_get_option(mpcb, SOF_BROADCAST)))) {
|
||||
#else /* IP_SOF_BROADCAST_RECV */
|
||||
(broadcast))) {
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
@@ -494,7 +567,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
|
||||
#if IP_SOF_BROADCAST
|
||||
/* broadcast filter? */
|
||||
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
|
||||
if (!ip_get_option(pcb, SOF_BROADCAST) && 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;
|
||||
@@ -616,13 +689,9 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
#endif /* CHECKSUM_GEN_UDP */
|
||||
/* output to IP */
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
|
||||
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*/
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
} else
|
||||
#endif /* LWIP_UDPLITE */
|
||||
{ /* UDP */
|
||||
@@ -655,13 +724,9 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
|
||||
/* output to IP */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
|
||||
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*/
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
}
|
||||
/* TODO: must this be increased even if error occured? */
|
||||
snmp_inc_udpoutdatagrams();
|
||||
@@ -722,8 +787,8 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
PCB is alread bound to, unless *all* PCBs with that port have tha
|
||||
REUSEADDR flag set. */
|
||||
#if SO_REUSE
|
||||
else if (((pcb->so_options & SOF_REUSEADDR) == 0) &&
|
||||
((ipcb->so_options & SOF_REUSEADDR) == 0)) {
|
||||
else if (!ip_get_option(pcb, SOF_REUSEADDR) &&
|
||||
!ip_get_option(ipcb, SOF_REUSEADDR)) {
|
||||
#else /* SO_REUSE */
|
||||
/* port matches that of PCB in list and REUSEADDR not set -> reject */
|
||||
else {
|
||||
@@ -745,24 +810,8 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
|
||||
/* no port specified? */
|
||||
if (port == 0) {
|
||||
#ifndef UDP_LOCAL_PORT_RANGE_START
|
||||
#define UDP_LOCAL_PORT_RANGE_START 4096
|
||||
#define UDP_LOCAL_PORT_RANGE_END 0x7fff
|
||||
#endif
|
||||
port = UDP_LOCAL_PORT_RANGE_START;
|
||||
ipcb = udp_pcbs;
|
||||
while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
|
||||
if (ipcb->local_port == port) {
|
||||
/* port is already used by another udp_pcb */
|
||||
port++;
|
||||
/* restart scanning all udp pcbs */
|
||||
ipcb = udp_pcbs;
|
||||
} else {
|
||||
/* go on with next udp pcb */
|
||||
ipcb = ipcb->next;
|
||||
}
|
||||
}
|
||||
if (ipcb != NULL) {
|
||||
port = udp_new_port();
|
||||
if (port == 0) {
|
||||
/* no more ports available in local range */
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
|
||||
return ERR_USE;
|
||||
|
||||
@@ -89,8 +89,7 @@ struct autoip
|
||||
};
|
||||
|
||||
|
||||
/** Init srand, has to be called before entering mainloop */
|
||||
void autoip_init(void);
|
||||
#define autoip_init() /* Compatibility define, no init needed. */
|
||||
|
||||
/** Set a struct autoip allocated by the application to work with */
|
||||
void autoip_set_struct(struct netif *netif, struct autoip *autoip);
|
||||
|
||||
@@ -41,29 +41,29 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ICMP_ER 0 /* echo reply */
|
||||
#define ICMP_DUR 3 /* destination unreachable */
|
||||
#define ICMP_SQ 4 /* source quench */
|
||||
#define ICMP_RD 5 /* redirect */
|
||||
#define ICMP_ER 0 /* echo reply */
|
||||
#define ICMP_DUR 3 /* destination unreachable */
|
||||
#define ICMP_SQ 4 /* source quench */
|
||||
#define ICMP_RD 5 /* redirect */
|
||||
#define ICMP_ECHO 8 /* echo */
|
||||
#define ICMP_TE 11 /* time exceeded */
|
||||
#define ICMP_PP 12 /* parameter problem */
|
||||
#define ICMP_TS 13 /* timestamp */
|
||||
#define ICMP_TE 11 /* time exceeded */
|
||||
#define ICMP_PP 12 /* parameter problem */
|
||||
#define ICMP_TS 13 /* timestamp */
|
||||
#define ICMP_TSR 14 /* timestamp reply */
|
||||
#define ICMP_IRQ 15 /* information request */
|
||||
#define ICMP_IR 16 /* information reply */
|
||||
#define ICMP_IR 16 /* information reply */
|
||||
|
||||
enum icmp_dur_type {
|
||||
ICMP_DUR_NET = 0, /* net unreachable */
|
||||
ICMP_DUR_HOST = 1, /* host unreachable */
|
||||
ICMP_DUR_NET = 0, /* net unreachable */
|
||||
ICMP_DUR_HOST = 1, /* host unreachable */
|
||||
ICMP_DUR_PROTO = 2, /* protocol unreachable */
|
||||
ICMP_DUR_PORT = 3, /* port unreachable */
|
||||
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
|
||||
ICMP_DUR_SR = 5 /* source route failed */
|
||||
ICMP_DUR_PORT = 3, /* port unreachable */
|
||||
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
|
||||
ICMP_DUR_SR = 5 /* source route failed */
|
||||
};
|
||||
|
||||
enum icmp_te_type {
|
||||
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
|
||||
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
|
||||
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
|
||||
};
|
||||
|
||||
|
||||
@@ -94,16 +94,16 @@ struct ip_pcb {
|
||||
/*
|
||||
* Option flags per-socket. These are the same like SO_XXX.
|
||||
*/
|
||||
/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */
|
||||
#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */
|
||||
#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */
|
||||
#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */
|
||||
/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */
|
||||
#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
|
||||
/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */
|
||||
#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */
|
||||
/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */
|
||||
/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */
|
||||
/*#define SOF_DEBUG 0x01U Unimplemented: turn on debugging info recording */
|
||||
#define SOF_ACCEPTCONN 0x02U /* socket has had listen() */
|
||||
#define SOF_REUSEADDR 0x04U /* allow local address reuse */
|
||||
#define SOF_KEEPALIVE 0x08U /* keep connections alive */
|
||||
/*#define SOF_DONTROUTE 0x10U Unimplemented: just use interface addresses */
|
||||
#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
|
||||
/*#define SOF_USELOOPBACK 0x40U Unimplemented: bypass hardware when possible */
|
||||
#define SOF_LINGER 0x80U /* linger on close if data present */
|
||||
/*#define SOF_OOBINLINE 0x0100U Unimplemented: leave received OOB data in line */
|
||||
/*#define SOF_REUSEPORT 0x0200U Unimplemented: allow local address & port reuse */
|
||||
|
||||
/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
|
||||
#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
|
||||
@@ -114,18 +114,20 @@ struct ip_pcb {
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_hdr {
|
||||
/* version / header length / type of service */
|
||||
PACK_STRUCT_FIELD(u16_t _v_hl_tos);
|
||||
/* version / header length */
|
||||
PACK_STRUCT_FIELD(u8_t _v_hl);
|
||||
/* type of service */
|
||||
PACK_STRUCT_FIELD(u8_t _tos);
|
||||
/* total length */
|
||||
PACK_STRUCT_FIELD(u16_t _len);
|
||||
/* identification */
|
||||
PACK_STRUCT_FIELD(u16_t _id);
|
||||
/* fragment offset field */
|
||||
PACK_STRUCT_FIELD(u16_t _offset);
|
||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
||||
#define IP_DF 0x4000 /* dont fragment flag */
|
||||
#define IP_MF 0x2000 /* more fragments flag */
|
||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
||||
#define IP_RF 0x8000U /* reserved fragment flag */
|
||||
#define IP_DF 0x4000U /* dont fragment flag */
|
||||
#define IP_MF 0x2000U /* more fragments flag */
|
||||
#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */
|
||||
/* time to live */
|
||||
PACK_STRUCT_FIELD(u8_t _ttl);
|
||||
/* protocol*/
|
||||
@@ -141,9 +143,9 @@ PACK_STRUCT_END
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
|
||||
#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)
|
||||
#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)
|
||||
#define IPH_V(hdr) ((hdr)->_v_hl >> 4)
|
||||
#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f)
|
||||
#define IPH_TOS(hdr) ((hdr)->_tos)
|
||||
#define IPH_LEN(hdr) ((hdr)->_len)
|
||||
#define IPH_ID(hdr) ((hdr)->_id)
|
||||
#define IPH_OFFSET(hdr) ((hdr)->_offset)
|
||||
@@ -151,7 +153,8 @@ PACK_STRUCT_END
|
||||
#define IPH_PROTO(hdr) ((hdr)->_proto)
|
||||
#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
|
||||
|
||||
#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
|
||||
#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (((v) << 4) | (hl))
|
||||
#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos)
|
||||
#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
|
||||
#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
|
||||
#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
|
||||
@@ -198,6 +201,13 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
/** Destination IP address of current_header */
|
||||
#define ip_current_dest_addr() (¤t_iphdr_dest)
|
||||
|
||||
/** Gets an IP pcb option (SOF_* flags) */
|
||||
#define ip_get_option(pcb, opt) ((pcb)->so_options & (opt))
|
||||
/** Sets an IP pcb option (SOF_* flags) */
|
||||
#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt))
|
||||
/** Resets an IP pcb option (SOF_* flags) */
|
||||
#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
|
||||
|
||||
#if IP_DEBUG
|
||||
void ip_debug_print(struct pbuf *p);
|
||||
#else
|
||||
|
||||
@@ -159,6 +159,11 @@ struct netconn {
|
||||
#if LWIP_SOCKET
|
||||
int socket;
|
||||
#endif /* LWIP_SOCKET */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
/** timeout to wait for sending data (which means enqueueing data for sending
|
||||
in internal buffers) */
|
||||
s32_t send_timeout;
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
/** timeout to wait for new data to be received
|
||||
(or connections to arrive for listening netconns) */
|
||||
@@ -230,8 +235,10 @@ void netconn_recved(struct netconn *conn, u32_t length);
|
||||
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
|
||||
ip_addr_t *addr, u16_t port);
|
||||
err_t netconn_send(struct netconn *conn, struct netbuf *buf);
|
||||
err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size,
|
||||
u8_t apiflags);
|
||||
err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
|
||||
u8_t apiflags, size_t *bytes_written);
|
||||
#define netconn_write(conn, dataptr, size, apiflags) \
|
||||
netconn_write_partly(conn, dataptr, size, apiflags, NULL)
|
||||
err_t netconn_close(struct netconn *conn);
|
||||
err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
|
||||
|
||||
@@ -262,6 +269,12 @@ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
|
||||
/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
|
||||
#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
|
||||
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
/** Set the send timeout in milliseconds */
|
||||
#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout))
|
||||
/** Get the send timeout in milliseconds */
|
||||
#define netconn_get_sendtimeout(conn) ((conn)->send_timeout)
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
/** Set the receive timeout in milliseconds */
|
||||
#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
|
||||
|
||||
@@ -89,6 +89,9 @@ struct api_msg_msg {
|
||||
const void *dataptr;
|
||||
size_t len;
|
||||
u8_t apiflags;
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
u32_t time_started;
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
} w;
|
||||
/** used for do_recv */
|
||||
struct {
|
||||
|
||||
@@ -204,27 +204,6 @@ extern "C" {
|
||||
#define ENOMEDIUM 123 /* No medium found */
|
||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||
|
||||
|
||||
#define ENSROK 0 /* DNS server returned answer with no data */
|
||||
#define ENSRNODATA 160 /* DNS server returned answer with no data */
|
||||
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
|
||||
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
|
||||
#define ENSRNOTFOUND 163 /* Domain name not found */
|
||||
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
|
||||
#define ENSRREFUSED 165 /* DNS server refused query */
|
||||
#define ENSRBADQUERY 166 /* Misformatted DNS query */
|
||||
#define ENSRBADNAME 167 /* Misformatted domain name */
|
||||
#define ENSRBADFAMILY 168 /* Unsupported address family */
|
||||
#define ENSRBADRESP 169 /* Misformatted DNS reply */
|
||||
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
|
||||
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
|
||||
#define ENSROF 172 /* End of file */
|
||||
#define ENSRFILE 173 /* Error reading file */
|
||||
#define ENSRNOMEM 174 /* Out of memory */
|
||||
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
|
||||
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
|
||||
#define ENSRCNAMELOOP 177 /* Domain name is too long */
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#define __LWIP_DEBUG_H__
|
||||
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
/** lower two bits indicate debug level
|
||||
* - 0 all
|
||||
|
||||
@@ -47,10 +47,6 @@ extern "C" {
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
/** Get the absolute difference between 2 u32_t values (correcting overflows)
|
||||
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
|
||||
#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
|
||||
|
||||
/* Endianess-optimized shifting of two u8_t to create one u16_t */
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define LWIP_MAKE_U16(a, b) ((a << 8) | b)
|
||||
|
||||
@@ -57,20 +57,19 @@ typedef s8_t err_t;
|
||||
#define ERR_INPROGRESS -5 /* Operation in progress */
|
||||
#define ERR_VAL -6 /* Illegal value. */
|
||||
#define ERR_WOULDBLOCK -7 /* Operation would block. */
|
||||
#define ERR_USE -8 /* Address in use. */
|
||||
#define ERR_ISCONN -9 /* Already connected. */
|
||||
|
||||
#define ERR_IS_FATAL(e) ((e) < ERR_WOULDBLOCK)
|
||||
#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
|
||||
|
||||
#define ERR_ABRT -8 /* Connection aborted. */
|
||||
#define ERR_RST -9 /* Connection reset. */
|
||||
#define ERR_CLSD -10 /* Connection closed. */
|
||||
#define ERR_CONN -11 /* Not connected. */
|
||||
#define ERR_ABRT -10 /* Connection aborted. */
|
||||
#define ERR_RST -11 /* Connection reset. */
|
||||
#define ERR_CLSD -12 /* Connection closed. */
|
||||
#define ERR_CONN -13 /* Not connected. */
|
||||
|
||||
#define ERR_ARG -12 /* Illegal argument. */
|
||||
#define ERR_ARG -14 /* Illegal argument. */
|
||||
|
||||
#define ERR_USE -13 /* Address in use. */
|
||||
|
||||
#define ERR_IF -14 /* Low-level netif error */
|
||||
#define ERR_ISCONN -15 /* Already connected. */
|
||||
#define ERR_IF -15 /* Low-level netif error */
|
||||
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
|
||||
@@ -43,11 +43,11 @@ extern "C" {
|
||||
/** x.X.x: Minor version of the stack */
|
||||
#define LWIP_VERSION_MINOR 4U
|
||||
/** x.x.X: Revision of the stack */
|
||||
#define LWIP_VERSION_REVISION 0U
|
||||
#define LWIP_VERSION_REVISION 1U
|
||||
/** For release candidates, this is set to 1..254
|
||||
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
|
||||
* For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
|
||||
#define LWIP_VERSION_RC 2U
|
||||
#define LWIP_VERSION_RC 0U
|
||||
|
||||
/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
|
||||
#define LWIP_RC_RELEASE 255U
|
||||
|
||||
@@ -43,6 +43,7 @@ extern "C" {
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
typedef size_t mem_size_t;
|
||||
#define MEM_SIZE_F SZT_F
|
||||
|
||||
/* aliases for C library malloc() */
|
||||
#define mem_init()
|
||||
@@ -68,7 +69,7 @@ typedef size_t mem_size_t;
|
||||
/* MEM_SIZE would have to be aligned, but using 64000 here instead of
|
||||
* 65535 leaves some room for alignment...
|
||||
*/
|
||||
#if MEM_SIZE > 64000l
|
||||
#if MEM_SIZE > 64000L
|
||||
typedef u32_t mem_size_t;
|
||||
#define MEM_SIZE_F U32_F
|
||||
#else
|
||||
|
||||
@@ -63,9 +63,9 @@ LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg),
|
||||
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
#endif /* NO_SYS==0 */
|
||||
|
||||
#if ARP_QUEUEING
|
||||
#if LWIP_ARP && ARP_QUEUEING
|
||||
LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE")
|
||||
#endif /* ARP_QUEUEING */
|
||||
#endif /* LWIP_ARP && ARP_QUEUEING */
|
||||
|
||||
#if LWIP_IGMP
|
||||
LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
|
||||
|
||||
@@ -163,6 +163,10 @@ struct netif {
|
||||
*/
|
||||
netif_status_callback_fn link_callback;
|
||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||
#if LWIP_NETIF_REMOVE_CALLBACK
|
||||
/** This function is called when the netif has been removed */
|
||||
netif_status_callback_fn remove_callback;
|
||||
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
|
||||
/** This field can be set by the device driver and could point
|
||||
* to state information for the device. */
|
||||
void *state;
|
||||
@@ -280,6 +284,9 @@ void netif_set_down(struct netif *netif);
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback);
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
#if LWIP_NETIF_REMOVE_CALLBACK
|
||||
void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback);
|
||||
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
|
||||
|
||||
void netif_set_link_up(struct netif *netif);
|
||||
void netif_set_link_down(struct netif *netif);
|
||||
@@ -308,6 +315,12 @@ void netif_poll_all(void);
|
||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint))
|
||||
#else /* LWIP_NETIF_HWADDRHINT */
|
||||
#define NETIF_SET_HWADDRHINT(netif, hint)
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -309,9 +309,11 @@
|
||||
/**
|
||||
* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.
|
||||
* (requires NO_SYS==0)
|
||||
* The default number of timeouts is calculated here for all enabled modules.
|
||||
* The formula expects settings to be either '0' or '1'.
|
||||
*/
|
||||
#ifndef MEMP_NUM_SYS_TIMEOUT
|
||||
#define MEMP_NUM_SYS_TIMEOUT 3
|
||||
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -461,6 +463,8 @@
|
||||
* 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.
|
||||
* Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan)
|
||||
* that returns 1 to accept a packet or 0 to drop a packet.
|
||||
*/
|
||||
#ifndef ETHARP_SUPPORT_VLAN
|
||||
#define ETHARP_SUPPORT_VLAN 0
|
||||
@@ -593,6 +597,26 @@
|
||||
#define IP_SOF_BROADCAST_RECV 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back
|
||||
* out on the netif where it was received. This should only be used for
|
||||
* wireless networks.
|
||||
* ATTENTION: When this is 1, make sure your netif driver correctly marks incoming
|
||||
* link-layer-broadcast/multicast packets as such using the corresponding pbuf flags!
|
||||
*/
|
||||
#ifndef IP_FORWARD_ALLOW_TX_ON_RX_NETIF
|
||||
#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first
|
||||
* local TCP/UDP pcb (default==0). This can prevent creating predictable port
|
||||
* numbers after booting a device.
|
||||
*/
|
||||
#ifndef LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS
|
||||
#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
----------------------------------
|
||||
---------- ICMP options ----------
|
||||
@@ -946,10 +970,11 @@
|
||||
|
||||
|
||||
/**
|
||||
* TCP_SND_BUF: TCP sender buffer space (bytes).
|
||||
* TCP_SND_BUF: TCP sender buffer space (bytes).
|
||||
* To achieve good performance, this should be at least 2 * TCP_MSS.
|
||||
*/
|
||||
#ifndef TCP_SND_BUF
|
||||
#define TCP_SND_BUF 256
|
||||
#define TCP_SND_BUF (2 * TCP_MSS)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -966,16 +991,32 @@
|
||||
* TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT).
|
||||
*/
|
||||
#ifndef TCP_SNDLOWAT
|
||||
#define TCP_SNDLOWAT ((TCP_SND_BUF)/2)
|
||||
#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater
|
||||
* TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less
|
||||
* than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below
|
||||
* this number, select returns writable (combined with TCP_SNDLOWAT).
|
||||
*/
|
||||
#ifndef TCP_SNDQUEUELOWAT
|
||||
#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2)
|
||||
#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb.
|
||||
* Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0.
|
||||
*/
|
||||
#ifndef TCP_OOSEQ_MAX_BYTES
|
||||
#define TCP_OOSEQ_MAX_BYTES 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb.
|
||||
* Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0.
|
||||
*/
|
||||
#ifndef TCP_OOSEQ_MAX_PBUFS
|
||||
#define TCP_OOSEQ_MAX_PBUFS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -1032,14 +1073,11 @@
|
||||
* LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all
|
||||
* events (accept, sent, etc) that happen in the system.
|
||||
* LWIP_CALLBACK_API==1: The PCB callback function is called directly
|
||||
* for the event.
|
||||
* for the event. This is the default.
|
||||
*/
|
||||
#ifndef LWIP_EVENT_API
|
||||
#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API)
|
||||
#define LWIP_EVENT_API 0
|
||||
#define LWIP_CALLBACK_API 1
|
||||
#else
|
||||
#define LWIP_EVENT_API 1
|
||||
#define LWIP_CALLBACK_API 0
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1102,6 +1140,14 @@
|
||||
#define LWIP_NETIF_LINK_CALLBACK 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called
|
||||
* when a netif has been removed
|
||||
*/
|
||||
#ifndef LWIP_NETIF_REMOVE_CALLBACK
|
||||
#define LWIP_NETIF_REMOVE_CALLBACK 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table
|
||||
* indices) in struct netif. TCP and UDP can make use of this to prevent
|
||||
@@ -1407,7 +1453,16 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing.
|
||||
* LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and
|
||||
* SO_SNDTIMEO processing.
|
||||
*/
|
||||
#ifndef LWIP_SO_SNDTIMEO
|
||||
#define LWIP_SO_SNDTIMEO 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
|
||||
* SO_RCVTIMEO processing.
|
||||
*/
|
||||
#ifndef LWIP_SO_RCVTIMEO
|
||||
#define LWIP_SO_RCVTIMEO 0
|
||||
@@ -1749,6 +1804,13 @@
|
||||
#ifndef CHECKSUM_GEN_TCP
|
||||
#define CHECKSUM_GEN_TCP 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets.
|
||||
*/
|
||||
#ifndef CHECKSUM_GEN_ICMP
|
||||
#define CHECKSUM_GEN_ICMP 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.
|
||||
@@ -1779,6 +1841,34 @@
|
||||
#define LWIP_CHECKSUM_ON_COPY 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
---------------------------------------
|
||||
---------- Hook options ---------------
|
||||
---------------------------------------
|
||||
*/
|
||||
|
||||
/* Hooks are undefined by default, define them to a function if you need them. */
|
||||
|
||||
/**
|
||||
* LWIP_HOOK_IP4_INPUT(pbuf, input_netif):
|
||||
* - called from ip_input() (IPv4)
|
||||
* - pbuf: received struct pbuf passed to ip_input()
|
||||
* - input_netif: struct netif on which the packet has been received
|
||||
* Return values:
|
||||
* - 0: Hook has not consumed the packet, packet is processed as normal
|
||||
* - != 0: Hook has consumed the packet.
|
||||
* If the hook consumed the packet, 'pbuf' is in the responsibility of the hook
|
||||
* (i.e. free it when done).
|
||||
*/
|
||||
|
||||
/**
|
||||
* LWIP_HOOK_IP4_ROUTE(dest):
|
||||
* - called from ip_route() (IPv4)
|
||||
* - dest: destination IPv4 address
|
||||
* Returns the destination netif or NULL if no destination netif is found. In
|
||||
* that case, ip_route() continues as normal.
|
||||
*/
|
||||
|
||||
/*
|
||||
---------------------------------------
|
||||
---------- Debugging options ----------
|
||||
|
||||
@@ -69,6 +69,12 @@ typedef enum {
|
||||
#define PBUF_FLAG_IS_CUSTOM 0x02U
|
||||
/** indicates this pbuf is UDP multicast to be looped back */
|
||||
#define PBUF_FLAG_MCASTLOOP 0x04U
|
||||
/** indicates this pbuf was received as link-level broadcast */
|
||||
#define PBUF_FLAG_LLBCAST 0x08U
|
||||
/** indicates this pbuf was received as link-level multicast */
|
||||
#define PBUF_FLAG_LLMCAST 0x10U
|
||||
/** indicates this pbuf includes a TCP FIN flag */
|
||||
#define PBUF_FLAG_TCP_FIN 0x20U
|
||||
|
||||
struct pbuf {
|
||||
/** next pbuf in singly linked pbuf chain */
|
||||
@@ -116,6 +122,24 @@ struct pbuf_custom {
|
||||
};
|
||||
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
|
||||
|
||||
#if LWIP_TCP && TCP_QUEUE_OOSEQ
|
||||
/** 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 NO_SYS && PBUF_POOL_FREE_OOSEQ
|
||||
extern volatile u8_t pbuf_free_ooseq_pending;
|
||||
void pbuf_free_ooseq();
|
||||
/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ()
|
||||
at regular intervals from main level to check if ooseq pbufs need to be
|
||||
freed! */
|
||||
#define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \
|
||||
/* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \
|
||||
ooseq queued pbufs now */ \
|
||||
pbuf_free_ooseq(); }}while(0)
|
||||
#endif /* NO_SYS && PBUF_POOL_FREE_OOSEQ*/
|
||||
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ */
|
||||
|
||||
/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
|
||||
#define pbuf_init()
|
||||
|
||||
|
||||
@@ -62,8 +62,10 @@ struct sockaddr {
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
#ifndef socklen_t
|
||||
# define socklen_t u32_t
|
||||
/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED
|
||||
to prevent this code from redefining it. */
|
||||
#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED)
|
||||
typedef u32_t socklen_t;
|
||||
#endif
|
||||
|
||||
/* Socket protocol types (TCP/UDP/RAW) */
|
||||
@@ -363,6 +365,7 @@ int lwip_fcntl(int s, int cmd, int val);
|
||||
#define read(a,b,c) lwip_read(a,b,c)
|
||||
#define write(a,b,c) lwip_write(a,b,c)
|
||||
#define close(s) lwip_close(s)
|
||||
#define fcntl(a,b,c) lwip_fcntl(a,b,c)
|
||||
#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */
|
||||
|
||||
#endif /* LWIP_COMPAT_SOCKETS */
|
||||
|
||||
@@ -271,9 +271,9 @@ void stats_init(void);
|
||||
/* Display of statistics */
|
||||
#if LWIP_STATS_DISPLAY
|
||||
void stats_display(void);
|
||||
void stats_display_proto(struct stats_proto *proto, char *name);
|
||||
void stats_display_proto(struct stats_proto *proto, const char *name);
|
||||
void stats_display_igmp(struct stats_igmp *igmp);
|
||||
void stats_display_mem(struct stats_mem *mem, char *name);
|
||||
void stats_display_mem(struct stats_mem *mem, const char *name);
|
||||
void stats_display_memp(struct stats_mem *mem, int index);
|
||||
void stats_display_sys(struct stats_sys *sys);
|
||||
#else /* LWIP_STATS_DISPLAY */
|
||||
|
||||
@@ -51,16 +51,22 @@ typedef u8_t sys_mbox_t;
|
||||
#define sys_sem_wait(s)
|
||||
#define sys_arch_sem_wait(s,t)
|
||||
#define sys_sem_free(s)
|
||||
#define sys_sem_valid(s) 0
|
||||
#define sys_sem_set_invalid(s)
|
||||
#define sys_mutex_new(mu) ERR_OK
|
||||
#define sys_mutex_lock(mu)
|
||||
#define sys_mutex_unlock(mu)
|
||||
#define sys_mutex_free(mu)
|
||||
#define sys_mutex_valid(mu) 0
|
||||
#define sys_mutex_set_invalid(mu)
|
||||
#define sys_mbox_new(m, s) ERR_OK
|
||||
#define sys_mbox_fetch(m,d)
|
||||
#define sys_mbox_tryfetch(m,d)
|
||||
#define sys_mbox_post(m,d)
|
||||
#define sys_mbox_trypost(m,d)
|
||||
#define sys_mbox_free(m)
|
||||
#define sys_mbox_valid(m)
|
||||
#define sys_mbox_set_invalid(m)
|
||||
|
||||
#define sys_thread_new(n,t,a,s,p)
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
|
||||
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip.h"
|
||||
@@ -156,11 +155,11 @@ enum tcp_state {
|
||||
*/
|
||||
#define TCP_PCB_COMMON(type) \
|
||||
type *next; /* for the linked list */ \
|
||||
enum tcp_state state; /* TCP state */ \
|
||||
u8_t prio; \
|
||||
void *callback_arg; \
|
||||
/* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \
|
||||
DEF_ACCEPT_CALLBACK \
|
||||
enum tcp_state state; /* TCP state */ \
|
||||
u8_t prio; \
|
||||
/* ports are in host byte order */ \
|
||||
u16_t local_port
|
||||
|
||||
@@ -187,21 +186,23 @@ struct tcp_pcb {
|
||||
|
||||
/* the rest of the fields are in host byte order
|
||||
as we have to do some math with them */
|
||||
|
||||
/* Timers */
|
||||
u8_t polltmr, pollinterval;
|
||||
u8_t last_timer;
|
||||
u32_t tmr;
|
||||
|
||||
/* receiver variables */
|
||||
u32_t rcv_nxt; /* next seqno expected */
|
||||
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;
|
||||
u8_t polltmr, pollinterval;
|
||||
|
||||
/* Retransmission timer. */
|
||||
s16_t rtime;
|
||||
|
||||
|
||||
u16_t mss; /* maximum segment size */
|
||||
|
||||
|
||||
/* RTT (round trip time) estimation variables */
|
||||
u32_t rttest; /* RTT estimate in 500ms ticks */
|
||||
u32_t rtseq; /* sequence number being timed */
|
||||
@@ -211,24 +212,25 @@ struct tcp_pcb {
|
||||
u8_t nrtx; /* number of retransmissions */
|
||||
|
||||
/* fast retransmit/recovery */
|
||||
u32_t lastack; /* Highest acknowledged seqno. */
|
||||
u8_t dupacks;
|
||||
|
||||
u32_t lastack; /* Highest acknowledged seqno. */
|
||||
|
||||
/* congestion avoidance/control variables */
|
||||
u16_t cwnd;
|
||||
u16_t cwnd;
|
||||
u16_t ssthresh;
|
||||
|
||||
/* sender variables */
|
||||
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
|
||||
window update. */
|
||||
u32_t snd_lbb; /* Sequence number of next byte to be buffered. */
|
||||
u16_t snd_wnd; /* sender window */
|
||||
u16_t snd_wnd_max; /* the maximum sender window announced by the remote host */
|
||||
|
||||
u16_t acked;
|
||||
|
||||
|
||||
u16_t snd_buf; /* Available buffer space for sending (in bytes). */
|
||||
#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3)
|
||||
#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
|
||||
u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */
|
||||
|
||||
#if TCP_OVERSIZE
|
||||
@@ -271,7 +273,7 @@ struct tcp_pcb {
|
||||
#endif /* LWIP_TCP_KEEPALIVE */
|
||||
|
||||
/* Persist timer counter */
|
||||
u32_t persist_cnt;
|
||||
u8_t persist_cnt;
|
||||
/* Persist timer back-off */
|
||||
u8_t persist_backoff;
|
||||
|
||||
@@ -333,7 +335,7 @@ void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err);
|
||||
(((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0)
|
||||
#else /* TCP_LISTEN_BACKLOG */
|
||||
#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \
|
||||
pcb->state == LISTEN)
|
||||
(pcb)->state == LISTEN)
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
void tcp_recved (struct tcp_pcb *pcb, u16_t len);
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip.h"
|
||||
@@ -51,7 +50,7 @@ extern "C" {
|
||||
/* Functions for interfacing with TCP: */
|
||||
|
||||
/* Lower layer interface to TCP: */
|
||||
#define tcp_init() /* Compatibility define, no init needed. */
|
||||
void tcp_init (void); /* Initialize this module. */
|
||||
void tcp_tmr (void); /* Must be called every
|
||||
TCP_TMR_INTERVAL
|
||||
ms. (Typically 250 ms). */
|
||||
@@ -71,6 +70,7 @@ 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);
|
||||
err_t tcp_process_refused_data(struct tcp_pcb *pcb);
|
||||
|
||||
/**
|
||||
* This is the Nagle algorithm: try to combine user data to send as few TCP
|
||||
@@ -84,15 +84,16 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
|
||||
#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
|
||||
((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \
|
||||
(((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
|
||||
((tpcb)->unsent->len >= (tpcb)->mss))) \
|
||||
((tpcb)->unsent->len >= (tpcb)->mss))) || \
|
||||
((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \
|
||||
) ? 1 : 0)
|
||||
#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)
|
||||
|
||||
|
||||
#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)
|
||||
#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0)
|
||||
#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0)
|
||||
#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0)
|
||||
#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0)
|
||||
#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0)
|
||||
/* is b<=a<=c? */
|
||||
#if 0 /* see bug #10548 */
|
||||
#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
|
||||
@@ -278,7 +279,6 @@ PACK_STRUCT_END
|
||||
struct tcp_seg {
|
||||
struct tcp_seg *next; /* used when putting segements on a queue */
|
||||
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 */
|
||||
#if TCP_OVERSIZE_DBGCHECK
|
||||
u16_t oversize_left; /* Extra bytes available at the end of the last
|
||||
@@ -302,14 +302,12 @@ struct tcp_seg {
|
||||
(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) = PP_HTONL(((u32_t)2 << 24) | \
|
||||
((u32_t)4 << 16) | \
|
||||
(((u32_t)TCP_MSS / 256) << 8) | \
|
||||
(TCP_MSS & 255))
|
||||
#define TCP_BUILD_MSS_OPTION(mss) htonl(0x02040000 | ((mss) & 0xFFFF))
|
||||
|
||||
/* Global variables: */
|
||||
extern struct tcp_pcb *tcp_input_pcb;
|
||||
extern u32_t tcp_ticks;
|
||||
extern u8_t tcp_active_pcbs_changed;
|
||||
|
||||
/* The TCP PCB lists. */
|
||||
union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */
|
||||
@@ -396,6 +394,24 @@ extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
|
||||
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
#define TCP_REG_ACTIVE(npcb) \
|
||||
do { \
|
||||
TCP_REG(&tcp_active_pcbs, npcb); \
|
||||
tcp_active_pcbs_changed = 1; \
|
||||
} while (0)
|
||||
|
||||
#define TCP_RMV_ACTIVE(npcb) \
|
||||
do { \
|
||||
TCP_RMV(&tcp_active_pcbs, npcb); \
|
||||
tcp_active_pcbs_changed = 1; \
|
||||
} while (0)
|
||||
|
||||
#define TCP_PCB_REMOVE_ACTIVE(pcb) \
|
||||
do { \
|
||||
tcp_pcb_remove(&tcp_active_pcbs, pcb); \
|
||||
tcp_active_pcbs_changed = 1; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Internal functions: */
|
||||
struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
|
||||
|
||||
@@ -77,6 +77,9 @@ typedef void (*tcpip_init_done_fn)(void *arg);
|
||||
/** Function prototype for functions passed to tcpip_callback() */
|
||||
typedef void (*tcpip_callback_fn)(void *ctx);
|
||||
|
||||
/* Forward declarations */
|
||||
struct tcpip_callback_msg;
|
||||
|
||||
void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg);
|
||||
|
||||
#if LWIP_NETCONN
|
||||
@@ -98,6 +101,10 @@ err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
|
||||
err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block);
|
||||
#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1)
|
||||
|
||||
struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx);
|
||||
void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg);
|
||||
err_t tcpip_trycallback(struct tcpip_callback_msg* msg);
|
||||
|
||||
/* 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);
|
||||
@@ -119,7 +126,8 @@ enum tcpip_msg_type {
|
||||
TCPIP_MSG_TIMEOUT,
|
||||
TCPIP_MSG_UNTIMEOUT,
|
||||
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||
TCPIP_MSG_CALLBACK
|
||||
TCPIP_MSG_CALLBACK,
|
||||
TCPIP_MSG_CALLBACK_STATIC
|
||||
};
|
||||
|
||||
struct tcpip_msg {
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
#if LWIP_TIMERS
|
||||
|
||||
#include "lwip/err.h"
|
||||
#if !NO_SYS
|
||||
#include "lwip/sys.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -154,7 +154,7 @@ err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
|
||||
/* The following functions are the lower layer interface to UDP. */
|
||||
void udp_input (struct pbuf *p, struct netif *inp);
|
||||
|
||||
#define udp_init() /* Compatibility define, not init needed. */
|
||||
void udp_init (void);
|
||||
|
||||
#if UDP_DEBUG
|
||||
void udp_debug_print(struct udp_hdr *udphdr);
|
||||
|
||||
@@ -94,8 +94,8 @@ PACK_STRUCT_BEGIN
|
||||
* if 'type' in ethernet header is ETHTYPE_VLAN.
|
||||
* See IEEE802.Q */
|
||||
struct eth_vlan_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t tpid);
|
||||
PACK_STRUCT_FIELD(u16_t prio_vid);
|
||||
PACK_STRUCT_FIELD(u16_t tpid);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
@@ -134,11 +134,11 @@ PACK_STRUCT_END
|
||||
/** 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 */
|
||||
#define ETHTYPE_ARP 0x0806U
|
||||
#define ETHTYPE_IP 0x0800U
|
||||
#define ETHTYPE_VLAN 0x8100U
|
||||
#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */
|
||||
#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */
|
||||
|
||||
/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
|
||||
* or known to be 32-bit aligned within the protocol header. */
|
||||
@@ -190,6 +190,7 @@ err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr);
|
||||
* 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)
|
||||
void etharp_cleanup_netif(struct netif *netif);
|
||||
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr);
|
||||
|
||||
@@ -34,14 +34,44 @@
|
||||
#ifndef __NETIF_SLIPIF_H__
|
||||
#define __NETIF_SLIPIF_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
/** Set this to 1 to start a thread that blocks reading on the serial line
|
||||
* (using sio_read()).
|
||||
*/
|
||||
#ifndef SLIP_USE_RX_THREAD
|
||||
#define SLIP_USE_RX_THREAD !NO_SYS
|
||||
#endif
|
||||
|
||||
/** Set this to 1 to enable functions to pass in RX bytes from ISR context.
|
||||
* If enabled, slipif_received_byte[s]() process incoming bytes and put assembled
|
||||
* packets on a queue, which is fed into lwIP from slipif_poll().
|
||||
* If disabled, slipif_poll() polls the serila line (using sio_tryread()).
|
||||
*/
|
||||
#ifndef SLIP_RX_FROM_ISR
|
||||
#define SLIP_RX_FROM_ISR 0
|
||||
#endif
|
||||
|
||||
/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets
|
||||
* received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available.
|
||||
* If disabled, packets will be dropped if more than one packet is received.
|
||||
*/
|
||||
#ifndef SLIP_RX_QUEUE
|
||||
#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
err_t slipif_init(struct netif * netif);
|
||||
void slipif_poll(struct netif *netif);
|
||||
#if SLIP_RX_FROM_ISR
|
||||
void slipif_process_rxqueue(struct netif *netif);
|
||||
void slipif_received_byte(struct netif *netif, u8_t data);
|
||||
void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len);
|
||||
#endif /* SLIP_RX_FROM_ISR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -65,13 +65,22 @@
|
||||
const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
|
||||
const struct eth_addr ethzero = {{0,0,0,0,0,0}};
|
||||
|
||||
/** The 24-bit IANA multicast OUI is 01-00-5e: */
|
||||
#define LL_MULTICAST_ADDR_0 0x01
|
||||
#define LL_MULTICAST_ADDR_1 0x00
|
||||
#define LL_MULTICAST_ADDR_2 0x5e
|
||||
|
||||
#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
/** the time an ARP entry stays valid after its last update,
|
||||
* for ARP_TMR_INTERVAL = 5000, this is
|
||||
* (240 * 5) seconds = 20 minutes.
|
||||
*/
|
||||
#define ARP_MAXAGE 240
|
||||
#define ARP_MAXAGE 240
|
||||
/** Re-request a used ARP entry 1 minute before it would expire to prevent
|
||||
* breaking a steadily used connection because the ARP entry timed out. */
|
||||
#define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 12)
|
||||
|
||||
/** the time an ARP entry stays pending after first request,
|
||||
* for ARP_TMR_INTERVAL = 5000, this is
|
||||
* (2 * 5) seconds = 10 seconds.
|
||||
@@ -86,7 +95,11 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}};
|
||||
enum etharp_state {
|
||||
ETHARP_STATE_EMPTY = 0,
|
||||
ETHARP_STATE_PENDING,
|
||||
ETHARP_STATE_STABLE
|
||||
ETHARP_STATE_STABLE,
|
||||
ETHARP_STATE_STABLE_REREQUESTING
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
,ETHARP_STATE_STATIC
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
};
|
||||
|
||||
struct etharp_entry {
|
||||
@@ -98,15 +111,10 @@ struct etharp_entry {
|
||||
struct pbuf *q;
|
||||
#endif /* ARP_QUEUEING */
|
||||
ip_addr_t ipaddr;
|
||||
struct eth_addr ethaddr;
|
||||
#if LWIP_SNMP
|
||||
struct netif *netif;
|
||||
#endif /* LWIP_SNMP */
|
||||
struct eth_addr ethaddr;
|
||||
u8_t state;
|
||||
u8_t ctime;
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
u8_t static_entry;
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
};
|
||||
|
||||
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
|
||||
@@ -119,7 +127,9 @@ static u8_t etharp_cached_entry;
|
||||
the cache (even if this means removing an active entry or so). */
|
||||
#define ETHARP_FLAG_TRY_HARD 1
|
||||
#define ETHARP_FLAG_FIND_ONLY 2
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
#define ETHARP_FLAG_STATIC_ENTRY 4
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \
|
||||
@@ -128,8 +138,6 @@ static u8_t etharp_cached_entry;
|
||||
#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint))
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
|
||||
static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);
|
||||
|
||||
|
||||
/* Some checks, instead of etharp_init(): */
|
||||
#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
|
||||
@@ -166,28 +174,23 @@ free_etharp_q(struct etharp_q_entry *q)
|
||||
|
||||
/** Clean up ARP table entries */
|
||||
static void
|
||||
free_entry(int i)
|
||||
etharp_free_entry(int i)
|
||||
{
|
||||
/* remove from SNMP ARP index tree */
|
||||
snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
|
||||
/* and empty packet queue */
|
||||
if (arp_table[i].q != NULL) {
|
||||
/* remove all queued packets */
|
||||
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
|
||||
free_etharp_q(arp_table[i].q);
|
||||
arp_table[i].q = NULL;
|
||||
}
|
||||
/* recycle entry for re-use */
|
||||
/* recycle entry for re-use */
|
||||
arp_table[i].state = ETHARP_STATE_EMPTY;
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
arp_table[i].static_entry = 0;
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
#ifdef LWIP_DEBUG
|
||||
/* for debugging, clean out the complete entry */
|
||||
arp_table[i].ctime = 0;
|
||||
#if LWIP_SNMP
|
||||
arp_table[i].netif = NULL;
|
||||
#endif /* LWIP_SNMP */
|
||||
ip_addr_set_zero(&arp_table[i].ipaddr);
|
||||
arp_table[i].ethaddr = ethzero;
|
||||
#endif /* LWIP_DEBUG */
|
||||
@@ -210,7 +213,7 @@ etharp_tmr(void)
|
||||
u8_t state = arp_table[i].state;
|
||||
if (state != ETHARP_STATE_EMPTY
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
&& (arp_table[i].static_entry == 0)
|
||||
&& (state != ETHARP_STATE_STATIC)
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
) {
|
||||
arp_table[i].ctime++;
|
||||
@@ -219,9 +222,14 @@ etharp_tmr(void)
|
||||
(arp_table[i].ctime >= ARP_MAXPENDING))) {
|
||||
/* pending or stable entry has become old! */
|
||||
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
|
||||
arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
|
||||
arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
|
||||
/* clean up entries that have just been expired */
|
||||
free_entry(i);
|
||||
etharp_free_entry(i);
|
||||
}
|
||||
else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) {
|
||||
/* Reset state to stable, so that the next transmitted packet will
|
||||
re-send an ARP request. */
|
||||
arp_table[i].state = ETHARP_STATE_STABLE;
|
||||
}
|
||||
#if ARP_QUEUEING
|
||||
/* still pending entry? (not expired) */
|
||||
@@ -255,7 +263,7 @@ etharp_tmr(void)
|
||||
* entry is found or could be recycled.
|
||||
*/
|
||||
static s8_t
|
||||
find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
etharp_find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
{
|
||||
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
|
||||
s8_t empty = ARP_TABLE_SIZE;
|
||||
@@ -284,15 +292,15 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
u8_t state = arp_table[i].state;
|
||||
/* no empty entry found yet and now we do find one? */
|
||||
if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i));
|
||||
/* remember first empty entry */
|
||||
empty = i;
|
||||
} else if (state != ETHARP_STATE_EMPTY) {
|
||||
LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE",
|
||||
state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE);
|
||||
LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE",
|
||||
state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE);
|
||||
/* if given, does IP address match IP address in ARP entry? */
|
||||
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i));
|
||||
/* found exact IP address match, simply bail out */
|
||||
return i;
|
||||
}
|
||||
@@ -313,10 +321,10 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
}
|
||||
}
|
||||
/* stable entry? */
|
||||
} else if (state == ETHARP_STATE_STABLE) {
|
||||
} else if (state >= ETHARP_STATE_STABLE) {
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
/* don't record old_stable for static entries since they never expire */
|
||||
if (arp_table[i].static_entry == 0)
|
||||
if (state < ETHARP_STATE_STATIC)
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
{
|
||||
/* remember entry with oldest stable entry in oldest, its age in maxtime */
|
||||
@@ -334,7 +342,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
|
||||
/* or no empty entry found and not allowed to recycle? */
|
||||
((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n"));
|
||||
return (s8_t)ERR_MEM;
|
||||
}
|
||||
|
||||
@@ -350,34 +358,34 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
/* 1) empty entry available? */
|
||||
if (empty < ARP_TABLE_SIZE) {
|
||||
i = empty;
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
|
||||
} else {
|
||||
/* 2) found recyclable stable entry? */
|
||||
if (old_stable < ARP_TABLE_SIZE) {
|
||||
/* recycle oldest stable*/
|
||||
i = old_stable;
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
|
||||
/* no queued packets should exist on stable entries */
|
||||
LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
|
||||
/* 3) found recyclable pending entry without queued packets? */
|
||||
} else if (old_pending < ARP_TABLE_SIZE) {
|
||||
/* recycle oldest pending */
|
||||
i = old_pending;
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
|
||||
/* 4) found recyclable pending entry with queued packets? */
|
||||
} else if (old_queue < ARP_TABLE_SIZE) {
|
||||
/* recycle oldest pending (queued packets are free in free_entry) */
|
||||
/* recycle oldest pending (queued packets are free in etharp_free_entry) */
|
||||
i = old_queue;
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
|
||||
/* no empty or recyclable entries found */
|
||||
} else {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n"));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n"));
|
||||
return (s8_t)ERR_MEM;
|
||||
}
|
||||
|
||||
/* { empty or recyclable entry found } */
|
||||
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
|
||||
free_entry(i);
|
||||
etharp_free_entry(i);
|
||||
}
|
||||
|
||||
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
|
||||
@@ -390,9 +398,6 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
|
||||
}
|
||||
arp_table[i].ctime = 0;
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
arp_table[i].static_entry = 0;
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
return (err_t)i;
|
||||
}
|
||||
|
||||
@@ -440,11 +445,11 @@ etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct
|
||||
* @see pbuf_free()
|
||||
*/
|
||||
static err_t
|
||||
update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
|
||||
etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
|
||||
{
|
||||
s8_t i;
|
||||
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",
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_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_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
|
||||
ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
|
||||
ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
|
||||
@@ -452,11 +457,11 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
|
||||
if (ip_addr_isany(ipaddr) ||
|
||||
ip_addr_isbroadcast(ipaddr, netif) ||
|
||||
ip_addr_ismulticast(ipaddr)) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
|
||||
return ERR_ARG;
|
||||
}
|
||||
/* find or create ARP entry */
|
||||
i = find_entry(ipaddr, flags);
|
||||
i = etharp_find_entry(ipaddr, flags);
|
||||
/* bail out if no entry could be found */
|
||||
if (i < 0) {
|
||||
return (err_t)i;
|
||||
@@ -465,21 +470,20 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
if (flags & ETHARP_FLAG_STATIC_ENTRY) {
|
||||
/* record static type */
|
||||
arp_table[i].static_entry = 1;
|
||||
}
|
||||
arp_table[i].state = ETHARP_STATE_STATIC;
|
||||
} else
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
{
|
||||
/* mark it stable */
|
||||
arp_table[i].state = ETHARP_STATE_STABLE;
|
||||
}
|
||||
|
||||
/* mark it stable */
|
||||
arp_table[i].state = ETHARP_STATE_STABLE;
|
||||
|
||||
#if LWIP_SNMP
|
||||
/* record network interface */
|
||||
arp_table[i].netif = netif;
|
||||
#endif /* LWIP_SNMP */
|
||||
/* insert in SNMP ARP index tree */
|
||||
snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
|
||||
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
|
||||
/* update address */
|
||||
ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
|
||||
/* reset time stamp */
|
||||
@@ -532,7 +536,7 @@ etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
|
||||
return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
|
||||
}
|
||||
|
||||
/** Remove a static entry from the ARP table previously added with a call to
|
||||
@@ -551,23 +555,39 @@ etharp_remove_static_entry(ip_addr_t *ipaddr)
|
||||
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
|
||||
|
||||
/* find or create ARP entry */
|
||||
i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
|
||||
i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
|
||||
/* bail out if no entry could be found */
|
||||
if (i < 0) {
|
||||
return (err_t)i;
|
||||
}
|
||||
|
||||
if ((arp_table[i].state != ETHARP_STATE_STABLE) ||
|
||||
(arp_table[i].static_entry == 0)) {
|
||||
if (arp_table[i].state != ETHARP_STATE_STATIC) {
|
||||
/* entry wasn't a static entry, cannot remove it */
|
||||
return ERR_ARG;
|
||||
}
|
||||
/* entry found, free it */
|
||||
free_entry(i);
|
||||
etharp_free_entry(i);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
|
||||
/**
|
||||
* Remove all ARP table entries of the specified netif.
|
||||
*
|
||||
* @param netif points to a network interface
|
||||
*/
|
||||
void etharp_cleanup_netif(struct netif *netif)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
|
||||
u8_t state = arp_table[i].state;
|
||||
if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) {
|
||||
etharp_free_entry(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds (stable) ethernet/IP address pair from ARP table
|
||||
* using interface and IP address index.
|
||||
@@ -590,8 +610,8 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
|
||||
|
||||
LWIP_UNUSED_ARG(netif);
|
||||
|
||||
i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
|
||||
if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
|
||||
i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
|
||||
if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) {
|
||||
*eth_ret = &arp_table[i].ethaddr;
|
||||
*ip_ret = &arp_table[i].ipaddr;
|
||||
return i;
|
||||
@@ -628,7 +648,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
|
||||
ethhdr = (struct eth_hdr *)p->payload;
|
||||
iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
|
||||
#if ETHARP_SUPPORT_VLAN
|
||||
if (ethhdr->type == ETHTYPE_VLAN) {
|
||||
if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
|
||||
iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
|
||||
}
|
||||
#endif /* ETHARP_SUPPORT_VLAN */
|
||||
@@ -645,7 +665,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
|
||||
/* update the source IP address in the cache, if present */
|
||||
/* @todo We could use ETHARP_FLAG_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, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
|
||||
etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
|
||||
}
|
||||
#endif /* ETHARP_TRUST_IP_MAC */
|
||||
|
||||
@@ -693,7 +713,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
ethhdr = (struct eth_hdr *)p->payload;
|
||||
hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
|
||||
#if ETHARP_SUPPORT_VLAN
|
||||
if (ethhdr->type == ETHTYPE_VLAN) {
|
||||
if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
|
||||
hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
|
||||
}
|
||||
#endif /* ETHARP_SUPPORT_VLAN */
|
||||
@@ -702,11 +722,10 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
|
||||
(hdr->hwlen != ETHARP_HWADDR_LEN) ||
|
||||
(hdr->protolen != sizeof(ip_addr_t)) ||
|
||||
(hdr->proto != PP_HTONS(ETHTYPE_IP)) ||
|
||||
(ethhdr->type != PP_HTONS(ETHTYPE_ARP))) {
|
||||
(hdr->proto != PP_HTONS(ETHTYPE_IP))) {
|
||||
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, hdr->hwlen, hdr->proto, hdr->protolen, ethhdr->type));
|
||||
("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
|
||||
hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen));
|
||||
ETHARP_STATS_INC(etharp.proterr);
|
||||
ETHARP_STATS_INC(etharp.drop);
|
||||
pbuf_free(p);
|
||||
@@ -739,7 +758,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
can result in directly sending the queued packets for this host.
|
||||
ARP message not directed to us?
|
||||
-> update the source IP address in the cache, if present */
|
||||
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
|
||||
etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
|
||||
for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
|
||||
|
||||
/* now act on the message itself */
|
||||
@@ -816,6 +835,28 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
/** Just a small helper function that sends a pbuf to an ethernet address
|
||||
* in the arp_table specified by the index 'arp_idx'.
|
||||
*/
|
||||
static err_t
|
||||
etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
|
||||
{
|
||||
LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE",
|
||||
arp_table[arp_idx].state >= ETHARP_STATE_STABLE);
|
||||
/* if arp table entry is about to expire: re-request it,
|
||||
but only if its state is ETHARP_STATE_STABLE to prevent flooding the
|
||||
network with ARP requests if this address is used frequently. */
|
||||
if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) &&
|
||||
(arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) {
|
||||
if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) {
|
||||
arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING;
|
||||
}
|
||||
}
|
||||
|
||||
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
|
||||
&arp_table[arp_idx].ethaddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve and fill-in Ethernet address header for outgoing IP packet.
|
||||
*
|
||||
@@ -837,7 +878,13 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
err_t
|
||||
etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
|
||||
{
|
||||
struct eth_addr *dest, mcastaddr;
|
||||
struct eth_addr *dest;
|
||||
struct eth_addr mcastaddr;
|
||||
ip_addr_t *dst_addr = ipaddr;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||
LWIP_ASSERT("q != NULL", q != NULL);
|
||||
LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL);
|
||||
|
||||
/* make room for Ethernet header - should not fail */
|
||||
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
|
||||
@@ -848,8 +895,6 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
/* assume unresolved Ethernet address */
|
||||
dest = NULL;
|
||||
/* Determine on destination hardware address. Broadcasts and multicasts
|
||||
* are special, other IP addresses are looked up in the ARP table. */
|
||||
|
||||
@@ -860,9 +905,9 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
|
||||
/* multicast destination IP address? */
|
||||
} else if (ip_addr_ismulticast(ipaddr)) {
|
||||
/* Hash IP multicast address to MAC address.*/
|
||||
mcastaddr.addr[0] = 0x01;
|
||||
mcastaddr.addr[1] = 0x00;
|
||||
mcastaddr.addr[2] = 0x5e;
|
||||
mcastaddr.addr[0] = LL_MULTICAST_ADDR_0;
|
||||
mcastaddr.addr[1] = LL_MULTICAST_ADDR_1;
|
||||
mcastaddr.addr[2] = LL_MULTICAST_ADDR_2;
|
||||
mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
|
||||
mcastaddr.addr[4] = ip4_addr3(ipaddr);
|
||||
mcastaddr.addr[5] = ip4_addr4(ipaddr);
|
||||
@@ -870,7 +915,9 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
|
||||
dest = &mcastaddr;
|
||||
/* unicast destination IP address? */
|
||||
} else {
|
||||
/* outside local network? */
|
||||
s8_t i;
|
||||
/* outside local network? if so, this can neither be a global broadcast nor
|
||||
a subnet broadcast. */
|
||||
if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
|
||||
!ip_addr_islinklocal(ipaddr)) {
|
||||
#if LWIP_AUTOIP
|
||||
@@ -886,7 +933,7 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
|
||||
/* interface has default gateway? */
|
||||
if (!ip_addr_isany(&netif->gw)) {
|
||||
/* send to hardware address of default gateway IP address */
|
||||
ipaddr = &(netif->gw);
|
||||
dst_addr = &(netif->gw);
|
||||
/* no default gateway available */
|
||||
} else {
|
||||
/* no route to destination error (default gateway missing) */
|
||||
@@ -900,19 +947,30 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
|
||||
u8_t etharp_cached_entry = *(netif->addr_hint);
|
||||
if (etharp_cached_entry < ARP_TABLE_SIZE) {
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) &&
|
||||
(ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) {
|
||||
if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
|
||||
(ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
|
||||
/* the per-pcb-cached entry is stable and the right one! */
|
||||
ETHARP_STATS_INC(etharp.cachehit);
|
||||
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
|
||||
&arp_table[etharp_cached_entry].ethaddr);
|
||||
return etharp_output_to_arp_index(netif, q, etharp_cached_entry);
|
||||
}
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
/* queue on destination Ethernet address belonging to ipaddr */
|
||||
return etharp_query(netif, ipaddr, q);
|
||||
|
||||
/* find stable entry: do this here since this is a critical path for
|
||||
throughput and etharp_find_entry() is kind of slow */
|
||||
for (i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||
if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
|
||||
(ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) {
|
||||
/* found an existing, stable entry */
|
||||
ETHARP_SET_HINT(netif, i);
|
||||
return etharp_output_to_arp_index(netif, q, i);
|
||||
}
|
||||
}
|
||||
/* no stable entry found, use the (slower) query function:
|
||||
queue on destination Ethernet address belonging to ipaddr */
|
||||
return etharp_query(netif, dst_addr, q);
|
||||
}
|
||||
|
||||
/* continuation for multicast/broadcast destinations */
|
||||
@@ -970,7 +1028,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
|
||||
}
|
||||
|
||||
/* find entry in ARP cache, ask to create entry if queueing packet */
|
||||
i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
|
||||
i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
|
||||
|
||||
/* could not find or create entry? */
|
||||
if (i < 0) {
|
||||
@@ -990,7 +1048,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
|
||||
/* { i is either a STABLE or (new or existing) PENDING entry } */
|
||||
LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
|
||||
((arp_table[i].state == ETHARP_STATE_PENDING) ||
|
||||
(arp_table[i].state == ETHARP_STATE_STABLE)));
|
||||
(arp_table[i].state >= ETHARP_STATE_STABLE)));
|
||||
|
||||
/* do we have a pending entry? or an implicit query request? */
|
||||
if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
|
||||
@@ -1010,7 +1068,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
|
||||
/* packet given? */
|
||||
LWIP_ASSERT("q != NULL", q != NULL);
|
||||
/* stable entry? */
|
||||
if (arp_table[i].state == ETHARP_STATE_STABLE) {
|
||||
if (arp_table[i].state >= ETHARP_STATE_STABLE) {
|
||||
/* we have a valid IP->Ethernet address mapping */
|
||||
ETHARP_SET_HINT(netif, i);
|
||||
/* send the packet */
|
||||
@@ -1128,6 +1186,8 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
||||
const u8_t * ethdst_hwaddr;
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||
|
||||
/* allocate a pbuf for the outgoing ARP request packet */
|
||||
p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);
|
||||
/* could allocate a pbuf for an ARP request? */
|
||||
@@ -1218,6 +1278,16 @@ ethernet_input(struct pbuf *p, struct netif *netif)
|
||||
{
|
||||
struct eth_hdr* ethhdr;
|
||||
u16_t type;
|
||||
#if LWIP_ARP || ETHARP_SUPPORT_VLAN
|
||||
s16_t ip_hdr_offset = SIZEOF_ETH_HDR;
|
||||
#endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */
|
||||
|
||||
if (p->len <= SIZEOF_ETH_HDR) {
|
||||
/* a packet with only an ethernet header (or less) is not valid for us */
|
||||
ETHARP_STATS_INC(etharp.proterr);
|
||||
ETHARP_STATS_INC(etharp.drop);
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = (struct eth_hdr *)p->payload;
|
||||
@@ -1233,14 +1303,25 @@ ethernet_input(struct pbuf *p, struct netif *netif)
|
||||
#if ETHARP_SUPPORT_VLAN
|
||||
if (type == PP_HTONS(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 (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
|
||||
/* a packet with only an ethernet/vlan header (or less) is not valid for us */
|
||||
ETHARP_STATS_INC(etharp.proterr);
|
||||
ETHARP_STATS_INC(etharp.drop);
|
||||
goto free_and_return;
|
||||
}
|
||||
#if defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */
|
||||
#ifdef ETHARP_VLAN_CHECK_FN
|
||||
if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) {
|
||||
#elif defined(ETHARP_VLAN_CHECK)
|
||||
if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
|
||||
#endif
|
||||
/* silently ignore this packet: not for our VLAN */
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* ETHARP_VLAN_CHECK */
|
||||
#endif /* defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */
|
||||
type = vlan->tpid;
|
||||
ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
|
||||
}
|
||||
#endif /* ETHARP_SUPPORT_VLAN */
|
||||
|
||||
@@ -1248,6 +1329,20 @@ ethernet_input(struct pbuf *p, struct netif *netif)
|
||||
netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type));
|
||||
#endif /* LWIP_ARP_FILTER_NETIF*/
|
||||
|
||||
if (ethhdr->dest.addr[0] & 1) {
|
||||
/* this might be a multicast or broadcast packet */
|
||||
if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) {
|
||||
if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) &&
|
||||
(ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) {
|
||||
/* mark the pbuf as link-layer multicast */
|
||||
p->flags |= PBUF_FLAG_LLMCAST;
|
||||
}
|
||||
} else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) {
|
||||
/* mark the pbuf as link-layer broadcast */
|
||||
p->flags |= PBUF_FLAG_LLBCAST;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
#if LWIP_ARP
|
||||
/* IP packet? */
|
||||
@@ -1260,7 +1355,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_ETH_HDR)) {
|
||||
if(pbuf_header(p, -ip_hdr_offset)) {
|
||||
LWIP_ASSERT("Can't move over header in packet", 0);
|
||||
goto free_and_return;
|
||||
} else {
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <lwip/stats.h>
|
||||
#include <lwip/snmp.h>
|
||||
#include "netif/etharp.h"
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "fsm.h"
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
#if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "magic.h"
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
#if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "md4.h"
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "fsm.h"
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "auth.h"
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "fsm.h"
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
#if PPP_SUPPORT
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "randm.h"
|
||||
#include "magic.h"
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
#if CHAP_SUPPORT || MD5_SUPPORT
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "auth.h"
|
||||
@@ -218,7 +218,7 @@ upap_timeout(void *arg)
|
||||
u->us_unit, u->us_timeouttime, u->us_clientstate));
|
||||
|
||||
if (u->us_clientstate != UPAPCS_AUTHREQ) {
|
||||
UPAPDEBUG(LOG_INFO, ("upap_timeout: not in AUTHREQ state!\n"));
|
||||
UPAPDEBUG(LOG_INFO, ("upap_timeout: not in AUTHREQ state!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,9 +83,9 @@
|
||||
|
||||
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp_impl.h"
|
||||
#include "lwip/ip.h" /* for ip_input() */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "randm.h"
|
||||
@@ -172,7 +172,9 @@ typedef struct PPPControlRx_s {
|
||||
/** the rx file descriptor */
|
||||
sio_fd_t fd;
|
||||
/** receive buffer - encoded data is stored here */
|
||||
#if PPP_INPROC_OWNTHREAD
|
||||
u_char rxbuf[PPPOS_RX_BUFSIZE];
|
||||
#endif /* PPP_INPROC_OWNTHREAD */
|
||||
|
||||
/* The input packet. */
|
||||
struct pbuf *inHead, *inTail;
|
||||
@@ -241,6 +243,7 @@ static void pppInputThread(void *arg);
|
||||
#endif /* PPP_INPROC_OWNTHREAD */
|
||||
static void pppDrop(PPPControlRx *pcrx);
|
||||
static void pppInProc(PPPControlRx *pcrx, u_char *s, int l);
|
||||
static void pppFreeCurrentInputPacket(PPPControlRx *pcrx);
|
||||
#endif /* PPPOS_SUPPORT */
|
||||
|
||||
|
||||
@@ -339,13 +342,17 @@ static u_char pppACCMMask[] = {
|
||||
0x80
|
||||
};
|
||||
|
||||
#if PPP_INPROC_OWNTHREAD
|
||||
/** Wake up the task blocked in reading from serial line (if any) */
|
||||
static void
|
||||
pppRecvWakeup(int pd)
|
||||
{
|
||||
PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
|
||||
sio_read_abort(pppControl[pd].fd);
|
||||
if (pppControl[pd].openFlag != 0) {
|
||||
sio_read_abort(pppControl[pd].fd);
|
||||
}
|
||||
}
|
||||
#endif /* PPP_INPROC_OWNTHREAD */
|
||||
#endif /* PPPOS_SUPPORT */
|
||||
|
||||
void
|
||||
@@ -361,9 +368,10 @@ pppLinkTerminated(int pd)
|
||||
{
|
||||
#if PPPOS_SUPPORT
|
||||
PPPControl* pc;
|
||||
#if PPP_INPROC_OWNTHREAD
|
||||
pppRecvWakeup(pd);
|
||||
#endif /* PPP_INPROC_OWNTHREAD */
|
||||
pc = &pppControl[pd];
|
||||
pppDrop(&pc->rx); /* bug fix #17726 */
|
||||
|
||||
PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
|
||||
if (pc->linkStatusCB) {
|
||||
@@ -387,9 +395,9 @@ pppLinkDown(int pd)
|
||||
} else
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
{
|
||||
#if PPPOS_SUPPORT
|
||||
#if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD
|
||||
pppRecvWakeup(pd);
|
||||
#endif /* PPPOS_SUPPORT */
|
||||
#endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,7 +447,7 @@ pppInit(void)
|
||||
|
||||
magicInit();
|
||||
|
||||
subnetMask = PP_HTONL(0xffffff00);
|
||||
subnetMask = PP_HTONL(0xffffff00UL);
|
||||
|
||||
for (i = 0; i < NUM_PPP; i++) {
|
||||
/* Initialize each protocol to the standard option set. */
|
||||
@@ -526,7 +534,7 @@ pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
|
||||
* pppOpen() is directly defined to this function.
|
||||
*/
|
||||
int
|
||||
pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
|
||||
pppOverSerialOpen(sio_fd_t fd, pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx)
|
||||
{
|
||||
PPPControl *pc;
|
||||
int pd;
|
||||
@@ -544,6 +552,8 @@ pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void
|
||||
pd = PPPERR_OPEN;
|
||||
} else {
|
||||
pc = &pppControl[pd];
|
||||
/* input pbuf left over from last session? */
|
||||
pppFreeCurrentInputPacket(&pc->rx);
|
||||
/* @todo: is this correct or do I overwrite something? */
|
||||
memset(pc, 0, sizeof(PPPControl));
|
||||
pc->rx.pd = pd;
|
||||
@@ -573,7 +583,7 @@ pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void
|
||||
pppStart(pd);
|
||||
#if PPP_INPROC_OWNTHREAD
|
||||
sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)&pc->rx, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO);
|
||||
#endif
|
||||
#endif /* PPP_INPROC_OWNTHREAD */
|
||||
}
|
||||
|
||||
return pd;
|
||||
@@ -594,7 +604,8 @@ pppOverEthernetClose(int pd)
|
||||
pppoe_destroy(&pc->netif);
|
||||
}
|
||||
|
||||
int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
|
||||
int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name,
|
||||
pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx)
|
||||
{
|
||||
PPPControl *pc;
|
||||
int pd;
|
||||
@@ -670,7 +681,9 @@ pppClose(int pd)
|
||||
pc->errCode = PPPERR_USER;
|
||||
/* This will leave us at PHASE_DEAD. */
|
||||
pppStop(pd);
|
||||
#if PPP_INPROC_OWNTHREAD
|
||||
pppRecvWakeup(pd);
|
||||
#endif /* PPP_INPROC_OWNTHREAD */
|
||||
#endif /* PPPOS_SUPPORT */
|
||||
}
|
||||
|
||||
@@ -681,20 +694,8 @@ pppClose(int pd)
|
||||
void
|
||||
pppSigHUP(int pd)
|
||||
{
|
||||
#if PPPOE_SUPPORT
|
||||
PPPControl *pc = &pppControl[pd];
|
||||
if(pc->ethif) {
|
||||
PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
|
||||
pppHup(pd);
|
||||
} else
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
{
|
||||
#if PPPOS_SUPPORT
|
||||
PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
|
||||
pppHup(pd);
|
||||
pppRecvWakeup(pd);
|
||||
#endif /* PPPOS_SUPPORT */
|
||||
}
|
||||
PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
|
||||
pppHup(pd);
|
||||
}
|
||||
|
||||
#if PPPOS_SUPPORT
|
||||
@@ -1271,7 +1272,7 @@ GetMask(u32_t addr)
|
||||
{
|
||||
u32_t mask, nmask;
|
||||
|
||||
htonl(addr);
|
||||
addr = htonl(addr);
|
||||
if (IP_CLASSA(addr)) { /* determine network mask for address class */
|
||||
nmask = IP_CLASSA_NET;
|
||||
} else if (IP_CLASSB(addr)) {
|
||||
@@ -1725,6 +1726,22 @@ out:
|
||||
* Drop the input packet.
|
||||
*/
|
||||
static void
|
||||
pppFreeCurrentInputPacket(PPPControlRx *pcrx)
|
||||
{
|
||||
if (pcrx->inHead != NULL) {
|
||||
if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
|
||||
pbuf_free(pcrx->inTail);
|
||||
}
|
||||
pbuf_free(pcrx->inHead);
|
||||
pcrx->inHead = NULL;
|
||||
}
|
||||
pcrx->inTail = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop the input packet and increase error counters.
|
||||
*/
|
||||
static void
|
||||
pppDrop(PPPControlRx *pcrx)
|
||||
{
|
||||
if (pcrx->inHead != NULL) {
|
||||
@@ -1732,13 +1749,8 @@ pppDrop(PPPControlRx *pcrx)
|
||||
PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload));
|
||||
#endif
|
||||
PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead));
|
||||
if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
|
||||
pbuf_free(pcrx->inTail);
|
||||
}
|
||||
pbuf_free(pcrx->inHead);
|
||||
pcrx->inHead = NULL;
|
||||
pcrx->inTail = NULL;
|
||||
}
|
||||
pppFreeCurrentInputPacket(pcrx);
|
||||
#if VJ_SUPPORT
|
||||
vj_uncompress_err(&pppControl[pcrx->pd].vjComp);
|
||||
#endif /* VJ_SUPPORT */
|
||||
@@ -1747,6 +1759,7 @@ pppDrop(PPPControlRx *pcrx)
|
||||
snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
|
||||
}
|
||||
|
||||
#if !PPP_INPROC_OWNTHREAD
|
||||
/** Pass received raw characters to PPPoS to be decoded. This function is
|
||||
* thread-safe and can be called from a dedicated RX-thread or from a main-loop.
|
||||
*
|
||||
@@ -1759,6 +1772,7 @@ pppos_input(int pd, u_char* data, int len)
|
||||
{
|
||||
pppInProc(&pppControl[pd].rx, data, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Process a received octet string.
|
||||
@@ -1809,6 +1823,7 @@ pppInProc(PPPControlRx *pcrx, u_char *s, int l)
|
||||
pppDrop(pcrx);
|
||||
/* Otherwise it's a good packet so pass it on. */
|
||||
} else {
|
||||
struct pbuf *inp;
|
||||
/* Trim off the checksum. */
|
||||
if(pcrx->inTail->len >= 2) {
|
||||
pcrx->inTail->len -= 2;
|
||||
@@ -1827,18 +1842,20 @@ pppInProc(PPPControlRx *pcrx, u_char *s, int l)
|
||||
}
|
||||
|
||||
/* Dispatch the packet thereby consuming it. */
|
||||
inp = pcrx->inHead;
|
||||
/* Packet consumed, release our references. */
|
||||
pcrx->inHead = NULL;
|
||||
pcrx->inTail = NULL;
|
||||
#if PPP_INPROC_MULTITHREADED
|
||||
if(tcpip_callback_with_block(pppInput, pcrx->inHead, 0) != ERR_OK) {
|
||||
if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) {
|
||||
PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
|
||||
pbuf_free(pcrx->inHead);
|
||||
pbuf_free(inp);
|
||||
LINK_STATS_INC(link.drop);
|
||||
snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
|
||||
}
|
||||
#else /* PPP_INPROC_MULTITHREADED */
|
||||
pppInput(pcrx->inHead);
|
||||
pppInput(inp);
|
||||
#endif /* PPP_INPROC_MULTITHREADED */
|
||||
pcrx->inHead = NULL;
|
||||
pcrx->inTail = NULL;
|
||||
}
|
||||
|
||||
/* Prepare for a new packet. */
|
||||
@@ -1912,10 +1929,12 @@ pppInProc(PPPControlRx *pcrx, u_char *s, int l)
|
||||
case PDDATA: /* Process data byte. */
|
||||
/* Make space to receive processed data. */
|
||||
if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
|
||||
if(pcrx->inTail) {
|
||||
if (pcrx->inTail != NULL) {
|
||||
pcrx->inTail->tot_len = pcrx->inTail->len;
|
||||
if (pcrx->inTail != pcrx->inHead) {
|
||||
pbuf_cat(pcrx->inHead, pcrx->inTail);
|
||||
/* give up the inTail reference now */
|
||||
pcrx->inTail = NULL;
|
||||
}
|
||||
}
|
||||
/* If we haven't started a packet, we need a packet header. */
|
||||
|
||||
@@ -46,67 +46,6 @@
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/timers.h"
|
||||
|
||||
/** Some defines for code we skip compared to the original pppd.
|
||||
* These are just here to minimise the use of the ugly "#if 0". */
|
||||
#define PPP_ADDITIONAL_CALLBACKS 0
|
||||
|
||||
/** Some error checks to test for unsupported code */
|
||||
#if CBCP_SUPPORT
|
||||
#error "CBCP is not supported in lwIP PPP"
|
||||
#endif
|
||||
#if CCP_SUPPORT
|
||||
#error "CCP is not supported in lwIP PPP"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pppd.h - PPP daemon global declarations.
|
||||
*
|
||||
* Copyright (c) 1989 Carnegie Mellon University.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted
|
||||
* provided that the above copyright notice and this paragraph are
|
||||
* duplicated in all such forms and that any documentation,
|
||||
* advertising materials, and other materials related to such
|
||||
* distribution and use acknowledge that the software was developed
|
||||
* by Carnegie Mellon University. The name of the
|
||||
* University may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* ppp_defs.h - PPP definitions.
|
||||
*
|
||||
* Copyright (c) 1994 The Australian National University.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, provided that the above copyright
|
||||
* notice appears in all copies. This software is provided without any
|
||||
* warranty, express or implied. The Australian National University
|
||||
* makes no representations about the suitability of this software for
|
||||
* any purpose.
|
||||
*
|
||||
* IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
|
||||
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
|
||||
* THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
|
||||
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
||||
* OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0)
|
||||
#define UNTIMEOUT(f, a) sys_untimeout((f), (a))
|
||||
|
||||
|
||||
#ifndef __u_char_defined
|
||||
|
||||
@@ -118,123 +57,6 @@ typedef unsigned char u_char;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Constants and structures defined by the internet system,
|
||||
* Per RFC 790, September 1981, and numerous additions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The basic PPP frame.
|
||||
*/
|
||||
#define PPP_HDRLEN 4 /* octets for standard ppp header */
|
||||
#define PPP_FCSLEN 2 /* octets for FCS */
|
||||
|
||||
|
||||
/*
|
||||
* Significant octet values.
|
||||
*/
|
||||
#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
|
||||
#define PPP_UI 0x03 /* Unnumbered Information */
|
||||
#define PPP_FLAG 0x7e /* Flag Sequence */
|
||||
#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
|
||||
#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
|
||||
|
||||
/*
|
||||
* Protocol field values.
|
||||
*/
|
||||
#define PPP_IP 0x21 /* Internet Protocol */
|
||||
#define PPP_AT 0x29 /* AppleTalk Protocol */
|
||||
#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
|
||||
#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
|
||||
#define PPP_COMP 0xfd /* compressed packet */
|
||||
#define PPP_IPCP 0x8021 /* IP Control Protocol */
|
||||
#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
|
||||
#define PPP_CCP 0x80fd /* Compression Control Protocol */
|
||||
#define PPP_LCP 0xc021 /* Link Control Protocol */
|
||||
#define PPP_PAP 0xc023 /* Password Authentication Protocol */
|
||||
#define PPP_LQR 0xc025 /* Link Quality Report protocol */
|
||||
#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
|
||||
#define PPP_CBCP 0xc029 /* Callback Control Protocol */
|
||||
|
||||
/*
|
||||
* Values for FCS calculations.
|
||||
*/
|
||||
#define PPP_INITFCS 0xffff /* Initial FCS value */
|
||||
#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
|
||||
#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
|
||||
|
||||
/*
|
||||
* Extended asyncmap - allows any character to be escaped.
|
||||
*/
|
||||
typedef u_char ext_accm[32];
|
||||
|
||||
/*
|
||||
* What to do with network protocol (NP) packets.
|
||||
*/
|
||||
enum NPmode {
|
||||
NPMODE_PASS, /* pass the packet through */
|
||||
NPMODE_DROP, /* silently drop the packet */
|
||||
NPMODE_ERROR, /* return an error */
|
||||
NPMODE_QUEUE /* save it up for later. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Inline versions of get/put char/short/long.
|
||||
* Pointer is advanced; we assume that both arguments
|
||||
* are lvalues and will already be in registers.
|
||||
* cp MUST be u_char *.
|
||||
*/
|
||||
#define GETCHAR(c, cp) { \
|
||||
(c) = *(cp)++; \
|
||||
}
|
||||
#define PUTCHAR(c, cp) { \
|
||||
*(cp)++ = (u_char) (c); \
|
||||
}
|
||||
|
||||
|
||||
#define GETSHORT(s, cp) { \
|
||||
(s) = *(cp); (cp)++; (s) <<= 8; \
|
||||
(s) |= *(cp); (cp)++; \
|
||||
}
|
||||
#define PUTSHORT(s, cp) { \
|
||||
*(cp)++ = (u_char) ((s) >> 8); \
|
||||
*(cp)++ = (u_char) (s & 0xff); \
|
||||
}
|
||||
|
||||
#define GETLONG(l, cp) { \
|
||||
(l) = *(cp); (cp)++; (l) <<= 8; \
|
||||
(l) |= *(cp); (cp)++; (l) <<= 8; \
|
||||
(l) |= *(cp); (cp)++; (l) <<= 8; \
|
||||
(l) |= *(cp); (cp)++; \
|
||||
}
|
||||
#define PUTLONG(l, cp) { \
|
||||
*(cp)++ = (u_char) ((l) >> 24); \
|
||||
*(cp)++ = (u_char) ((l) >> 16); \
|
||||
*(cp)++ = (u_char) ((l) >> 8); \
|
||||
*(cp)++ = (u_char) (l); \
|
||||
}
|
||||
|
||||
|
||||
#define INCPTR(n, cp) ((cp) += (n))
|
||||
#define DECPTR(n, cp) ((cp) -= (n))
|
||||
|
||||
#define BCMP(s0, s1, l) memcmp((u_char *)(s0), (u_char *)(s1), (l))
|
||||
#define BCOPY(s, d, l) MEMCPY((d), (s), (l))
|
||||
#define BZERO(s, n) memset(s, 0, n)
|
||||
|
||||
#if PPP_DEBUG
|
||||
#define PRINTMSG(m, l) { m[l] = '\0'; LWIP_DEBUGF(LOG_INFO, ("Remote message: %s\n", m)); }
|
||||
#else /* PPP_DEBUG */
|
||||
#define PRINTMSG(m, l)
|
||||
#endif /* PPP_DEBUG */
|
||||
|
||||
/*
|
||||
* MAKEHEADER - Add PPP Header fields to a packet.
|
||||
*/
|
||||
#define MAKEHEADER(p, t) { \
|
||||
PUTCHAR(PPP_ALLSTATIONS, p); \
|
||||
PUTCHAR(PPP_UI, p); \
|
||||
PUTSHORT(t, p); }
|
||||
|
||||
/*************************
|
||||
*** PUBLIC DEFINITIONS ***
|
||||
@@ -267,89 +89,10 @@ enum NPmode {
|
||||
*** PUBLIC DATA TYPES ***
|
||||
************************/
|
||||
|
||||
/*
|
||||
* The following struct gives the addresses of procedures to call
|
||||
* for a particular protocol.
|
||||
*/
|
||||
struct protent {
|
||||
u_short protocol; /* PPP protocol number */
|
||||
/* Initialization procedure */
|
||||
void (*init) (int unit);
|
||||
/* Process a received packet */
|
||||
void (*input) (int unit, u_char *pkt, int len);
|
||||
/* Process a received protocol-reject */
|
||||
void (*protrej) (int unit);
|
||||
/* Lower layer has come up */
|
||||
void (*lowerup) (int unit);
|
||||
/* Lower layer has gone down */
|
||||
void (*lowerdown) (int unit);
|
||||
/* Open the protocol */
|
||||
void (*open) (int unit);
|
||||
/* Close the protocol */
|
||||
void (*close) (int unit, char *reason);
|
||||
#if PPP_ADDITIONAL_CALLBACKS
|
||||
/* Print a packet in readable form */
|
||||
int (*printpkt) (u_char *pkt, int len,
|
||||
void (*printer) (void *, char *, ...),
|
||||
void *arg);
|
||||
/* Process a received data packet */
|
||||
void (*datainput) (int unit, u_char *pkt, int len);
|
||||
#endif /* PPP_ADDITIONAL_CALLBACKS */
|
||||
int enabled_flag; /* 0 if protocol is disabled */
|
||||
char *name; /* Text name of protocol */
|
||||
#if PPP_ADDITIONAL_CALLBACKS
|
||||
/* Check requested options, assign defaults */
|
||||
void (*check_options) (u_long);
|
||||
/* Configure interface for demand-dial */
|
||||
int (*demand_conf) (int unit);
|
||||
/* Say whether to bring up link for this pkt */
|
||||
int (*active_pkt) (u_char *pkt, int len);
|
||||
#endif /* PPP_ADDITIONAL_CALLBACKS */
|
||||
};
|
||||
|
||||
/*
|
||||
* The following structure records the time in seconds since
|
||||
* the last NP packet was sent or received.
|
||||
*/
|
||||
struct ppp_idle {
|
||||
u_short xmit_idle; /* seconds since last NP packet sent */
|
||||
u_short recv_idle; /* seconds since last NP packet received */
|
||||
};
|
||||
|
||||
struct ppp_settings {
|
||||
|
||||
u_int disable_defaultip : 1; /* Don't use hostname for default IP addrs */
|
||||
u_int auth_required : 1; /* Peer is required to authenticate */
|
||||
u_int explicit_remote : 1; /* remote_name specified with remotename opt */
|
||||
u_int refuse_pap : 1; /* Don't wanna auth. ourselves with PAP */
|
||||
u_int refuse_chap : 1; /* Don't wanna auth. ourselves with CHAP */
|
||||
u_int usehostname : 1; /* Use hostname for our_name */
|
||||
u_int usepeerdns : 1; /* Ask peer for DNS adds */
|
||||
|
||||
u_short idle_time_limit; /* Shut down link if idle for this long */
|
||||
int maxconnect; /* Maximum connect time (seconds) */
|
||||
|
||||
char user [MAXNAMELEN + 1]; /* Username for PAP */
|
||||
char passwd [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */
|
||||
char our_name [MAXNAMELEN + 1]; /* Our name for authentication purposes */
|
||||
char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */
|
||||
};
|
||||
|
||||
struct ppp_addrs {
|
||||
ip_addr_t our_ipaddr, his_ipaddr, netmask, dns1, dns2;
|
||||
};
|
||||
|
||||
/*****************************
|
||||
*** PUBLIC DATA STRUCTURES ***
|
||||
*****************************/
|
||||
|
||||
/* Buffers for outgoing packets. */
|
||||
extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
|
||||
|
||||
extern struct ppp_settings ppp_settings;
|
||||
|
||||
extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */
|
||||
|
||||
|
||||
/***********************
|
||||
*** PUBLIC FUNCTIONS ***
|
||||
@@ -386,6 +129,10 @@ enum pppAuthType {
|
||||
|
||||
void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd);
|
||||
|
||||
/* Link status callback function prototype */
|
||||
typedef void (*pppLinkStatusCB_fn)(void *ctx, int errCode, void *arg);
|
||||
|
||||
#if PPPOS_SUPPORT
|
||||
/*
|
||||
* Open a new PPP connection using the given serial I/O device.
|
||||
* This initializes the PPP control block but does not
|
||||
@@ -393,12 +140,16 @@ void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
|
||||
* Return a new PPP connection descriptor on success or
|
||||
* an error code (negative) on failure.
|
||||
*/
|
||||
int pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);
|
||||
int pppOverSerialOpen(sio_fd_t fd, pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx);
|
||||
#endif /* PPPOS_SUPPORT */
|
||||
|
||||
#if PPPOE_SUPPORT
|
||||
/*
|
||||
* Open a new PPP Over Ethernet (PPPOE) connection.
|
||||
*/
|
||||
int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);
|
||||
int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name,
|
||||
pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx);
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
|
||||
/* for source code compatibility */
|
||||
#define pppOpen(fd,cb,ls) pppOverSerialOpen(fd,cb,ls)
|
||||
@@ -426,55 +177,22 @@ int pppIOCtl(int pd, int cmd, void *arg);
|
||||
*/
|
||||
u_short pppMTU(int pd);
|
||||
|
||||
#if PPPOS_SUPPORT && !PPP_INPROC_OWNTHREAD
|
||||
/*
|
||||
* Write n characters to a ppp link.
|
||||
* RETURN: >= 0 Number of characters written, -1 Failed to write to device.
|
||||
* PPP over Serial: this is the input function to be called for received data.
|
||||
* If PPP_INPROC_OWNTHREAD==1, a seperate input thread using the blocking
|
||||
* sio_read() is used, so this is deactivated.
|
||||
*/
|
||||
int pppWrite(int pd, const u_char *s, int n);
|
||||
|
||||
void pppInProcOverEthernet(int pd, struct pbuf *pb);
|
||||
|
||||
struct pbuf *pppSingleBuf(struct pbuf *p);
|
||||
|
||||
void pppLinkTerminated(int pd);
|
||||
|
||||
void pppLinkDown(int pd);
|
||||
|
||||
void pppos_input(int pd, u_char* data, int len);
|
||||
#endif /* PPPOS_SUPPORT && !PPP_INPROC_OWNTHREAD */
|
||||
|
||||
/* Configure i/f transmit parameters */
|
||||
void ppp_send_config (int, u16_t, u32_t, int, int);
|
||||
/* Set extended transmit ACCM */
|
||||
void ppp_set_xaccm (int, ext_accm *);
|
||||
/* Configure i/f receive parameters */
|
||||
void ppp_recv_config (int, int, u32_t, int, int);
|
||||
/* Find out how long link has been idle */
|
||||
int get_idle_time (int, struct ppp_idle *);
|
||||
|
||||
/* Configure VJ TCP header compression */
|
||||
int sifvjcomp (int, int, u8_t, u8_t);
|
||||
/* Configure i/f down (for IP) */
|
||||
int sifup (int);
|
||||
/* Set mode for handling packets for proto */
|
||||
int sifnpmode (int u, int proto, enum NPmode mode);
|
||||
/* Configure i/f down (for IP) */
|
||||
int sifdown (int);
|
||||
/* Configure IP addresses for i/f */
|
||||
int sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t);
|
||||
/* Reset i/f IP addresses */
|
||||
int cifaddr (int, u32_t, u32_t);
|
||||
/* Create default route through i/f */
|
||||
int sifdefaultroute (int, u32_t, u32_t);
|
||||
/* Delete default route through i/f */
|
||||
int cifdefaultroute (int, u32_t, u32_t);
|
||||
|
||||
/* Get appropriate netmask for address */
|
||||
u32_t GetMask (u32_t);
|
||||
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
/* Set an lwIP-style status-callback for the selected PPP device */
|
||||
void ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback);
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
/* Set an lwIP-style link-callback for the selected PPP device */
|
||||
void ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback);
|
||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||
|
||||
|
||||
363
src/netif/ppp/ppp_impl.h
Normal file
363
src/netif/ppp/ppp_impl.h
Normal file
@@ -0,0 +1,363 @@
|
||||
/*****************************************************************************
|
||||
* ppp.h - Network Point to Point Protocol header file.
|
||||
*
|
||||
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
|
||||
* portions Copyright (c) 1997 Global Election Systems Inc.
|
||||
*
|
||||
* The authors hereby grant permission to use, copy, modify, distribute,
|
||||
* and license this software and its documentation for any purpose, provided
|
||||
* that existing copyright notices are retained in all copies and that this
|
||||
* notice and the following disclaimer are included verbatim in any
|
||||
* distributions. No written agreement, license, or royalty fee is required
|
||||
* for any of the authorized uses.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
* REVISION HISTORY
|
||||
*
|
||||
* 03-01-01 Marc Boucher <marc@mbsi.ca>
|
||||
* Ported to lwIP.
|
||||
* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
|
||||
* Original derived from BSD codes.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef PPP_IMPL_H
|
||||
#define PPP_IMPL_H
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/sio.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/timers.h"
|
||||
|
||||
/** Some defines for code we skip compared to the original pppd.
|
||||
* These are just here to minimise the use of the ugly "#if 0". */
|
||||
#define PPP_ADDITIONAL_CALLBACKS 0
|
||||
|
||||
/** Some error checks to test for unsupported code */
|
||||
#if CBCP_SUPPORT
|
||||
#error "CBCP is not supported in lwIP PPP"
|
||||
#endif
|
||||
#if CCP_SUPPORT
|
||||
#error "CCP is not supported in lwIP PPP"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pppd.h - PPP daemon global declarations.
|
||||
*
|
||||
* Copyright (c) 1989 Carnegie Mellon University.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted
|
||||
* provided that the above copyright notice and this paragraph are
|
||||
* duplicated in all such forms and that any documentation,
|
||||
* advertising materials, and other materials related to such
|
||||
* distribution and use acknowledge that the software was developed
|
||||
* by Carnegie Mellon University. The name of the
|
||||
* University may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* ppp_defs.h - PPP definitions.
|
||||
*
|
||||
* Copyright (c) 1994 The Australian National University.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, provided that the above copyright
|
||||
* notice appears in all copies. This software is provided without any
|
||||
* warranty, express or implied. The Australian National University
|
||||
* makes no representations about the suitability of this software for
|
||||
* any purpose.
|
||||
*
|
||||
* IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
|
||||
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
|
||||
* THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
|
||||
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
||||
* OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0)
|
||||
#define UNTIMEOUT(f, a) sys_untimeout((f), (a))
|
||||
|
||||
|
||||
/*
|
||||
* Constants and structures defined by the internet system,
|
||||
* Per RFC 790, September 1981, and numerous additions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The basic PPP frame.
|
||||
*/
|
||||
#define PPP_HDRLEN 4 /* octets for standard ppp header */
|
||||
#define PPP_FCSLEN 2 /* octets for FCS */
|
||||
|
||||
|
||||
/*
|
||||
* Significant octet values.
|
||||
*/
|
||||
#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
|
||||
#define PPP_UI 0x03 /* Unnumbered Information */
|
||||
#define PPP_FLAG 0x7e /* Flag Sequence */
|
||||
#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
|
||||
#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
|
||||
|
||||
/*
|
||||
* Protocol field values.
|
||||
*/
|
||||
#define PPP_IP 0x21 /* Internet Protocol */
|
||||
#define PPP_AT 0x29 /* AppleTalk Protocol */
|
||||
#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
|
||||
#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
|
||||
#define PPP_COMP 0xfd /* compressed packet */
|
||||
#define PPP_IPCP 0x8021 /* IP Control Protocol */
|
||||
#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
|
||||
#define PPP_CCP 0x80fd /* Compression Control Protocol */
|
||||
#define PPP_LCP 0xc021 /* Link Control Protocol */
|
||||
#define PPP_PAP 0xc023 /* Password Authentication Protocol */
|
||||
#define PPP_LQR 0xc025 /* Link Quality Report protocol */
|
||||
#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
|
||||
#define PPP_CBCP 0xc029 /* Callback Control Protocol */
|
||||
|
||||
/*
|
||||
* Values for FCS calculations.
|
||||
*/
|
||||
#define PPP_INITFCS 0xffff /* Initial FCS value */
|
||||
#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
|
||||
#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
|
||||
|
||||
/*
|
||||
* Extended asyncmap - allows any character to be escaped.
|
||||
*/
|
||||
typedef u_char ext_accm[32];
|
||||
|
||||
/*
|
||||
* What to do with network protocol (NP) packets.
|
||||
*/
|
||||
enum NPmode {
|
||||
NPMODE_PASS, /* pass the packet through */
|
||||
NPMODE_DROP, /* silently drop the packet */
|
||||
NPMODE_ERROR, /* return an error */
|
||||
NPMODE_QUEUE /* save it up for later. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Inline versions of get/put char/short/long.
|
||||
* Pointer is advanced; we assume that both arguments
|
||||
* are lvalues and will already be in registers.
|
||||
* cp MUST be u_char *.
|
||||
*/
|
||||
#define GETCHAR(c, cp) { \
|
||||
(c) = *(cp)++; \
|
||||
}
|
||||
#define PUTCHAR(c, cp) { \
|
||||
*(cp)++ = (u_char) (c); \
|
||||
}
|
||||
|
||||
|
||||
#define GETSHORT(s, cp) { \
|
||||
(s) = *(cp); (cp)++; (s) <<= 8; \
|
||||
(s) |= *(cp); (cp)++; \
|
||||
}
|
||||
#define PUTSHORT(s, cp) { \
|
||||
*(cp)++ = (u_char) ((s) >> 8); \
|
||||
*(cp)++ = (u_char) (s & 0xff); \
|
||||
}
|
||||
|
||||
#define GETLONG(l, cp) { \
|
||||
(l) = *(cp); (cp)++; (l) <<= 8; \
|
||||
(l) |= *(cp); (cp)++; (l) <<= 8; \
|
||||
(l) |= *(cp); (cp)++; (l) <<= 8; \
|
||||
(l) |= *(cp); (cp)++; \
|
||||
}
|
||||
#define PUTLONG(l, cp) { \
|
||||
*(cp)++ = (u_char) ((l) >> 24); \
|
||||
*(cp)++ = (u_char) ((l) >> 16); \
|
||||
*(cp)++ = (u_char) ((l) >> 8); \
|
||||
*(cp)++ = (u_char) (l); \
|
||||
}
|
||||
|
||||
|
||||
#define INCPTR(n, cp) ((cp) += (n))
|
||||
#define DECPTR(n, cp) ((cp) -= (n))
|
||||
|
||||
#define BCMP(s0, s1, l) memcmp((u_char *)(s0), (u_char *)(s1), (l))
|
||||
#define BCOPY(s, d, l) MEMCPY((d), (s), (l))
|
||||
#define BZERO(s, n) memset(s, 0, n)
|
||||
|
||||
#if PPP_DEBUG
|
||||
#define PRINTMSG(m, l) { m[l] = '\0'; LWIP_DEBUGF(LOG_INFO, ("Remote message: %s\n", m)); }
|
||||
#else /* PPP_DEBUG */
|
||||
#define PRINTMSG(m, l)
|
||||
#endif /* PPP_DEBUG */
|
||||
|
||||
/*
|
||||
* MAKEHEADER - Add PPP Header fields to a packet.
|
||||
*/
|
||||
#define MAKEHEADER(p, t) { \
|
||||
PUTCHAR(PPP_ALLSTATIONS, p); \
|
||||
PUTCHAR(PPP_UI, p); \
|
||||
PUTSHORT(t, p); }
|
||||
|
||||
/************************
|
||||
*** PUBLIC DATA TYPES ***
|
||||
************************/
|
||||
|
||||
/*
|
||||
* The following struct gives the addresses of procedures to call
|
||||
* for a particular protocol.
|
||||
*/
|
||||
struct protent {
|
||||
u_short protocol; /* PPP protocol number */
|
||||
/* Initialization procedure */
|
||||
void (*init) (int unit);
|
||||
/* Process a received packet */
|
||||
void (*input) (int unit, u_char *pkt, int len);
|
||||
/* Process a received protocol-reject */
|
||||
void (*protrej) (int unit);
|
||||
/* Lower layer has come up */
|
||||
void (*lowerup) (int unit);
|
||||
/* Lower layer has gone down */
|
||||
void (*lowerdown) (int unit);
|
||||
/* Open the protocol */
|
||||
void (*open) (int unit);
|
||||
/* Close the protocol */
|
||||
void (*close) (int unit, char *reason);
|
||||
#if PPP_ADDITIONAL_CALLBACKS
|
||||
/* Print a packet in readable form */
|
||||
int (*printpkt) (u_char *pkt, int len,
|
||||
void (*printer) (void *, char *, ...),
|
||||
void *arg);
|
||||
/* Process a received data packet */
|
||||
void (*datainput) (int unit, u_char *pkt, int len);
|
||||
#endif /* PPP_ADDITIONAL_CALLBACKS */
|
||||
int enabled_flag; /* 0 if protocol is disabled */
|
||||
char *name; /* Text name of protocol */
|
||||
#if PPP_ADDITIONAL_CALLBACKS
|
||||
/* Check requested options, assign defaults */
|
||||
void (*check_options) (u_long);
|
||||
/* Configure interface for demand-dial */
|
||||
int (*demand_conf) (int unit);
|
||||
/* Say whether to bring up link for this pkt */
|
||||
int (*active_pkt) (u_char *pkt, int len);
|
||||
#endif /* PPP_ADDITIONAL_CALLBACKS */
|
||||
};
|
||||
|
||||
/*
|
||||
* The following structure records the time in seconds since
|
||||
* the last NP packet was sent or received.
|
||||
*/
|
||||
struct ppp_idle {
|
||||
u_short xmit_idle; /* seconds since last NP packet sent */
|
||||
u_short recv_idle; /* seconds since last NP packet received */
|
||||
};
|
||||
|
||||
struct ppp_settings {
|
||||
|
||||
u_int disable_defaultip : 1; /* Don't use hostname for default IP addrs */
|
||||
u_int auth_required : 1; /* Peer is required to authenticate */
|
||||
u_int explicit_remote : 1; /* remote_name specified with remotename opt */
|
||||
u_int refuse_pap : 1; /* Don't wanna auth. ourselves with PAP */
|
||||
u_int refuse_chap : 1; /* Don't wanna auth. ourselves with CHAP */
|
||||
u_int usehostname : 1; /* Use hostname for our_name */
|
||||
u_int usepeerdns : 1; /* Ask peer for DNS adds */
|
||||
|
||||
u_short idle_time_limit; /* Shut down link if idle for this long */
|
||||
int maxconnect; /* Maximum connect time (seconds) */
|
||||
|
||||
char user [MAXNAMELEN + 1]; /* Username for PAP */
|
||||
char passwd [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */
|
||||
char our_name [MAXNAMELEN + 1]; /* Our name for authentication purposes */
|
||||
char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */
|
||||
};
|
||||
|
||||
/*****************************
|
||||
*** PUBLIC DATA STRUCTURES ***
|
||||
*****************************/
|
||||
|
||||
/* Buffers for outgoing packets. */
|
||||
extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
|
||||
|
||||
extern struct ppp_settings ppp_settings;
|
||||
|
||||
extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */
|
||||
|
||||
|
||||
/***********************
|
||||
*** PUBLIC FUNCTIONS ***
|
||||
***********************/
|
||||
|
||||
/*
|
||||
* Write n characters to a ppp link.
|
||||
* RETURN: >= 0 Number of characters written, -1 Failed to write to device.
|
||||
*/
|
||||
int pppWrite(int pd, const u_char *s, int n);
|
||||
|
||||
void pppInProcOverEthernet(int pd, struct pbuf *pb);
|
||||
|
||||
struct pbuf *pppSingleBuf(struct pbuf *p);
|
||||
|
||||
void pppLinkTerminated(int pd);
|
||||
|
||||
void pppLinkDown(int pd);
|
||||
|
||||
/* Configure i/f transmit parameters */
|
||||
void ppp_send_config (int, u16_t, u32_t, int, int);
|
||||
/* Set extended transmit ACCM */
|
||||
void ppp_set_xaccm (int, ext_accm *);
|
||||
/* Configure i/f receive parameters */
|
||||
void ppp_recv_config (int, int, u32_t, int, int);
|
||||
/* Find out how long link has been idle */
|
||||
int get_idle_time (int, struct ppp_idle *);
|
||||
|
||||
/* Configure VJ TCP header compression */
|
||||
int sifvjcomp (int, int, u8_t, u8_t);
|
||||
/* Configure i/f down (for IP) */
|
||||
int sifup (int);
|
||||
/* Set mode for handling packets for proto */
|
||||
int sifnpmode (int u, int proto, enum NPmode mode);
|
||||
/* Configure i/f down (for IP) */
|
||||
int sifdown (int);
|
||||
/* Configure IP addresses for i/f */
|
||||
int sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t);
|
||||
/* Reset i/f IP addresses */
|
||||
int cifaddr (int, u32_t, u32_t);
|
||||
/* Create default route through i/f */
|
||||
int sifdefaultroute (int, u32_t, u32_t);
|
||||
/* Delete default route through i/f */
|
||||
int cifdefaultroute (int, u32_t, u32_t);
|
||||
|
||||
/* Get appropriate netmask for address */
|
||||
u32_t GetMask (u32_t);
|
||||
|
||||
#endif /* PPP_SUPPORT */
|
||||
|
||||
#endif /* PPP_IMPL_H */
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
#include "netif/ppp_oe.h"
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "lwip/timers.h"
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include "md5.h"
|
||||
#include "randm.h"
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "ppp.h"
|
||||
#include "ppp_impl.h"
|
||||
#include "pppdebug.h"
|
||||
|
||||
#include "vj.h"
|
||||
|
||||
@@ -35,6 +35,19 @@
|
||||
* This file is built upon the file: src/arch/rtxc/netif/sioslip.c
|
||||
*
|
||||
* Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>
|
||||
* Simon Goldschmidt
|
||||
*
|
||||
* Usage: This netif can be used in three ways:
|
||||
* 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read()
|
||||
* until data is received.
|
||||
* 2) In your main loop, call slipif_poll() to check for new RX bytes,
|
||||
* completed packets are fed into netif->input().
|
||||
* 3) Call slipif_received_byte[s]() from your serial RX ISR and
|
||||
* slipif_process_rxqueue() from your main loop. ISR level decodes
|
||||
* packets and puts completed packets on a queue which is fed into
|
||||
* the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for
|
||||
* pbuf_alloc to work on ISR level!).
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -49,20 +62,28 @@
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/sio.h"
|
||||
#include "lwip/sys.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 SLIP_END 0xC0 /* 0300: start and end of every packet */
|
||||
#define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */
|
||||
#define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */
|
||||
#define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */
|
||||
|
||||
/** Maximum packet size that is received by this netif */
|
||||
#ifndef SLIP_MAX_SIZE
|
||||
#define SLIP_MAX_SIZE 1500
|
||||
#endif
|
||||
|
||||
/** Define this to the interface speed for SNMP
|
||||
* (sio_fd is the sio_fd_t returned by sio_open).
|
||||
* The default value of zero means 'unknown'.
|
||||
*/
|
||||
#ifndef SLIP_SIO_SPEED
|
||||
#define SLIP_SIO_SPEED(sio_fd) 0
|
||||
#endif
|
||||
|
||||
enum slipif_recv_state {
|
||||
SLIP_RECV_NORMAL,
|
||||
@@ -73,8 +94,11 @@ 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;
|
||||
u8_t state;
|
||||
u16_t i, recved;
|
||||
#if SLIP_RX_FROM_ISR
|
||||
struct pbuf *rxpackets;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -101,9 +125,11 @@ slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len));
|
||||
priv = netif->state;
|
||||
|
||||
/* Send pbuf out on the serial I/O device. */
|
||||
/* Start with packet delimiter. */
|
||||
sio_send(SLIP_END, priv->sd);
|
||||
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
@@ -111,59 +137,39 @@ slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
c = ((u8_t *)q->payload)[i];
|
||||
switch (c) {
|
||||
case SLIP_END:
|
||||
/* need to escape this byte (0xC0 -> 0xDB, 0xDC) */
|
||||
sio_send(SLIP_ESC, priv->sd);
|
||||
sio_send(SLIP_ESC_END, priv->sd);
|
||||
break;
|
||||
case SLIP_ESC:
|
||||
/* need to escape this byte (0xDB -> 0xDB, 0xDD) */
|
||||
sio_send(SLIP_ESC, priv->sd);
|
||||
sio_send(SLIP_ESC_ESC, priv->sd);
|
||||
break;
|
||||
default:
|
||||
/* normal byte - no need for escaping */
|
||||
sio_send(c, priv->sd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* End with packet delimiter. */
|
||||
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_read() or sio_tryread().
|
||||
*
|
||||
* @param netif the lwip network interface structure for this slipif
|
||||
* @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
|
||||
* @param c received character (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, u8_t block)
|
||||
static struct pbuf*
|
||||
slipif_rxbyte(struct netif *netif, u8_t c)
|
||||
{
|
||||
struct slipif_priv *priv;
|
||||
u8_t c;
|
||||
struct pbuf *t;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
@@ -171,89 +177,105 @@ slipif_input(struct netif *netif, u8_t block)
|
||||
|
||||
priv = netif->state;
|
||||
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved));
|
||||
t = priv->q;
|
||||
priv->p = priv->q = NULL;
|
||||
priv->i = priv->recved = 0;
|
||||
return t;
|
||||
}
|
||||
return NULL;
|
||||
case SLIP_ESC:
|
||||
priv->state = SLIP_RECV_ESCAPE;
|
||||
return NULL;
|
||||
} /* end switch (c) */
|
||||
break;
|
||||
case SLIP_RECV_ESCAPE:
|
||||
/* un-escape END or ESC bytes, leave other bytes
|
||||
(although that would be a protocol error) */
|
||||
switch (c) {
|
||||
case SLIP_ESC_END:
|
||||
c = SLIP_END;
|
||||
break;
|
||||
case SLIP_ESC_ESC:
|
||||
c = SLIP_ESC;
|
||||
break;
|
||||
case SLIP_RECV_ESCAPE:
|
||||
switch (c) {
|
||||
case SLIP_ESC_END:
|
||||
c = SLIP_END;
|
||||
break;
|
||||
case SLIP_ESC_ESC:
|
||||
c = SLIP_ESC;
|
||||
break;
|
||||
}
|
||||
priv->state = SLIP_RECV_NORMAL;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
priv->state = SLIP_RECV_NORMAL;
|
||||
break;
|
||||
} /* end switch (priv->state) */
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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 (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 (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;
|
||||
}
|
||||
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 */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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 a single pbuf, set it to NULL so next time a new
|
||||
* pbuf is allocated */
|
||||
priv->p = NULL;
|
||||
}
|
||||
}
|
||||
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 a single pbuf, set it to NULL so next time a new
|
||||
* pbuf is allocated */
|
||||
priv->p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !NO_SYS
|
||||
/** Like slipif_rxbyte, but passes completed packets to netif->input
|
||||
*
|
||||
* @param netif The lwip network interface structure for this slipif
|
||||
* @param data received character
|
||||
*/
|
||||
static void
|
||||
slipif_rxbyte_input(struct netif *netif, u8_t c)
|
||||
{
|
||||
struct pbuf *p;
|
||||
p = slipif_rxbyte(netif, c);
|
||||
if (p != NULL) {
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SLIP_USE_RX_THREAD
|
||||
/**
|
||||
* The SLIP input thread.
|
||||
*
|
||||
@@ -264,20 +286,17 @@ slipif_input(struct netif *netif, u8_t block)
|
||||
static void
|
||||
slipif_loop_thread(void *nf)
|
||||
{
|
||||
struct pbuf *p;
|
||||
u8_t c;
|
||||
struct netif *netif = (struct netif *)nf;
|
||||
struct slipif_priv *priv = (struct slipif_priv *)netif->state;
|
||||
|
||||
while (1) {
|
||||
p = slipif_input(netif, SLIP_BLOCK);
|
||||
if (p != NULL) {
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
if (sio_read(priv->sd, &c, 1) > 0) {
|
||||
slipif_rxbyte_input(netif, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* !NO_SYS */
|
||||
#endif /* SLIP_USE_RX_THREAD */
|
||||
|
||||
/**
|
||||
* SLIP netif initialization
|
||||
@@ -291,17 +310,20 @@ slipif_loop_thread(void *nf)
|
||||
* ERR_IF is serial line couldn't be opened
|
||||
*
|
||||
* @note netif->num must contain the number of the serial port to open
|
||||
* (0 by default)
|
||||
* (0 by default). If netif->state is != NULL, it is interpreted as an
|
||||
* u8_t pointer pointing to the serial port number instead of netif->num.
|
||||
*
|
||||
*/
|
||||
err_t
|
||||
slipif_init(struct netif *netif)
|
||||
{
|
||||
struct slipif_priv *priv;
|
||||
u8_t sio_num;
|
||||
|
||||
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));
|
||||
priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv));
|
||||
if (!priv) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
@@ -312,8 +334,14 @@ slipif_init(struct netif *netif)
|
||||
netif->mtu = SLIP_MAX_SIZE;
|
||||
netif->flags |= NETIF_FLAG_POINTTOPOINT;
|
||||
|
||||
/* Try to open the serial port (netif->num contains the port number). */
|
||||
priv->sd = sio_open(netif->num);
|
||||
/* netif->state or netif->num contain the port number */
|
||||
if (netif->state != NULL) {
|
||||
sio_num = *(u8_t*)netif->state;
|
||||
} else {
|
||||
sio_num = netif->num;
|
||||
}
|
||||
/* Try to open the serial port. */
|
||||
priv->sd = sio_open(sio_num);
|
||||
if (!priv->sd) {
|
||||
/* Opening the serial port failed. */
|
||||
mem_free(priv);
|
||||
@@ -326,18 +354,20 @@ slipif_init(struct netif *netif)
|
||||
priv->state = SLIP_RECV_NORMAL;
|
||||
priv->i = 0;
|
||||
priv->recved = 0;
|
||||
#if SLIP_RX_FROM_ISR
|
||||
priv->rxpackets = NULL;
|
||||
#endif
|
||||
|
||||
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!
|
||||
*/
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0);
|
||||
/* initialize the snmp variables and counters inside the struct netif */
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd));
|
||||
|
||||
#if SLIP_USE_RX_THREAD
|
||||
/* Create a thread to poll the serial line. */
|
||||
sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
|
||||
SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
|
||||
#endif /* SLIP_USE_RX_THREAD */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -349,19 +379,132 @@ slipif_init(struct netif *netif)
|
||||
void
|
||||
slipif_poll(struct netif *netif)
|
||||
{
|
||||
struct pbuf *p;
|
||||
u8_t c;
|
||||
struct slipif_priv *priv;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||
|
||||
priv = netif->state;
|
||||
priv = (struct slipif_priv *)netif->state;
|
||||
|
||||
while ((p = slipif_input(netif, SLIP_DONTBLOCK)) != NULL) {
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
while (sio_tryread(priv->sd, &c, 1) > 0) {
|
||||
slipif_rxbyte_input(netif, c);
|
||||
}
|
||||
}
|
||||
|
||||
#if SLIP_RX_FROM_ISR
|
||||
/**
|
||||
* Feeds the IP layer with incoming packets that were receive
|
||||
*
|
||||
* @param netif The lwip network interface structure for this slipif
|
||||
*/
|
||||
void
|
||||
slipif_process_rxqueue(struct netif *netif)
|
||||
{
|
||||
struct slipif_priv *priv;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||
|
||||
priv = (struct slipif_priv *)netif->state;
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
while (priv->rxpackets != NULL) {
|
||||
struct pbuf *p = priv->rxpackets;
|
||||
#if SLIP_RX_QUEUE
|
||||
/* dequeue packet */
|
||||
struct pbuf *q = p;
|
||||
while ((q->len != q->tot_len) && (q->next != NULL)) {
|
||||
q = q->next;
|
||||
}
|
||||
priv->rxpackets = q->next;
|
||||
q->next = NULL;
|
||||
#else /* SLIP_RX_QUEUE */
|
||||
priv->rxpackets = NULL;
|
||||
#endif /* SLIP_RX_QUEUE */
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
}
|
||||
}
|
||||
|
||||
/** Like slipif_rxbyte, but queues completed packets.
|
||||
*
|
||||
* @param netif The lwip network interface structure for this slipif
|
||||
* @param data Received serial byte
|
||||
*/
|
||||
static void
|
||||
slipif_rxbyte_enqueue(struct netif *netif, u8_t data)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct slipif_priv *priv = (struct slipif_priv *)netif->state;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
p = slipif_rxbyte(netif, data);
|
||||
if (p != NULL) {
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
if (priv->rxpackets != NULL) {
|
||||
#if SLIP_RX_QUEUE
|
||||
/* queue multiple pbufs */
|
||||
struct pbuf *q = p;
|
||||
while(q->next != NULL) {
|
||||
q = q->next;
|
||||
}
|
||||
q->next = p;
|
||||
} else {
|
||||
#else /* SLIP_RX_QUEUE */
|
||||
pbuf_free(priv->rxpackets);
|
||||
}
|
||||
{
|
||||
#endif /* SLIP_RX_QUEUE */
|
||||
priv->rxpackets = p;
|
||||
}
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a received byte, completed packets are put on a queue that is
|
||||
* fed into IP through slipif_process_rxqueue().
|
||||
*
|
||||
* This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
|
||||
*
|
||||
* @param netif The lwip network interface structure for this slipif
|
||||
* @param data received character
|
||||
*/
|
||||
void
|
||||
slipif_received_byte(struct netif *netif, u8_t data)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||
slipif_rxbyte_enqueue(netif, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process multiple received byte, completed packets are put on a queue that is
|
||||
* fed into IP through slipif_process_rxqueue().
|
||||
*
|
||||
* This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
|
||||
*
|
||||
* @param netif The lwip network interface structure for this slipif
|
||||
* @param data received character
|
||||
* @param len Number of received characters
|
||||
*/
|
||||
void
|
||||
slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len)
|
||||
{
|
||||
u8_t i;
|
||||
u8_t *rxdata = data;
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||
|
||||
for (i = 0; i < len; i++, rxdata++) {
|
||||
slipif_rxbyte_enqueue(netif, *rxdata);
|
||||
}
|
||||
}
|
||||
#endif /* SLIP_RX_FROM_ISR */
|
||||
|
||||
#endif /* LWIP_HAVE_SLIPIF */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#error "This tests needs MEM-statistics enabled"
|
||||
#endif
|
||||
#if LWIP_DNS
|
||||
/*#error "This test needs DNS turned off (as it mallocs on init)"*/
|
||||
#error "This test needs DNS turned off (as it mallocs on init)"
|
||||
#endif
|
||||
|
||||
/* Setups/teardown functions */
|
||||
@@ -67,7 +67,7 @@ Suite *
|
||||
mem_suite(void)
|
||||
{
|
||||
TFun tests[] = {
|
||||
test_mem_one,
|
||||
test_mem_one
|
||||
};
|
||||
return create_suite("MEM", tests, sizeof(tests)/sizeof(TFun), mem_setup, mem_teardown);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,8 @@ create_arp_response(ip_addr_t *adr)
|
||||
|
||||
etharphdr->hwtype = htons(/*HWTYPE_ETHERNET*/ 1);
|
||||
etharphdr->proto = htons(ETHTYPE_IP);
|
||||
etharphdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(ip_addr_t));
|
||||
etharphdr->hwlen = ETHARP_HWADDR_LEN;
|
||||
etharphdr->protolen = sizeof(ip_addr_t);
|
||||
etharphdr->opcode = htons(ARP_REPLY);
|
||||
|
||||
SMEMCPY(ðarphdr->sipaddr, adr, sizeof(ip_addr_t));
|
||||
@@ -255,7 +256,7 @@ Suite *
|
||||
etharp_suite(void)
|
||||
{
|
||||
TFun tests[] = {
|
||||
test_etharp_table,
|
||||
test_etharp_table
|
||||
};
|
||||
return create_suite("ETHARP", tests, sizeof(tests)/sizeof(TFun), etharp_setup, etharp_teardown);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ int main()
|
||||
tcp_suite,
|
||||
tcp_oos_suite,
|
||||
mem_suite,
|
||||
etharp_suite,
|
||||
etharp_suite
|
||||
};
|
||||
size_t num = sizeof(suites)/sizeof(void*);
|
||||
LWIP_ASSERT("No suites defined", num > 0);
|
||||
@@ -43,4 +43,3 @@ int main()
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
50
test/unit/lwipopts.h
Normal file
50
test/unit/lwipopts.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIPOPTS_H__
|
||||
#define __LWIPOPTS_H__
|
||||
|
||||
/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
|
||||
#define NO_SYS 1
|
||||
#define LWIP_NETCONN 0
|
||||
#define LWIP_SOCKET 0
|
||||
|
||||
/* Minimal changes to opt.h required for tcp unit tests: */
|
||||
#define MEM_SIZE 16000
|
||||
#define TCP_SND_QUEUELEN 40
|
||||
#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN
|
||||
#define TCP_SND_BUF (12 * TCP_MSS)
|
||||
#define TCP_WND (10 * TCP_MSS)
|
||||
|
||||
/* Minimal changes to opt.h required for etharp unit tests: */
|
||||
#define ETHARP_SUPPORT_STATIC_ENTRIES 1
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
@@ -36,43 +36,40 @@ tcp_remove_all(void)
|
||||
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(ip_addr_t* src_ip, ip_addr_t* dst_ip,
|
||||
static struct pbuf*
|
||||
tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* 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)
|
||||
u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd)
|
||||
{
|
||||
struct pbuf* p;
|
||||
struct pbuf *p, *q;
|
||||
struct ip_hdr* iphdr;
|
||||
struct tcp_hdr* tcphdr;
|
||||
u16_t pbuf_len = (u16_t)(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);
|
||||
/* first pbuf must be big enough to hold the headers */
|
||||
EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
|
||||
if (data_len > 0) {
|
||||
/* first pbuf must be big enough to hold at least 1 data byte, too */
|
||||
EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
|
||||
}
|
||||
|
||||
memset(p->payload, 0, p->len);
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
memset(q->payload, 0, q->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_VHL_SET(iphdr, 4, IP_HLEN / 4);
|
||||
IPH_TOS_SET(iphdr, 0);
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
|
||||
/* let p point to TCP header */
|
||||
pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
|
||||
|
||||
tcphdr = p->payload;
|
||||
@@ -82,13 +79,20 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip,
|
||||
tcphdr->ackno = htonl(ackno);
|
||||
TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
|
||||
TCPH_FLAGS_SET(tcphdr, headerflags);
|
||||
tcphdr->wnd = htons(TCP_WND);
|
||||
tcphdr->wnd = htons(wnd);
|
||||
|
||||
/* copy data */
|
||||
memcpy((char*)tcphdr + sizeof(struct tcp_hdr), data, data_len);
|
||||
if (data_len > 0) {
|
||||
/* let p point to TCP data */
|
||||
pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr));
|
||||
/* copy data */
|
||||
pbuf_take(p, data, data_len);
|
||||
/* let p point to TCP header again */
|
||||
pbuf_header(p, sizeof(struct tcp_hdr));
|
||||
}
|
||||
|
||||
/* calculate checksum */
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest),
|
||||
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, src_ip, dst_ip,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
|
||||
pbuf_header(p, sizeof(struct ip_hdr));
|
||||
@@ -96,6 +100,40 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip,
|
||||
return p;
|
||||
}
|
||||
|
||||
/** Create a TCP segment usable for passing to tcp_input */
|
||||
struct pbuf*
|
||||
tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* 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)
|
||||
{
|
||||
return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data,
|
||||
data_len, seqno, ackno, headerflags, TCP_WND);
|
||||
}
|
||||
|
||||
/** 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->lastack + ackno_offset, headerflags);
|
||||
}
|
||||
|
||||
/** 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
|
||||
* - TCP window can be adjusted
|
||||
*/
|
||||
struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len,
|
||||
u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd)
|
||||
{
|
||||
return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
|
||||
data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd);
|
||||
}
|
||||
|
||||
/** Safely bring a tcp_pcb into the requested state */
|
||||
void
|
||||
tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip,
|
||||
@@ -190,6 +228,67 @@ test_tcp_new_counters_pcb(struct test_tcp_counters* counters)
|
||||
tcp_arg(pcb, counters);
|
||||
tcp_recv(pcb, test_tcp_counters_recv);
|
||||
tcp_err(pcb, test_tcp_counters_err);
|
||||
pcb->snd_wnd = TCP_WND;
|
||||
pcb->snd_wnd_max = TCP_WND;
|
||||
}
|
||||
return pcb;
|
||||
}
|
||||
|
||||
/** Calls tcp_input() after adjusting current_iphdr_dest */
|
||||
void test_tcp_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
struct ip_hdr *iphdr = (struct ip_hdr*)p->payload;
|
||||
ip_addr_copy(current_iphdr_dest, iphdr->dest);
|
||||
ip_addr_copy(current_iphdr_src, iphdr->src);
|
||||
current_netif = inp;
|
||||
current_header = iphdr;
|
||||
|
||||
tcp_input(p, inp);
|
||||
|
||||
current_iphdr_dest.addr = 0;
|
||||
current_iphdr_src.addr = 0;
|
||||
current_netif = NULL;
|
||||
current_header = NULL;
|
||||
}
|
||||
|
||||
static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p,
|
||||
ip_addr_t *ipaddr)
|
||||
{
|
||||
struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state;
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
txcounters->num_tx_calls++;
|
||||
txcounters->num_tx_bytes += p->tot_len;
|
||||
if (txcounters->copy_tx_packets) {
|
||||
struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
|
||||
err_t err;
|
||||
EXPECT(p_copy != NULL);
|
||||
err = pbuf_copy(p_copy, p);
|
||||
EXPECT(err == ERR_OK);
|
||||
if (txcounters->tx_packets == NULL) {
|
||||
txcounters->tx_packets = p_copy;
|
||||
} else {
|
||||
pbuf_cat(txcounters->tx_packets, p_copy);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters,
|
||||
ip_addr_t *ip_addr, ip_addr_t *netmask)
|
||||
{
|
||||
struct netif *n;
|
||||
memset(netif, 0, sizeof(struct netif));
|
||||
memset(txcounters, 0, sizeof(struct test_tcp_txcounters));
|
||||
netif->output = test_tcp_netif_output;
|
||||
netif->state = txcounters;
|
||||
netif->flags |= NETIF_FLAG_UP;
|
||||
ip_addr_copy(netif->netmask, *netmask);
|
||||
ip_addr_copy(netif->ip_addr, *ip_addr);
|
||||
for (n = netif_list; n != NULL; n = n->next) {
|
||||
if (n == netif) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
netif->next = NULL;
|
||||
netif_list = netif;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../lwip_check.h"
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
/* counters used for test_tcp_counters_* callback functions */
|
||||
struct test_tcp_counters {
|
||||
@@ -18,6 +19,13 @@ struct test_tcp_counters {
|
||||
u32_t expected_data_len;
|
||||
};
|
||||
|
||||
struct test_tcp_txcounters {
|
||||
u32_t num_tx_calls;
|
||||
u32_t num_tx_bytes;
|
||||
u8_t copy_tx_packets;
|
||||
struct pbuf *tx_packets;
|
||||
};
|
||||
|
||||
/* Helper functions */
|
||||
void tcp_remove_all(void);
|
||||
|
||||
@@ -26,6 +34,8 @@ struct pbuf* tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip,
|
||||
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);
|
||||
struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len,
|
||||
u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd);
|
||||
void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip,
|
||||
ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port);
|
||||
void test_tcp_counters_err(void* arg, err_t err);
|
||||
@@ -33,4 +43,10 @@ err_t test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err
|
||||
|
||||
struct tcp_pcb* test_tcp_new_counters_pcb(struct test_tcp_counters* counters);
|
||||
|
||||
void test_tcp_input(struct pbuf *p, struct netif *inp);
|
||||
|
||||
void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters,
|
||||
ip_addr_t *ip_addr, ip_addr_t *netmask);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,21 +4,48 @@
|
||||
#include "lwip/stats.h"
|
||||
#include "tcp_helper.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4307) /* we explicitly wrap around TCP seqnos */
|
||||
#endif
|
||||
|
||||
#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
|
||||
#error "This tests needs TCP- and MEMP-statistics enabled"
|
||||
#endif
|
||||
#if TCP_SND_BUF <= TCP_WND
|
||||
#error "This tests needs TCP_SND_BUF to be > TCP_WND"
|
||||
#endif
|
||||
|
||||
static u8_t test_tcp_timer;
|
||||
|
||||
/* our own version of tcp_tmr so we can reset fast/slow timer state */
|
||||
static void
|
||||
test_tcp_tmr(void)
|
||||
{
|
||||
tcp_fasttmr();
|
||||
if (++test_tcp_timer & 1) {
|
||||
tcp_slowtmr();
|
||||
}
|
||||
}
|
||||
|
||||
/* Setups/teardown functions */
|
||||
|
||||
static void
|
||||
tcp_setup(void)
|
||||
{
|
||||
/* reset iss to default (6510) */
|
||||
tcp_ticks = 0;
|
||||
tcp_ticks = 0 - (tcp_next_iss() - 6510);
|
||||
tcp_next_iss();
|
||||
tcp_ticks = 0;
|
||||
|
||||
test_tcp_timer = 0;
|
||||
tcp_remove_all();
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_teardown(void)
|
||||
{
|
||||
netif_list = NULL;
|
||||
tcp_remove_all();
|
||||
}
|
||||
|
||||
@@ -76,7 +103,7 @@ START_TEST(test_tcp_recv_inseq)
|
||||
EXPECT(p != NULL);
|
||||
if (p != NULL) {
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p, &netif);
|
||||
test_tcp_input(p, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
@@ -91,6 +118,537 @@ START_TEST(test_tcp_recv_inseq)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data.
|
||||
* At the end, send more data. */
|
||||
START_TEST(test_tcp_fast_retx_recover)
|
||||
{
|
||||
struct netif netif;
|
||||
struct test_tcp_txcounters txcounters;
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf* p;
|
||||
char data1[] = { 1, 2, 3, 4};
|
||||
char data2[] = { 5, 6, 7, 8};
|
||||
char data3[] = { 9, 10, 11, 12};
|
||||
char data4[] = {13, 14, 15, 16};
|
||||
char data5[] = {17, 18, 19, 20};
|
||||
char data6[] = {21, 22, 23, 24};
|
||||
ip_addr_t remote_ip, local_ip, netmask;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
err_t err;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
/* initialize local vars */
|
||||
IP4_ADDR(&local_ip, 192, 168, 1, 1);
|
||||
IP4_ADDR(&remote_ip, 192, 168, 1, 2);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
|
||||
/* 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);
|
||||
pcb->mss = TCP_MSS;
|
||||
/* disable initial congestion window (we don't send a SYN here...) */
|
||||
pcb->cwnd = pcb->snd_wnd;
|
||||
|
||||
/* send data1 */
|
||||
err = tcp_write(pcb, data1, sizeof(data1), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
EXPECT_RET(txcounters.num_tx_calls == 1);
|
||||
EXPECT_RET(txcounters.num_tx_bytes == sizeof(data1) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr));
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
/* "recv" ACK for data1 */
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 4, TCP_ACK);
|
||||
EXPECT_RET(p != NULL);
|
||||
test_tcp_input(p, &netif);
|
||||
EXPECT_RET(txcounters.num_tx_calls == 0);
|
||||
EXPECT_RET(pcb->unacked == NULL);
|
||||
/* send data2 */
|
||||
err = tcp_write(pcb, data2, sizeof(data2), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
EXPECT_RET(txcounters.num_tx_calls == 1);
|
||||
EXPECT_RET(txcounters.num_tx_bytes == sizeof(data2) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr));
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
/* duplicate ACK for data1 (data2 is lost) */
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
|
||||
EXPECT_RET(p != NULL);
|
||||
test_tcp_input(p, &netif);
|
||||
EXPECT_RET(txcounters.num_tx_calls == 0);
|
||||
EXPECT_RET(pcb->dupacks == 1);
|
||||
/* send data3 */
|
||||
err = tcp_write(pcb, data3, sizeof(data3), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
/* nagle enabled, no tx calls */
|
||||
EXPECT_RET(txcounters.num_tx_calls == 0);
|
||||
EXPECT_RET(txcounters.num_tx_bytes == 0);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
/* 2nd duplicate ACK for data1 (data2 and data3 are lost) */
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
|
||||
EXPECT_RET(p != NULL);
|
||||
test_tcp_input(p, &netif);
|
||||
EXPECT_RET(txcounters.num_tx_calls == 0);
|
||||
EXPECT_RET(pcb->dupacks == 2);
|
||||
/* queue data4, don't send it (unsent-oversize is != 0) */
|
||||
err = tcp_write(pcb, data4, sizeof(data4), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
/* 3nd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
|
||||
EXPECT_RET(p != NULL);
|
||||
test_tcp_input(p, &netif);
|
||||
/*EXPECT_RET(txcounters.num_tx_calls == 1);*/
|
||||
EXPECT_RET(pcb->dupacks == 3);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
/* TODO: check expected data?*/
|
||||
|
||||
/* send data5, not output yet */
|
||||
err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
/*err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);*/
|
||||
EXPECT_RET(txcounters.num_tx_calls == 0);
|
||||
EXPECT_RET(txcounters.num_tx_bytes == 0);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
{
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
err = tcp_write(pcb, data6, TCP_MSS, TCP_WRITE_FLAG_COPY);
|
||||
i++;
|
||||
}while(err == ERR_OK);
|
||||
EXPECT_RET(err != ERR_OK);
|
||||
}
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
/*EXPECT_RET(txcounters.num_tx_calls == 0);
|
||||
EXPECT_RET(txcounters.num_tx_bytes == 0);*/
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
|
||||
/* send even more data */
|
||||
err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
/* ...and even more data */
|
||||
err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
/* ...and even more data */
|
||||
err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
/* ...and even more data */
|
||||
err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
|
||||
/* send ACKs for data2 and data3 */
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 12, TCP_ACK);
|
||||
EXPECT_RET(p != NULL);
|
||||
test_tcp_input(p, &netif);
|
||||
/*EXPECT_RET(txcounters.num_tx_calls == 0);*/
|
||||
|
||||
/* ...and even more data */
|
||||
err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
/* ...and even more data */
|
||||
err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
|
||||
#if 0
|
||||
/* create expected segment */
|
||||
p1 = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);
|
||||
EXPECT_RET(p != NULL);
|
||||
if (p != NULL) {
|
||||
/* pass the segment to tcp_input */
|
||||
test_tcp_input(p, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT_RET(counters.close_calls == 0);
|
||||
EXPECT_RET(counters.recv_calls == 1);
|
||||
EXPECT_RET(counters.recved_bytes == data_len);
|
||||
EXPECT_RET(counters.err_calls == 0);
|
||||
}
|
||||
#endif
|
||||
/* make sure the pcb is freed */
|
||||
EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
|
||||
tcp_abort(pcb);
|
||||
EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static u8_t tx_data[TCP_WND*2];
|
||||
|
||||
static void
|
||||
check_seqnos(struct tcp_seg *segs, int num_expected, u32_t *seqnos_expected)
|
||||
{
|
||||
struct tcp_seg *s = segs;
|
||||
int i;
|
||||
for (i = 0; i < num_expected; i++, s = s->next) {
|
||||
EXPECT_RET(s != NULL);
|
||||
EXPECT(s->tcphdr->seqno == htonl(seqnos_expected[i]));
|
||||
}
|
||||
EXPECT(s == NULL);
|
||||
}
|
||||
|
||||
/** Send data with sequence numbers that wrap around the u32_t range.
|
||||
* Then, provoke fast retransmission by duplicate ACKs and check that all
|
||||
* segment lists are still properly sorted. */
|
||||
START_TEST(test_tcp_fast_rexmit_wraparound)
|
||||
{
|
||||
struct netif netif;
|
||||
struct test_tcp_txcounters txcounters;
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf* p;
|
||||
ip_addr_t remote_ip, local_ip, netmask;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
err_t err;
|
||||
#define SEQNO1 (0xFFFFFF00 - TCP_MSS)
|
||||
#define ISS 6510
|
||||
u16_t i, sent_total = 0;
|
||||
u32_t seqnos[] = {
|
||||
SEQNO1,
|
||||
SEQNO1 + (1 * TCP_MSS),
|
||||
SEQNO1 + (2 * TCP_MSS),
|
||||
SEQNO1 + (3 * TCP_MSS),
|
||||
SEQNO1 + (4 * TCP_MSS),
|
||||
SEQNO1 + (5 * TCP_MSS)};
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
for (i = 0; i < sizeof(tx_data); i++) {
|
||||
tx_data[i] = (u8_t)i;
|
||||
}
|
||||
|
||||
/* initialize local vars */
|
||||
IP4_ADDR(&local_ip, 192, 168, 1, 1);
|
||||
IP4_ADDR(&remote_ip, 192, 168, 1, 2);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
|
||||
/* create and initialize the pcb */
|
||||
tcp_ticks = SEQNO1 - ISS;
|
||||
pcb = test_tcp_new_counters_pcb(&counters);
|
||||
EXPECT_RET(pcb != NULL);
|
||||
EXPECT(pcb->lastack == SEQNO1);
|
||||
tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
|
||||
pcb->mss = TCP_MSS;
|
||||
/* disable initial congestion window (we don't send a SYN here...) */
|
||||
pcb->cwnd = 2*TCP_MSS;
|
||||
|
||||
/* send 6 mss-sized segments */
|
||||
for (i = 0; i < 6; i++) {
|
||||
err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
sent_total += TCP_MSS;
|
||||
}
|
||||
check_seqnos(pcb->unsent, 6, seqnos);
|
||||
EXPECT(pcb->unacked == NULL);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT(txcounters.num_tx_calls == 2);
|
||||
EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U));
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
|
||||
check_seqnos(pcb->unacked, 2, seqnos);
|
||||
check_seqnos(pcb->unsent, 4, &seqnos[2]);
|
||||
|
||||
/* ACK the first segment */
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, TCP_MSS, TCP_ACK);
|
||||
test_tcp_input(p, &netif);
|
||||
/* ensure this didn't trigger a retransmission */
|
||||
EXPECT(txcounters.num_tx_calls == 1);
|
||||
EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
check_seqnos(pcb->unacked, 2, &seqnos[1]);
|
||||
check_seqnos(pcb->unsent, 3, &seqnos[3]);
|
||||
|
||||
/* 3 dupacks */
|
||||
EXPECT(pcb->dupacks == 0);
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
|
||||
test_tcp_input(p, &netif);
|
||||
EXPECT(txcounters.num_tx_calls == 0);
|
||||
EXPECT(pcb->dupacks == 1);
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
|
||||
test_tcp_input(p, &netif);
|
||||
EXPECT(txcounters.num_tx_calls == 0);
|
||||
EXPECT(pcb->dupacks == 2);
|
||||
/* 3rd dupack -> fast rexmit */
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
|
||||
test_tcp_input(p, &netif);
|
||||
EXPECT(pcb->dupacks == 3);
|
||||
EXPECT(txcounters.num_tx_calls == 4);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
EXPECT(pcb->unsent == NULL);
|
||||
check_seqnos(pcb->unacked, 5, &seqnos[1]);
|
||||
|
||||
/* make sure the pcb is freed */
|
||||
EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
|
||||
tcp_abort(pcb);
|
||||
EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/** Send data with sequence numbers that wrap around the u32_t range.
|
||||
* Then, provoke RTO retransmission and check that all
|
||||
* segment lists are still properly sorted. */
|
||||
START_TEST(test_tcp_rto_rexmit_wraparound)
|
||||
{
|
||||
struct netif netif;
|
||||
struct test_tcp_txcounters txcounters;
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
ip_addr_t remote_ip, local_ip, netmask;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
err_t err;
|
||||
#define SEQNO1 (0xFFFFFF00 - TCP_MSS)
|
||||
#define ISS 6510
|
||||
u16_t i, sent_total = 0;
|
||||
u32_t seqnos[] = {
|
||||
SEQNO1,
|
||||
SEQNO1 + (1 * TCP_MSS),
|
||||
SEQNO1 + (2 * TCP_MSS),
|
||||
SEQNO1 + (3 * TCP_MSS),
|
||||
SEQNO1 + (4 * TCP_MSS),
|
||||
SEQNO1 + (5 * TCP_MSS)};
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
for (i = 0; i < sizeof(tx_data); i++) {
|
||||
tx_data[i] = (u8_t)i;
|
||||
}
|
||||
|
||||
/* initialize local vars */
|
||||
IP4_ADDR(&local_ip, 192, 168, 1, 1);
|
||||
IP4_ADDR(&remote_ip, 192, 168, 1, 2);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
|
||||
/* create and initialize the pcb */
|
||||
tcp_ticks = 0;
|
||||
tcp_ticks = 0 - tcp_next_iss();
|
||||
tcp_ticks = SEQNO1 - tcp_next_iss();
|
||||
pcb = test_tcp_new_counters_pcb(&counters);
|
||||
EXPECT_RET(pcb != NULL);
|
||||
EXPECT(pcb->lastack == SEQNO1);
|
||||
tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
|
||||
pcb->mss = TCP_MSS;
|
||||
/* disable initial congestion window (we don't send a SYN here...) */
|
||||
pcb->cwnd = 2*TCP_MSS;
|
||||
|
||||
/* send 6 mss-sized segments */
|
||||
for (i = 0; i < 6; i++) {
|
||||
err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
sent_total += TCP_MSS;
|
||||
}
|
||||
check_seqnos(pcb->unsent, 6, seqnos);
|
||||
EXPECT(pcb->unacked == NULL);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT(txcounters.num_tx_calls == 2);
|
||||
EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U));
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
|
||||
check_seqnos(pcb->unacked, 2, seqnos);
|
||||
check_seqnos(pcb->unsent, 4, &seqnos[2]);
|
||||
|
||||
/* call the tcp timer some times */
|
||||
for (i = 0; i < 10; i++) {
|
||||
test_tcp_tmr();
|
||||
EXPECT(txcounters.num_tx_calls == 0);
|
||||
}
|
||||
/* 11th call to tcp_tmr: RTO rexmit fires */
|
||||
test_tcp_tmr();
|
||||
EXPECT(txcounters.num_tx_calls == 1);
|
||||
check_seqnos(pcb->unacked, 1, seqnos);
|
||||
check_seqnos(pcb->unsent, 5, &seqnos[1]);
|
||||
|
||||
/* fake greater cwnd */
|
||||
pcb->cwnd = pcb->snd_wnd;
|
||||
/* send more data */
|
||||
err = tcp_output(pcb);
|
||||
EXPECT(err == ERR_OK);
|
||||
/* check queues are sorted */
|
||||
EXPECT(pcb->unsent == NULL);
|
||||
check_seqnos(pcb->unacked, 6, seqnos);
|
||||
|
||||
/* make sure the pcb is freed */
|
||||
EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
|
||||
tcp_abort(pcb);
|
||||
EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data.
|
||||
* At the end, send more data. */
|
||||
static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent)
|
||||
{
|
||||
struct netif netif;
|
||||
struct test_tcp_txcounters txcounters;
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf *p;
|
||||
ip_addr_t remote_ip, local_ip, netmask;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
err_t err;
|
||||
u16_t sent_total, i;
|
||||
u8_t expected = 0xFE;
|
||||
|
||||
for (i = 0; i < sizeof(tx_data); i++) {
|
||||
u8_t d = (u8_t)i;
|
||||
if (d == 0xFE) {
|
||||
d = 0xF0;
|
||||
}
|
||||
tx_data[i] = d;
|
||||
}
|
||||
if (zero_window_probe_from_unsent) {
|
||||
tx_data[TCP_WND] = expected;
|
||||
} else {
|
||||
tx_data[0] = expected;
|
||||
}
|
||||
|
||||
/* initialize local vars */
|
||||
IP4_ADDR(&local_ip, 192, 168, 1, 1);
|
||||
IP4_ADDR(&remote_ip, 192, 168, 1, 2);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
|
||||
/* 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);
|
||||
pcb->mss = TCP_MSS;
|
||||
/* disable initial congestion window (we don't send a SYN here...) */
|
||||
pcb->cwnd = pcb->snd_wnd;
|
||||
|
||||
/* send a full window (minus 1 packets) of TCP data in MSS-sized chunks */
|
||||
sent_total = 0;
|
||||
if ((TCP_WND - TCP_MSS) % TCP_MSS != 0) {
|
||||
u16_t initial_data_len = (TCP_WND - TCP_MSS) % TCP_MSS;
|
||||
err = tcp_write(pcb, &tx_data[sent_total], initial_data_len, TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
EXPECT(txcounters.num_tx_calls == 1);
|
||||
EXPECT(txcounters.num_tx_bytes == initial_data_len + 40U);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
sent_total += initial_data_len;
|
||||
}
|
||||
for (; sent_total < (TCP_WND - TCP_MSS); sent_total += TCP_MSS) {
|
||||
err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
EXPECT(txcounters.num_tx_calls == 1);
|
||||
EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
}
|
||||
EXPECT(sent_total == (TCP_WND - TCP_MSS));
|
||||
|
||||
/* now ACK the packet before the first */
|
||||
p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
|
||||
test_tcp_input(p, &netif);
|
||||
/* ensure this didn't trigger a retransmission */
|
||||
EXPECT(txcounters.num_tx_calls == 0);
|
||||
EXPECT(txcounters.num_tx_bytes == 0);
|
||||
|
||||
EXPECT(pcb->persist_backoff == 0);
|
||||
/* send the last packet, now a complete window has been sent */
|
||||
err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
|
||||
sent_total += TCP_MSS;
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
EXPECT(txcounters.num_tx_calls == 1);
|
||||
EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
EXPECT(pcb->persist_backoff == 0);
|
||||
|
||||
if (zero_window_probe_from_unsent) {
|
||||
/* ACK all data but close the TX window */
|
||||
p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_WND, TCP_ACK, 0);
|
||||
test_tcp_input(p, &netif);
|
||||
/* ensure this didn't trigger any transmission */
|
||||
EXPECT(txcounters.num_tx_calls == 0);
|
||||
EXPECT(txcounters.num_tx_bytes == 0);
|
||||
EXPECT(pcb->persist_backoff == 1);
|
||||
}
|
||||
|
||||
/* send one byte more (out of window) -> persist timer starts */
|
||||
err = tcp_write(pcb, &tx_data[sent_total], 1, TCP_WRITE_FLAG_COPY);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
err = tcp_output(pcb);
|
||||
EXPECT_RET(err == ERR_OK);
|
||||
EXPECT(txcounters.num_tx_calls == 0);
|
||||
EXPECT(txcounters.num_tx_bytes == 0);
|
||||
memset(&txcounters, 0, sizeof(txcounters));
|
||||
if (!zero_window_probe_from_unsent) {
|
||||
/* no persist timer unless a zero window announcement has been received */
|
||||
EXPECT(pcb->persist_backoff == 0);
|
||||
} else {
|
||||
EXPECT(pcb->persist_backoff == 1);
|
||||
|
||||
/* call tcp_timer some more times to let persist timer count up */
|
||||
for (i = 0; i < 4; i++) {
|
||||
test_tcp_tmr();
|
||||
EXPECT(txcounters.num_tx_calls == 0);
|
||||
EXPECT(txcounters.num_tx_bytes == 0);
|
||||
}
|
||||
|
||||
/* this should trigger the zero-window-probe */
|
||||
txcounters.copy_tx_packets = 1;
|
||||
test_tcp_tmr();
|
||||
txcounters.copy_tx_packets = 0;
|
||||
EXPECT(txcounters.num_tx_calls == 1);
|
||||
EXPECT(txcounters.num_tx_bytes == 1 + 40U);
|
||||
EXPECT(txcounters.tx_packets != NULL);
|
||||
if (txcounters.tx_packets != NULL) {
|
||||
u8_t sent;
|
||||
u16_t ret;
|
||||
ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U);
|
||||
EXPECT(ret == 1);
|
||||
EXPECT(sent == expected);
|
||||
}
|
||||
if (txcounters.tx_packets != NULL) {
|
||||
pbuf_free(txcounters.tx_packets);
|
||||
txcounters.tx_packets = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure the pcb is freed */
|
||||
EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
|
||||
tcp_abort(pcb);
|
||||
EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
|
||||
START_TEST(test_tcp_tx_full_window_lost_from_unsent)
|
||||
{
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
test_tcp_tx_full_window_lost(1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_tcp_tx_full_window_lost_from_unacked)
|
||||
{
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
test_tcp_tx_full_window_lost(0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/** Create the suite including all tests for this module */
|
||||
Suite *
|
||||
@@ -99,6 +657,11 @@ tcp_suite(void)
|
||||
TFun tests[] = {
|
||||
test_tcp_new_abort,
|
||||
test_tcp_recv_inseq,
|
||||
test_tcp_fast_retx_recover,
|
||||
test_tcp_fast_rexmit_wraparound,
|
||||
test_tcp_rto_rexmit_wraparound,
|
||||
test_tcp_tx_full_window_lost_from_unacked,
|
||||
test_tcp_tx_full_window_lost_from_unsent
|
||||
};
|
||||
return create_suite("TCP", tests, sizeof(tests)/sizeof(TFun), tcp_setup, tcp_teardown);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,18 @@ static int tcp_oos_count(struct tcp_pcb* pcb)
|
||||
return num;
|
||||
}
|
||||
|
||||
/** Get the numbers of pbufs on the ooseq list */
|
||||
static int tcp_oos_pbuf_count(struct tcp_pcb* pcb)
|
||||
{
|
||||
int num = 0;
|
||||
struct tcp_seg* seg = pcb->ooseq;
|
||||
while(seg != NULL) {
|
||||
num += pbuf_clen(seg->p);
|
||||
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
|
||||
@@ -180,7 +192,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ)
|
||||
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);
|
||||
test_tcp_input(p_8_9, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -192,7 +204,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 9); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_4_8, &netif);
|
||||
test_tcp_input(p_4_8, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -206,7 +218,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_4_10, &netif);
|
||||
test_tcp_input(p_4_10, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -220,7 +232,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_2_14, &netif);
|
||||
test_tcp_input(p_2_14, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -232,7 +244,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 15); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_fin, &netif);
|
||||
test_tcp_input(p_fin, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -244,7 +256,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 15); /* includes FIN */
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(pinseq, &netif);
|
||||
test_tcp_input(pinseq, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 1);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
@@ -330,7 +342,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
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);
|
||||
test_tcp_input(p_1_2, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -342,7 +354,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_4_8, &netif);
|
||||
test_tcp_input(p_4_8, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -356,7 +368,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 8);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_3_11, &netif);
|
||||
test_tcp_input(p_3_11, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -371,7 +383,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 11);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_2_12, &netif);
|
||||
test_tcp_input(p_2_12, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -385,7 +397,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 12);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(pinseq, &netif);
|
||||
test_tcp_input(pinseq, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
@@ -394,7 +406,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
EXPECT(pcb->ooseq == NULL);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_15_1, &netif);
|
||||
test_tcp_input(p_15_1, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
@@ -406,7 +418,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_15_1a, &netif);
|
||||
test_tcp_input(p_15_1a, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 1);
|
||||
@@ -418,7 +430,7 @@ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
|
||||
EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
|
||||
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(pinseqFIN, &netif);
|
||||
test_tcp_input(pinseqFIN, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 1);
|
||||
EXPECT(counters.recv_calls == 2);
|
||||
@@ -440,6 +452,7 @@ static char data_full_wnd[TCP_WND];
|
||||
* to simulate overruning the rxwin with ooseq queueing enabled */
|
||||
START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
|
||||
{
|
||||
#if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS
|
||||
int i, k;
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
@@ -449,7 +462,6 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
|
||||
struct netif netif;
|
||||
int datalen = 0;
|
||||
int datalen2;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
for(i = 0; i < sizeof(data_full_wnd); i++) {
|
||||
data_full_wnd[i] = (char)i;
|
||||
@@ -478,9 +490,9 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
|
||||
int count, expected_datalen;
|
||||
struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)],
|
||||
TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK);
|
||||
EXPECT(p != NULL);
|
||||
EXPECT_RET(p != NULL);
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p, &netif);
|
||||
test_tcp_input(p, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -502,9 +514,9 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
|
||||
|
||||
/* pass in one more segment, cleary overrunning the rxwin */
|
||||
p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK);
|
||||
EXPECT(p_ovr != NULL);
|
||||
EXPECT_RET(p_ovr != NULL);
|
||||
/* pass the segment to tcp_input */
|
||||
tcp_input(p_ovr, &netif);
|
||||
test_tcp_input(p_ovr, &netif);
|
||||
/* check if counters are as expected */
|
||||
EXPECT(counters.close_calls == 0);
|
||||
EXPECT(counters.recv_calls == 0);
|
||||
@@ -516,7 +528,356 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
|
||||
EXPECT_OOSEQ(datalen == datalen2);
|
||||
|
||||
/* now pass inseq */
|
||||
tcp_input(pinseq, &netif);
|
||||
test_tcp_input(pinseq, &netif);
|
||||
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);
|
||||
#endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_tcp_recv_ooseq_max_bytes)
|
||||
{
|
||||
#if TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
|
||||
int i, k;
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf *p_ovr;
|
||||
ip_addr_t remote_ip, local_ip;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
struct netif netif;
|
||||
int datalen = 0;
|
||||
int datalen2;
|
||||
|
||||
for(i = 0; i < sizeof(data_full_wnd); i++) {
|
||||
data_full_wnd[i] = (char)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);
|
||||
/* initialize counter struct */
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
counters.expected_data_len = TCP_WND;
|
||||
counters.expected_data = data_full_wnd;
|
||||
|
||||
/* 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);
|
||||
pcb->rcv_nxt = 0x8000;
|
||||
|
||||
/* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */
|
||||
|
||||
/* create segments and 'recv' them */
|
||||
for(k = 1, i = 1; k < TCP_OOSEQ_MAX_BYTES; k += TCP_MSS, i++) {
|
||||
int count;
|
||||
struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[k],
|
||||
TCP_MSS, k, 0, TCP_ACK);
|
||||
EXPECT_RET(p != NULL);
|
||||
EXPECT_RET(p->next == NULL);
|
||||
/* pass the segment to tcp_input */
|
||||
test_tcp_input(p, &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 */
|
||||
count = tcp_oos_pbuf_count(pcb);
|
||||
EXPECT_OOSEQ(count == i);
|
||||
datalen = tcp_oos_tcplen(pcb);
|
||||
EXPECT_OOSEQ(datalen == (i * TCP_MSS));
|
||||
}
|
||||
|
||||
/* pass in one more segment, overrunning the limit */
|
||||
p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[k+1], 1, k+1, 0, TCP_ACK);
|
||||
EXPECT_RET(p_ovr != NULL);
|
||||
/* pass the segment to tcp_input */
|
||||
test_tcp_input(p_ovr, &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 (ensure the new segment was not accepted) */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1));
|
||||
datalen2 = tcp_oos_tcplen(pcb);
|
||||
EXPECT_OOSEQ(datalen2 == ((i-1) * TCP_MSS));
|
||||
|
||||
/* 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);
|
||||
#endif /* TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_tcp_recv_ooseq_max_pbufs)
|
||||
{
|
||||
#if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
|
||||
int i;
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf *p_ovr;
|
||||
ip_addr_t remote_ip, local_ip;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
struct netif netif;
|
||||
int datalen = 0;
|
||||
int datalen2;
|
||||
|
||||
for(i = 0; i < sizeof(data_full_wnd); i++) {
|
||||
data_full_wnd[i] = (char)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);
|
||||
/* initialize counter struct */
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
counters.expected_data_len = TCP_WND;
|
||||
counters.expected_data = data_full_wnd;
|
||||
|
||||
/* 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);
|
||||
pcb->rcv_nxt = 0x8000;
|
||||
|
||||
/* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */
|
||||
|
||||
/* create segments and 'recv' them */
|
||||
for(i = 1; i <= TCP_OOSEQ_MAX_PBUFS; i++) {
|
||||
int count;
|
||||
struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[i],
|
||||
1, i, 0, TCP_ACK);
|
||||
EXPECT_RET(p != NULL);
|
||||
EXPECT_RET(p->next == NULL);
|
||||
/* pass the segment to tcp_input */
|
||||
test_tcp_input(p, &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 */
|
||||
count = tcp_oos_pbuf_count(pcb);
|
||||
EXPECT_OOSEQ(count == i);
|
||||
datalen = tcp_oos_tcplen(pcb);
|
||||
EXPECT_OOSEQ(datalen == i);
|
||||
}
|
||||
|
||||
/* pass in one more segment, overrunning the limit */
|
||||
p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[i+1], 1, i+1, 0, TCP_ACK);
|
||||
EXPECT_RET(p_ovr != NULL);
|
||||
/* pass the segment to tcp_input */
|
||||
test_tcp_input(p_ovr, &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 (ensure the new segment was not accepted) */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1));
|
||||
datalen2 = tcp_oos_tcplen(pcb);
|
||||
EXPECT_OOSEQ(datalen2 == (i-1));
|
||||
|
||||
/* 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);
|
||||
#endif /* TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
check_rx_counters(struct tcp_pcb *pcb, struct test_tcp_counters *counters, u32_t exp_close_calls, u32_t exp_rx_calls,
|
||||
u32_t exp_rx_bytes, u32_t exp_err_calls, int exp_oos_count, int exp_oos_len)
|
||||
{
|
||||
int oos_len;
|
||||
EXPECT(counters->close_calls == exp_close_calls);
|
||||
EXPECT(counters->recv_calls == exp_rx_calls);
|
||||
EXPECT(counters->recved_bytes == exp_rx_bytes);
|
||||
EXPECT(counters->err_calls == exp_err_calls);
|
||||
/* check that pbuf is queued in ooseq */
|
||||
EXPECT_OOSEQ(tcp_oos_count(pcb) == exp_oos_count);
|
||||
oos_len = tcp_oos_tcplen(pcb);
|
||||
EXPECT_OOSEQ(exp_oos_len == oos_len);
|
||||
}
|
||||
|
||||
/* this test uses 4 packets:
|
||||
* - data (len=TCP_MSS)
|
||||
* - FIN
|
||||
* - data after FIN (len=1) (invalid)
|
||||
* - 2nd FIN (invalid)
|
||||
*
|
||||
* the parameter 'delay_packet' is a bitmask that choses which on these packets is ooseq
|
||||
*/
|
||||
static void test_tcp_recv_ooseq_double_FINs(int delay_packet)
|
||||
{
|
||||
int i, k;
|
||||
struct test_tcp_counters counters;
|
||||
struct tcp_pcb* pcb;
|
||||
struct pbuf *p_normal_fin, *p_data_after_fin, *p, *p_2nd_fin_ooseq;
|
||||
ip_addr_t remote_ip, local_ip;
|
||||
u16_t remote_port = 0x100, local_port = 0x101;
|
||||
struct netif netif;
|
||||
u32_t exp_rx_calls = 0, exp_rx_bytes = 0, exp_close_calls = 0, exp_oos_pbufs = 0, exp_oos_tcplen = 0;
|
||||
int first_dropped = 0xff;
|
||||
int last_dropped = 0;
|
||||
|
||||
for(i = 0; i < sizeof(data_full_wnd); i++) {
|
||||
data_full_wnd[i] = (char)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);
|
||||
/* initialize counter struct */
|
||||
memset(&counters, 0, sizeof(counters));
|
||||
counters.expected_data_len = TCP_WND;
|
||||
counters.expected_data = data_full_wnd;
|
||||
|
||||
/* 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);
|
||||
pcb->rcv_nxt = 0x8000;
|
||||
|
||||
/* create segments */
|
||||
p = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK);
|
||||
p_normal_fin = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS, 0, TCP_ACK|TCP_FIN);
|
||||
k = 1;
|
||||
p_data_after_fin = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS+1], k, TCP_MSS+1, 0, TCP_ACK);
|
||||
p_2nd_fin_ooseq = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS+1+k, 0, TCP_ACK|TCP_FIN);
|
||||
|
||||
if(delay_packet & 1) {
|
||||
/* drop normal data */
|
||||
first_dropped = 1;
|
||||
last_dropped = 1;
|
||||
} else {
|
||||
/* send normal data */
|
||||
test_tcp_input(p, &netif);
|
||||
exp_rx_calls++;
|
||||
exp_rx_bytes += TCP_MSS;
|
||||
}
|
||||
/* check if counters are as expected */
|
||||
check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);
|
||||
|
||||
if(delay_packet & 2) {
|
||||
/* drop FIN */
|
||||
if(first_dropped > 2) {
|
||||
first_dropped = 2;
|
||||
}
|
||||
last_dropped = 2;
|
||||
} else {
|
||||
/* send FIN */
|
||||
test_tcp_input(p_normal_fin, &netif);
|
||||
if (first_dropped < 2) {
|
||||
/* already dropped packets, this one is ooseq */
|
||||
exp_oos_pbufs++;
|
||||
exp_oos_tcplen++;
|
||||
} else {
|
||||
/* inseq */
|
||||
exp_close_calls++;
|
||||
}
|
||||
}
|
||||
/* check if counters are as expected */
|
||||
check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);
|
||||
|
||||
if(delay_packet & 4) {
|
||||
/* drop data-after-FIN */
|
||||
if(first_dropped > 3) {
|
||||
first_dropped = 3;
|
||||
}
|
||||
last_dropped = 3;
|
||||
} else {
|
||||
/* send data-after-FIN */
|
||||
test_tcp_input(p_data_after_fin, &netif);
|
||||
if (first_dropped < 3) {
|
||||
/* already dropped packets, this one is ooseq */
|
||||
if (delay_packet & 2) {
|
||||
/* correct FIN was ooseq */
|
||||
exp_oos_pbufs++;
|
||||
exp_oos_tcplen += k;
|
||||
}
|
||||
} else {
|
||||
/* inseq: no change */
|
||||
}
|
||||
}
|
||||
/* check if counters are as expected */
|
||||
check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);
|
||||
|
||||
if(delay_packet & 8) {
|
||||
/* drop 2nd-FIN */
|
||||
if(first_dropped > 4) {
|
||||
first_dropped = 4;
|
||||
}
|
||||
last_dropped = 4;
|
||||
} else {
|
||||
/* send 2nd-FIN */
|
||||
test_tcp_input(p_2nd_fin_ooseq, &netif);
|
||||
if (first_dropped < 3) {
|
||||
/* already dropped packets, this one is ooseq */
|
||||
if (delay_packet & 2) {
|
||||
/* correct FIN was ooseq */
|
||||
exp_oos_pbufs++;
|
||||
exp_oos_tcplen++;
|
||||
}
|
||||
} else {
|
||||
/* inseq: no change */
|
||||
}
|
||||
}
|
||||
/* check if counters are as expected */
|
||||
check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);
|
||||
|
||||
if(delay_packet & 1) {
|
||||
/* dropped normal data before */
|
||||
test_tcp_input(p, &netif);
|
||||
exp_rx_calls++;
|
||||
exp_rx_bytes += TCP_MSS;
|
||||
if((delay_packet & 2) == 0) {
|
||||
/* normal FIN was NOT delayed */
|
||||
exp_close_calls++;
|
||||
exp_oos_pbufs = exp_oos_tcplen = 0;
|
||||
}
|
||||
}
|
||||
/* check if counters are as expected */
|
||||
check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);
|
||||
|
||||
if(delay_packet & 2) {
|
||||
/* dropped normal FIN before */
|
||||
test_tcp_input(p_normal_fin, &netif);
|
||||
exp_close_calls++;
|
||||
exp_oos_pbufs = exp_oos_tcplen = 0;
|
||||
}
|
||||
/* check if counters are as expected */
|
||||
check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);
|
||||
|
||||
if(delay_packet & 4) {
|
||||
/* dropped data-after-FIN before */
|
||||
test_tcp_input(p_data_after_fin, &netif);
|
||||
}
|
||||
/* check if counters are as expected */
|
||||
check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);
|
||||
|
||||
if(delay_packet & 8) {
|
||||
/* dropped 2nd-FIN before */
|
||||
test_tcp_input(p_2nd_fin_ooseq, &netif);
|
||||
}
|
||||
/* check if counters are as expected */
|
||||
check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);
|
||||
|
||||
/* check that ooseq data has been dumped */
|
||||
EXPECT(pcb->ooseq == NULL);
|
||||
|
||||
/* make sure the pcb is freed */
|
||||
@@ -524,7 +885,32 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
|
||||
tcp_abort(pcb);
|
||||
EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/** create multiple segments and pass them to tcp_input with the first segment missing
|
||||
* to simulate overruning the rxwin with ooseq queueing enabled */
|
||||
#define FIN_TEST(name, num) \
|
||||
START_TEST(name) \
|
||||
{ \
|
||||
LWIP_UNUSED_ARG(_i); \
|
||||
test_tcp_recv_ooseq_double_FINs(num); \
|
||||
} \
|
||||
END_TEST
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_0, 0)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_1, 1)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_2, 2)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_3, 3)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_4, 4)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_5, 5)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_6, 6)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_7, 7)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_8, 8)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_9, 9)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_10, 10)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_11, 11)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_12, 12)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_13, 13)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_14, 14)
|
||||
FIN_TEST(test_tcp_recv_ooseq_double_FIN_15, 15)
|
||||
|
||||
|
||||
/** Create the suite including all tests for this module */
|
||||
@@ -535,6 +921,24 @@ tcp_oos_suite(void)
|
||||
test_tcp_recv_ooseq_FIN_OOSEQ,
|
||||
test_tcp_recv_ooseq_FIN_INSEQ,
|
||||
test_tcp_recv_ooseq_overrun_rxwin,
|
||||
test_tcp_recv_ooseq_max_bytes,
|
||||
test_tcp_recv_ooseq_max_pbufs,
|
||||
test_tcp_recv_ooseq_double_FIN_0,
|
||||
test_tcp_recv_ooseq_double_FIN_1,
|
||||
test_tcp_recv_ooseq_double_FIN_2,
|
||||
test_tcp_recv_ooseq_double_FIN_3,
|
||||
test_tcp_recv_ooseq_double_FIN_4,
|
||||
test_tcp_recv_ooseq_double_FIN_5,
|
||||
test_tcp_recv_ooseq_double_FIN_6,
|
||||
test_tcp_recv_ooseq_double_FIN_7,
|
||||
test_tcp_recv_ooseq_double_FIN_8,
|
||||
test_tcp_recv_ooseq_double_FIN_9,
|
||||
test_tcp_recv_ooseq_double_FIN_10,
|
||||
test_tcp_recv_ooseq_double_FIN_11,
|
||||
test_tcp_recv_ooseq_double_FIN_12,
|
||||
test_tcp_recv_ooseq_double_FIN_13,
|
||||
test_tcp_recv_ooseq_double_FIN_14,
|
||||
test_tcp_recv_ooseq_double_FIN_15
|
||||
};
|
||||
return create_suite("TCP_OOS", tests, sizeof(tests)/sizeof(TFun), tcp_oos_setup, tcp_oos_teardown);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user