Compare commits

...

113 Commits

Author SHA1 Message Date
likewise
ec0c2bea6e Changed behaviour into implementation. 2005-01-01 18:06:21 +00:00
likewise
1b3682cfa9 Updated CHANGELOG. 2004-12-30 01:28:16 +00:00
likewise
2a9ee35411 Removed assertion that always equaled true. 2004-12-27 14:50:03 +00:00
likewise
0e0a7d82de Re-enabled ARP packet queueing. (Now that multi-packet queueing is disabled in etharp.c). 2004-12-27 14:45:12 +00:00
likewise
dfa96852f0 Disabled queueing more than 1 packet on a ARP entry, as I suspect this clashes with the TCP segment queueing. 2004-12-27 14:44:19 +00:00
likewise
a549ec0382 Added inline source documentation. 2004-12-27 14:42:02 +00:00
likewise
c61f01b206 tcp_write(): optimize order of valid states checks, most common first.
added assertion: when the queues are NULL, queuelen must be zero.
remove ACK flags from a PCB, only when we could succesfully sent
an empty ACK packet.
2004-12-26 01:36:37 +00:00
likewise
15257f4524 Update comment on ETHARP_QUEUEING. Defaulted to being disabled. 2004-12-24 21:58:53 +00:00
christiaans
089378ef87 christiaans: cosmetic change debug formatters as requested by Tom. 2004-12-07 08:16:27 +00:00
christiaans
805f495d84 christiaans: Fixed SO_REUSE default to 0. Actually we should fix udp so it won't depend on the socket layer. 2004-12-06 11:50:53 +00:00
likewise
928dd94ba6 etharp.c: Corrected DHCP_DOES_ARP_CHECK behaviour. 2004-11-30 17:22:18 +00:00
likewise
b429918b32 etharp.c: re-arranged code in find_entry(), supposedly making it more readable for all cases. 2004-11-29 11:01:20 +00:00
likewise
62a37a4876 Updates the FILES contents to better reflect the current state. 2004-11-29 09:39:51 +00:00
likewise
0e96ece6c6 Surround definition of tcp_timer_needed with #if !NO_SYS #endif. (see lwip-users 15-11-2004). 2004-11-28 18:23:00 +00:00
likewise
f1eca32536 Mentioned ARP race fix. 2004-11-28 18:06:47 +00:00
likewise
ed59dc1ada Prevented a race condition between a new ARP request and the ARP timer.
Timeouts stay the same (halved the ARP timer, doubled the counts), but
ETHARP_MAX_PENDING should be at least 2 to prevent it from reaching 0 right away,
giving too little time for any ARP responses to be noted.
2004-11-28 18:00:20 +00:00
likewise
a5cd3fcafd Added a missing "not" in the comment, the code was correct. 2004-11-25 14:04:45 +00:00
likewise
f3def542ee Compile dammit 2004-11-25 14:03:31 +00:00
likewise
aa249922df Removed redundant closing bracket. 2004-11-25 13:59:06 +00:00
likewise
37a0c57bed 2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net>
* ip.c: Exploit the fact that ip_addr_isbroadcast() now checks that the
     given IP address actually belongs to the network of the given interface.
2004-11-25 13:57:05 +00:00
likewise
90b7e68b4e Removed the Smurf. 2004-11-25 13:52:34 +00:00
likewise
1a0c497007 Mentioned Kieran's and my changes - Leon. 2004-11-25 13:33:57 +00:00
likewise
fd49ee3c8d 2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net>
* ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are
    comparing network addresses (identifiers), not the network masks
    themselves.
  * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given
    IP address actually belongs to the network of the given interface.
2004-11-25 13:33:07 +00:00
likewise
3488a5c3c4 2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net>
* etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD.
    Do not try hard to insert arbitrary packet's source address,
    etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD.
    etharp_query() now always DOES call ETHARP_TRY_HARD so that users
    querying an address will see it appear in the cache (DHCP could
    suffer from this when a server invalidly gave an in-use address.)
2004-11-25 13:32:31 +00:00
likewise
ae4955f59e Replaced erronous LWIP_ERRORF with LWIP_DEBUGF 2004-11-25 11:23:37 +00:00
likewise
fab107a9df DECLINE message was unicast instead of broadcast 2004-11-25 11:10:53 +00:00
kieranm
bb87d19e84 Kieran Mansley - kjm25@cam.ac.uk - 24th Nov 2004
* Increase pcb->snd_buf by 1 when an ACK is received in SYN_SENT state to ensure correct operation
2004-11-24 17:05:41 +00:00
kieranm
4e309b7992 Kieran Mansley - kjm25@cam.ac.uk - 24th Nov 2004
* Changed pcb->rttest from u16_t to u32_t - comparisons with tcp_ticks (which is u32_t) were failing after 9 hours of operation
2004-11-24 17:04:34 +00:00
kieranm
64aa4c716d Kieran Mansley - kjm25@cam.ac.uk - 24th Nov 2004
* Increased argument checking at start of pbuf_queue() and made resulting errors more verbose
2004-11-24 17:03:03 +00:00
jani
6b0852a21f reduce msleep interval from 250 to 1 ms in ppp 2004-11-09 13:03:32 +00:00
jani
8afd3e882e #if directive style fix 2004-11-09 11:44:06 +00:00
likewise
791fa28817 Removed static declaration of dhcp_release(). 2004-11-04 19:19:29 +00:00
christiaans
3fab752640 Removed struct netif; forward decl. is already included from ip_addr.h.
Hit me if it breaks exsisting code.
2004-10-29 14:57:38 +00:00
christiaans
67dd939d83 Match update_arp_entry() to prototype. 2004-10-28 08:21:33 +00:00
likewise
ec9b447be1 17th October 2004 Leon Woestenberg <leon.woestenberg@gmx.net>
rawapi.txt: Explicitly name full nomenclature for two different API's.
2004-10-17 21:28:25 +00:00
likewise
99e3fe9ae1 17th October 2004 Leon Woestenberg <leon.woestenberg@gmx.net>
ethernetif.c: Fix lwip/stats.h support, reported by Andrew McGeachie.
2004-10-17 18:13:18 +00:00
likewise
eb99d21022 Mentioned adapted TCP behaviour; send ACK even if one was pending, iff rcv_wnd is above threshold. 2004-10-16 15:12:56 +00:00
likewise
793cbcdff8 Mentioned adapted TCP behaviour; send ACK even if one was pending, iff rcv_wnd is above threshold. 2004-10-16 15:07:26 +00:00
kieranm
751557bcbf 16th October 2004 - Kieran Mansley - kjm25@cam.ac.uk
- Add code to tcp_recved() to send an ACK (window update)
immediately, even if one is already pending, if the rcv_wnd is above a
threshold (currently TCP_WND/2)
 - This avoids waiting for a timer to expire to send a delayed ACK in
order to open the window if the stack is only receiving data.
2004-10-16 12:57:52 +00:00
likewise
252dcd8626 Reverted back the TCP_BETWEEN macro. It does not work on all archs. 2004-10-14 12:24:52 +00:00
likewise
0ad7ea16d2 Bring interface up/down with netif_set_up/down(). Fixes bug 10547. 2004-10-14 11:57:53 +00:00
likewise
79842d4fdd Mentioned TCP retransmit time-out changes contributed by Sam Jansen, committed Kieran Mansley. 2004-10-13 21:40:51 +00:00
kieranm
1e1f5d5462 Kieran Mansley - kjm25@cam.ac.uk - 20th September 2004
* Change the return type of ethernetif_init from void to err_t to avoid confusing porters.
2004-09-20 17:00:31 +00:00
kieranm
19d8ffe177 Kieran Mansley - kjm25@cam.ac.uk - 20th September 2004
* Check if the pbuf is NULL before freeing it, when draining the mbox as part of netconn_delete.
2004-09-20 16:58:01 +00:00
kieranm
4cb8192c1d Kieran Mansley - kjm25@cam.ac.uk - 20th September 2004
* Corrected "out by one" error on one of the TCP_SEQ_BETWEEN macro calls introduced recently
2004-09-20 16:53:48 +00:00
kieranm
2ed5bc5195 Kieran Mansley - kjm25@cam.ac.uk - 12th September 2004
Applied patch from Sam Jansen as detailed in
http://lists.gnu.org/archive/html/lwip-users/2004-07/msg00106.html
to correctly handle retransmission after a retransmission timeout
2004-09-12 16:34:06 +00:00
kieranm
fae1397468 Rename lwip_chksum and add LWIP_CHKSUM macro so that ports can "override" the standard implementation with one of their own. 2004-09-12 16:17:58 +00:00
kieranm
e871548772 Fixed typo (missing "{") in previous checkin 2004-09-12 16:03:54 +00:00
kieranm
a3d27e30e0 Add TCP_SEQ_BETWEEN macro for comparing a range of sequence numbers 2004-09-12 15:56:12 +00:00
likewise
89abd1f58e Do no longer try to free pbuf when TCP_EVENT_RECV() is called without a callback handler, and without packet.
The standard HTTP server failed on this (as reported by three users).
2004-09-08 22:33:46 +00:00
softins
fae709d9ea Added my July and August updates. 2004-08-20 16:56:20 +00:00
softins
36df79b207 Make sure the first pbuf queued on an ARP entry is properly ref counted. 2004-08-20 09:17:52 +00:00
likewise
b9ebcd7738 Ingress TCP keep-alive with garbage byte support. 2004-08-17 09:32:31 +00:00
likewise
515fb5a3fd First packet on queue generated assertion failure. Reported by David Haas on lwip-users on Friday 13th. 2004-08-17 08:39:43 +00:00
likewise
785f90d9fa Updated the use of Savannah docs (merged from STABLE-0_7 branch). 2004-08-11 00:15:03 +00:00
likewise
22ac311496 Support for PACK_STRUCT_USE_INCLUDES was broken.
Added one missing PACK_STRUCT_END.
2004-08-10 14:50:44 +00:00
likewise
0e31ca73c0 Have PBUF_LINK_HLEN default to 14 bytes (for Ethernet). 2004-08-10 14:41:12 +00:00
likewise
98ba558fa5 Mentioned 1.0.0. 2004-07-29 11:28:27 +00:00
softins
c4ef1e5c19 Add (int) cast in LWIP_DEBUGF() to avoid compiler warnings about comparison. 2004-07-27 16:19:16 +00:00
softins
1fa0d66f15 Stop compiler complaining of empty if statement when LWIP_DEBUGF() empty. 2004-07-27 16:08:26 +00:00
softins
4680307a34 Stop compiler complaining of empty if statement when LWIP_DEBUGF() empty.
Close an unclosed comment.
2004-07-27 16:08:05 +00:00
softins
42a6fa972d Corrected IPH_TOS() macro: returns a byte, so doesn't need htons(). 2004-07-27 14:46:24 +00:00
softins
1da6c35a6d Added a couple of casts to quiet the compiler.
No need to test isascii(c) before isdigit(c) or isxdigit(c).
2004-07-27 14:43:58 +00:00
likewise
7c427a4dce Made some comments more explicit. 2004-07-25 23:41:01 +00:00
likewise
c2abae538b pbuf_free() assert triggered by NULLified inseg.p. Reported by Karl Jeacle on 25-7-2004 on lwip-users. 2004-07-25 23:17:07 +00:00
kieranm
eb69032773 Kieran Mansley - kjm25@cam.ac.uk - 23rd July 2004
Now handle CLOSED state in tcp_close() explicitely, and free the pcb.
This is for the case that a pcb has been allocated but never used (so
is in the default "CLOSED" state) and needs to be freed.
2004-07-23 13:07:00 +00:00
likewise
fb5452910f I hate it when it takes twice to fix a typo 2004-07-22 22:10:17 +00:00
likewise
a6d37fcb25 Removed copy-paste errors. 2004-07-22 22:07:00 +00:00
likewise
fb18e1f036 Removed obsolete debug define. 2004-07-22 21:56:31 +00:00
likewise
786cbee510 Support for learning DNS servers through DHCP. 2004-07-22 21:56:09 +00:00
softins
a4f5673ff3 Small corrections to some debugging statements, to pacify compiler. 2004-07-22 08:06:00 +00:00
softins
1121f2b7f7 Made data types consistent in inet_ntoa().
Added casts for return values of checksum routines, to pacify compiler.
2004-07-22 08:03:02 +00:00
softins
4d30218eb2 Updated low_level_output() to match prototype for netif->linkoutput
and changed low_level_input() similarly for consistency.
2004-07-21 09:31:03 +00:00
softins
d7699ca81d Changed debug statements to use the tidier ip4_addrN() macros. 2004-07-21 09:23:11 +00:00
softins
afc3bc6b65 Added trivial (int) cast to keep compiler happier. 2004-07-21 08:57:05 +00:00
softins
6f066fca82 Changed recv_raw() from int to u8_t, to match prototype of raw_recv() in raw.h
and so avoid compiler error.
2004-07-21 08:55:26 +00:00
softins
5e24ae49a6 Removed spurious semicolon and added missing end-of-comment. 2004-07-21 08:36:15 +00:00
likewise
bf74ffe974 Outgoing packets caused ARP requests even when the destination IP was already cached.
Matched documentation.
2004-07-20 23:18:09 +00:00
likewise
2074861b57 Outgoing packets caused ARP requests even when the destination IP was already cached. 2004-07-20 23:07:54 +00:00
likewise
58b64d42f1 Additional fix for TCP retransmit fix (as discussed by Sam Jansen en Kieran Mansley on lwip-devel, July 13 2004). 2004-07-14 23:21:53 +00:00
likewise
a6ab0405ea Disabled some code by #if 0 #endif rather than /* */. 2004-07-14 23:19:08 +00:00
kieranm
8273b54108 Kieran Mansley - 14th July 2004
* Only move a single segment from the unacked queue to the unsent queue when performing a retransmit
2004-07-14 09:48:27 +00:00
kieranm
c356f560e8 Kieran Mansley - 14th July 2004
* Fixed whitespace indenting in parts of tcp_in.c
 * Changed adjustment of ssthresh in response to fast retransmit
 * Commented out iteration of unsent list when new ACK received as we no longer put all unacked data on unsent list when retransmitting
2004-07-14 09:45:01 +00:00
likewise
8d052ecf24 Source documentation added. 2004-07-12 20:42:16 +00:00
likewise
45e36d9f56 Dependencies on C library memset() etc., so include <string.h>. 2004-07-05 00:00:21 +00:00
likewise
c222d8b672 Updated with latest changes. 2004-07-04 23:52:40 +00:00
likewise
efed3f1f0d Mentioned placement of closing curly brace (block end). 2004-07-04 23:44:43 +00:00
likewise
7524893802 Dependencies on C library memset() etc., so include <string.h>. 2004-07-04 23:43:38 +00:00
likewise
25a0273b05 LWIP_TIMEVAL_PRIVATE must be defined in architecture cc.h file, either 1 or 0. Defaults to 1.
Dependencies on C library memset() etc., so include <string.h> and <errno.h>.
2004-07-04 23:43:02 +00:00
likewise
ce0410b205 LWIP_TIMEVAL_PRIVATE must be defined in architecture cc.h file, either 1 or 0. Defaults to 1. 2004-07-04 23:42:14 +00:00
likewise
efe5ce5c78 Made loop counters unsigned where possible. 2004-07-04 23:40:44 +00:00
likewise
07f52b4b96 Fixed compile errors. 2004-06-30 22:14:03 +00:00
likewise
0be3598990 Style fixes. 2004-06-30 18:42:54 +00:00
likewise
c3284c30cd Make restarting() DHCP on on interface more robust by cleaning old state information. 2004-06-30 18:42:33 +00:00
likewise
2d94bf4998 Bug fix: etharp_output() should not free pbufs.
Bug was introduced in 1.60 and reported by Tim Newsham on 30-Jun-2004 on lwip-users.
2004-06-30 18:41:39 +00:00
likewise
31c1e72b8c ip_forward() returns netif on which packet was forwarded. 2004-06-30 18:39:17 +00:00
likewise
d11fcafad8 Added netif up/down basics. 2004-06-30 18:38:07 +00:00
kieranm
27c6d299cf Kieran Mansley - kjm25@cam.ac.uk - 30th May 2004
* Fixed bug #9160 after discussion on mailing list
 - alters use of MEM_ALIGN_SIZE in pbuf_alloc when calling mem_malloc for a PBUF_RAM pbuf
2004-05-30 14:04:30 +00:00
kieranm
450dd65165 Kieran Mansley - kjm25@cam.ac.uk - 26th May 2004
* Fixed bug 9076 (changes to pbuf tot_len and seg dataptr when trimming front edge of a received packet)
2004-05-26 10:04:15 +00:00
likewise
26819e6c39 Fixed documentation for internal function. 2004-05-13 00:28:38 +00:00
likewise
6587efb3e8 Fixed #if ETHARP_QUEUEING to #if ARP_QUEUEING. 2004-05-07 01:20:28 +00:00
likewise
8d2200f29b Optimized search loop a bit. Conditional code for ETHARP_QUEUEING option. 2004-05-07 01:06:56 +00:00
likewise
e4295396ac Re-instantiated the pack directives. Nested structs do break individual field natural alignment on arm-gcc. 2004-05-06 03:27:13 +00:00
likewise
5c7a70df28 Fixed wrong argument to find_entry() in etharp_query(). 2004-05-06 02:55:53 +00:00
likewise
16a7a8258f Fixed ETH_EMPTY into ETHARP_STABLE_EMPTY. 2004-05-06 02:54:06 +00:00
likewise
fb1f61b212 Do not empty entries unless allowed to in find_entry(). 2004-05-06 02:51:15 +00:00
likewise
c3137df39c More fixes. 2004-05-06 02:49:10 +00:00
likewise
2df9cd7262 Exported etharp_request(). 2004-05-06 02:43:47 +00:00
likewise
a23f6afbee Fixed typos. 2004-05-06 02:38:42 +00:00
likewise
e37f7fafc1 Optimized through re-use of common code. Results in 50 lines less and more modular code.
Work towards timed out and retries of ARP requests. Currently, one timed out ARP request.
2004-05-06 02:35:27 +00:00
likewise
7b803465ad Simplified update_arp_entry(). 2004-05-06 00:14:39 +00:00
likewise
273612b251 Prevent non-unicast addresses from polluting the ARP cache. 2004-05-05 23:47:33 +00:00
likewise
e2bc8e86e2 Removed a closing bracket, left over after removing pack directives. 2004-05-05 23:04:17 +00:00
48 changed files with 1597 additions and 1046 deletions

View File

@@ -5,17 +5,107 @@ FUTURE
problems with exoteric (/DSP) architectures showing these problems.
We still have to fix some of these issues neatly.
* TODO: the ARP layer is not protected against concurrent access. If
you run from a multitasking OS, serialize access to ARP (called from
your network device driver and from a timeout thread.)
HISTORY
(HEAD)
2004-12-28 Leon Woestenberg <leon.woestenberg@gmx.net>
* etharp.*: Disabled multiple packets on the ARP queue.
This clashes with TCP queueing.
2004-11-28 Leon Woestenberg <leon.woestenberg@gmx.net>
* etharp.*: Fixed race condition from ARP request to ARP timeout.
Halved the ARP period, doubled the period counts.
ETHARP_MAX_PENDING now should be at least 2. This prevents
the counter from reaching 0 right away (which would allow
too little time for ARP responses to be received).
2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net>
* dhcp.c: Decline messages were not multicast but unicast.
* etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD.
Do not try hard to insert arbitrary packet's source address,
etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD.
etharp_query() now always DOES call ETHARP_TRY_HARD so that users
querying an address will see it appear in the cache (DHCP could
suffer from this when a server invalidly gave an in-use address.)
* ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are
comparing network addresses (identifiers), not the network masks
themselves.
* ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given
IP address actually belongs to the network of the given interface.
2004-11-24 Kieran Mansley <kjm25@cam.ac.uk>
* tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state.
(STABLE-1_1_0-RC1)
2004-10-16 Kieran Mansley <kjm25@cam.ac.uk>
* tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately,
even if one is already pending, if the rcv_wnd is above a threshold
(currently TCP_WND/2). This avoids waiting for a timer to expire to send a
delayed ACK in order to open the window if the stack is only receiving data.
2004-09-12 Kieran Mansley <kjm25@cam.ac.uk>
* tcp*.*: Retransmit time-out handling improvement by Sam Jansen.
2004-08-20 Tony Mountifield <tony@softins.co.uk>
* etharp.c: Make sure the first pbuf queued on an ARP entry
is properly ref counted.
2004-07-27 Tony Mountifield <tony@softins.co.uk>
* debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler
warnings about comparison.
* pbuf.c: Stopped compiler complaining of empty if statement
when LWIP_DEBUGF() empty. Closed an unclosed comment.
* tcp.c: Stopped compiler complaining of empty if statement
when LWIP_DEBUGF() empty.
* ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons().
* inet.c: Added a couple of casts to quiet the compiler.
No need to test isascii(c) before isdigit(c) or isxdigit(c).
2004-07-22 Tony Mountifield <tony@softins.co.uk>
* inet.c: Made data types consistent in inet_ntoa().
Added casts for return values of checksum routines, to pacify compiler.
* ip_frag.c, tcp_out.c, sockets.c, pbuf.c
Small corrections to some debugging statements, to pacify compiler.
2004-07-21 Tony Mountifield <tony@softins.co.uk>
* etharp.c: Removed spurious semicolon and added missing end-of-comment.
* ethernetif.c Updated low_level_output() to match prototype for
netif->linkoutput and changed low_level_input() similarly for consistency.
* api_msg.c: Changed recv_raw() from int to u8_t, to match prototype
of raw_recv() in raw.h and so avoid compiler error.
* sockets.c: Added trivial (int) cast to keep compiler happier.
* ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros.
(STABLE-1_0_0)
++ Changes:
2004-07-05 Leon Woestenberg <leon.woestenberg@gmx.net>
* sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure
your cc.h file defines this either 1 or 0. If non-defined,
defaults to 1.
* .c: Added <string.h> and <errno.h> includes where used.
* etharp.c: Made some array indices unsigned.
2004-06-27 Leon Woestenberg <leon.woestenberg@gmx.net>
* netif.*: Added netif_set_up()/down().
* dhcp.c: Changes to restart program flow.
2004-05-07 Leon Woestenberg <leon.woestenberg@gmx.net>
* etharp.c: In find_entry(), instead of a list traversal per candidate, do a
single-pass lookup for different candidates. Should exploit locality.
2004-04-29 Leon Woestenberg <leon.woestenberg@gmx.net>
* tcp*.c: Cleaned up source comment documentation for Doxygen processing.
* opt.h: ETHHARP_ALWAYS_INSERT option removed to comply with ARP RFC.
* opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC.
* etharp.c: update_arp_entry() only adds new ARP entries when adviced to by
the caller. This deprecates the ETHHARP_ALWAYS_INSERT overrule option.
the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option.
++ Bug fixes:

View File

@@ -6,7 +6,7 @@ in lwIP development.
2 How to contribute to lwIP
Here is a short list of suggestions to anybody working with lwIP and
trying to contribute bugreports, fixes, enhancements, platform ports etc.
trying to contribute bug reports, fixes, enhancements, platform ports etc.
First of all as you may already know lwIP is a volunteer project so feedback
to fixes or questions might often come late. Hopefully the bug and patch tracking
features of Savannah help us not lose users' input.
@@ -14,19 +14,20 @@ features of Savannah help us not lose users' input.
2.1 Source code style:
1. do not use tabs.
2. identation is two spaces per level.
2. indentation is two spaces per level (i.e. per tab).
3. end debug messages with a trailing newline (\n).
4. one space between keyword and opening bracket.
5. no space between function and opening bracket.
6. one space and no newline before opening curly braces of a block.
7. spaces surrounding assignment and comparisons.
8. use current source code style as further reference.
7. closing curly brace on a single line.
8. spaces surrounding assignment and comparisons.
9. use current source code style as further reference.
2.2 Source code documentation style:
1. JavaDoc compliant and Doxygen compatible.
2. Function documentation above functions in .c files, not .h files.
(This forces you to synchronize documentation and behaviour.)
(This forces you to synchronize documentation and implementation.)
3. Use current documentation style as further reference.
2.3 Bug reports and patches:
@@ -55,9 +56,7 @@ features of Savannah help us not lose users' input.
2.4 Platform porters:
1. If you've ported lwIP to a platform (an OS, a uC/processor or a combination of these) and you think it
could benefit others[1] you might want to post an url to a tarball or zip from which it can be imported
to the contrib CVS module. Then you get CVS access and have to maintain your port :)
[1] - lwIP CVS should not be just a place to keep your port so you don't have to set up your own CVS :)
Especially welcome are ports to common enough OS/hardware that others can have access too.
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
you think it could benefit others[1] you might want discuss this on the mailing list. You
can also ask for CVS access to submit and maintain your port in the contrib CVS module.

View File

@@ -1,20 +1,21 @@
Raw TCP/IP interface for lwIP 0.5
Raw TCP/IP interface for lwIP
Author: Adam Dunkels
Authors: Adam Dunkels, Leon Woestenberg
lwIP provides two Application Program's Interfaces (APIs) for programs
to use for communication with the TCP/IP code: the sequential API
(often just called "the API") and the raw TCP/IP interface. This
document is intended as a description of the latter. For lwIP versions
lower than 0.5, this API was not documented.
to use for communication with the TCP/IP code:
* low-level "core" / "callback" or "raw" API.
* higher-level "sequential" API.
The sequential API provides a way for ordinary, sequential, programs
to use the lwIP stack. It is quite similar to the BSD socket API. The
model of execution is based on the open-read-write-close
model of execution is based on the blocking open-read-write-close
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
code and the application program must reside in different execution
contexts (threads).
** The remainder of this document discusses the "raw" API. **
The raw TCP/IP interface allows the application program to integrate
better with the TCP/IP code. Program execution is event based by
having callback functions being called from within the TCP/IP
@@ -34,7 +35,6 @@ Both APIs can be used simultaneously by different application
programs. In fact, the sequential API is implemented as an application
program using the raw TCP/IP interface.
--- Callbacks
Program execution is driven by callbacks. Each callback is an ordinary

View File

@@ -115,40 +115,16 @@ tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
zip -r lwip-0.6.3.zip lwip-0.6.3
First, make a local release directory to work in, I use "lwip-releases":
Now, sign the archives with a detached GPG binary signature as follows:
mkdir lwip-releases
cd lwip-releases
gpg -b lwip-0.6.3.tar.gz
gpg -b lwip-0.6.3.tar.bz2
gpg -b lwip-0.6.3.zip
Now, make a new release by creating a new directory for it (these are
Savannah conventions so that it shows up in the Files list real nice):
Upload these files using anonymous FTP:
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
mkdir stable.pkg
mkdir stable.pkg 0.6.3
We can now copy the tar archive we made earlier into the release directory:
cp ../../../lwip-0.6.3.tar.gz .
Finally, synchronize this directory upwards to Savannah:
rsync -n -e "ssh -1" -t -u -v -r *.pkg likewise@savannah.nongnu.org:/upload/lwip
This does a "dry run": no files are modified! After you have confirmed that
this is what you intended to do, remove "-n" and actually synchronize for
real. The release should now be available here:
http://savannah.nongnu.org/files/?group=lwip
---
Explanation of rsync options used:
-t: preserve file timestamps
-u: do not overwrite existing files, unless they are older
-v: be verbose (long format file attributes)
-r: recurse into directories
-n: dry-run, do not modify anything.
---
ncftp>mput *0.6.3.*
Additionally, you may post a news item on Savannah, like this:

View File

@@ -154,6 +154,12 @@ cc.h - Architecture environment, some compiler specific, some
Typedefs for the types used by lwip -
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
Compiler hints for packing lwip's structures -
PACK_STRUCT_FIELD(x)
PACK_STRUCT_STRUCT
PACK_STRUCT_BEGIN
PACK_STRUCT_END
Platform specific diagnostic output -
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.

View File

@@ -1,11 +1,13 @@
api/ - The code for the API.
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/raw API.
core/ - The core files including protocol implementations, memory
and buffer management etc.
core/ - The core of the TPC/IP stack; protocol implementations,
memory and buffer management, and the low-level raw API.
include/ - lwIP include files.
netif/ - Generic network interface device drivers are kept here.
netif/ - Generic network interface device drivers are kept here,
as well as the ARP module.
For more information on the various subdirectories, check the FILES
file in each directory.

View File

@@ -280,9 +280,10 @@ netconn_delete(struct netconn *conn)
if (conn->recvmbox != SYS_MBOX_NULL) {
while (sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {
if (conn->type == NETCONN_TCP) {
pbuf_free((struct pbuf *)mem);
if(mem != NULL)
pbuf_free((struct pbuf *)mem);
} else {
netbuf_delete((struct netbuf *)mem);
netbuf_delete((struct netbuf *)mem);
}
}
sys_mbox_free(conn->recvmbox);

View File

@@ -38,7 +38,7 @@
#include "lwip/tcpip.h"
#if LWIP_RAW
static int
static u8_t
recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
struct ip_addr *addr)
{

View File

@@ -32,12 +32,14 @@
*
*/
#include <string.h>
#include <errno.h>
#include "lwip/opt.h"
#include "lwip/api.h"
#include "lwip/arch.h"
#include "lwip/sys.h"
#define LWIP_TIMEVAL_PRIVATE
#include "lwip/sockets.h"
#define NUM_SOCKETS MEMP_NUM_NETCONN
@@ -416,7 +418,7 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
ip_addr_debug_print(SOCKETS_DEBUG, addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
} else {
#if SOCKETS_DEBUG > 0
#if SOCKETS_DEBUG
addr = netbuf_fromaddr(buf);
port = netbuf_fromport(buf);
@@ -1139,7 +1141,7 @@ int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *opt
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") );
break;
case TCP_KEEPALIVE:
*(int*)optval = sock->conn->pcb.tcp->keepalive;
*(int*)optval = (int)sock->conn->pcb.tcp->keepalive;
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval));
break;
} /* switch */
@@ -1307,7 +1309,7 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_
break;
case TCP_KEEPALIVE:
sock->conn->pcb.tcp->keepalive = (u32_t)(*(int*)optval);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %u\n", s, sock->conn->pcb.tcp->keepalive));
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n", s, sock->conn->pcb.tcp->keepalive));
break;
} /* switch */
break;

View File

@@ -46,32 +46,39 @@
static void (* tcpip_init_done)(void *arg) = NULL;
static void *tcpip_init_done_arg;
static sys_mbox_t mbox;
#if LWIP_TCP
static int tcpip_tcp_timer_active = 0;
static void
tcpip_tcp_timer(void *arg)
{
(void)arg;
/* call TCP timer handler */
tcp_tmr();
/* timer still needed? */
if (tcp_active_pcbs || tcp_tw_pcbs) {
/* restart timer */
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
} else {
tcpip_tcp_timer_active = 0;
/* disable timer */
tcpip_tcp_timer_active = 0;
}
}
#if !NO_SYS
void
tcp_timer_needed(void)
{
/* timer is off but needed again? */
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
tcpip_tcp_timer_active = 1;
/* enable and start timer */
tcpip_tcp_timer_active = 1;
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
}
}
#endif /* !NO_SYS */
#endif /* LWIP_TCP */
static void

View File

@@ -67,6 +67,9 @@
* to remove the DHCP client.
*
*/
#include <string.h>
#include "lwip/stats.h"
#include "lwip/mem.h"
#include "lwip/udp.h"
@@ -82,7 +85,8 @@
#if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */
/** global transaction identifier, must be
* unique for each DHCP request. */
* unique for each DHCP request. We simply increment, starting
* with this value (easy to match with a packet analyzer) */
static u32_t xid = 0xABCD0000;
/** DHCP client state machine functions */
@@ -96,7 +100,6 @@ static void dhcp_check(struct netif *netif);
static void dhcp_bind(struct netif *netif);
static err_t dhcp_decline(struct netif *netif);
static err_t dhcp_rebind(struct netif *netif);
static err_t dhcp_release(struct netif *netif);
static void dhcp_set_state(struct dhcp *dhcp, unsigned char new_state);
/** receive, unfold, parse and free incoming messages */
@@ -231,10 +234,11 @@ static err_t dhcp_select(struct netif *netif)
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 3);
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
dhcp_option_trailer(dhcp);
/* shrink the pbuf to the actual content length */
@@ -293,18 +297,20 @@ void dhcp_coarse_tmr()
/**
* DHCP transaction timeout handling
*
* A DHCP server is expected to respond within a
* short period of time.
* A DHCP server is expected to respond within a short period of time.
* This timer checks whether an outstanding DHCP request is timed out.
*
*/
void dhcp_fine_tmr()
{
struct netif *netif = netif_list;
/* loop through clients */
/* loop through netif's */
while (netif != NULL) {
/* only act on DHCP configured interfaces */
if (netif->dhcp != NULL) {
/* timer is active (non zero), and triggers (zeroes) now */
/* timer is active (non zero), and is about to trigger now */
if (netif->dhcp->request_timeout-- == 1) {
/* { netif->dhcp->request_timeout == 0 } */
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
/* this clients' request timeout triggered */
dhcp_timeout(netif);
@@ -383,8 +389,8 @@ static void dhcp_t1_timeout(struct netif *netif)
struct dhcp *dhcp = netif->dhcp;
LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_t1_timeout()\n"));
if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
/* just retry to renew */
/* note that the rebind timer will eventually time-out if renew does not work */
/* just retry to renew - note that the rebind timer (t2) will
* eventually time-out if renew tries fail. */
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));
dhcp_renew(netif);
}
@@ -479,6 +485,19 @@ static void dhcp_handle_ack(struct netif *netif)
if (option_ptr != NULL) {
dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
}
/* DNS servers */
option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);
if (option_ptr != NULL) {
u8_t n;
dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]);
/* limit to at most DHCP_MAX_DNS DNS servers */
if (dhcp->dns_count > DHCP_MAX_DNS) dhcp->dns_count = DHCP_MAX_DNS;
for (n = 0; n < dhcp->dns_count; n++)
{
dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2+(n<<2)]));
}
}
}
/**
@@ -501,39 +520,43 @@ err_t dhcp_start(struct netif *netif)
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_start(netif=%p) %c%c%u\n", netif, netif->name[0], netif->name[1], netif->num));
netif->flags &= ~NETIF_FLAG_DHCP;
/* no DHCP client attached yet? */
if (dhcp == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
dhcp = mem_malloc(sizeof(struct dhcp));
if (dhcp == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
netif->flags &= ~NETIF_FLAG_DHCP;
return ERR_MEM;
}
/* clear data structure */
memset(dhcp, 0, sizeof(struct dhcp));
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));
dhcp->pcb = udp_new();
if (dhcp->pcb == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
mem_free((void *)dhcp);
dhcp = NULL;
netif->flags &= ~NETIF_FLAG_DHCP;
return ERR_MEM;
}
/* store this dhcp client in the netif */
netif->dhcp = dhcp;
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): created new udp pcb\n"));
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));
/* already has DHCP client attached */
} else {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
}
/* clear data structure */
memset(dhcp, 0, sizeof(struct dhcp));
/* allocate UDP PCB */
dhcp->pcb = udp_new();
if (dhcp->pcb == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
mem_free((void *)dhcp);
netif->dhcp = dhcp = NULL;
return ERR_MEM;
}
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
/* (re)start the DHCP negotiation */
result = dhcp_discover(netif);
if (result != ERR_OK) {
/* free resources allocated above */
dhcp_stop(netif);
return ERR_MEM;
}
netif->flags |= NETIF_FLAG_DHCP;
return result;
}
@@ -656,8 +679,10 @@ static err_t dhcp_decline(struct netif *netif)
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
udp_send(dhcp->pcb, dhcp->p_out);
/* @todo: should we really connect here? we are performing sendto() */
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
/* per section 4.4.4, broadcast DECLINE messages */
udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
dhcp_delete_request(netif);
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
} else {
@@ -694,10 +719,11 @@ static err_t dhcp_discover(struct netif *netif)
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
dhcp_option_short(dhcp, 576);
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 3);
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
dhcp_option_trailer(dhcp);
@@ -781,6 +807,8 @@ static void dhcp_bind(struct netif *netif)
netif_set_netmask(netif, &sn_mask);
LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08lx\n", gw_addr.addr));
netif_set_gw(netif, &gw_addr);
/* bring the interface up */
netif_set_up(netif);
/* netif is now bound to DHCP leased address */
dhcp_set_state(dhcp, DHCP_BOUND);
}
@@ -898,7 +926,7 @@ static err_t dhcp_rebind(struct netif *netif)
*
* @param netif network interface which must release its lease
*/
static err_t dhcp_release(struct netif *netif)
err_t dhcp_release(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
err_t result;
@@ -907,8 +935,13 @@ static err_t dhcp_release(struct netif *netif)
/* idle DHCP client */
dhcp_set_state(dhcp, DHCP_OFF);
/* clean old DHCP offer */
dhcp->server_ip_addr.addr = 0;
dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;
dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;
dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
dhcp->dns_count = 0;
/* create and initialize the DHCP message header */
result = dhcp_create_request(netif);
if (result == ERR_OK) {
@@ -930,11 +963,14 @@ static err_t dhcp_release(struct netif *netif)
dhcp->tries++;
msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %u msecs\n", msecs));
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %u msecs\n", msecs));
/* bring the interface down */
netif_set_down(netif);
/* remove IP address from interface */
netif_set_ipaddr(netif, IP_ADDR_ANY);
netif_set_gw(netif, IP_ADDR_ANY);
netif_set_netmask(netif, IP_ADDR_ANY);
/* TODO: netif_down(netif); */
return result;
}

View File

@@ -46,10 +46,21 @@
#include "lwip/def.h"
#include "lwip/inet.h"
#include "lwip/sys.h"
/* This is a reference implementation of the checksum algorithm
- it may not work on all architectures, and all processors, particularly
if they have issues with alignment and 16 bit access.
- in this case you will need to port it to your architecture and
#define LWIP_CHKSUM <your_checksum_routine>
in your sys_arch.h
*/
#ifndef LWIP_CHKSUM
#define LWIP_CHKSUM lwip_standard_chksum
static u16_t
lwip_chksum(void *dataptr, int len)
lwip_standard_chksum(void *dataptr, int len)
{
u32_t acc;
@@ -75,6 +86,7 @@ lwip_chksum(void *dataptr, int len)
return (u16_t)acc;
}
#endif
/* inet_chksum_pseudo:
*
@@ -96,7 +108,7 @@ inet_chksum_pseudo(struct pbuf *p,
for(q = p; q != NULL; q = q->next) {
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
(void *)q, (void *)q->next));
acc += lwip_chksum(q->payload, q->len);
acc += LWIP_CHKSUM(q->payload, q->len);
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%lx \n", acc));*/
while (acc >> 16) {
acc = (acc & 0xffffUL) + (acc >> 16);
@@ -122,7 +134,7 @@ inet_chksum_pseudo(struct pbuf *p,
acc = (acc & 0xffffUL) + (acc >> 16);
}
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%lx\n", acc));
return ~(acc & 0xffffUL);
return (u16_t)~(acc & 0xffffUL);
}
/* inet_chksum:
@@ -136,11 +148,11 @@ inet_chksum(void *dataptr, u16_t len)
{
u32_t acc;
acc = lwip_chksum(dataptr, len);
acc = LWIP_CHKSUM(dataptr, len);
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
return ~(acc & 0xffff);
return (u16_t)~(acc & 0xffff);
}
u16_t
@@ -153,7 +165,7 @@ inet_chksum_pbuf(struct pbuf *p)
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += lwip_chksum(q->payload, q->len);
acc += LWIP_CHKSUM(q->payload, q->len);
while (acc >> 16) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
@@ -166,7 +178,7 @@ inet_chksum_pbuf(struct pbuf *p)
if (swapped) {
acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);
}
return ~(acc & 0xffffUL);
return (u16_t)~(acc & 0xffffUL);
}
/* Here for now until needed in other places in lwIP */
@@ -232,12 +244,12 @@ inet_chksum_pbuf(struct pbuf *p)
base = 8;
}
for (;;) {
if (isascii(c) && isdigit(c)) {
val = (val * base) + (c - '0');
if (isdigit(c)) {
val = (val * base) + (int)(c - '0');
c = *++cp;
} else if (base == 16 && isascii(c) && isxdigit(c)) {
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) |
(c + 10 - (islower(c) ? 'a' : 'A'));
(int)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else
break;
@@ -302,17 +314,17 @@ inet_chksum_pbuf(struct pbuf *p)
*/
char *inet_ntoa(struct in_addr addr)
{
static u8_t str[16];
static char str[16];
u32_t s_addr = addr.s_addr;
u8_t inv[3];
u8_t *rp;
char inv[3];
char *rp;
u8_t *ap;
u8_t rem;
u8_t n;
u8_t i;
rp = str;
ap = (char *)&s_addr;
ap = (u8_t *)&s_addr;
for(n = 0; n < 4; n++) {
i = 0;
do {

View File

@@ -74,7 +74,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
case ICMP_ECHO:
/* broadcast or multicast destination address? */
if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {
LWIP_DEBUGF(ICMP_DEBUG, ("Smurf.\n"));
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
ICMP_STATS_INC(icmp.err);
pbuf_free(p);
return;

View File

@@ -85,7 +85,7 @@ ip_route(struct ip_addr *dest)
/* iterate through netifs */
for(netif = netif_list; netif != NULL; netif = netif->next) {
/* network mask matches? */
if (ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
/* return netif on which to forward IP packet */
return netif;
}
@@ -101,7 +101,7 @@ ip_route(struct ip_addr *dest)
* checksum and outputs the packet on the appropriate interface.
*/
static void
static struct netif *
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
@@ -113,14 +113,14 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%lx found\n",
iphdr->dest.addr));
snmp_inc_ipnoroutes();
return;
return (struct netif *)NULL;
}
/* 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"));
snmp_inc_ipnoroutes();
return;
return (struct netif *)NULL;
}
/* decrement TTL */
@@ -132,7 +132,7 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
icmp_time_exceeded(p, ICMP_TE_TTL);
snmp_inc_icmpouttimeexcds();
}
return;
return (struct netif *)NULL;
}
/* Incrementally update the IP checksum. */
@@ -152,6 +152,7 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
PERF_STOP("ip_forward");
/* transmit pbuf on chosen interface */
netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
return netif;
}
#endif /* IP_FORWARD */
@@ -163,13 +164,16 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
* forwarded (using ip_forward). The IP checksum is always checked.
*
* Finally, the packet is sent to the upper layer protocol input function.
*
*
*
*/
err_t
ip_input(struct pbuf *p, struct netif *inp) {
static struct ip_hdr *iphdr;
static struct netif *netif;
static u16_t iphdrlen;
struct ip_hdr *iphdr;
struct netif *netif;
u16_t iphdrlen;
IP_STATS_INC(ip.recv);
snmp_inc_ipinreceives();
@@ -220,36 +224,34 @@ ip_input(struct pbuf *p, struct netif *inp) {
* but we'll do it anyway just to be sure that its done. */
pbuf_realloc(p, ntohs(IPH_LEN(iphdr)));
/* is this packet for us? */
for(netif = netif_list; netif != NULL; netif = netif->next) {
/* match packet against an interface, i.e. is this packet for us? */
for (netif = netif_list; netif != NULL; netif = netif->next) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%lx netif->ip_addr 0x%lx (0x%lx, 0x%lx, 0x%lx)\n",
iphdr->dest.addr, netif->ip_addr.addr,
iphdr->dest.addr & netif->netmask.addr,
netif->ip_addr.addr & netif->netmask.addr,
iphdr->dest.addr & ~(netif->netmask.addr)));
iphdr->dest.addr, netif->ip_addr.addr,
iphdr->dest.addr & netif->netmask.addr,
netif->ip_addr.addr & netif->netmask.addr,
iphdr->dest.addr & ~(netif->netmask.addr)));
/* interface configured? */
if (!ip_addr_isany(&(netif->ip_addr)))
/* interface is up and configured? */
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr))))
{
/* unicast to this interface address? */
if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
/* or broadcast matching this interface network address? */
(ip_addr_isbroadcast(&(iphdr->dest), netif) &&
ip_addr_maskcmp(&(iphdr->dest), &(netif->ip_addr), &(netif->netmask))) ||
/* or restricted broadcast? */
ip_addr_cmp(&(iphdr->dest), IP_ADDR_BROADCAST)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
break;
/* or broadcast on this interface network address? */
ip_addr_isbroadcast(&(iphdr->dest), netif)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
break;
}
}
}
#if LWIP_DHCP
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
* using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
* According to RFC 1542 section 3.1.1, referred by RFC 2131). */
* According to RFC 1542 section 3.1.1, referred by RFC 2131).
*/
if (netif == NULL) {
/* remote port is DHCP server? */
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
@@ -262,7 +264,7 @@ ip_input(struct pbuf *p, struct netif *inp) {
}
}
#endif /* LWIP_DHCP */
/* packet not for us? */
/* packet not for us? */
if (netif == NULL) {
/* packet not for us, route or discard */
LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
@@ -295,7 +297,7 @@ ip_input(struct pbuf *p, struct netif *inp) {
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%x) (while IP_REASSEMBLY == 0).\n",
ntohs(IPH_OFFSET(iphdr))));
ntohs(IPH_OFFSET(iphdr))));
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
snmp_inc_ipunknownprotos();
@@ -375,8 +377,8 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t tos,
u8_t proto, struct netif *netif)
{
static struct ip_hdr *iphdr;
static u16_t ip_id = 0;
struct ip_hdr *iphdr;
u16_t ip_id = 0;
snmp_inc_ipoutrequests();
@@ -484,17 +486,17 @@ ip_debug_print(struct pbuf *p)
IPH_PROTO(iphdr),
ntohs(IPH_CHKSUM(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3ld | %3ld | %3ld | %3ld | (src)\n",
ntohl(iphdr->src.addr) >> 24 & 0xff,
ntohl(iphdr->src.addr) >> 16 & 0xff,
ntohl(iphdr->src.addr) >> 8 & 0xff,
ntohl(iphdr->src.addr) & 0xff));
LWIP_DEBUGF(IP_DEBUG, ("| %3u | %3u | %3u | %3u | (src)\n",
ip4_addr1(&iphdr->src),
ip4_addr2(&iphdr->src),
ip4_addr3(&iphdr->src),
ip4_addr4(&iphdr->src)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3ld | %3ld | %3ld | %3ld | (dest)\n",
ntohl(iphdr->dest.addr) >> 24 & 0xff,
ntohl(iphdr->dest.addr) >> 16 & 0xff,
ntohl(iphdr->dest.addr) >> 8 & 0xff,
ntohl(iphdr->dest.addr) & 0xff));
LWIP_DEBUGF(IP_DEBUG, ("| %3u | %3u | %3u | %3u | (dest)\n",
ip4_addr1(&iphdr->dest),
ip4_addr2(&iphdr->dest),
ip4_addr3(&iphdr->dest),
ip4_addr4(&iphdr->dest)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
}
#endif /* IP_DEBUG */

View File

@@ -60,9 +60,12 @@ u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
/* address matches network interface address exactly? => no broadcast */
else if (addr->addr == netif->ip_addr.addr)
return 0;
/* host identifier bits are all ones? => network broadcast address */
else if ((addr->addr & ~netif->netmask.addr) ==
(ip_addr_broadcast.addr & ~netif->netmask.addr))
/* on the same (sub) network... */
else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
/* ...and host identifier bits are all ones? =>... */
&& ((addr->addr & ~netif->netmask.addr) ==
(ip_addr_broadcast.addr & ~netif->netmask.addr)))
/* => network broadcast address */
return 1;
else
return 0;

View File

@@ -243,7 +243,7 @@ ip_reass(struct pbuf *p)
variable. */
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: memcpy from %p (%d) to %p, %d bytes\n",
&ip_reassbuf[i], i, q->payload,
(void *)&ip_reassbuf[i], i, q->payload,
q->len > ip_reasslen - i ? ip_reasslen - i : q->len));
memcpy(q->payload, &ip_reassbuf[i],
q->len > ip_reasslen - i ? ip_reasslen - i : q->len);

View File

@@ -77,7 +77,7 @@ ip_route(struct ip_addr *dest)
struct netif *netif;
for(netif = netif_list; netif != NULL; netif = netif->next) {
if (ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
return netif;
}
}

View File

@@ -35,7 +35,7 @@
int
ip_addr_maskcmp(struct ip_addr *addr1, struct ip_addr *addr2,
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
struct ip_addr *mask)
{
return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&

View File

@@ -36,6 +36,7 @@
*
*/
#include <string.h>
#include "lwip/arch.h"
#include "lwip/opt.h"

View File

@@ -68,7 +68,6 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
err_t (* input)(struct pbuf *p, struct netif *netif))
{
static int netifnum = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
@@ -208,10 +207,10 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
#endif
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: IP address of interface %c%c set to %u.%u.%u.%u\n",
netif->name[0], netif->name[1],
(unsigned int)(ntohl(netif->ip_addr.addr) >> 24 & 0xff),
(unsigned int)(ntohl(netif->ip_addr.addr) >> 16 & 0xff),
(unsigned int)(ntohl(netif->ip_addr.addr) >> 8 & 0xff),
(unsigned int)(ntohl(netif->ip_addr.addr) & 0xff)));
ip4_addr1(&netif->ip_addr),
ip4_addr2(&netif->ip_addr),
ip4_addr3(&netif->ip_addr),
ip4_addr4(&netif->ip_addr)));
}
void
@@ -219,11 +218,11 @@ netif_set_gw(struct netif *netif, struct ip_addr *gw)
{
ip_addr_set(&(netif->gw), gw);
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: GW address of interface %c%c set to %u.%u.%u.%u\n",
netif->name[0], netif->name[1],
(unsigned int)(ntohl(netif->gw.addr) >> 24 & 0xff),
(unsigned int)(ntohl(netif->gw.addr) >> 16 & 0xff),
(unsigned int)(ntohl(netif->gw.addr) >> 8 & 0xff),
(unsigned int)(ntohl(netif->gw.addr) & 0xff)));
netif->name[0], netif->name[1],
ip4_addr1(&netif->gw),
ip4_addr2(&netif->gw),
ip4_addr3(&netif->gw),
ip4_addr4(&netif->gw)));
}
void
@@ -231,11 +230,11 @@ netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
{
ip_addr_set(&(netif->netmask), netmask);
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: netmask of interface %c%c set to %u.%u.%u.%u\n",
netif->name[0], netif->name[1],
(unsigned int)(ntohl(netif->netmask.addr) >> 24 & 0xff),
(unsigned int)(ntohl(netif->netmask.addr) >> 16 & 0xff),
(unsigned int)(ntohl(netif->netmask.addr) >> 8 & 0xff),
(unsigned int)(ntohl(netif->netmask.addr) & 0xff)));
netif->name[0], netif->name[1],
ip4_addr1(&netif->netmask),
ip4_addr2(&netif->netmask),
ip4_addr3(&netif->netmask),
ip4_addr4(&netif->netmask)));
}
void
@@ -246,6 +245,41 @@ netif_set_default(struct netif *netif)
netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
}
/**
* Bring an interface up, available for processing
* traffic.
*
* @note: Enabling DHCP on a down interface will make it come
* up once configured.
*
* @see dhcp_start()
*/
void netif_set_up(struct netif *netif)
{
netif->flags |= NETIF_FLAG_UP;
}
/**
* Ask if an interface is up
*/
u8_t netif_is_up(struct netif *netif)
{
return (netif->flags & NETIF_FLAG_UP)?1:0;
}
/**
* Bring an interface down, disabling any traffic processing.
*
* @note: Enabling DHCP on a down interface will make it come
* up once configured.
*
* @see dhcp_start()
*/
void netif_set_down(struct netif *netif)
{
netif->flags &= ~NETIF_FLAG_UP;
}
void
netif_init(void)
{

View File

@@ -183,7 +183,7 @@ pbuf_pool_alloc(void)
/**
* Allocates a pbuf.
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
*
* The actual memory allocated for the pbuf is determined by the
* layer at which the pbuf is allocated and the requested size
@@ -306,7 +306,7 @@ pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
break;
case PBUF_RAM:
/* If pbuf is to be allocated in RAM, allocate memory for it. */
p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + length + offset));
p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + offset) + MEM_ALIGN_SIZE(length));
if (p == NULL) {
return NULL;
}
@@ -319,7 +319,7 @@ pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
break;
/* pbuf references existing (static constant) ROM payload? */
/* pbuf references existing (non-volatile static constant) ROM payload? */
case PBUF_ROM:
/* pbuf references existing (externally allocated) RAM payload? */
case PBUF_REF:
@@ -482,8 +482,8 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
/* boundary check fails? */
if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
(u8_t *)p->payload,
(u8_t *)p + sizeof(struct pbuf)) );\
(void *)p->payload,
(void *)(p + 1)));\
/* restore old payload pointer */
p->payload = payload;
/* bail out unsuccesfully */
@@ -520,7 +520,8 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
*
* For a pbuf chain, this is repeated for each pbuf in the chain,
* up to the first pbuf which has a non-zero reference count after
* decrementing. (This might de-allocate the whole chain.)
* decrementing. So, when all reference counts are one, the whole
* chain is free'd.
*
* @param pbuf The pbuf (chain) to be dereferenced.
*
@@ -586,7 +587,7 @@ pbuf_free(struct pbuf *p)
p->len = p->tot_len = PBUF_POOL_BUFSIZE;
p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));
PBUF_POOL_FREE(p);
/* a ROM or RAM referencing pbuf */
/* is this a ROM or RAM referencing pbuf? */
} else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {
memp_free(MEMP_PBUF, p);
/* p->flags == PBUF_FLAG_RAM */
@@ -600,7 +601,7 @@ pbuf_free(struct pbuf *p)
/* (and so the remaining pbufs in chain as well) */
} else {
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %u, ending here.\n", (void *)p, (unsigned int)p->ref));
/* stop walking through chain */
/* stop walking through the chain */
p = NULL;
}
}
@@ -663,8 +664,8 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
{
struct pbuf *p;
LWIP_ASSERT("h != NULL", h != NULL);
LWIP_ASSERT("t != NULL", t != NULL);
LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);
LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL);
if ((h == NULL) || (t == NULL)) return;
/* proceed to last pbuf of chain */
@@ -674,10 +675,14 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
}
/* { p is last pbuf of first h chain, p->next == NULL } */
LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
LWIP_ASSERT("p->next == NULL", p->next == NULL);
/* add total length of second chain to last pbuf total of first chain */
p->tot_len += t->tot_len;
/* chain last pbuf of head (p) with first of tail (t) */
p->next = t;
/* p->next now references t, but the caller will drop its reference to t,
* so netto there is no change to the reference count of t.
*/
}
/**
@@ -705,8 +710,8 @@ pbuf_chain(struct pbuf *h, struct pbuf *t)
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
}
/* For packet queueing. Note that queued packets must be dequeued first
* before calling any pbuf functions. */
/* For packet queueing. Note that queued packets MUST be dequeued first
* using pbuf_dequeue() before calling other pbuf_() functions. */
#if ARP_QUEUEING
/**
* Add a packet to the end of a queue.
@@ -714,6 +719,7 @@ pbuf_chain(struct pbuf *h, struct pbuf *t)
* @param q pointer to first packet on the queue
* @param n packet to be queued
*
* Both packets MUST be given, and must be different.
*/
void
pbuf_queue(struct pbuf *p, struct pbuf *n)
@@ -722,9 +728,13 @@ pbuf_queue(struct pbuf *p, struct pbuf *n)
struct pbuf *q = p;
#endif
/* programmer stupidity checks */
LWIP_ASSERT("p != NULL", p != NULL);
LWIP_ASSERT("n != NULL", n != NULL);
if ((p == NULL) || (n == NULL)) return;
LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);
LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);
LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);
if ((p == NULL) || (n == NULL) || (p == n)){
LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"))
return;
}
/* iterate through all packets on queue */
while (p->next != NULL) {
@@ -739,9 +749,10 @@ pbuf_queue(struct pbuf *p, struct pbuf *n)
p = p->next;
/* { p->tot_len == p->len => p is last pbuf of a packet } */
}
#endif
/* { p->tot_len == p->len and p is last pbuf of a packet } */
/* { p is last pbuf of a packet } */
/* proceed to next packet on queue */
#endif
/* proceed to next pbuf */
if (p->next != NULL) p = p->next;
}
/* { p->tot_len == p->len and p->next == NULL } ==>
@@ -750,15 +761,19 @@ pbuf_queue(struct pbuf *p, struct pbuf *n)
p->next = n;
/* n is now referenced to by the (packet p in the) queue */
pbuf_ref(n);
#if PBUF_DEBUG
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2,
("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n",
(void *)n, (void *)p, (void *)q));
#endif
}
/**
* Remove a packet from the head of a queue.
*
* The caller MUST reference the remainder of the queue (as returned).
* The caller MUST reference the remainder of the queue (as returned). The
* caller MUST NOT call pbuf_ref() as it implicitly takes over the reference
* from p.
*
* @param p pointer to first packet on the queue which will be dequeued.
* @return first packet on the remaining queue (NULL if no further packets).
@@ -770,7 +785,7 @@ pbuf_dequeue(struct pbuf *p)
struct pbuf *q;
LWIP_ASSERT("p != NULL", p != NULL);
/* iterate through all pbufs in packet */
/* iterate through all pbufs in packet p */
while (p->tot_len != p->len) {
/* make sure invariant condition holds */
LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);
@@ -779,15 +794,16 @@ pbuf_dequeue(struct pbuf *p)
p = p->next;
}
/* { p->tot_len == p->len } => p is the last pbuf of the first packet */
/* remember next packet on queue */
/* remember next packet on queue in q */
q = p->next;
/* dequeue p from queue */
/* dequeue packet p from queue */
p->next = NULL;
/* any next packet on queue? */
if (q != NULL) {
/* although q is no longer referenced by p, it MUST be referenced by
* the caller, who is maintaining this packet queue */
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: at least one packet on queue, first %p\n", (void *)q));
* the caller, who is maintaining this packet queue. So, we do not call
* pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q));
} else {
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n"));
}
@@ -808,7 +824,7 @@ pbuf_dequeue(struct pbuf *p)
*
* @note You MUST explicitly use p = pbuf_take(p);
* The pbuf you give as argument, may have been replaced
* by pbuf_take()!
* by a (differently located) copy through pbuf_take()!
*
* @note Any replaced pbufs will be freed through pbuf_free().
* This may deallocate them if they become no longer referenced.
@@ -836,7 +852,9 @@ pbuf_take(struct pbuf *p)
/* PBUF_POOL buffers are faster if we can use them */
if (p->len <= PBUF_POOL_BUFSIZE) {
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
if (q == NULL) LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
if (q == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
}
} else {
/* no replacement pbuf yet */
q = NULL;
@@ -845,7 +863,9 @@ pbuf_take(struct pbuf *p)
/* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */
if (q == NULL) {
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
if (q == NULL) LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));
if (q == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));
}
}
/* replacement pbuf could be allocated? */
if (q != NULL)
@@ -928,8 +948,10 @@ pbuf_dechain(struct pbuf *p)
/* q is no longer referenced by p, free it */
LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
tail_gone = pbuf_free(q);
if (tail_gone > 0) LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE,
("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
if (tail_gone > 0) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE,
("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
}
/* return remaining tail or NULL if deallocated */
}
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */

View File

@@ -38,6 +38,8 @@
*
*/
#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"

View File

@@ -30,6 +30,7 @@
*
*/
#include <string.h>
#include "lwip/opt.h"

View File

@@ -41,6 +41,8 @@
*
*/
#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
@@ -120,6 +122,18 @@ tcp_close(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
#endif /* TCP_DEBUG */
switch (pcb->state) {
case CLOSED:
/* Closing a pcb in the CLOSED state might seem erroneous,
* however, it is in this state once allocated and as yet unused
* and the user needs some way to free it should the need arise.
* Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
* or for a pcb that has been used and then entered the CLOSED state
* 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;
memp_free(MEMP_TCP_PCB, pcb);
pcb = NULL;
break;
case LISTEN:
err = ERR_OK;
tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);
@@ -430,6 +444,16 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
* continue to transmit.
*/
tcp_ack(pcb);
}
else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {
/* If we can send a window update such that there is a full
* segment available in the window, do so now. This is sort of
* nagle-like in its goals, and tries to hit a compromise between
* sending acks each time the window is updated, and only sending
* window updates when a timer expires. The "threshold" used
* above (currently TCP_WND/2) can be tuned to be more or less
* aggressive */
tcp_ack_now(pcb);
}
LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %u bytes, wnd %u (%u).\n",
@@ -545,7 +569,9 @@ tcp_slowtmr(void)
/* Steps through all of the active PCBs. */
prev = NULL;
pcb = tcp_active_pcbs;
if (pcb == NULL) LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
if (pcb == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
}
while (pcb != NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
@@ -574,7 +600,6 @@ tcp_slowtmr(void)
if (pcb->state != SYN_SENT) {
pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
}
tcp_rexmit(pcb);
/* Reduce congestion window and ssthresh. */
eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
pcb->ssthresh = eff_wnd >> 1;
@@ -584,7 +609,10 @@ tcp_slowtmr(void)
pcb->cwnd = pcb->mss;
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %u ssthresh %u\n",
pcb->cwnd, pcb->ssthresh));
}
/* The following needs to be called AFTER cwnd is set to one mss - STJ */
tcp_rexmit_rto(pcb);
}
}
/* Check if this PCB has stayed too long in FIN-WAIT-2 */
if (pcb->state == FIN_WAIT_2) {
@@ -830,7 +858,7 @@ tcp_kill_prio(u8_t prio)
}
}
if (inactive != NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB 0x%p (%ld)\n",
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%ld)\n",
(void *)inactive, inactivity));
tcp_abort(inactive);
}
@@ -852,7 +880,7 @@ tcp_kill_timewait(void)
}
}
if (inactive != NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB 0x%p (%ld)\n",
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%ld)\n",
(void *)inactive, inactivity));
tcp_abort(inactive);
}

View File

@@ -351,7 +351,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
increase the reference counter in the pbuf. If so, the buffer
isn't actually deallocated by the call to pbuf_free(), only the
reference count is decreased. */
pbuf_free(inseg.p);
if (inseg.p != NULL) pbuf_free(inseg.p);
#if TCP_INPUT_DEBUG
#if TCP_DEBUG
tcp_debug_print_state(pcb->state);
@@ -503,12 +503,14 @@ tcp_process(struct tcp_pcb *pcb)
/* First, determine if the reset is acceptable. */
if (pcb->state == SYN_SENT) {
if (ackno == pcb->snd_nxt) {
acceptable = 1;
acceptable = 1;
}
} else {
if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
acceptable = 1;
/*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
*/
if(TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)){
acceptable = 1;
}
}
@@ -538,6 +540,7 @@ tcp_process(struct tcp_pcb *pcb)
pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
if ((flags & TCP_ACK) && (flags & TCP_SYN)
&& ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
pcb->snd_buf ++;
pcb->rcv_nxt = seqno + 1;
pcb->lastack = ackno;
pcb->snd_wnd = tcphdr->wnd;
@@ -562,8 +565,9 @@ tcp_process(struct tcp_pcb *pcb)
case SYN_RCVD:
if (flags & TCP_ACK &&
!(flags & TCP_RST)) {
if (TCP_SEQ_LT(pcb->lastack, ackno) &&
TCP_SEQ_LEQ(ackno, pcb->snd_nxt)) {
/*if (TCP_SEQ_LT(pcb->lastack, ackno) &&
TCP_SEQ_LEQ(ackno, pcb->snd_nxt)) { */
if(TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
pcb->state = ESTABLISHED;
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %u -> %u.\n", inseg.tcphdr->src, inseg.tcphdr->dest));
#if LWIP_CALLBACK_API
@@ -672,6 +676,7 @@ tcp_receive(struct tcp_pcb *pcb)
s32_t off;
int m;
u32_t right_wnd_edge;
u16_t new_tot_len;
if (flags & TCP_ACK) {
@@ -699,43 +704,50 @@ tcp_receive(struct tcp_pcb *pcb)
pcb->acked = 0;
if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){
++pcb->dupacks;
if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
if (!(pcb->flags & TF_INFR)) {
/* This is fast retransmit. Retransmit the first unacked segment. */
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %u (%lu), fast retransmit %lu\n",
(unsigned int)pcb->dupacks, pcb->lastack,
ntohl(pcb->unacked->tcphdr->seqno)));
tcp_rexmit(pcb);
/* Set ssthresh to max (FlightSize / 2, 2*SMSS) */
pcb->ssthresh = LWIP_MAX((pcb->snd_max -
pcb->lastack) / 2,
2 * pcb->mss);
++pcb->dupacks;
if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
if (!(pcb->flags & TF_INFR)) {
/* This is fast retransmit. Retransmit the first unacked segment. */
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %u (%lu), fast retransmit %lu\n",
(unsigned int)pcb->dupacks, pcb->lastack,
ntohl(pcb->unacked->tcphdr->seqno)));
tcp_rexmit(pcb);
/* Set ssthresh to max (FlightSize / 2, 2*SMSS) */
/*pcb->ssthresh = LWIP_MAX((pcb->snd_max -
pcb->lastack) / 2,
2 * pcb->mss);*/
/* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */
if(pcb->cwnd > pcb->snd_wnd)
pcb->ssthresh = pcb->snd_wnd / 2;
else
pcb->ssthresh = pcb->cwnd / 2;
pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
pcb->flags |= TF_INFR;
} else {
/* Inflate the congestion window, but not if it means that
the value overflows. */
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
pcb->cwnd += pcb->mss;
}
}
}
pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
pcb->flags |= TF_INFR;
} else {
/* Inflate the congestion window, but not if it means that
the value overflows. */
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
pcb->cwnd += pcb->mss;
}
}
}
} else {
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %lu %lu\n",
pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %lu %lu\n",
pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));
}
} else if (TCP_SEQ_LT(pcb->lastack, ackno) &&
TCP_SEQ_LEQ(ackno, pcb->snd_max)) {
} else
/*if (TCP_SEQ_LT(pcb->lastack, ackno) &&
TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */
if(TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){
/* We come here when the ACK acknowledges new data. */
/* Reset the "IN Fast Retransmit" flag, since we are no longer
in fast retransmit. Also reset the congestion window to the
slow start threshold. */
if (pcb->flags & TF_INFR) {
pcb->flags &= ~TF_INFR;
pcb->cwnd = pcb->ssthresh;
pcb->flags &= ~TF_INFR;
pcb->cwnd = pcb->ssthresh;
}
/* Reset the number of retransmissions. */
@@ -756,86 +768,85 @@ tcp_receive(struct tcp_pcb *pcb)
ssthresh). */
if (pcb->state >= ESTABLISHED) {
if (pcb->cwnd < pcb->ssthresh) {
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
pcb->cwnd += pcb->mss;
}
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
pcb->cwnd += pcb->mss;
}
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %u\n", pcb->cwnd));
} else {
u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
if (new_cwnd > pcb->cwnd) {
pcb->cwnd = new_cwnd;
}
u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
if (new_cwnd > pcb->cwnd) {
pcb->cwnd = new_cwnd;
}
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %u\n", pcb->cwnd));
}
}
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %lu, unacked->seqno %lu:%lu\n",
ackno,
pcb->unacked != NULL?
ntohl(pcb->unacked->tcphdr->seqno): 0,
pcb->unacked != NULL?
ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
ackno,
pcb->unacked != NULL?
ntohl(pcb->unacked->tcphdr->seqno): 0,
pcb->unacked != NULL?
ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
/* Remove segment from the unacknowledged list if the incoming
ACK acknowlegdes them. */
ACK acknowlegdes them. */
while (pcb->unacked != NULL &&
TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
TCP_TCPLEN(pcb->unacked), ackno)) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unacked\n",
ntohl(pcb->unacked->tcphdr->seqno),
ntohl(pcb->unacked->tcphdr->seqno) +
TCP_TCPLEN(pcb->unacked)));
TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
TCP_TCPLEN(pcb->unacked), ackno)) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unacked\n",
ntohl(pcb->unacked->tcphdr->seqno),
ntohl(pcb->unacked->tcphdr->seqno) +
TCP_TCPLEN(pcb->unacked)));
next = pcb->unacked;
pcb->unacked = pcb->unacked->next;
next = pcb->unacked;
pcb->unacked = pcb->unacked->next;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));
pcb->snd_queuelen -= pbuf_clen(next->p);
tcp_seg_free(next);
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));
pcb->snd_queuelen -= pbuf_clen(next->p);
tcp_seg_free(next);
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unacked)\n", (unsigned int)pcb->snd_queuelen));
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
pcb->unsent != NULL);
}
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unacked)\n", (unsigned int)pcb->snd_queuelen));
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
pcb->unsent != NULL);
}
}
pcb->polltmr = 0;
}
/* We go through the ->unsent list to see if any of the segments
on the list are acknowledged by the ACK. This may seem
strange since an "unsent" segment shouldn't be acked. The
rationale is that lwIP puts all outstanding segments on the
->unsent list after a retransmission, so these segments may
in fact have been sent once. */
while (pcb->unsent != NULL &&
TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent),
ackno) &&
TCP_SEQ_LEQ(ackno, pcb->snd_max)) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unsent\n",
ntohl(pcb->unsent->tcphdr->seqno),
ntohl(pcb->unsent->tcphdr->seqno) +
TCP_TCPLEN(pcb->unsent)));
/* We go through the ->unsent list to see if any of the segments
on the list are acknowledged by the ACK. This may seem
strange since an "unsent" segment shouldn't be acked. The
rationale is that lwIP puts all outstanding segments on the
->unsent list after a retransmission, so these segments may
in fact have been sent once. */
while (pcb->unsent != NULL &&
/*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&
TCP_SEQ_LEQ(ackno, pcb->snd_max)*/
TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)
) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unsent\n",
ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
TCP_TCPLEN(pcb->unsent)));
next = pcb->unsent;
pcb->unsent = pcb->unsent->next;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));
pcb->snd_queuelen -= pbuf_clen(next->p);
tcp_seg_free(next);
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unsent)\n", (unsigned int)pcb->snd_queuelen));
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
pcb->unsent != NULL);
}
if (pcb->unsent != NULL) {
pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
}
next = pcb->unsent;
pcb->unsent = pcb->unsent->next;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));
pcb->snd_queuelen -= pbuf_clen(next->p);
tcp_seg_free(next);
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unsent)\n", (unsigned int)pcb->snd_queuelen));
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_receive: valid queue length",
pcb->unacked != NULL || pcb->unsent != NULL);
}
if (pcb->unsent != NULL) {
pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
}
}
/* End of ACK for new data processing. */
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %u rtseq %lu ackno %lu\n",
pcb->rttest, pcb->rtseq, ackno));
pcb->rttest, pcb->rtseq, ackno));
/* RTT estimation calculations. This is done by checking if the
incoming segment acknowledges the segment we use to take a
@@ -844,20 +855,20 @@ tcp_receive(struct tcp_pcb *pcb)
m = tcp_ticks - pcb->rttest;
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %u ticks (%u msec).\n",
m, m * TCP_SLOW_INTERVAL));
m, m * TCP_SLOW_INTERVAL));
/* This is taken directly from VJs original code in his paper */
m = m - (pcb->sa >> 3);
pcb->sa += m;
if (m < 0) {
m = -m;
m = -m;
}
m = m - (pcb->sv >> 2);
pcb->sv += m;
pcb->rto = (pcb->sa >> 3) + pcb->sv;
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %u (%u miliseconds)\n",
pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
pcb->rttest = 0;
}
@@ -868,290 +879,309 @@ tcp_receive(struct tcp_pcb *pcb)
if (tcplen > 0) {
/* This code basically does three things:
+) If the incoming segment contains data that is the next
in-sequence data, this data is passed to the application. This
might involve trimming the first edge of the data. The rcv_nxt
variable and the advertised window are adjusted.
+) If the incoming segment contains data that is the next
in-sequence data, this data is passed to the application. This
might involve trimming the first edge of the data. The rcv_nxt
variable and the advertised window are adjusted.
+) If the incoming segment has data that is above the next
sequence number expected (->rcv_nxt), the segment is placed on
the ->ooseq queue. This is done by finding the appropriate
place in the ->ooseq queue (which is ordered by sequence
number) and trim the segment in both ends if needed. An
immediate ACK is sent to indicate that we received an
out-of-sequence segment.
+) If the incoming segment has data that is above the next
sequence number expected (->rcv_nxt), the segment is placed on
the ->ooseq queue. This is done by finding the appropriate
place in the ->ooseq queue (which is ordered by sequence
number) and trim the segment in both ends if needed. An
immediate ACK is sent to indicate that we received an
out-of-sequence segment.
+) Finally, we check if the first segment on the ->ooseq queue
now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
rcv_nxt > ooseq->seqno, we must trim the first edge of the
segment on ->ooseq before we adjust rcv_nxt. The data in the
segments that are now on sequence are chained onto the
incoming segment so that we only need to call the application
once.
+) Finally, we check if the first segment on the ->ooseq queue
now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
rcv_nxt > ooseq->seqno, we must trim the first edge of the
segment on ->ooseq before we adjust rcv_nxt. The data in the
segments that are now on sequence are chained onto the
incoming segment so that we only need to call the application
once.
*/
/* First, we check if we must trim the first edge. We have to do
this if the sequence number of the incoming segment is less
than rcv_nxt, and the sequence number plus the length of the
segment is larger than rcv_nxt. */
if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {
/* Trimming the first edge is done by pushing the payload
pointer in the pbuf downwards. This is somewhat tricky since
we do not want to discard the full contents of the pbuf up to
the new starting point of the data since we have to keep the
TCP header which is present in the first pbuf in the chain.
What is done is really quite a nasty hack: the first pbuf in
the pbuf chain is pointed to by inseg.p. Since we need to be
able to deallocate the whole pbuf, we cannot change this
inseg.p pointer to point to any of the later pbufs in the
chain. Instead, we point the ->payload pointer in the first
pbuf to data in one of the later pbufs. We also set the
inseg.data pointer to point to the right place. This way, the
->p pointer will still point to the first pbuf, but the
->p->payload pointer will point to data in another pbuf.
After we are done with adjusting the pbuf pointers we must
adjust the ->data pointer in the seg and the segment
length.*/
off = pcb->rcv_nxt - seqno;
if (inseg.p->len < off) {
p = inseg.p;
while (p->len < off) {
off -= p->len;
inseg.p->tot_len -= p->len;
p->len = 0;
p = p->next;
}
pbuf_header(p, -off);
} else {
pbuf_header(inseg.p, -off);
}
inseg.dataptr = inseg.p->payload;
inseg.len -= pcb->rcv_nxt - seqno;
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
/* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
if(TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno+1, seqno+tcplen-1)){
/* Trimming the first edge is done by pushing the payload
pointer in the pbuf downwards. This is somewhat tricky since
we do not want to discard the full contents of the pbuf up to
the new starting point of the data since we have to keep the
TCP header which is present in the first pbuf in the chain.
What is done is really quite a nasty hack: the first pbuf in
the pbuf chain is pointed to by inseg.p. Since we need to be
able to deallocate the whole pbuf, we cannot change this
inseg.p pointer to point to any of the later pbufs in the
chain. Instead, we point the ->payload pointer in the first
pbuf to data in one of the later pbufs. We also set the
inseg.data pointer to point to the right place. This way, the
->p pointer will still point to the first pbuf, but the
->p->payload pointer will point to data in another pbuf.
After we are done with adjusting the pbuf pointers we must
adjust the ->data pointer in the seg and the segment
length.*/
off = pcb->rcv_nxt - seqno;
p = inseg.p;
if (inseg.p->len < off) {
new_tot_len = inseg.p->tot_len - off;
while (p->len < off) {
off -= p->len;
/* KJM following line changed (with addition of new_tot_len var)
to fix bug #9076
inseg.p->tot_len -= p->len; */
p->tot_len = new_tot_len;
p->len = 0;
p = p->next;
}
pbuf_header(p, -off);
} else {
pbuf_header(inseg.p, -off);
}
else{
/* the whole segment is < rcv_nxt */
/* must be a duplicate of a packet that has already been correctly handled */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %lu\n", seqno));
tcp_ack_now(pcb);
/* KJM following line changed to use p->payload rather than inseg->p->payload
to fix bug #9076 */
inseg.dataptr = p->payload;
inseg.len -= pcb->rcv_nxt - seqno;
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
}
else{
if(TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
/* the whole segment is < rcv_nxt */
/* must be a duplicate of a packet that has already been correctly handled */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %lu\n", seqno));
tcp_ack_now(pcb);
}
}
/* The sequence number must be within the window (above rcv_nxt
and below rcv_nxt + rcv_wnd) in order to be further
processed. */
if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
/*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
if(TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){
if (pcb->rcv_nxt == seqno) {
/* The incoming segment is the next in sequence. We check if
/* The incoming segment is the next in sequence. We check if
we have to trim the end of the segment and update rcv_nxt
and pass the data to the application. */
#if TCP_QUEUE_OOSEQ
if (pcb->ooseq != NULL &&
TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
/* We have to trim the second edge of the incoming
if (pcb->ooseq != NULL &&
TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
/* We have to trim the second edge of the incoming
segment. */
inseg.len = pcb->ooseq->tcphdr->seqno - seqno;
pbuf_realloc(inseg.p, inseg.len);
}
inseg.len = pcb->ooseq->tcphdr->seqno - seqno;
pbuf_realloc(inseg.p, inseg.len);
}
#endif /* TCP_QUEUE_OOSEQ */
tcplen = TCP_TCPLEN(&inseg);
tcplen = TCP_TCPLEN(&inseg);
pcb->rcv_nxt += tcplen;
pcb->rcv_nxt += tcplen;
/* Update the receiver's (our) window. */
if (pcb->rcv_wnd < tcplen) {
pcb->rcv_wnd = 0;
} else {
pcb->rcv_wnd -= tcplen;
}
/* Update the receiver's (our) window. */
if (pcb->rcv_wnd < tcplen) {
pcb->rcv_wnd = 0;
} else {
pcb->rcv_wnd -= tcplen;
}
/* If there is data in the segment, we make preparations to
pass this up to the application. The ->recv_data variable
is used for holding the pbuf that goes to the
application. The code for reassembling out-of-sequence data
chains its data on this pbuf as well.
/* If there is data in the segment, we make preparations to
pass this up to the application. The ->recv_data variable
is used for holding the pbuf that goes to the
application. The code for reassembling out-of-sequence data
chains its data on this pbuf as well.
If the segment was a FIN, we set the TF_GOT_FIN flag that will
be used to indicate to the application that the remote side has
closed its end of the connection. */
if (inseg.p->tot_len > 0) {
recv_data = inseg.p;
/* Since this pbuf now is the responsibility of the
application, we delete our reference to it so that we won't
(mistakingly) deallocate it. */
inseg.p = NULL;
}
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
recv_flags = TF_GOT_FIN;
}
If the segment was a FIN, we set the TF_GOT_FIN flag that will
be used to indicate to the application that the remote side has
closed its end of the connection. */
if (inseg.p->tot_len > 0) {
recv_data = inseg.p;
/* Since this pbuf now is the responsibility of the
application, we delete our reference to it so that we won't
(mistakingly) deallocate it. */
inseg.p = NULL;
}
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
recv_flags = TF_GOT_FIN;
}
#if TCP_QUEUE_OOSEQ
/* We now check if we have segments on the ->ooseq queue that
/* We now check if we have segments on the ->ooseq queue that
is now in sequence. */
while (pcb->ooseq != NULL &&
pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
while (pcb->ooseq != NULL &&
pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
cseg = pcb->ooseq;
seqno = pcb->ooseq->tcphdr->seqno;
cseg = pcb->ooseq;
seqno = pcb->ooseq->tcphdr->seqno;
pcb->rcv_nxt += TCP_TCPLEN(cseg);
if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
pcb->rcv_wnd = 0;
} else {
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
}
if (cseg->p->tot_len > 0) {
/* Chain this pbuf onto the pbuf that we will pass to
the application. */
if (recv_data) {
pcb->rcv_nxt += TCP_TCPLEN(cseg);
if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
pcb->rcv_wnd = 0;
} else {
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
}
if (cseg->p->tot_len > 0) {
/* Chain this pbuf onto the pbuf that we will pass to
the application. */
if (recv_data) {
pbuf_cat(recv_data, cseg->p);
} else {
recv_data = cseg->p;
}
cseg->p = NULL;
}
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
recv_flags = TF_GOT_FIN;
}
recv_data = cseg->p;
}
cseg->p = NULL;
}
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
recv_flags = TF_GOT_FIN;
}
pcb->ooseq = cseg->next;
tcp_seg_free(cseg);
}
pcb->ooseq = cseg->next;
tcp_seg_free(cseg);
}
#endif /* TCP_QUEUE_OOSEQ */
/* Acknowledge the segment(s). */
tcp_ack(pcb);
/* Acknowledge the segment(s). */
tcp_ack(pcb);
} else {
/* We get here if the incoming segment is out-of-sequence. */
tcp_ack_now(pcb);
/* We get here if the incoming segment is out-of-sequence. */
tcp_ack_now(pcb);
#if TCP_QUEUE_OOSEQ
/* We queue the segment on the ->ooseq queue. */
if (pcb->ooseq == NULL) {
pcb->ooseq = tcp_seg_copy(&inseg);
} else {
/* If the queue is not empty, we walk through the queue and
try to find a place where the sequence number of the
incoming segment is between the sequence numbers of the
previous and the next segment on the ->ooseq queue. That is
the place where we put the incoming segment. If needed, we
trim the second edges of the previous and the incoming
segment so that it will fit into the sequence.
/* We queue the segment on the ->ooseq queue. */
if (pcb->ooseq == NULL) {
pcb->ooseq = tcp_seg_copy(&inseg);
} else {
/* If the queue is not empty, we walk through the queue and
try to find a place where the sequence number of the
incoming segment is between the sequence numbers of the
previous and the next segment on the ->ooseq queue. That is
the place where we put the incoming segment. If needed, we
trim the second edges of the previous and the incoming
segment so that it will fit into the sequence.
If the incoming segment has the same sequence number as a
segment on the ->ooseq queue, we discard the segment that
contains less data. */
If the incoming segment has the same sequence number as a
segment on the ->ooseq queue, we discard the segment that
contains less data. */
prev = NULL;
for(next = pcb->ooseq; next != NULL; next = next->next) {
if (seqno == next->tcphdr->seqno) {
/* The sequence number of the incoming segment is the
prev = NULL;
for(next = pcb->ooseq; next != NULL; next = next->next) {
if (seqno == next->tcphdr->seqno) {
/* The sequence number of the incoming segment is the
same as the sequence number of the segment on
->ooseq. We check the lengths to see which one to
discard. */
if (inseg.len > next->len) {
/* The incoming segment is larger than the old
if (inseg.len > next->len) {
/* The incoming segment is larger than the old
segment. We replace the old segment with the new
one. */
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next->next;
if (prev != NULL) {
prev->next = cseg;
} else {
pcb->ooseq = cseg;
}
}
break;
} else {
/* Either the lenghts are the same or the incoming
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next->next;
if (prev != NULL) {
prev->next = cseg;
} else {
pcb->ooseq = cseg;
}
}
break;
} else {
/* Either the lenghts are the same or the incoming
segment was smaller than the old one; in either
case, we ditch the incoming segment. */
break;
}
} else {
if (prev == NULL) {
if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
/* The sequence number of the incoming segment is lower
than the sequence number of the first segment on the
queue. We put the incoming segment first on the
queue. */
break;
}
} else {
if (prev == NULL) {
if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
/* The sequence number of the incoming segment is lower
than the sequence number of the first segment on the
queue. We put the incoming segment first on the
queue. */
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
/* We need to trim the incoming segment. */
inseg.len = next->tcphdr->seqno - seqno;
pbuf_realloc(inseg.p, inseg.len);
}
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next;
pcb->ooseq = cseg;
}
break;
}
} else if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
/* The sequence number of the incoming segment is in
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
/* We need to trim the incoming segment. */
inseg.len = next->tcphdr->seqno - seqno;
pbuf_realloc(inseg.p, inseg.len);
}
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next;
pcb->ooseq = cseg;
}
break;
}
} else
/*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){
/* The sequence number of the incoming segment is in
between the sequence numbers of the previous and
the next segment on ->ooseq. We trim and insert the
incoming segment and trim the previous segment, if
needed. */
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
/* We need to trim the incoming segment. */
inseg.len = next->tcphdr->seqno - seqno;
pbuf_realloc(inseg.p, inseg.len);
}
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
/* We need to trim the incoming segment. */
inseg.len = next->tcphdr->seqno - seqno;
pbuf_realloc(inseg.p, inseg.len);
}
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next;
prev->next = cseg;
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
/* We need to trim the prev segment. */
prev->len = seqno - prev->tcphdr->seqno;
pbuf_realloc(prev->p, prev->len);
}
}
break;
}
/* If the "next" segment is the last segment on the
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next;
prev->next = cseg;
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
/* We need to trim the prev segment. */
prev->len = seqno - prev->tcphdr->seqno;
pbuf_realloc(prev->p, prev->len);
}
}
break;
}
/* If the "next" segment is the last segment on the
ooseq queue, we add the incoming segment to the end
of the list. */
if (next->next == NULL &&
TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
next->next = tcp_seg_copy(&inseg);
if (next->next != NULL) {
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
/* We need to trim the last segment. */
next->len = seqno - next->tcphdr->seqno;
pbuf_realloc(next->p, next->len);
}
}
break;
if (next->next == NULL &&
TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
next->next = tcp_seg_copy(&inseg);
if (next->next != NULL) {
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
/* We need to trim the last segment. */
next->len = seqno - next->tcphdr->seqno;
pbuf_realloc(next->p, next->len);
}
}
break;
}
}
prev = next;
}
}
}
prev = next;
}
}
#endif /* TCP_QUEUE_OOSEQ */
}
} else {
/*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
tcp_ack_now(pcb);
}
}
} else {
/* Segments with length 0 is taken care of here. Segments that
fall out of the window are ACKed. */
if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
/*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
tcp_ack_now(pcb);
}
}
@@ -1185,7 +1215,7 @@ tcp_parseopt(struct tcp_pcb *pcb)
++c;
/* NOP option. */
} else if (opt == 0x02 &&
opts[c + 1] == 0x04) {
opts[c + 1] == 0x04) {
/* An MSS option with the right option length. */
mss = (opts[c + 2] << 8) | opts[c + 3];
pcb->mss = mss > TCP_MSS? TCP_MSS: mss;

View File

@@ -62,16 +62,21 @@ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
err_t
tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
{
/* no data, no length, flags, copy=1, no optdata, no optdatalen */
return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
}
/*
* NB. tcp_write() enqueues data for sending, but does not send it
* straight away. It waits in the expectation of more data being sent
* soon (as it can send them more efficiently by combining them
* together). To prompt the system to send data now, call
* tcp_output() after calling tcp_write().
/**
* Write data for sending (but does not send it immediately).
*
* It waits in the expectation of more data being sent soon (as
* it can send them more efficiently by combining them together).
* To prompt the system to send data now, call tcp_output() after
* calling tcp_write().
*
* @arg pcb Protocol control block of the TCP connection to enqueue data for.
*
* @see tcp_write()
*/
err_t
@@ -79,10 +84,11 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
{
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb,
arg, len, (unsigned int)copy));
if (pcb->state == SYN_SENT ||
pcb->state == SYN_RCVD ||
pcb->state == ESTABLISHED ||
pcb->state == CLOSE_WAIT) {
/* connection is in valid state for data transmission? */
if (pcb->state == ESTABLISHED ||
pcb->state == CLOSE_WAIT ||
pcb->state == SYN_SENT ||
pcb->state == SYN_RCVD) {
if (len > 0) {
return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
}
@@ -93,10 +99,24 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
}
}
/**
* Enqueue either data or TCP options (but not both) for tranmission
*
*
*
* @arg pcb Protocol control block for the TCP connection to enqueue data for.
* @arg arg Pointer to the data to be enqueued for sending.
* @arg len Data length in bytes
* @arg flags
* @arg copy 1 if data must be copied, 0 if data is non-volatile and can be
* referenced.
* @arg optdata
* @arg optlen
*/
err_t
tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
u8_t flags, u8_t copy,
u8_t *optdata, u8_t optlen)
u8_t flags, u8_t copy,
u8_t *optdata, u8_t optlen)
{
struct pbuf *p;
struct tcp_seg *seg, *useg, *queue;
@@ -107,39 +127,43 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%u)\n",
(void *)pcb, arg, len, (unsigned int)flags, (unsigned int)copy));
left = len;
ptr = arg;
LWIP_ASSERT("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",
len == 0 || optlen == 0);
LWIP_ASSERT("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",
arg == NULL || optdata == NULL);
/* fail on too much data */
if (len > pcb->snd_buf) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%u > snd_buf=%u)\n", len, pcb->snd_buf));
return ERR_MEM;
}
left = len;
ptr = arg;
/* seqno will be the sequence number of the first segment enqueued
* by the call to this function. */
seqno = pcb->snd_lbb;
queue = NULL;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %u\n", (unsigned int)pcb->snd_queuelen));
/* Check if the queue length exceeds the configured maximum queue
* length. If so, we return an error. */
/* If total number of pbufs on the unsent/unacked queues exceeds the
* configured maximum, return an error */
queuelen = pcb->snd_queuelen;
if (queuelen >= TCP_SND_QUEUELEN) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %u (max %u)\n", queuelen, TCP_SND_QUEUELEN));
goto memerr;
}
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
pcb->unsent != NULL);
if (queuelen != 0) {
LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",
pcb->unacked != NULL || pcb->unsent != NULL);
} else {
LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",
pcb->unacked == NULL && pcb->unsent == NULL);
}
seg = useg = NULL;
seglen = 0;
/* First, break up the data into segments and tuck them together in
* the local "queue" variable. */
useg = queue = seg = NULL;
seglen = 0;
while (queue == NULL || left > 0) {
/* The segment length should be the MSS if the data to be enqueued
@@ -155,20 +179,25 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
seg->next = NULL;
seg->p = NULL;
/* first segment of to-be-queued data? */
if (queue == NULL) {
useg = queue = seg;
queue = seg;
}
/* subsequent segments of to-be-queued data */
else {
/* Attach the segment to the end of the queued segments. */
/* Attach the segment to the end of the queued segments */
LWIP_ASSERT("useg != NULL", useg != NULL);
useg->next = seg;
useg = seg;
}
/* remember last segment of to-be-queued data for next iteration */
useg = seg;
/* If copy is set, memory should be allocated
* and data copied into pbuf, otherwise data comes from
* ROM or other static memory, and need not be copied. If
* optdata is != NULL, we have options instead of data. */
/* options? */
if (optdata != NULL) {
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
goto memerr;
@@ -176,6 +205,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
++queuelen;
seg->dataptr = seg->p->payload;
}
/* copy from volatile memory? */
else if (copy) {
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %u\n", seglen));
@@ -189,8 +219,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
}
/* do not copy data */
else {
/* first, allocate a pbuf for holding the data.
/* First, allocate a pbuf for holding the data.
* since the referenced data is available at least until it is sent out on the
* link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
* instead of PBUF_REF here.
@@ -200,6 +229,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
goto memerr;
}
++queuelen;
/* reference the non-volatile payload data */
p->payload = ptr;
seg->dataptr = ptr;
@@ -214,7 +244,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
++queuelen;
/* Concatenate the headers and data pbufs together. */
pbuf_cat(seg->p, p);
pbuf_cat(seg->p/*header*/, p/*data*/);
p = NULL;
}
@@ -226,16 +256,10 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
}
seg->len = seglen;
#if 0 /* Was commented out. TODO: can someone say why this is here? */
if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
++seg->len;
}
#endif
/* Build TCP header. */
/* build TCP header */
if (pbuf_header(seg->p, TCP_HLEN)) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
TCP_STATS_INC(tcp.err);
goto memerr;
}
@@ -268,7 +292,6 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
ptr = (void *)((char *)ptr + seglen);
}
/* Now that the data to be enqueued has been broken up into TCP
segments in the queue variable, we add them to the end of the
pcb->unsent queue. */
@@ -278,6 +301,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
else {
for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
}
/* { useg is last segment on the unsent queue, NULL if list is empty } */
/* If there is room in the last pbuf on the unsent queue,
chain the first pbuf on the queue together with that. */
@@ -285,24 +309,27 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
TCP_TCPLEN(useg) != 0 &&
!(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
!(flags & (TCP_SYN | TCP_FIN)) &&
/* fit within max seg size */
useg->len + queue->len <= pcb->mss) {
/* Remove TCP header from first segment. */
/* Remove TCP header from first segment of our to-be-queued list */
pbuf_header(queue->p, -TCP_HLEN);
pbuf_cat(useg->p, queue->p);
useg->len += queue->len;
useg->next = queue->next;
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining, new len %u\n", useg->len));
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %u\n", useg->len));
if (seg == queue) {
seg = NULL;
}
memp_free(MEMP_TCP_SEG, queue);
}
else {
/* empty list */
if (useg == NULL) {
/* initialize list with this segment */
pcb->unsent = queue;
}
/* enqueue segment */
else {
useg->next = queue;
}
@@ -312,12 +339,12 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
}
pcb->snd_lbb += len;
pcb->snd_buf -= len;
/* update number of segments on the queues */
pcb->snd_queuelen = queuelen;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
pcb->unsent != NULL);
LWIP_ASSERT("tcp_enqueue: valid queue length",
pcb->unacked != NULL || pcb->unsent != NULL);
}
/* Set the PSH flag in the last segment that we enqueued, but only
@@ -336,7 +363,6 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
pcb->unsent != NULL);
}
LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));
return ERR_MEM;
@@ -364,7 +390,6 @@ tcp_output(struct tcp_pcb *pcb)
wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
seg = pcb->unsent;
/* useg should point to last segment on unacked queue */
@@ -372,24 +397,24 @@ tcp_output(struct tcp_pcb *pcb)
if (useg != NULL) {
for (; useg->next != NULL; useg = useg->next);
}
/* If the TF_ACK_NOW flag is set, we check if there is data that is
to be sent. If data is to be sent out, we'll just piggyback our
acknowledgement with the outgoing segment. If no data will be
sent (either because the ->unsent queue is empty or because the
window doesn't allow it) we'll have to construct an empty ACK
segment and send it. */
/* If the TF_ACK_NOW flag is set and no data will be sent (either
* because the ->unsent queue is empty or because the window does
* not allow it), construct an empty ACK segment and send it.
*
* If data is to be sent, we will just piggyback the ACK (see below).
*/
if (pcb->flags & TF_ACK_NOW &&
(seg == NULL ||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
if (p == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
return ERR_BUF;
}
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %lu\n", pcb->rcv_nxt));
/* remove ACK flags from the PCB, as we send an empty ACK now */
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
tcphdr = p->payload;
tcphdr->src = htons(pcb->local_port);
@@ -406,7 +431,6 @@ tcp_output(struct tcp_pcb *pcb)
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
IP_PROTO_TCP, p->tot_len);
#endif
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP);
pbuf_free(p);
@@ -431,7 +455,7 @@ tcp_output(struct tcp_pcb *pcb)
ntohl(seg->tcphdr->seqno), pcb->lastack));
}
#endif /* TCP_CWND_DEBUG */
/* data available and window allows it to be sent? */
while (seg != NULL &&
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
#if TCP_CWND_DEBUG
@@ -458,13 +482,26 @@ tcp_output(struct tcp_pcb *pcb)
/* put segment on unacknowledged list if length > 0 */
if (TCP_TCPLEN(seg) > 0) {
seg->next = NULL;
/* unacked list is empty? */
if (pcb->unacked == NULL) {
pcb->unacked = seg;
useg = seg;
/* unacked list is not empty? */
} else {
useg->next = seg;
useg = useg->next;
/* In the case of fast retransmit, the packet should not go to the tail
* of the unacked queue, but rather at the head. We need to check for
* this case. -STJ Jul 27, 2004 */
if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
/* add segment to head of unacked list */
seg->next = pcb->unacked;
pcb->unacked = seg;
} else {
/* add segment to tail of unacked list */
useg->next = seg;
useg = useg->next;
}
}
/* do not queue empty segments on the unacked list */
} else {
tcp_seg_free(seg);
}
@@ -473,6 +510,9 @@ tcp_output(struct tcp_pcb *pcb)
return ERR_OK;
}
/**
* Actually send a TCP segment over IP
*/
static void
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
{
@@ -568,6 +608,36 @@ tcp_rst(u32_t seqno, u32_t ackno,
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));
}
/* requeue all unacked segments for retransmission */
void
tcp_rexmit_rto(struct tcp_pcb *pcb)
{
struct tcp_seg *seg;
if (pcb->unacked == NULL) {
return;
}
/* Move all unacked segments to the head of the unsent queue */
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
/* concatenate unsent queue after unacked queue */
seg->next = pcb->unsent;
/* unsent queue is the concatenated queue (of unacked, unsent) */
pcb->unsent = pcb->unacked;
/* unacked queue is now empty */
pcb->unacked = NULL;
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
/* increment number of retransmissions */
++pcb->nrtx;
/* Don't take any RTT measurements after retransmitting. */
pcb->rttest = 0;
/* Do the actual retransmission */
tcp_output(pcb);
}
void
tcp_rexmit(struct tcp_pcb *pcb)
{
@@ -577,14 +647,11 @@ tcp_rexmit(struct tcp_pcb *pcb)
return;
}
/* Move all unacked segments to the unsent queue. */
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
seg->next = pcb->unsent;
/* Move the first unacked segment to the unsent queue */
seg = pcb->unacked->next;
pcb->unacked->next = pcb->unsent;
pcb->unsent = pcb->unacked;
pcb->unacked = NULL;
pcb->unacked = seg;
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
@@ -598,6 +665,7 @@ tcp_rexmit(struct tcp_pcb *pcb)
}
void
tcp_keepalive(struct tcp_pcb *pcb)
{
@@ -608,7 +676,7 @@ tcp_keepalive(struct tcp_pcb *pcb)
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %ld pcb->tmr %ld pcb->keep_cnt %ld\n", tcp_ticks, pcb->tmr, pcb->keep_cnt));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %lu pcb->tmr %lu pcb->keep_cnt %u\n", tcp_ticks, pcb->tmr, pcb->keep_cnt));
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);

View File

@@ -42,6 +42,8 @@
*
*/
#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"
@@ -134,10 +136,10 @@ udp_input(struct pbuf *p, struct netif *inp)
again_1:
/* Iterate through the UDP pcb list for a fully matching pcb */
for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
for (pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
#else /* SO_REUSE */
/* Iterate through the UDP pcb list for a fully matching pcb */
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
#endif /* SO_REUSE */
/* print the PCB local and remote address */
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n",
@@ -159,7 +161,7 @@ udp_input(struct pbuf *p, struct netif *inp)
/* PCB local IP address matches UDP destination IP address? */
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
#if SO_REUSE
if(pcb->so_options & SOF_REUSEPORT) {
if (pcb->so_options & SOF_REUSEPORT) {
if(reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n"));
@@ -173,7 +175,7 @@ udp_input(struct pbuf *p, struct netif *inp)
p->ref++;
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref));
} else {
if(reuse) {
if (reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
}
@@ -192,9 +194,9 @@ udp_input(struct pbuf *p, struct netif *inp)
again_2:
for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
for (pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
#else /* SO_REUSE */
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
#endif /* SO_REUSE */
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n",
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
@@ -210,8 +212,8 @@ udp_input(struct pbuf *p, struct netif *inp)
/* ...matching interface address? */
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
#if SO_REUSE
if(pcb->so_options & SOF_REUSEPORT) {
if(reuse) {
if (pcb->so_options & SOF_REUSEPORT) {
if (reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n"));
} else {
@@ -224,7 +226,7 @@ udp_input(struct pbuf *p, struct netif *inp)
p->ref++;
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref));
} else {
if(reuse) {
if (reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
}
@@ -354,9 +356,10 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *dst_ip, u16_t dst_port)
{
err_t err;
/* temporary space for current PCB remote address */
struct ip_addr pcb_remote_ip;
u16_t pcb_remote_port;
/* remember remote peer address of PCB */
/* remember current remote peer address of PCB */
pcb_remote_ip.addr = pcb->remote_ip.addr;
pcb_remote_port = pcb->remote_port;
/* copy packet destination address to PCB remote peer address */
@@ -364,7 +367,7 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
pcb->remote_port = dst_port;
/* send to the packet destination address */
err = udp_send(pcb, p);
/* reset PCB remote peer address */
/* restore PCB remote peer address */
pcb->remote_ip.addr = pcb_remote_ip.addr;
pcb->remote_port = pcb_remote_port;
return err;
@@ -431,7 +434,9 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
udphdr->chksum = 0x0000;
/* find the outgoing network interface for this packet */
if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
netif = ip_route(&(pcb->remote_ip));
/* no outgoing network interface could be found? */
if (netif == NULL) {
LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%lx\n", pcb->remote_ip.addr));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;

View File

@@ -71,24 +71,36 @@ void icmp_input(struct pbuf *p, struct netif *inp);
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct icmp_echo_hdr {
u16_t _type_code;
u16_t chksum;
u16_t id;
u16_t seqno;
};
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u16_t seqno);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
PACK_STRUCT_BEGIN
struct icmp_dur_hdr {
u16_t _type_code;
u16_t chksum;
u32_t unused;
};
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t unused);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
PACK_STRUCT_BEGIN
struct icmp_te_hdr {
u16_t _type_code;
u16_t chksum;
u32_t unused;
};
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t unused);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)
#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)

View File

@@ -40,7 +40,6 @@
#include "lwip/err.h"
struct netif;
void ip_init(void);
struct netif *ip_route(struct ip_addr *dest);
@@ -94,31 +93,41 @@ err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */
#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_hdr {
/* version / header length / type of service */
u16_t _v_hl_tos;
PACK_STRUCT_FIELD(u16_t _v_hl_tos);
/* total length */
u16_t _len;
PACK_STRUCT_FIELD(u16_t _len);
/* identification */
u16_t _id;
PACK_STRUCT_FIELD(u16_t _id);
/* fragment offset field */
u16_t _offset;
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 */
/* time to live / protocol*/
u16_t _ttl_proto;
PACK_STRUCT_FIELD(u16_t _ttl_proto);
/* checksum */
u16_t _chksum;
PACK_STRUCT_FIELD(u16_t _chksum);
/* source and destination IP addresses */
struct ip_addr src;
struct ip_addr dest;
};
PACK_STRUCT_FIELD(struct ip_addr src);
PACK_STRUCT_FIELD(struct ip_addr dest);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# 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) (htons((ntohs((hdr)->_v_hl_tos) & 0xff)))
#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)
#define IPH_LEN(hdr) ((hdr)->_len)
#define IPH_ID(hdr) ((hdr)->_id)
#define IPH_OFFSET(hdr) ((hdr)->_offset)

View File

@@ -34,13 +34,29 @@
#include "lwip/arch.h"
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr {
u32_t addr;
};
PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr2 {
u16_t addrw[2];
};
PACK_STRUCT_FIELD(u16_t addrw[2]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* For compatibility with BSD code */
struct in_addr {
@@ -101,7 +117,15 @@ extern const struct ip_addr ip_addr_broadcast;
#define ip_addr_set(dest, src) (dest)->addr = \
((src) == NULL? 0:\
(src)->addr)
#define ip_addr_maskcmp(addr1, addr2, mask) (((addr1)->addr & \
/**
* Determine if two address are on the same network.
*
* @arg addr1 IP address 1
* @arg addr2 IP address 2
* @arg mask network identifier mask
* @return !0 if the network identifiers of both address match
*/
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
(mask)->addr) == \
((addr2)->addr & \
(mask)->addr))

View File

@@ -45,7 +45,7 @@ struct ip_addr {
(ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \
(ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)
int ip_addr_maskcmp(struct ip_addr *addr1, struct ip_addr *addr2,
int ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
struct ip_addr *mask);
int ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2);
void ip_addr_set(struct ip_addr *dest, struct ip_addr *src);

View File

@@ -42,6 +42,20 @@
#include "arch/cc.h"
#ifndef PACK_STRUCT_BEGIN
#define PACK_STRUCT_BEGIN
#endif /* PACK_STRUCT_BEGIN */
#ifndef PACK_STRUCT_END
#define PACK_STRUCT_END
#endif /* PACK_STRUCT_END */
#ifndef PACK_STRUCT_FIELD
#define PACK_STRUCT_FIELD(x) x
#endif /* PACK_STRUCT_FIELD */
#ifdef LWIP_PROVIDE_ERRNO
#define EPERM 1 /* Operation not permitted */

View File

@@ -71,7 +71,7 @@
/** print debug message only if debug message type is enabled...
* AND is of correct type AND is at least DBG_LEVEL
*/
# define LWIP_DEBUGF(debug,x) do { if (((debug) & DBG_ON) && ((debug) & DBG_TYPES_ON) && (((debug) & DBG_MASK_LEVEL) >= DBG_MIN_LEVEL)) { LWIP_PLATFORM_DIAG(x); if ((debug) & DBG_HALT) while(1); } } while(0)
# define LWIP_DEBUGF(debug,x) do { if (((debug) & DBG_ON) && ((debug) & DBG_TYPES_ON) && ((int)((debug) & DBG_MASK_LEVEL) >= DBG_MIN_LEVEL)) { LWIP_PLATFORM_DIAG(x); if ((debug) & DBG_HALT) while(1); } } while(0)
# define LWIP_ERROR(x) do { LWIP_PLATFORM_DIAG(x); } while(0)
#else /* LWIP_DEBUG */
# define LWIP_DEBUGF(debug,x)

View File

@@ -43,6 +43,10 @@ struct dhcp
struct ip_addr offered_sn_mask;
struct ip_addr offered_gw_addr;
struct ip_addr offered_bc_addr;
#define DHCP_MAX_DNS 2
u32_t dns_count; /* actual number of DNS servers obtained */
struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */
u32_t offered_t0_lease; /* lease period (in seconds) */
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
@@ -55,43 +59,58 @@ struct dhcp
#endif
};
/* MUST be compiled with "pack structs" or equivalent! */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** minimum set of fields of any DHCP message */
struct dhcp_msg
{
u8_t op;
u8_t htype;
u8_t hlen;
u8_t hops;
u32_t xid;
u16_t secs;
u16_t flags;
struct ip_addr ciaddr;
struct ip_addr yiaddr;
struct ip_addr siaddr;
struct ip_addr giaddr;
PACK_STRUCT_FIELD(u8_t op);
PACK_STRUCT_FIELD(u8_t htype);
PACK_STRUCT_FIELD(u8_t hlen);
PACK_STRUCT_FIELD(u8_t hops);
PACK_STRUCT_FIELD(u32_t xid);
PACK_STRUCT_FIELD(u16_t secs);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FIELD(struct ip_addr ciaddr);
PACK_STRUCT_FIELD(struct ip_addr yiaddr);
PACK_STRUCT_FIELD(struct ip_addr siaddr);
PACK_STRUCT_FIELD(struct ip_addr giaddr);
#define DHCP_CHADDR_LEN 16U
u8_t chaddr[DHCP_CHADDR_LEN];
PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
#define DHCP_SNAME_LEN 64U
u8_t sname[DHCP_SNAME_LEN];
PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
#define DHCP_FILE_LEN 128U
u8_t file[DHCP_FILE_LEN];
u32_t cookie;
PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
PACK_STRUCT_FIELD(u32_t cookie);
#define DHCP_MIN_OPTIONS_LEN 68U
/** make sure user does not configure this too small */
#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
# undef DHCP_OPTIONS_LEN
#endif
/** allow this to be configured in lwipopts.h, but not too small */
#if ((!defined(DHCP_OPTIONS_LEN)) || (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
#if (!defined(DHCP_OPTIONS_LEN))
/** set this to be sufficient for your options in outgoing DHCP msgs */
# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN
#endif
u8_t options[DHCP_OPTIONS_LEN];
};
PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** start DHCP configuration */
err_t dhcp_start(struct netif *netif);
/** enforce early lease renewal (not needed normally)*/
err_t dhcp_renew(struct netif *netif);
/** release the DHCP lease, usually called before dhcp_stop()*/
err_t dhcp_release(struct netif *netif);
/** stop DHCP configuration */
void dhcp_stop(struct netif *netif);
/** enforce lease renewal */
err_t dhcp_renew(struct netif *netif);
/** inform server of our IP address */
/** inform server of our manual IP address */
void dhcp_inform(struct netif *netif);
/** if enabled, check whether the offered IP address is not in use, using ARP */
@@ -165,7 +184,8 @@ void dhcp_fine_tmr(void);
/** BootP options */
#define DHCP_OPTION_PAD 0
#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */
#define DHCP_OPTION_ROUTER 3
#define DHCP_OPTION_ROUTER 3
#define DHCP_OPTION_DNS_SERVER 6
#define DHCP_OPTION_HOSTNAME 12
#define DHCP_OPTION_IP_TTL 23
#define DHCP_OPTION_MTU 26

View File

@@ -53,7 +53,7 @@
/** whether the network interface is 'up'. this is
* a software flag used to control whether this network
* interface is enabled and processes traffic.
* TODO: who should act on this flag, lwIP stack or driver?? */
*/
#define NETIF_FLAG_UP 0x1U
/** if set, the netif has broadcast capability */
#define NETIF_FLAG_BROADCAST 0x2U
@@ -105,6 +105,8 @@ struct netif {
u16_t mtu;
/** flags (see NETIF_FLAG_ above) */
u8_t flags;
/** link type */
u8_t link_type;
/** descriptive abbreviation */
char name[2];
/** number of this interface */
@@ -141,5 +143,8 @@ void netif_set_default(struct netif *netif);
void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);
void netif_set_netmask(struct netif *netif, struct ip_addr *netmast);
void netif_set_gw(struct netif *netif, struct ip_addr *gw);
void netif_set_up(struct netif *netif);
void netif_set_down(struct netif *netif);
u8_t netif_is_up(struct netif *netif);
#endif /* __LWIP_NETIF_H__ */

View File

@@ -146,10 +146,10 @@ a lot of data that needs to be copied, this should be set high. */
#endif
/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
link level header. */
link level header. Defaults to 14 for Ethernet. */
#ifndef PBUF_LINK_HLEN
#define PBUF_LINK_HLEN 0
#define PBUF_LINK_HLEN 14
#endif
@@ -163,17 +163,23 @@ a lot of data that needs to be copied, this should be set high. */
/**
* If enabled, outgoing packets are queued during hardware address
* resolution. The etharp.c implementation queues 1 packet only.
* resolution.
*
* This feature has not stabilized yet. Single-packet queueing is
* believed to be stable, multi-packet queueing is believed to
* clash with the TCP segment queueing.
*
* As multi-packet-queueing is currently disabled, enabling this
* _should_ work, but we need your testing feedback on lwip-users.
*
*/
#ifndef ARP_QUEUEING
#define ARP_QUEUEING 1
#endif
/** If enabled, the first packet queued will not be overwritten by
* later packets. If disabled, later packets overwrite early packets
* in the queue. Default is disabled, which is recommended.
*/
#ifndef ARP_QUEUE_FIRST
#define ARP_QUEUE_FIRST 0
/* This option is deprecated */
#ifdef ETHARP_QUEUE_FIRST
#error ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h.
#endif
/* This option is removed to comply with the ARP standard */
@@ -341,7 +347,7 @@ a lot of data that needs to be copied, this should be set high. */
/* ---------- Socket Options ---------- */
/* Enable SO_REUSEADDR and SO_REUSEPORT options */
#ifndef SO_REUSE
# define SO_REUSE 1
# define SO_REUSE 0
#endif

View File

@@ -209,7 +209,11 @@ struct linger {
* only define this in sockets.c so it does not interfere
* with other projects namespaces where timeval is present
*/
#ifdef LWIP_TIMEVAL_PRIVATE
#ifndef LWIP_TIMEVAL_PRIVATE
#define LWIP_TIMEVAL_PRIVATE 1
#endif
#if LWIP_TIMEVAL_PRIVATE
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */

View File

@@ -105,6 +105,7 @@ void tcp_input (struct pbuf *p, struct netif *inp);
/* Used within the TCP code only: */
err_t tcp_output (struct tcp_pcb *pcb);
void tcp_rexmit (struct tcp_pcb *pcb);
void tcp_rexmit_rto (struct tcp_pcb *pcb);
@@ -112,7 +113,11 @@ void tcp_rexmit (struct tcp_pcb *pcb);
#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)
/* is b<=a<=c? */
#if 0 /* see bug #10548 */
#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
#endif
#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))
#define TCP_FIN 0x01U
#define TCP_SYN 0x02U
#define TCP_RST 0x04U
@@ -161,16 +166,25 @@ void tcp_rexmit (struct tcp_pcb *pcb);
#define TCP_KEEPCNT 9 /* Counter for KEEPALIVE probes */
#define TCP_MAXIDLE TCP_KEEPCNT * TCP_KEEPINTVL /* Maximum KEEPALIVE probe time */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct tcp_hdr {
u16_t src;
u16_t dest;
u32_t seqno;
u32_t ackno;
u16_t _hdrlen_rsvd_flags;
u16_t wnd;
u16_t chksum;
u16_t urgp;
};
PACK_STRUCT_FIELD(u16_t src);
PACK_STRUCT_FIELD(u16_t dest);
PACK_STRUCT_FIELD(u32_t seqno);
PACK_STRUCT_FIELD(u32_t ackno);
PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);
PACK_STRUCT_FIELD(u16_t wnd);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t urgp);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)
#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)
@@ -199,18 +213,13 @@ enum tcp_state {
TIME_WAIT = 10
};
/* the TCP protocol control block */
struct tcp_pcb {
/* Common members of all PCB types */
/** common PCB members */
IP_PCB;
/* Protocol specific PCB members */
struct tcp_pcb *next; /* for the linked list */
enum tcp_state state; /* TCP state */
/** protocol specific PCB members */
struct tcp_pcb *next; /* for the linked list */
enum tcp_state state; /* TCP state */
u8_t prio;
void *callback_arg;
@@ -226,7 +235,7 @@ struct tcp_pcb {
#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
#define TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */
/* receiver varables */
/* receiver variables */
u32_t rcv_nxt; /* next seqno expected */
u16_t rcv_wnd; /* receiver window */
@@ -239,10 +248,10 @@ struct tcp_pcb {
u16_t mss; /* maximum segment size */
/* RTT estimation variables. */
u16_t rttest; /* RTT estimate in 500ms ticks */
/* RTT (round trip time) estimation variables */
u32_t rttest; /* RTT estimate in 500ms ticks */
u32_t rtseq; /* sequence number being timed */
s16_t sa, sv;
s16_t sa, sv; /* @todo document this */
u16_t rto; /* retransmission time-out */
u8_t nrtx; /* number of retransmissions */
@@ -366,7 +375,7 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
#define TCP_EVENT_RECV(pcb,p,err,ret) \
if((pcb)->recv != NULL) \
{ ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \
pbuf_free(p); }
if (p) pbuf_free(p); }
#define TCP_EVENT_CONNECTED(pcb,err,ret) \
if((pcb)->connected != NULL) \
(ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))
@@ -378,7 +387,7 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
(errf)((arg),(err))
#endif /* LWIP_EVENT_API */
/* This structure is used to repressent TCP segments when queued. */
/* This structure represents a TCP segment on the unsent and unacked queues */
struct tcp_seg {
struct tcp_seg *next; /* used when putting segements on a queue */
struct pbuf *p; /* buffer containing data + TCP header */

View File

@@ -41,11 +41,11 @@
#define UDP_HLEN 8
struct udp_hdr {
u16_t src;
u16_t dest; /* src/dest UDP ports */
u16_t len;
u16_t chksum;
};
PACK_STRUCT_FIELD(u16_t src);
PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */
PACK_STRUCT_FIELD(u16_t len);
PACK_STRUCT_FIELD(u16_t chksum);
} PACK_STRUCT_STRUCT;
#define UDP_FLAGS_NOCHKSUM 0x01U
#define UDP_FLAGS_UDPLITE 0x02U

View File

@@ -44,38 +44,71 @@
#include "lwip/netif.h"
#include "lwip/ip.h"
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct eth_addr {
u8_t addr[6];
};
PACK_STRUCT_FIELD(u8_t addr[6]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct eth_hdr {
#if ETH_PAD_SIZE
u8_t padding[ETH_PAD_SIZE];
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
#endif
PACK_STRUCT_FIELD(struct eth_addr dest);
PACK_STRUCT_FIELD(struct eth_addr src);
PACK_STRUCT_FIELD(u16_t type);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
struct eth_addr dest;
struct eth_addr src;
u16_t type;
};
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** the ARP message */
struct etharp_hdr {
struct eth_hdr ethhdr;
u16_t hwtype;
u16_t proto;
u16_t _hwlen_protolen;
u16_t opcode;
struct eth_addr shwaddr;
struct ip_addr2 sipaddr;
struct eth_addr dhwaddr;
struct ip_addr2 dipaddr;
};
PACK_STRUCT_FIELD(struct eth_hdr ethhdr);
PACK_STRUCT_FIELD(u16_t hwtype);
PACK_STRUCT_FIELD(u16_t proto);
PACK_STRUCT_FIELD(u16_t _hwlen_protolen);
PACK_STRUCT_FIELD(u16_t opcode);
PACK_STRUCT_FIELD(struct eth_addr shwaddr);
PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ethip_hdr {
struct eth_hdr eth);
struct ip_hdr ip;
};
PACK_STRUCT_FIELD(struct eth_hdr eth);
PACK_STRUCT_FIELD(struct ip_hdr ip);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define ARP_TMR_INTERVAL 10000
/** 5 seconds period */
#define ARP_TMR_INTERVAL 5000
#define ETHTYPE_ARP 0x0806
#define ETHTYPE_IP 0x0800
@@ -88,5 +121,6 @@ void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
err_t etharp_output(struct netif *netif, struct ip_addr *ipaddr,
struct pbuf *q);
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);
#endif /* __NETIF_ARP_H__ */

View File

@@ -1,17 +1,18 @@
This directory contains generic network interface device drivers that
don't contain any hardware or architecture specific code. The files
do not contain any hardware or architecture specific code. The files
are:
etharp.c
Implements the ARP (Address Resolution Protocol) over
Ethernet. The code in this file should be used together with
Ethernet device drivers.
Ethernet device drivers. Note that this module has been
largely made Ethernet independent so you should be able to
adapt this for other link layers (such as Firewire).
ethernetif.c
An example of how an Ethernet device driver could look. This
file can be used as a "skeleton" for developing new Ethernet
network device drivers. It uses the etharp.c ARP code.
!!!THIS FILE IS NOT IN SYNC WITH CURRENT CODE !!!!
loopif.c
An example network interface that shows how a "loopback"

View File

@@ -55,13 +55,17 @@
# include "lwip/dhcp.h"
#endif
/* allows new queueing code to be disabled (0) for regression testing */
#define ARP_NEW_QUEUE 1
/** the time an ARP entry stays valid after its last update, (120 * 10) seconds = 20 minutes. */
#define ARP_MAXAGE 120
/** the time an ARP entry stays pending after first request, (1 * 10) seconds = 10 seconds. */
#define ARP_MAXPENDING 1
/** the time an ARP entry stays valid after its last update,
* (240 * 5) seconds = 20 minutes.
*/
#define ARP_MAXAGE 240
/** the time an ARP entry stays pending after first request,
* (2 * 5) seconds = 10 seconds.
*
* @internal Keep this number at least 2, otherwise it might
* run out instantly if the timeout occurs directly after a request.
*/
#define ARP_MAXPENDING 2
#define HWTYPE_ETHERNET 1
@@ -79,37 +83,40 @@ enum etharp_state {
ETHARP_STATE_EMPTY,
ETHARP_STATE_PENDING,
ETHARP_STATE_STABLE,
/** @internal convenience transitional state used in etharp_tmr() */
/** @internal transitional state used in etharp_tmr() for convenience*/
ETHARP_STATE_EXPIRED
};
struct etharp_entry {
struct ip_addr ipaddr;
struct eth_addr ethaddr;
enum etharp_state state;
#if ARP_QUEUEING
/**
* Pointer to queue of pending outgoing packets on this ARP entry.
* Must be at most a single packet for now. */
struct pbuf *p;
*/
struct pbuf *p;
#endif
struct ip_addr ipaddr;
struct eth_addr ethaddr;
enum etharp_state state;
u8_t ctime;
};
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
static s8_t find_arp_entry(void);
/** ask update_arp_entry() to add instead of merely update an ARP entry */
#define ARP_INSERT_FLAG 1
static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
/**
* Try hard to create a new entry - we want the IP address to appear in
* the cache (even if this means removing an active entry or so). */
#define ETHARP_TRY_HARD 1
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);
static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
/**
* Initializes ARP module.
*/
void
etharp_init(void)
{
s8_t i;
u8_t i;
/* clear ARP entries */
for(i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].state = ETHARP_STATE_EMPTY;
@@ -123,30 +130,35 @@ etharp_init(void)
/**
* Clears expired entries in the ARP table.
*
* This function should be called every ETHARP_TMR_INTERVAL microseconds (10 seconds),
* This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
* in order to expire entries in the ARP table.
*/
void
etharp_tmr(void)
{
s8_t i;
u8_t i;
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
/* remove expired entries from the ARP table */
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].ctime++;
/* a resolved/stable entry? */
/* stable entry? */
if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
/* entry has become old? */
(arp_table[i].ctime >= ARP_MAXAGE)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i));
arp_table[i].state = ETHARP_STATE_EXPIRED;
/* an unresolved/pending entry? */
} else if ((arp_table[i].state == ETHARP_STATE_PENDING) &&
/* entry unresolved/pending for too long? */
(arp_table[i].ctime >= ARP_MAXPENDING)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));
arp_table[i].state = ETHARP_STATE_EXPIRED;
/* pending entry? */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* entry unresolved/pending for too long? */
if (arp_table[i].ctime >= ARP_MAXPENDING) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));
arp_table[i].state = ETHARP_STATE_EXPIRED;
#if ARP_QUEUEING
} else if (arp_table[i].p != NULL) {
/* resend an ARP query here */
#endif
}
}
/* clean up entries that have just been expired */
if (arp_table[i].state == ETHARP_STATE_EXPIRED) {
@@ -166,59 +178,161 @@ etharp_tmr(void)
}
/**
* Return an empty ARP entry (possibly recycling the oldest stable entry).
* Search the ARP table for a matching or new entry.
*
* If an IP address is given, return a pending or stable ARP entry that matches
* the address. If no match is found, create a new entry with this address set,
* but in state ETHARP_EMPTY. The caller must check and possibly change the
* state of the returned entry.
*
* If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
*
* In all cases, attempt to create new entries from an empty entry. If no
* empty entries are available and ETHARP_TRY_HARD flag is set, recycle
* old entries. Heuristic choose the least important entry for recycling.
*
* @return The ARP entry index that is available, ERR_MEM if no usable
* entry is found.
* @param ipaddr IP address to find in ARP cache, or to add if not found.
* @param flags
* - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
* active (stable or pending) entries.
*
* @return The ARP entry index that matched or is created, ERR_MEM if no
* entry is found or could be recycled.
*/
static s8_t
find_arp_entry(void)
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
{
s8_t i, j;
u8_t maxtime = 0;
j = ARP_TABLE_SIZE;
/* search ARP table for an unused or old entry */
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* empty entry? */
if (arp_table[i].state == ETHARP_STATE_EMPTY) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning empty entry %u\n", i));
return i;
/* stable entry? */
} else if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* remember entry with oldest stable entry in j */
if (arp_table[i].ctime >= maxtime) maxtime = arp_table[j = i].ctime;
}
}
/* no empty entry found? */
if (i == ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j));
/* fall-back to oldest stable */
i = j;
}
/* no available entry found? */
if (i == ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n"));
/* return failure */
return ERR_MEM;
}
/* clean up the oldest stable entry (to be recycled) */
if (arp_table[i].state == ETHARP_STATE_STABLE) {
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
s8_t empty = ARP_TABLE_SIZE;
u8_t i = 0, age_pending = 0, age_stable = 0;
#if ARP_QUEUEING
/* and empty the packet queue */
if (arp_table[i].p != NULL) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p)));
/* remove all queued packets */
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
}
/* oldest entry with packets on queue */
s8_t old_queue = ARP_TABLE_SIZE;
/* its age */
u8_t age_queue = 0;
#endif
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_arp_entry: recycling oldest stable entry %u\n", i));
arp_table[i].state = ETHARP_STATE_EMPTY;
/**
* a) do a search through the cache, remember candidates
* b) select candidate entry
* c) create new entry
*/
/* a) in a single search sweep, do all of this
* 1) remember the first empty entry (if any)
* 2) remember the oldest stable entry (if any)
* 3) remember the oldest pending entry without queued packets (if any)
* 4) remember the oldest pending entry with queued packets (if any)
* 5) search for a matching IP entry, either pending or stable
* until 5 matches, or all entries are searched for.
*/
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* no empty entry found yet and now we do find one? */
if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %d\n", i));
/* remember first empty entry */
empty = i;
}
/* pending entry? */
else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* 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 | DBG_TRACE, ("find_entry: found matching pending entry %d\n", i));
/* found exact IP address match, simply bail out */
return i;
#if ARP_QUEUEING
/* pending with queued packets? */
} else if (arp_table[i].p != NULL) {
if (arp_table[i].ctime >= age_queue) {
old_queue = i;
age_queue = arp_table[i].ctime;
}
#endif
/* pending without queued packets? */
} else {
if (arp_table[i].ctime >= age_pending) {
old_pending = i;
age_pending = arp_table[i].ctime;
}
}
}
/* stable entry? */
else if (arp_table[i].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 | DBG_TRACE, ("find_entry: found matching stable entry %d\n", i));
/* found exact IP address match, simply bail out */
return i;
/* remember entry with oldest stable entry in oldest, its age in maxtime */
} else if (arp_table[i].ctime >= age_stable) {
old_stable = i;
age_stable = arp_table[i].ctime;
}
}
}
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u\n", i));
return i;
/* { we have no match } => try to create a new entry */
/* no empty entry found and not allowed to recycle? */
if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))
{
return (s8_t)ERR_MEM;
}
/* b) choose the least destructive entry to recycle:
* 1) empty entry
* 2) oldest stable entry
* 3) oldest pending entry without queued packets
* 4) oldest pending entry without queued packets
*
* { ETHARP_TRY_HARD is set at this point }
*/
/* 1) empty entry available? */
if (empty < ARP_TABLE_SIZE) {
i = empty;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %d\n", i));
}
/* 2) found recyclable stable entry? */
else if (old_stable < ARP_TABLE_SIZE) {
/* recycle oldest stable*/
i = old_stable;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %d\n", i));
#if ARP_QUEUEING
/* no queued packets should exist on stable entries */
LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL);
#endif
/* 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 | DBG_TRACE, ("find_entry: selecting oldest pending entry %d (without queue)\n", i));
#if ARP_QUEUEING
/* 4) found recyclable pending entry with queued packets? */
} else if (old_queue < ARP_TABLE_SIZE) {
/* recycle oldest pending */
i = old_queue;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %d, freeing packet queue %p\n", i, (void *)(arp_table[i].p)));
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
#endif
/* no empty or recyclable entries found */
} else {
return (s8_t)ERR_MEM;
}
/* { empty or recyclable entry found } */
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
/* recycle entry (no-op for an already empty entry) */
arp_table[i].state = ETHARP_STATE_EMPTY;
/* IP address given? */
if (ipaddr != NULL) {
/* set IP address */
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
}
arp_table[i].ctime = 0;
return (err_t)i;
}
/**
@@ -230,15 +344,17 @@ find_arp_entry(void)
* @param ipaddr IP address of the inserted ARP entry.
* @param ethaddr Ethernet address of the inserted ARP entry.
* @param flags Defines behaviour:
* - ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified,
* - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
* only existing ARP entries will be updated.
*
* @return pbuf If non-NULL, a packet that was queued on a pending entry.
* You should sent it and must call pbuf_free() afterwards.
* @return
* - ERR_OK Succesfully updated ARP cache.
* - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.
* - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
*
* @see pbuf_free()
*/
static struct pbuf *
static err_t
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{
s8_t i, k;
@@ -248,97 +364,52 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),
ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
/* do not update for 0.0.0.0 addresses */
if (ipaddr->addr == 0) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add 0.0.0.0 to ARP cache\n"));
return NULL;
/* non-unicast address? */
if (ip_addr_isany(ipaddr) ||
ip_addr_isbroadcast(ipaddr, netif) ||
ip_addr_ismulticast(ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
return ERR_ARG;
}
/* Walk through the ARP mapping table and try to find an entry to update.
* If none is found, a new IP -> MAC address mapping is inserted. */
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* Check if the source IP address of the incoming packet matches
* the IP address in this ARP table entry. */
if (arp_table[i].state != ETHARP_STATE_EMPTY &&
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
/* pending entry? */
if (arp_table[i].state == ETHARP_STATE_PENDING) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: pending entry %u goes stable\n", i));
/* A pending entry was found, mark it stable */
arp_table[i].state = ETHARP_STATE_STABLE;
/* fall-through to next if */
}
/* stable entry? (possibly just marked stable) */
if (arp_table[i].state == ETHARP_STATE_STABLE) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));
/* An old entry found, update this and return. */
for (k = 0; k < netif->hwaddr_len; ++k) {
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
}
/* reset time stamp */
arp_table[i].ctime = 0;
/* find or create ARP entry */
i = find_entry(ipaddr, flags);
/* bail out if no entry could be found */
if (i < 0) return (err_t)i;
/* mark it stable */
arp_table[i].state = ETHARP_STATE_STABLE;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));
/* update address */
for (k = 0; k < netif->hwaddr_len; ++k) {
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
}
/* reset time stamp */
arp_table[i].ctime = 0;
/* this is where we will send out queued packets! */
#if ARP_QUEUEING
while (arp_table[i].p != NULL) {
/* get the first packet on the queue (if any) */
struct pbuf *p = arp_table[i].p;
/* Ethernet header */
struct eth_hdr *ethhdr = p->payload;;
/* remember (and reference) remainder of queue */
/* note: this will also terminate the p pbuf chain */
arp_table[i].p = pbuf_dequeue(p);
/* fill-in Ethernet header */
for (k = 0; k < netif->hwaddr_len; ++k) {
ethhdr->dest.addr[k] = ethaddr->addr[k];
ethhdr->src.addr[k] = netif->hwaddr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
/* send the queued IP packet */
netif->linkoutput(netif, p);
/* free the queued IP packet */
pbuf_free(p);
}
#endif
/* IP addresses should only occur once in the ARP entry, we are done */
return NULL;
}
} /* if STABLE */
} /* for all ARP entries */
/* no matching ARP entry was found */
LWIP_ASSERT("update_arp_entry: i == ARP_TABLE_SIZE", i == ARP_TABLE_SIZE);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: IP address not yet in table\n"));
/* allowed to insert a new entry? */
if (flags & ARP_INSERT_FLAG)
{
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n"));
/* find an empty or old entry. */
i = find_arp_entry();
if (i == ERR_MEM) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n"));
return NULL;
}
/* set IP address */
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
/* set Ethernet hardware address */
while (arp_table[i].p != NULL) {
/* get the first packet on the queue */
struct pbuf *p = arp_table[i].p;
/* Ethernet header */
struct eth_hdr *ethhdr = p->payload;
/* remember (and reference) remainder of queue */
/* note: this will also terminate the p pbuf chain */
arp_table[i].p = pbuf_dequeue(p);
/* fill-in Ethernet header */
for (k = 0; k < netif->hwaddr_len; ++k) {
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
ethhdr->dest.addr[k] = ethaddr->addr[k];
ethhdr->src.addr[k] = netif->hwaddr[k];
}
/* reset time-stamp */
arp_table[i].ctime = 0;
/* mark as stable */
arp_table[i].state = ETHARP_STATE_STABLE;
/* no queued packet */
#if ARP_QUEUEING
arp_table[i].p = NULL;
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
/* send the queued IP packet */
netif->linkoutput(netif, p);
/* free the queued IP packet */
pbuf_free(p);
}
#endif
}
else
{
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no matching stable entry to update\n"));
}
return NULL;
return ERR_OK;
}
/**
@@ -364,15 +435,17 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
/* Only insert an entry if the source IP address of the
incoming IP packet comes from a host on the local network. */
hdr = p->payload;
/* source is on local network? */
if (!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
/* source is not on the local network? */
if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
/* do nothing */
return;
}
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
/* update ARP table, ask to insert entry */
update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), ARP_INSERT_FLAG);
/* update ARP table */
/* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
* back soon (for example, if the destination IP address is ours. */
update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);
}
@@ -425,7 +498,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
if (for_us) {
/* add IP address in ARP cache; assume requester wants to talk to us.
* can result in directly sending the queued packets for this host. */
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ARP_INSERT_FLAG);
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
/* ARP message not directed to us? */
} else {
/* update the source IP address in the cache, if present */
@@ -481,8 +554,9 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
/* ARP reply. We already updated the ARP cache earlier. */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
/* DHCP wants to know about ARP replies to our wanna-have-address */
if (for_us) dhcp_arp_reply(netif, &sipaddr);
/* When unconfigured, DHCP wants to know about ARP replies from the
* address offered to us, as that means someone else uses it already! */
if (netif->ip_addr.addr == 0) dhcp_arp_reply(netif, &sipaddr);
#endif
break;
default:
@@ -496,44 +570,33 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
/**
* Resolve and fill-in Ethernet address header for outgoing packet.
*
* If ARP has the Ethernet address in cache, the given packet is
* returned, ready to be sent.
* For IP multicast and broadcast, corresponding Ethernet addresses
* are selected and the packet is transmitted on the link.
*
* If ARP does not have the Ethernet address in cache the packet is
* queued (if enabled and space available) and a ARP request is sent.
* This ARP request is returned as a pbuf, which should be sent by
* the caller.
*
* A returned non-NULL packet should be sent by the caller.
*
* If ARP failed to allocate resources, NULL is returned.
* For unicast addresses, the packet is submitted to etharp_query(). In
* case the IP address is outside the local network, the IP address of
* the gateway is used.
*
* @param netif The lwIP network interface which the IP packet will be sent on.
* @param ipaddr The IP address of the packet destination.
* @param pbuf The pbuf(s) containing the IP packet to be sent.
*
* @return If non-NULL, a packet ready to be sent by caller.
*
* @return
* - ERR_BUF Could not make room for Ethernet header.
* - ERR_MEM Hardware address unknown, and no more ARP entries available
* to query for address or queue the packet.
* - ERR_RTE No route to destination (no gateway to external networks).
* - ERR_RTE No route to destination (no gateway to external networks),
* or the return type of either etharp_query() or netif->linkoutput().
*/
err_t
etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{
struct eth_addr *dest, *srcaddr, mcastaddr;
struct eth_hdr *ethhdr;
s8_t i;
err_t result = ERR_OK;
u8_t i;
/* make room for Ethernet header - should not fail*/
/* make room for Ethernet header - should not fail */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
/* bail out */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));
LINK_STATS_INC(link.lenerr);
pbuf_free(q);
return ERR_BUF;
}
@@ -542,14 +605,13 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
/* Determine on destination hardware address. Broadcasts and multicasts
* are special, other IP addresses are looked up in the ARP table. */
/* destination IP address is an IP broadcast address? */
if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, netif)) {
/* broadcast destination IP address? */
if (ip_addr_isbroadcast(ipaddr, netif)) {
/* broadcast on Ethernet also */
dest = (struct eth_addr *)&ethbroadcast;
}
/* destination IP address is an IP multicast address? */
else if (ip_addr_ismulticast(ipaddr)) {
/* Hash IP multicast address to MAC address. */
/* 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;
@@ -558,47 +620,39 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
mcastaddr.addr[5] = ip4_addr4(ipaddr);
/* destination Ethernet address is multicast */
dest = &mcastaddr;
}
/* destination IP address is an IP unicast address */
else {
/* unicast destination IP address? */
} else {
/* outside local network? */
if (!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
/* interface has default gateway? */
if (netif->gw.addr != 0) {
/* send to hardware address of default gateway IP address */
ipaddr = &(netif->gw);
/* no default gateway available? */
/* no default gateway available */
} else {
/* destination unreachable, discard packet */
pbuf_free(q);
/* no route to destination error (default gateway missing) */
return ERR_RTE;
}
}
result = etharp_query(netif, ipaddr, q);
} /* else unicast */
/* destination Ethernet address known */
if (dest != NULL) {
/* obtain source Ethernet address of the given interface */
srcaddr = (struct eth_addr *)netif->hwaddr;
/* A valid IP->MAC address mapping was found, fill in the
* Ethernet header for the outgoing packet */
ethhdr = q->payload;
for(i = 0; i < netif->hwaddr_len; i++) {
ethhdr->dest.addr[i] = dest->addr[i];
ethhdr->src.addr[i] = srcaddr->addr[i];
}
ethhdr->type = htons(ETHTYPE_IP);
/* send packet */
result = netif->linkoutput(netif, q);
/* queue on destination Ethernet address belonging to ipaddr */
return etharp_query(netif, ipaddr, q);
}
/* never reached; here for safety */
pbuf_free(q);
return result;
/* continuation for multicast/broadcast destinations */
/* obtain source Ethernet address of the given interface */
srcaddr = (struct eth_addr *)netif->hwaddr;
ethhdr = q->payload;
for (i = 0; i < netif->hwaddr_len; i++) {
ethhdr->dest.addr[i] = dest->addr[i];
ethhdr->src.addr[i] = srcaddr->addr[i];
}
ethhdr->type = htons(ETHTYPE_IP);
/* send packet directly on the link */
return netif->linkoutput(netif, q);
}
/**
* Send an ARP request for the given IP address.
* Send an ARP request for the given IP address and/or queue a packet.
*
* If the IP address was not yet in the cache, a pending ARP cache entry
* is added and an ARP request is sent for the given address. The packet
@@ -607,13 +661,17 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
* If the IP address was already pending in the cache, a new ARP request
* is sent for the given address. The packet is queued on this entry.
*
* If the IP address was already stable in the cache, the packet is
* directly sent. An ARP request is sent out.
* If the IP address was already stable in the cache, and a packet is
* given, it is directly sent and no ARP request is sent out.
*
* @param netif The lwIP network interface where ipaddr
* If the IP address was already stable in the cache, and no packet is
* given, an ARP request is sent out.
*
* @param netif The lwIP network interface on which ipaddr
* must be queried for.
* @param ipaddr The IP address to be resolved.
* @param q If non-NULL, a pbuf that must be delivered to the IP address.
* q is not freed by this function.
*
* @return
* - ERR_BUF Could not make room for Ethernet header.
@@ -621,34 +679,116 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
* to query for address or queue the packet.
* - ERR_MEM Could not queue packet due to memory shortage.
* - ERR_RTE No route to destination (no gateway to external networks).
*
* @note Might be used in the future by manual IP configuration
* as well.
* - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
*
* TODO: use the ctime field to see how long ago an ARP request was sent,
* possibly retry.
*/
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{
struct pbuf *p;
struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
err_t result = ERR_OK;
err_t result = ERR_MEM;
s8_t i; /* ARP entry index */
u8_t k; /* Ethernet address octet index */
/* Do three things in this order (by design):
*
* 1) send out ARP request
* 2) find entry in ARP cache
* 3) handle the packet
*/
/* non-unicast address? */
if (ip_addr_isbroadcast(ipaddr, netif) ||
ip_addr_ismulticast(ipaddr) ||
ip_addr_isany(ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
return ERR_ARG;
}
/* find entry in ARP cache, ask to create entry if queueing packet */
i = find_entry(ipaddr, ETHARP_TRY_HARD);
/* could not find or create entry? */
if (i < 0)
{
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));
return (err_t)i;
}
/* mark a fresh entry as pending (we just sent a request) */
if (arp_table[i].state == ETHARP_STATE_EMPTY) {
arp_table[i].state = ETHARP_STATE_PENDING;
}
/* { 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)));
/* do we have a pending entry? or an implicit query request? */
if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
/* try to resolve it; send out ARP request */
result = etharp_request(netif, ipaddr);
}
/* packet given? */
if (q != NULL) {
/* stable entry? */
if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* we have a valid IP->Ethernet address mapping,
* fill in the Ethernet header for the outgoing packet */
struct eth_hdr *ethhdr = q->payload;
for(k = 0; k < netif->hwaddr_len; k++) {
ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];
ethhdr->src.addr[k] = srcaddr->addr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));
/* send the packet */
result = netif->linkoutput(netif, q);
/* pending entry? (either just created or already pending */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
#if ARP_QUEUEING /* queue the given q packet */
/* copy any PBUF_REF referenced payloads into PBUF_RAM */
/* (the caller of lwIP assumes the referenced payload can be
* freed after it returns from the lwIP call that brought us here) */
p = pbuf_take(q);
/* packet could be taken over? */
if (p != NULL) {
/* queue packet ... */
if (arp_table[i].p == NULL) {
/* ... in the empty queue */
pbuf_ref(p);
arp_table[i].p = p;
#if 0 /* multi-packet-queueing disabled, see bug #11400 */
} else {
/* ... at tail of non-empty queue */
pbuf_queue(arp_table[i].p, p);
#endif
}
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %d\n", (void *)q, i));
result = ERR_OK;
} else {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
/* { result == ERR_MEM } through initialization */
}
#else /* ARP_QUEUEING == 0 */
/* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
/* { result == ERR_MEM } through initialization */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
#endif
}
}
return result;
}
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)
{
struct pbuf *p;
struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
err_t result = ERR_OK;
u8_t k; /* ARP entry index */
/* allocate a pbuf for the outgoing ARP request packet */
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
/* could allocate a pbuf for an ARP request? */
if (p != NULL) {
struct etharp_hdr *hdr = p->payload;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending ARP request.\n"));
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));
hdr->opcode = htons(ARP_REQUEST);
for (k = 0; k < netif->hwaddr_len; k++)
{
@@ -680,77 +820,7 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
/* could not allocate pbuf for ARP request */
} else {
result = ERR_MEM;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_query: could not allocate pbuf for ARP request.\n"));
}
/* search entry of queried IP address in the ARP cache */
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* valid ARP cache entry with matching IP address? */
if (arp_table[i].state != ETHARP_STATE_EMPTY &&
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
/* pending entry? */
if (arp_table[i].state == ETHARP_STATE_PENDING) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending in entry %u\n", i));
/* { i != ARP_TABLE_SIZE } */
break;
}
else if (arp_table[i].state == ETHARP_STATE_STABLE) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable in entry %u\n", i));
/* { i != ARP_TABLE_SIZE } */
break;
}
}
}
/* queried address not yet in ARP table? */
if (i == ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n"));
/* find an available (unused or old) entry */
i = find_arp_entry();
/* bail out if no ARP entries are available */
if (i == ERR_MEM) {
LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n"));
return ERR_MEM;
}
/* i is available, create ARP entry */
arp_table[i].state = ETHARP_STATE_PENDING;
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
arp_table[i].p = NULL;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: added pending entry %u for IP address\n", i));
}
/* { i is either a (new or existing) PENDING or STABLE entry } */
/* packet given? */
if (q != NULL) {
/* stable entry? */
if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* we have a valid IP->Ethernet address mapping,
* fill in the Ethernet header for the outgoing packet */
struct eth_hdr *ethhdr = q->payload;
for(k = 0; k < netif->hwaddr_len; k++) {
ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];
ethhdr->src.addr[k] = srcaddr->addr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));
/* send the packet */
result = netif->linkoutput(netif, q);
#if ARP_QUEUEING /* queue the given q packet */
/* pending entry? (either just created or already pending */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* copy any PBUF_REF referenced payloads into PBUF_RAM */
/* (the caller assumes the referenced payload can be freed) */
p = pbuf_take(q);
/* queue packet */
if (p != NULL) {
pbuf_queue(arp_table[i].p, p);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %d\n", (void *)q, i));
} else {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
result = ERR_MEM;
}
#endif
}
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));
}
return result;
}

View File

@@ -42,6 +42,7 @@
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include <lwip/stats.h>
#include "netif/etharp.h"
@@ -64,9 +65,7 @@ static err_t ethernetif_output(struct netif *netif, struct pbuf *p,
static void
low_level_init(struct netif *netif)
{
struct ethernetif *ethernetif;
ethernetif = netif->state;
struct ethernetif *ethernetif = netif->state;
/* set MAC hardware address length */
netif->hwaddr_len = 6;
@@ -95,8 +94,9 @@ low_level_init(struct netif *netif)
*/
static err_t
low_level_output(struct ethernetif *ethernetif, struct pbuf *p)
low_level_output(struct netif *netif, struct pbuf *p)
{
struct ethernetif *ethernetif = netif->state;
struct pbuf *q;
initiate transfer();
@@ -118,7 +118,7 @@ low_level_output(struct ethernetif *ethernetif, struct pbuf *p)
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
#ifdef LINK_STATS
#if LINK_STATS
lwip_stats.link.xmit++;
#endif /* LINK_STATS */
@@ -134,8 +134,9 @@ low_level_output(struct ethernetif *ethernetif, struct pbuf *p)
*/
static struct pbuf *
low_level_input(struct ethernetif *ethernetif)
low_level_input(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
struct pbuf *p, *q;
u16_t len;
@@ -170,12 +171,12 @@ low_level_input(struct ethernetif *ethernetif)
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
#ifdef LINK_STATS
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
} else {
drop packet();
#ifdef LINK_STATS
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif /* LINK_STATS */
@@ -223,13 +224,13 @@ ethernetif_input(struct netif *netif)
ethernetif = netif->state;
/* move received packet into a new pbuf */
p = low_level_input(ethernetif);
p = low_level_input(netif);
/* no packet could be read, silently ignore this */
if (p == NULL) return;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
#ifdef LINK_STATS
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
@@ -273,7 +274,7 @@ arp_timer(void *arg)
*
*/
void
err_t
ethernetif_init(struct netif *netif)
{
struct ethernetif *ethernetif;
@@ -299,5 +300,7 @@ ethernetif_init(struct netif *netif)
etharp_init();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
return ERR_OK;
}

View File

@@ -49,6 +49,8 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <string.h>
#include "ppp.h"
#if PPP_SUPPORT > 0
#include "auth.h"

View File

@@ -49,6 +49,9 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <string.h>
#include "ppp.h"
#if PPP_SUPPORT > 0
#include "fsm.h"

View File

@@ -78,6 +78,9 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <string.h>
#include "ppp.h"
#if PPP_SUPPORT > 0
#include "randm.h"
@@ -1233,7 +1236,7 @@ static void pppMain(void *arg)
pppInProc(pd, p->payload, c);
} else {
PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
sys_msleep(250); /* give other tasks a chance to run */
sys_msleep(1); /* give other tasks a chance to run */
}
}
}

View File

@@ -28,11 +28,12 @@
* for a 16 bit processor.
*/
#include <string.h>
#include "ppp.h"
#include "vj.h"
#include "pppdebug.h"
#if VJ_SUPPORT > 0
#if LINK_STATS

View File

@@ -11,6 +11,7 @@
* pragmatically since otherwise unsigned comparisons can result
* against negative integers quite easily, and fail in subtle ways.
*/
PACK_STRUCT_BEGIN
struct ip
{
#if defined(NO_CHAR_BITFIELDS)
@@ -38,6 +39,7 @@ struct ip
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
PACK_STRUCT_END
typedef u32_t tcp_seq;
@@ -45,6 +47,7 @@ typedef u32_t tcp_seq;
* TCP header.
* Per RFC 793, September, 1981.
*/
PACK_STRUCT_BEGIN
struct tcphdr
{
u_short th_sport; /* source port */
@@ -68,5 +71,6 @@ struct tcphdr
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
};
PACK_STRUCT_END
#endif /* VJBSDHDR_H */