Compare commits
179 Commits
merged_fro
...
STABLE-1_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb99d21022 | ||
|
|
793cbcdff8 | ||
|
|
751557bcbf | ||
|
|
252dcd8626 | ||
|
|
0ad7ea16d2 | ||
|
|
79842d4fdd | ||
|
|
1e1f5d5462 | ||
|
|
19d8ffe177 | ||
|
|
4cb8192c1d | ||
|
|
2ed5bc5195 | ||
|
|
fae1397468 | ||
|
|
e871548772 | ||
|
|
a3d27e30e0 | ||
|
|
89abd1f58e | ||
|
|
fae709d9ea | ||
|
|
36df79b207 | ||
|
|
b9ebcd7738 | ||
|
|
515fb5a3fd | ||
|
|
785f90d9fa | ||
|
|
22ac311496 | ||
|
|
0e31ca73c0 | ||
|
|
98ba558fa5 | ||
|
|
c4ef1e5c19 | ||
|
|
1fa0d66f15 | ||
|
|
4680307a34 | ||
|
|
42a6fa972d | ||
|
|
1da6c35a6d | ||
|
|
7c427a4dce | ||
|
|
c2abae538b | ||
|
|
eb69032773 | ||
|
|
fb5452910f | ||
|
|
a6d37fcb25 | ||
|
|
fb18e1f036 | ||
|
|
786cbee510 | ||
|
|
a4f5673ff3 | ||
|
|
1121f2b7f7 | ||
|
|
4d30218eb2 | ||
|
|
d7699ca81d | ||
|
|
afc3bc6b65 | ||
|
|
6f066fca82 | ||
|
|
5e24ae49a6 | ||
|
|
bf74ffe974 | ||
|
|
2074861b57 | ||
|
|
58b64d42f1 | ||
|
|
a6ab0405ea | ||
|
|
8273b54108 | ||
|
|
c356f560e8 | ||
|
|
8d052ecf24 | ||
|
|
45e36d9f56 | ||
|
|
c222d8b672 | ||
|
|
efed3f1f0d | ||
|
|
7524893802 | ||
|
|
25a0273b05 | ||
|
|
ce0410b205 | ||
|
|
efe5ce5c78 | ||
|
|
07f52b4b96 | ||
|
|
0be3598990 | ||
|
|
c3284c30cd | ||
|
|
2d94bf4998 | ||
|
|
31c1e72b8c | ||
|
|
d11fcafad8 | ||
|
|
27c6d299cf | ||
|
|
450dd65165 | ||
|
|
26819e6c39 | ||
|
|
6587efb3e8 | ||
|
|
8d2200f29b | ||
|
|
e4295396ac | ||
|
|
5c7a70df28 | ||
|
|
16a7a8258f | ||
|
|
fb1f61b212 | ||
|
|
c3137df39c | ||
|
|
2df9cd7262 | ||
|
|
a23f6afbee | ||
|
|
e37f7fafc1 | ||
|
|
7b803465ad | ||
|
|
273612b251 | ||
|
|
e2bc8e86e2 | ||
|
|
79110ba469 | ||
|
|
9dd10e46ab | ||
|
|
29df95c514 | ||
|
|
015cb1a35d | ||
|
|
b217b020a5 | ||
|
|
0c960a82ce | ||
|
|
e84cc8c0ad | ||
|
|
c69b93b246 | ||
|
|
5e13b9528d | ||
|
|
8bb3cab9d2 | ||
|
|
ed201c35d2 | ||
|
|
4eadc22a36 | ||
|
|
4e2260c74c | ||
|
|
a5148c14a1 | ||
|
|
955d6206ee | ||
|
|
5df22b3468 | ||
|
|
aef86ec5ef | ||
|
|
94d3b04d68 | ||
|
|
d31830225c | ||
|
|
8f309a3fec | ||
|
|
1fe4edbe1c | ||
|
|
fe1696cef7 | ||
|
|
de2e311e6e | ||
|
|
384fb3c353 | ||
|
|
8603e19516 | ||
|
|
7a2751043a | ||
|
|
e2b0c6c702 | ||
|
|
5b12c61a81 | ||
|
|
b8ee8808b4 | ||
|
|
2db9551750 | ||
|
|
7dc51270ee | ||
|
|
237b5a2467 | ||
|
|
110e5af36c | ||
|
|
7d4aef9576 | ||
|
|
811b360df7 | ||
|
|
d91b54882a | ||
|
|
9106a1f2d5 | ||
|
|
2e2dada561 | ||
|
|
6d704c728e | ||
|
|
6c6f32f17f | ||
|
|
0e4ce326c2 | ||
|
|
d27448da8a | ||
|
|
d36b723056 | ||
|
|
2c8aa6f6f4 | ||
|
|
6f7c8fb355 | ||
|
|
82f852abf3 | ||
|
|
239c6fe070 | ||
|
|
579d2ad811 | ||
|
|
0cb355cd7c | ||
|
|
86135d12b9 | ||
|
|
10d42c6fa3 | ||
|
|
6434f7efad | ||
|
|
bfdf19f56c | ||
|
|
79c7a7a43d | ||
|
|
175053085a | ||
|
|
3d90c062fd | ||
|
|
fda71b1230 | ||
|
|
a916de3b66 | ||
|
|
30e5dfddb9 | ||
|
|
f9dea9d35b | ||
|
|
4ea55b1bbc | ||
|
|
caf3c16826 | ||
|
|
a6f1111469 | ||
|
|
33d0096b81 | ||
|
|
ed4c5d88a3 | ||
|
|
e85a892111 | ||
|
|
70cd10beae | ||
|
|
3a784509df | ||
|
|
5c7189124c | ||
|
|
f81c2744cc | ||
|
|
4bf3359574 | ||
|
|
47984b0496 | ||
|
|
3c339323ed | ||
|
|
7399722a88 | ||
|
|
7bfea6edb7 | ||
|
|
f75da2c393 | ||
|
|
475576ec20 | ||
|
|
f6a8e1df03 | ||
|
|
e1c4bfad05 | ||
|
|
1ed40e7983 | ||
|
|
035fcce9de | ||
|
|
19eed5ff8a | ||
|
|
7129d4797c | ||
|
|
707d31a083 | ||
|
|
79e66ac841 | ||
|
|
1b96391cdf | ||
|
|
eed8ea5bc1 | ||
|
|
a646b5374f | ||
|
|
fa9b1ba947 | ||
|
|
7d58c0c2be | ||
|
|
3c71c378bc | ||
|
|
e4a6d199fe | ||
|
|
bdfdc2bb83 | ||
|
|
351e590e01 | ||
|
|
45756246b9 | ||
|
|
611fb3a1f9 | ||
|
|
ec1c2a714e | ||
|
|
55f64f13c7 | ||
|
|
bbc33080e7 | ||
|
|
506a57392c | ||
|
|
f0e0e72e4d | ||
|
|
7108c57876 |
107
CHANGELOG
107
CHANGELOG
@@ -1,17 +1,114 @@
|
||||
TODO
|
||||
FUTURE
|
||||
|
||||
* TODO: Fix unaligned 16-bit access in checksum routine.
|
||||
* TODO: Fix assumptions on storage sizes wherever we cast.
|
||||
* TODO: See why large ICMP (ping) packets do not work (fragmentation?).
|
||||
* TODO: The lwIP source code makes some invalid assumptions on processor
|
||||
word-length, storage sizes and alignment. See the mailing lists for
|
||||
problems with exoteric (/DSP) architectures showing these problems.
|
||||
We still have to fix some of these issues neatly.
|
||||
|
||||
HISTORY
|
||||
|
||||
(DEVEL)
|
||||
(HEAD)
|
||||
|
||||
(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: 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 ETHARP_ALWAYS_INSERT overrule option.
|
||||
|
||||
++ Bug fixes:
|
||||
|
||||
2004-04-27 Leon Woestenberg <leon.woestenberg@gmx.net>
|
||||
* etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution
|
||||
suggested by Timmy Brolin. Fix for 32-bit processors that cannot access
|
||||
non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix
|
||||
is to prefix the 14-bit Ethernet headers with two padding bytes.
|
||||
|
||||
2004-04-23 Leon Woestenberg <leon.woestenberg@gmx.net>
|
||||
* ip_addr.c: Fix in the ip_addr_isbroadcast() check.
|
||||
* etharp.c: Fixed the case where the packet that initiates the ARP request
|
||||
is not queued, and gets lost. Fixed the case where the packets destination
|
||||
address is already known; we now always queue the packet and perform an ARP
|
||||
request.
|
||||
|
||||
(STABLE-0_7_0)
|
||||
|
||||
++ Bug fixes:
|
||||
|
||||
* Fixed TCP bug for SYN_SENT to ESTABLISHED state transition.
|
||||
* Fixed TCP bug in dequeueing of FIN from out of order segment queue.
|
||||
* Fixed two possible NULL references in rare cases.
|
||||
|
||||
(STABLE-0_6_6)
|
||||
|
||||
++ Bug fixes:
|
||||
|
||||
* Fixed DHCP which did not include the IP address in DECLINE messages.
|
||||
|
||||
++ Changes:
|
||||
|
||||
* etharp.c has been hauled over a bit.
|
||||
|
||||
(STABLE-0_6_5)
|
||||
|
||||
++ Bug fixes:
|
||||
|
||||
2
COPYING
2
COPYING
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
@@ -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,13 +14,14 @@ 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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -272,6 +272,11 @@ level of complexity of UDP, the interface is significantly simpler.
|
||||
Sets the remote end of the pcb. This function does not generate any
|
||||
network traffic, but only set the remote address of the pcb.
|
||||
|
||||
- err_t udp_disconnect(struct udp_pcb *pcb)
|
||||
|
||||
Remove the remote end of the pcb. This function does not generate
|
||||
any network traffic, but only removes the remote address of the pcb.
|
||||
|
||||
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
|
||||
Sends the pbuf p. The pbuf is not deallocated.
|
||||
|
||||
110
doc/savannah.txt
110
doc/savannah.txt
@@ -2,33 +2,70 @@ Daily Use Guide for using Savannah for lwIP
|
||||
|
||||
Table of Contents:
|
||||
|
||||
1 - Anonymous CVS checkouts and updates (to be elaborated)
|
||||
1 - Obtaining lwIP from the CVS repository
|
||||
2 - Committers/developers CVS access using SSH (to be written)
|
||||
3 - Merging from DEVEL branch to main trunk (stable branch)
|
||||
4 - How to release lwIP
|
||||
|
||||
|
||||
1 Anonymous CVS checkouts and updates
|
||||
-------------------------------------
|
||||
|
||||
Obtain lwIP from the CVS main trunk (stable)
|
||||
1 Obtaining lwIP from the CVS repository
|
||||
----------------------------------------
|
||||
|
||||
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip login
|
||||
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout lwip
|
||||
To perform an anonymous CVS checkout of the main trunk (this is where
|
||||
bug fixes and incremental enhancements occur), do this:
|
||||
|
||||
Or, obtain a specific release as follows:
|
||||
export CVS_RSH=ssh
|
||||
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout lwip
|
||||
|
||||
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip login
|
||||
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout -r STABLE-0_6_3 -d lwip-0.6.3 lwip
|
||||
(If SSH asks about authenticity of the host, you can check the key
|
||||
fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
|
||||
|
||||
Or, obtain a development branch as follows:
|
||||
Or, obtain a stable branch (updated with bug fixes only) as follows:
|
||||
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout -r STABLE-0_7 -d lwip-0.7 lwip
|
||||
|
||||
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip login
|
||||
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout -r DEVEL -d lwip-DEVEL lwip
|
||||
Or, obtain a specific (fixed) release as follows:
|
||||
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout -r STABLE-0_7_0 -d lwip-0.7.0 lwip
|
||||
|
||||
Or, obtain a development branch (considered unstable!) as follows:
|
||||
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout -r DEVEL -d lwip-DEVEL lwip
|
||||
|
||||
3 Committers/developers CVS access using SSH
|
||||
--------------------------------------------
|
||||
|
||||
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
|
||||
As such, CVS commits to the server occur through a SSH tunnel for project members.
|
||||
To create a SSH2 key pair in UNIX-like environments, do this:
|
||||
|
||||
ssh-keygen -t dsa
|
||||
|
||||
Under Windows, a recommended SSH client is "PuTTY", freely available with good
|
||||
documentation and a graphic user interface. Use its key generator.
|
||||
|
||||
Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
|
||||
a while so that Savannah can update its configuration (This can take minutes).
|
||||
|
||||
Try to login using SSH:
|
||||
|
||||
ssh -v your_login@subversions.gnu.org
|
||||
|
||||
If it tells you:
|
||||
|
||||
Authenticating with public key "your_key_name"...
|
||||
Server refused to allocate pty
|
||||
|
||||
then you could login; Savannah refuses to give you a shell - which is OK, as we
|
||||
are allowed to use SSH for CVS only. Now, you should be able to do this:
|
||||
|
||||
export CVS_RSH=ssh
|
||||
cvs -d:ext:your_login@subversions.gnu.org:/cvsroot/lwip checkout lwip
|
||||
|
||||
after which you can edit your local files with bug fixes or new features and
|
||||
commit them. Make sure you know what you are doing when using CVS to make
|
||||
changes on the repository. If in doubt, ask on the lwip-members mailing list.
|
||||
|
||||
3 Merging from DEVEL branch to main trunk (stable)
|
||||
---------------------------------------------------------
|
||||
--------------------------------------------------
|
||||
|
||||
Merging is a delicate process in CVS and requires the
|
||||
following disciplined steps in order to prevent conflicts
|
||||
@@ -51,6 +88,9 @@ cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
|
||||
(This will apply the changes between 'merged_from_DEVEL_to_main'
|
||||
and 'DEVEL' to your work set of files)
|
||||
|
||||
We can now commit the merge result.
|
||||
cvs commit -R -m "Merged from DEVEL to main."
|
||||
|
||||
If this worked out OK, we now move the tag in the DEVEL branch
|
||||
to this merge point, so we can use this point for future merges:
|
||||
|
||||
@@ -66,47 +106,25 @@ Login CVS using pserver authentication, then export a clean copy of the
|
||||
tagged tree. Export is similar to a checkout, except that the CVS metadata
|
||||
is not created locally.
|
||||
|
||||
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip login
|
||||
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip export -r STABLE-0_6_3 -d lwip-0.6.3 lwip
|
||||
export CVS_RSH=ssh
|
||||
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip export -r STABLE-0_6_3 -d lwip-0.6.3 lwip
|
||||
|
||||
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
|
||||
|
||||
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:
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/arch.h"
|
||||
@@ -415,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 != 0
|
||||
addr = netbuf_fromaddr(buf);
|
||||
port = netbuf_fromport(buf);
|
||||
|
||||
@@ -993,7 +996,7 @@ int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *opt
|
||||
/* UNIMPL case SO_SNDBUF: */
|
||||
/* UNIMPL case SO_RCVLOWAT: */
|
||||
/* UNIMPL case SO_SNDLOWAT: */
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
case SO_REUSEADDR:
|
||||
case SO_REUSEPORT:
|
||||
#endif /* SO_REUSE */
|
||||
@@ -1079,7 +1082,7 @@ int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *opt
|
||||
/* UNIMPL case SO_DONTROUTE: */
|
||||
case SO_KEEPALIVE:
|
||||
/* UNIMPL case SO_OOBINCLUDE: */
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
case SO_REUSEADDR:
|
||||
case SO_REUSEPORT:
|
||||
#endif /* SO_REUSE */
|
||||
@@ -1138,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 */
|
||||
@@ -1182,7 +1185,7 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_
|
||||
/* UNIMPL case SO_SNDBUF: */
|
||||
/* UNIMPL case SO_RCVLOWAT: */
|
||||
/* UNIMPL case SO_SNDLOWAT: */
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
case SO_REUSEADDR:
|
||||
case SO_REUSEPORT:
|
||||
#endif /* SO_REUSE */
|
||||
@@ -1264,7 +1267,7 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_
|
||||
/* UNIMPL case SO_DONTROUTE: */
|
||||
case SO_KEEPALIVE:
|
||||
/* UNIMPL case SO_OOBINCLUDE: */
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
case SO_REUSEADDR:
|
||||
case SO_REUSEPORT:
|
||||
#endif /* SO_REUSE */
|
||||
@@ -1306,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;
|
||||
|
||||
@@ -56,19 +56,25 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
117
src/core/dhcp.c
117
src/core/dhcp.c
@@ -67,20 +67,26 @@
|
||||
* to remove the DHCP client.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "netif/etharp.h"
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/dhcp.h"
|
||||
|
||||
#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 */
|
||||
@@ -229,10 +235,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 */
|
||||
@@ -291,18 +298,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);
|
||||
@@ -381,8 +390,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);
|
||||
}
|
||||
@@ -404,7 +413,6 @@ static void dhcp_t2_timeout(struct netif *netif)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract options from the server ACK message.
|
||||
*
|
||||
* @param netif the netif under DHCP control
|
||||
*/
|
||||
@@ -478,6 +486,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)]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,39 +521,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;
|
||||
}
|
||||
|
||||
@@ -693,10 +718,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);
|
||||
|
||||
@@ -706,15 +732,9 @@ static err_t dhcp_discover(struct netif *netif)
|
||||
/* set receive callback function with netif as user data */
|
||||
udp_recv(dhcp->pcb, dhcp_recv, netif);
|
||||
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||
udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
|
||||
|
||||
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: send()ing\n"));
|
||||
|
||||
udp_send(dhcp->pcb, dhcp->p_out);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: bind()ing\n"));
|
||||
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: connect()ing\n"));
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
|
||||
udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
|
||||
dhcp_delete_request(netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover: SELECTING\n"));
|
||||
@@ -786,6 +806,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);
|
||||
}
|
||||
@@ -881,10 +903,11 @@ static err_t dhcp_rebind(struct netif *netif)
|
||||
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
/* set remote IP association to any DHCP server */
|
||||
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||
udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
|
||||
udp_send(dhcp->pcb, dhcp->p_out);
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
/* broadcast to server */
|
||||
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_rebind: REBINDING\n"));
|
||||
} else {
|
||||
@@ -911,8 +934,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) {
|
||||
@@ -934,11 +962,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;
|
||||
}
|
||||
@@ -1243,10 +1274,10 @@ static err_t dhcp_create_request(struct netif *netif)
|
||||
dhcp->msg_out->xid = htonl(dhcp->xid);
|
||||
dhcp->msg_out->secs = 0;
|
||||
dhcp->msg_out->flags = 0;
|
||||
dhcp->msg_out->ciaddr = netif->ip_addr.addr;
|
||||
dhcp->msg_out->yiaddr = 0;
|
||||
dhcp->msg_out->siaddr = 0;
|
||||
dhcp->msg_out->giaddr = 0;
|
||||
dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;
|
||||
dhcp->msg_out->yiaddr.addr = 0;
|
||||
dhcp->msg_out->siaddr.addr = 0;
|
||||
dhcp->msg_out->giaddr.addr = 0;
|
||||
for (i = 0; i < DHCP_CHADDR_LEN; i++) {
|
||||
/* copy netif hardware address, pad with zeroes */
|
||||
dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
|
||||
@@ -1418,3 +1449,5 @@ static u32_t dhcp_get_option_long(u8_t *ptr)
|
||||
LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%lu\n", value));
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
@@ -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;
|
||||
@@ -300,18 +312,19 @@ inet_chksum_pbuf(struct pbuf *p)
|
||||
/* Convert numeric IP address into decimal dotted ASCII representation.
|
||||
* returns ptr to static buffer; not reentrant!
|
||||
*/
|
||||
u8_t *inet_ntoa(u32_t addr)
|
||||
char *inet_ntoa(struct in_addr addr)
|
||||
{
|
||||
static u8_t str[16];
|
||||
u8_t inv[3];
|
||||
u8_t *rp;
|
||||
static char str[16];
|
||||
u32_t s_addr = addr.s_addr;
|
||||
char inv[3];
|
||||
char *rp;
|
||||
u8_t *ap;
|
||||
u8_t rem;
|
||||
u8_t n;
|
||||
u8_t i;
|
||||
|
||||
rp = str;
|
||||
ap = (u8_t *)&addr;
|
||||
ap = (u8_t *)&s_addr;
|
||||
for(n = 0; n < 4; n++) {
|
||||
i = 0;
|
||||
do {
|
||||
|
||||
@@ -72,8 +72,8 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
code = *(((u8_t *)p->payload)+1);
|
||||
switch (type) {
|
||||
case ICMP_ECHO:
|
||||
if (ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) ||
|
||||
ip_addr_ismulticast(&iphdr->dest)) {
|
||||
/* broadcast or multicast destination address? */
|
||||
if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("Smurf.\n"));
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
pbuf_free(p);
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/* @file
|
||||
*
|
||||
* This is the IP layer implementation for incoming and outgoing IP traffic.
|
||||
*
|
||||
* @see ip_frag.c
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
@@ -30,18 +37,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ip.c
|
||||
*
|
||||
* This is the code for the IP layer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/ip.h"
|
||||
@@ -63,18 +60,17 @@
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
|
||||
/* ip_init:
|
||||
*
|
||||
/**
|
||||
* Initializes the IP layer.
|
||||
*/
|
||||
|
||||
void
|
||||
ip_init(void)
|
||||
{
|
||||
/* no initializations as of yet */
|
||||
}
|
||||
|
||||
/* ip_route:
|
||||
*
|
||||
/**
|
||||
* Finds the appropriate network interface for a given IP address. It
|
||||
* searches the list of network interfaces linearly. A match is found
|
||||
* if the masked IP address of the network interface equals the masked
|
||||
@@ -99,14 +95,13 @@ ip_route(struct ip_addr *dest)
|
||||
}
|
||||
#if IP_FORWARD
|
||||
|
||||
/* ip_forward:
|
||||
*
|
||||
/**
|
||||
* Forwards an IP packet. It finds an appropriate route for the
|
||||
* packet, decrements the TTL value of the packet, adjusts the
|
||||
* 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;
|
||||
@@ -118,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. */
|
||||
* 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 */
|
||||
@@ -137,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. */
|
||||
@@ -157,11 +152,11 @@ 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 */
|
||||
|
||||
/* ip_input:
|
||||
*
|
||||
/**
|
||||
* This function is called by the network interface device driver when
|
||||
* an IP packet is received. The function does the basic checks of the
|
||||
* IP header such as packet size being at least larger than the header
|
||||
@@ -169,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();
|
||||
@@ -209,6 +207,7 @@ ip_input(struct pbuf *p, struct netif *inp) {
|
||||
}
|
||||
|
||||
/* verify checksum */
|
||||
#if CHECKSUM_CHECK_IP
|
||||
if (inet_chksum(iphdr, iphdrlen) != 0) {
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%x) failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen)));
|
||||
@@ -219,41 +218,43 @@ ip_input(struct pbuf *p, struct netif *inp) {
|
||||
snmp_inc_ipindiscards();
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Trim pbuf. This should have been done at the netif layer,
|
||||
but we'll do it anyway just to be sure that its done. */
|
||||
* 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->netmask)) &&
|
||||
(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;
|
||||
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). */
|
||||
* 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).
|
||||
*/
|
||||
if (netif == NULL) {
|
||||
/* remote port is DHCP server? */
|
||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
|
||||
@@ -266,13 +267,13 @@ 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"));
|
||||
#if IP_FORWARD
|
||||
/* non-broadcast packet? */
|
||||
if (!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask))) {
|
||||
if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
|
||||
/* try to forward IP packet on (other) interfaces */
|
||||
ip_forward(p, iphdr, inp);
|
||||
}
|
||||
@@ -284,30 +285,30 @@ ip_input(struct pbuf *p, struct netif *inp) {
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if IP_REASSEMBLY
|
||||
/* packet consists of multiple fragments? */
|
||||
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
|
||||
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
|
||||
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04x tot_len=%u len=%u MF=%u offset=%u), calling ip_reass()\n",
|
||||
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
|
||||
/* reassemble the packet*/
|
||||
p = ip_reass(p);
|
||||
/* packet not fully reassembled yet? */
|
||||
if (p == NULL) {
|
||||
return ERR_OK;
|
||||
}
|
||||
iphdr = p->payload;
|
||||
}
|
||||
#else /* IP_REASSEMBLY */
|
||||
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
|
||||
#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();
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* IP_REASSEMBLY */
|
||||
}
|
||||
|
||||
#if IP_OPTIONS == 0
|
||||
#if IP_OPTIONS == 0 /* no support for IP options in the IP header? */
|
||||
if (iphdrlen > IP_HLEN) {
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n"));
|
||||
pbuf_free(p);
|
||||
@@ -324,7 +325,8 @@ ip_input(struct pbuf *p, struct netif *inp) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len));
|
||||
|
||||
#if LWIP_RAW
|
||||
if (!raw_input(p, inp)) {
|
||||
/* raw input did not eat the packet? */
|
||||
if (raw_input(p, inp) == 0) {
|
||||
#endif /* LWIP_RAW */
|
||||
|
||||
switch (IPH_PROTO(iphdr)) {
|
||||
@@ -347,8 +349,8 @@ ip_input(struct pbuf *p, struct netif *inp) {
|
||||
break;
|
||||
default:
|
||||
/* send ICMP destination protocol unreachable unless is was a broadcast */
|
||||
if (!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) &&
|
||||
!ip_addr_ismulticast(&(iphdr->dest))) {
|
||||
if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
|
||||
!ip_addr_ismulticast(&(iphdr->dest))) {
|
||||
p->payload = iphdr;
|
||||
icmp_dest_unreach(p, ICMP_DUR_PROTO);
|
||||
}
|
||||
@@ -359,7 +361,6 @@ ip_input(struct pbuf *p, struct netif *inp) {
|
||||
IP_STATS_INC(ip.proterr);
|
||||
IP_STATS_INC(ip.drop);
|
||||
snmp_inc_ipunknownprotos();
|
||||
|
||||
}
|
||||
#if LWIP_RAW
|
||||
} /* LWIP_RAW */
|
||||
@@ -367,9 +368,7 @@ ip_input(struct pbuf *p, struct netif *inp) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/* ip_output_if:
|
||||
*
|
||||
/**
|
||||
* Sends an IP packet on a network interface. This function constructs
|
||||
* the IP header and calculates the IP header checksum. If the source
|
||||
* IP address is NULL, the IP address of the outgoing network
|
||||
@@ -381,8 +380,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();
|
||||
|
||||
@@ -415,7 +414,9 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
}
|
||||
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
#if CHECKSUM_GEN_IP
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
#endif
|
||||
} else {
|
||||
iphdr = p->payload;
|
||||
dest = &(iphdr->dest);
|
||||
@@ -437,8 +438,7 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
return netif->output(netif, p, dest);
|
||||
}
|
||||
|
||||
/* ip_output:
|
||||
*
|
||||
/**
|
||||
* Simple interface to ip_output_if. It finds the outgoing network
|
||||
* interface and calls upon ip_output_if to do the actual work.
|
||||
*/
|
||||
@@ -489,17 +489,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 */
|
||||
|
||||
@@ -32,7 +32,38 @@
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
|
||||
const struct ip_addr ip_addr_any = { 0x00000000UL };
|
||||
const struct ip_addr ip_addr_broadcast = { 0xffffffffUL };
|
||||
|
||||
/* Determine if an address is a broadcast address on a network interface
|
||||
*
|
||||
* @param addr address to be checked
|
||||
* @param netif the network interface against which the address is checked
|
||||
* @return returns non-zero if the address is a broadcast address
|
||||
*
|
||||
*/
|
||||
|
||||
u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
|
||||
{
|
||||
/* all ones (broadcast) or all zeroes (old skool broadcast) */
|
||||
if ((addr->addr == ip_addr_broadcast.addr) ||
|
||||
(addr->addr == ip_addr_any.addr))
|
||||
return 1;
|
||||
/* no broadcast support on this network interface? */
|
||||
else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)
|
||||
/* the given address cannot be a broadcast address
|
||||
* nor can we check against any broadcast addresses */
|
||||
return 0;
|
||||
/* 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))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/* @file
|
||||
*
|
||||
* This is the IP packet segmentation and reassembly implementation.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
@@ -31,14 +37,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* ip_frag.c
|
||||
*
|
||||
* This is the code for IP segmentation and reassembly
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/ip.h"
|
||||
@@ -245,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);
|
||||
@@ -294,7 +292,6 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
rambuf->tot_len = rambuf->len = mtu;
|
||||
rambuf->payload = MEM_ALIGN((void *)buf);
|
||||
|
||||
|
||||
/* Copy the IP header in it */
|
||||
iphdr = rambuf->payload;
|
||||
memcpy(iphdr, p->payload, IP_HLEN);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/opt.h"
|
||||
@@ -54,6 +55,8 @@ struct mem {
|
||||
u16_t used;
|
||||
#elif MEM_ALIGNMENT == 4
|
||||
u32_t used;
|
||||
#elif MEM_ALIGNMENT == 8
|
||||
u64_t used;
|
||||
#else
|
||||
#error "unhandled MEM_ALIGNMENT size"
|
||||
#endif /* MEM_ALIGNMENT */
|
||||
@@ -292,7 +295,7 @@ mem_malloc(mem_size_t size)
|
||||
}
|
||||
sys_sem_signal(mem_sem);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
|
||||
(u32_t)mem + SIZEOF_STRUCT_MEM + size <= (u32_t)ram_end);
|
||||
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
|
||||
(unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
|
||||
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
|
||||
|
||||
@@ -120,7 +120,7 @@ static u8_t memp_memory[(MEMP_NUM_PBUF *
|
||||
static sys_sem_t mutex;
|
||||
#endif
|
||||
|
||||
#ifndef LWIP_NOASSERT
|
||||
#if MEMP_SANITY_CHECK
|
||||
static int
|
||||
memp_sanity(void)
|
||||
{
|
||||
@@ -140,7 +140,7 @@ memp_sanity(void)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* LWIP_DEBUG */
|
||||
#endif /* MEMP_SANITY_CHECK*/
|
||||
|
||||
void
|
||||
memp_init(void)
|
||||
@@ -217,7 +217,7 @@ memp_malloc(memp_t type)
|
||||
sys_sem_signal(mutex);
|
||||
#endif /* SYS_LIGHTWEIGHT_PROT */
|
||||
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
||||
((u32_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % MEM_ALIGNMENT) == 0);
|
||||
((mem_ptr_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % MEM_ALIGNMENT) == 0);
|
||||
|
||||
mem = MEM_ALIGN((u8_t *)memp + sizeof(struct memp));
|
||||
return mem;
|
||||
@@ -261,7 +261,9 @@ memp_free(memp_t type, void *mem)
|
||||
memp->next = memp_tab[type];
|
||||
memp_tab[type] = memp;
|
||||
|
||||
#if MEMP_SANITY_CHECK
|
||||
LWIP_ASSERT("memp sanity", memp_sanity());
|
||||
#endif
|
||||
|
||||
#if SYS_LIGHTWEIGHT_PROT
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
|
||||
@@ -39,23 +39,24 @@
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
|
||||
struct netif *netif_list = NULL;
|
||||
struct netif *netif_default = NULL;
|
||||
|
||||
/**
|
||||
* Add a network interface to the list of lwIP netifs.
|
||||
*
|
||||
* @param netif a pre-allocated netif structure
|
||||
* @param ipaddr IP address for the new netif
|
||||
* @param netmask network mask for the new netif
|
||||
* @param gw default gateway IP address for the new netif
|
||||
* @param state opaque data passed to the new netif
|
||||
* @param init callback function that initializes the interface
|
||||
* @param input callback function that...
|
||||
* @param input callback function that is called to pass
|
||||
* ingress packets up in the protocol layer stack.
|
||||
*
|
||||
* @return netif, or NULL if failed.
|
||||
*/
|
||||
@@ -67,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 */
|
||||
@@ -171,7 +171,7 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
/* address is actually being changed? */
|
||||
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)
|
||||
{
|
||||
extern struct tcp_pcb *tcp_active_pcbs;
|
||||
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
|
||||
LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));
|
||||
pcb = tcp_active_pcbs;
|
||||
while (pcb != NULL) {
|
||||
@@ -186,7 +186,7 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
pcb = pcb->next;
|
||||
}
|
||||
}
|
||||
for (lpcb = tcp_listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
/* PCB bound to current local interface address? */
|
||||
if (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr))) {
|
||||
/* The PCB is listening to the old ipaddr and
|
||||
@@ -197,12 +197,20 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
}
|
||||
#endif
|
||||
ip_addr_set(&(netif->ip_addr), ipaddr);
|
||||
#if 0 /* only allowed for Ethernet interfaces TODO: how can we check? */
|
||||
/** For Ethernet network interfaces, we would like to send a
|
||||
* "gratuitous ARP"; this is an ARP packet sent by a node in order
|
||||
* to spontaneously cause other nodes to update an entry in their
|
||||
* ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
|
||||
*/
|
||||
etharp_query(netif, ipaddr, NULL);
|
||||
#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
|
||||
@@ -210,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
|
||||
@@ -222,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
|
||||
@@ -237,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)
|
||||
{
|
||||
|
||||
144
src/core/pbuf.c
144
src/core/pbuf.c
@@ -11,12 +11,15 @@
|
||||
* list. This is called a "pbuf chain".
|
||||
*
|
||||
* Multiple packets may be queued, also using this singly linked list.
|
||||
* This is called a "packet queue". So, a packet queue consists of one
|
||||
* or more pbuf chains, each of which consist of one or more pbufs.
|
||||
* This is called a "packet queue".
|
||||
*
|
||||
* So, a packet queue consists of one or more pbuf chains, each of
|
||||
* which consist of one or more pbufs. Currently, queues are only
|
||||
* supported in a limited section of lwIP, this is the etharp queueing
|
||||
* code. Outside of this section no packet queues are supported yet.
|
||||
*
|
||||
* The differences between a pbuf chain and a packet queue are very
|
||||
* subtle. Currently, queues are only supported in a limited section
|
||||
* of lwIP, this is the etharp queueing code. Outside of this section
|
||||
* no packet queues are supported as of yet.
|
||||
* precise but subtle.
|
||||
*
|
||||
* The last pbuf of a packet has a ->tot_len field that equals the
|
||||
* ->len field. It can be found by traversing the list. If the last
|
||||
@@ -100,7 +103,7 @@ pbuf_init(void)
|
||||
u16_t i;
|
||||
|
||||
pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0];
|
||||
LWIP_ASSERT("pbuf_init: pool aligned", (long)pbuf_pool % MEM_ALIGNMENT == 0);
|
||||
LWIP_ASSERT("pbuf_init: pool aligned", (mem_ptr_t)pbuf_pool % MEM_ALIGNMENT == 0);
|
||||
|
||||
#if PBUF_STATS
|
||||
lwip_stats.pbuf.avail = PBUF_POOL_SIZE;
|
||||
@@ -254,7 +257,7 @@ pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
|
||||
/* make the payload pointer point 'offset' bytes into pbuf data memory */
|
||||
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));
|
||||
LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
|
||||
((u32_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||
((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||
/* the total length of the pbuf chain is the requested size */
|
||||
p->tot_len = length;
|
||||
/* set the length of the first pbuf in the chain */
|
||||
@@ -290,7 +293,7 @@ pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
|
||||
q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;
|
||||
q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));
|
||||
LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
|
||||
((u32_t)q->payload % MEM_ALIGNMENT) == 0);
|
||||
((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
|
||||
q->ref = 1;
|
||||
/* calculate remaining length to be allocated */
|
||||
rem_len -= q->len;
|
||||
@@ -303,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;
|
||||
}
|
||||
@@ -314,7 +317,7 @@ pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
|
||||
p->flags = PBUF_FLAG_RAM;
|
||||
|
||||
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
|
||||
((u32_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||
((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||
break;
|
||||
/* pbuf references existing (static constant) ROM payload? */
|
||||
case PBUF_ROM:
|
||||
@@ -450,76 +453,82 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
|
||||
*
|
||||
* The ->payload, ->tot_len and ->len fields are adjusted.
|
||||
*
|
||||
* @param hdr_size Number of bytes to increment header size which
|
||||
* @param hdr_size_inc Number of bytes to increment header size which
|
||||
* increases the size of the pbuf. New space is on the front.
|
||||
* (Using a negative value decreases the header size.)
|
||||
* If hdr_size_inc is 0, this function does nothing and returns succesful.
|
||||
*
|
||||
* PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
|
||||
* the call will fail. A check is made that the increase in header size does
|
||||
* not move the payload pointer in front of the start of the buffer.
|
||||
* @return 1 on failure, 0 on success.
|
||||
* @return non-zero on failure, zero on success.
|
||||
*
|
||||
* @note May not be called on a packet queue.
|
||||
*/
|
||||
u8_t
|
||||
pbuf_header(struct pbuf *p, s16_t header_size)
|
||||
pbuf_header(struct pbuf *p, s16_t header_size_increment)
|
||||
{
|
||||
void *payload;
|
||||
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
if ((header_size_increment == 0) || (p == NULL)) return 0;
|
||||
|
||||
/* remember current payload pointer */
|
||||
payload = p->payload;
|
||||
|
||||
/* pbuf types containing payloads? */
|
||||
if (p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_POOL) {
|
||||
/* set new payload pointer */
|
||||
p->payload = (u8_t *)p->payload - header_size;
|
||||
p->payload = (u8_t *)p->payload - header_size_increment;
|
||||
/* boundary check fails? */
|
||||
if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {
|
||||
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p\n",
|
||||
(u8_t *)p->payload,
|
||||
(u8_t *)p + sizeof(struct pbuf)) );\
|
||||
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
|
||||
(void *)p->payload,
|
||||
(void *)(p + 1)));\
|
||||
/* restore old payload pointer */
|
||||
p->payload = payload;
|
||||
/* bail out unsuccesfully */
|
||||
return 1;
|
||||
}
|
||||
/* pbuf types refering to payloads? */
|
||||
/* pbuf types refering to external payloads? */
|
||||
} else if (p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_ROM) {
|
||||
/* hide a header in the payload? */
|
||||
if ((header_size < 0) && (header_size - p->len <= 0)) {
|
||||
if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) {
|
||||
/* increase payload pointer */
|
||||
p->payload = (u8_t *)p->payload - header_size;
|
||||
p->payload = (u8_t *)p->payload - header_size_increment;
|
||||
} else {
|
||||
/* cannot expand payload to front (yet!)
|
||||
* bail out unsuccesfully */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", (void *)payload, (void *)p->payload, header_size) );
|
||||
/* modify pbuf length fields */
|
||||
p->len += header_size;
|
||||
p->tot_len += header_size;
|
||||
p->len += header_size_increment;
|
||||
p->tot_len += header_size_increment;
|
||||
|
||||
LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n",
|
||||
(void *)payload, (void *)p->payload, header_size_increment));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dereference a pbuf (chain) and deallocate any no-longer-used
|
||||
* pbufs at the head of this chain.
|
||||
* Dereference a pbuf chain or queue and deallocate any no-longer-used
|
||||
* pbufs at the head of this chain or queue.
|
||||
*
|
||||
* Decrements the pbuf reference count. If it reaches
|
||||
* zero, the pbuf is deallocated.
|
||||
* Decrements the pbuf reference count. If it reaches zero, the pbuf is
|
||||
* deallocated.
|
||||
*
|
||||
* For a pbuf chain, this is repeated for each pbuf in the chain,
|
||||
* up to a pbuf which has a non-zero reference count after
|
||||
* decrementing. (This might de-allocate the whole chain.)
|
||||
* up to the first pbuf which has a non-zero reference count after
|
||||
* decrementing. So, when all reference counts are one, the whole
|
||||
* chain is free'd.
|
||||
*
|
||||
* @param pbuf The pbuf (chain) to be dereferenced.
|
||||
*
|
||||
* @return the number of pbufs that were de-allocated
|
||||
* from the head of the chain.
|
||||
*
|
||||
* @note MUST NOT be called on a packet queue.
|
||||
* @note MUST NOT be called on a packet queue (Not verified to work yet).
|
||||
* @note the reference counter of a pbuf equals the number of pointers
|
||||
* that refer to the pbuf (or into the pbuf).
|
||||
*
|
||||
@@ -542,6 +551,8 @@ pbuf_free(struct pbuf *p)
|
||||
u8_t count;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
/* if assertions are disabled, proceed with debug output */
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
|
||||
return 0;
|
||||
@@ -576,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 */
|
||||
@@ -590,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;
|
||||
}
|
||||
}
|
||||
@@ -708,11 +719,13 @@ pbuf_chain(struct pbuf *h, struct pbuf *t)
|
||||
void
|
||||
pbuf_queue(struct pbuf *p, struct pbuf *n)
|
||||
{
|
||||
#if PBUF_DEBUG /* remember head of queue */
|
||||
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;
|
||||
if ((p == NULL) || (n == NULL)) return;
|
||||
|
||||
/* iterate through all packets on queue */
|
||||
while (p->next != NULL) {
|
||||
@@ -720,25 +733,39 @@ pbuf_queue(struct pbuf *p, struct pbuf *n)
|
||||
#if PBUF_DEBUG
|
||||
/* iterate through all pbufs in packet */
|
||||
while (p->tot_len != p->len) {
|
||||
/* make sure invariant condition holds */
|
||||
LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);
|
||||
/* make sure each packet is complete */
|
||||
LWIP_ASSERT("p->next != NULL", p->next != NULL);
|
||||
p = p->next;
|
||||
/* { p->tot_len == p->len => p is last pbuf of a packet } */
|
||||
}
|
||||
#endif
|
||||
/* now p->tot_len == p->len */
|
||||
/* { p is last pbuf of a packet } */
|
||||
/* proceed to next packet on queue */
|
||||
p = p->next;
|
||||
#endif
|
||||
/* proceed to next pbuf */
|
||||
if (p->next != NULL) p = p->next;
|
||||
}
|
||||
/* { p->tot_len == p->len and p->next == NULL } ==>
|
||||
* { p is last pbuf of last packet on queue } */
|
||||
/* chain last pbuf of queue with n */
|
||||
p->next = n;
|
||||
/* n is now referenced to one more time */
|
||||
/* n is now referenced to by the (packet p in the) queue */
|
||||
pbuf_ref(n);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_queue: referencing queued packet %p\n", (void *)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 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).
|
||||
*
|
||||
@@ -749,19 +776,28 @@ 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);
|
||||
/* make sure each packet is complete */
|
||||
LWIP_ASSERT("p->next != NULL", p->next != NULL);
|
||||
p = p->next;
|
||||
}
|
||||
/* remember next packet on queue */
|
||||
/* { p->tot_len == p->len } => p is the last pbuf of the first packet */
|
||||
/* remember next packet on queue in q */
|
||||
q = p->next;
|
||||
/* dequeue p from queue */
|
||||
p->next = NULL;
|
||||
/* q is now referenced to one less time */
|
||||
pbuf_free(q);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: dereferencing remaining queue %p\n", (void *)q));
|
||||
/* 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. 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"));
|
||||
}
|
||||
return q;
|
||||
}
|
||||
#endif
|
||||
@@ -779,7 +815,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.
|
||||
@@ -807,7 +843,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;
|
||||
@@ -816,7 +854,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)
|
||||
@@ -899,8 +939,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) */
|
||||
|
||||
116
src/core/raw.c
116
src/core/raw.c
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* @file
|
||||
* Raw Access module
|
||||
*
|
||||
* Implementation of raw protocol PCBs for low-level handling of
|
||||
* different types of protocols besides (or overriding) those
|
||||
* already available in lwIP.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
@@ -35,20 +38,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* raw.c
|
||||
*
|
||||
* The code for the Raw Access to the IP
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/raw.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
@@ -57,11 +55,10 @@
|
||||
#include "lwip/snmp.h"
|
||||
|
||||
#if LWIP_RAW
|
||||
/* The list of RAW PCBs */
|
||||
|
||||
/** The list of RAW PCBs */
|
||||
static struct raw_pcb *raw_pcbs = NULL;
|
||||
|
||||
|
||||
void
|
||||
raw_init(void)
|
||||
{
|
||||
@@ -69,42 +66,54 @@ raw_init(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if in incoming IP packet is covered by a RAW pcb and
|
||||
* and process it if possible
|
||||
* Determine if in incoming IP packet is covered by a RAW PCB
|
||||
* and if so, pass it to a user-provided receive callback function.
|
||||
*
|
||||
* Given an incoming IP datagram (as a chain of pbufs) this function
|
||||
* finds a corresponding RAW PCB and
|
||||
* finds a corresponding RAW PCB and calls the corresponding receive
|
||||
* callback function.
|
||||
*
|
||||
* @param pbuf pbuf to be demultiplexed to a RAW PCB.
|
||||
* @param netif network interface on which the datagram was received.
|
||||
* @return 0 if packet is not eated (pbuf needs to be freed then)
|
||||
* or 1 if the packet has been eaten (pbuf needs not to be freed
|
||||
* then)
|
||||
* @Return - 1 if the packet has been eaten by a RAW PCB receive
|
||||
* callback function. The caller MAY NOT not reference the
|
||||
* packet any longer, and MAY NOT call pbuf_free().
|
||||
* @return - 0 if packet is not eaten (pbuf is still referenced by the
|
||||
* caller).
|
||||
*
|
||||
*/
|
||||
int
|
||||
u8_t
|
||||
raw_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
struct raw_pcb *pcb;
|
||||
struct ip_hdr *iphdr;
|
||||
int proto;
|
||||
int rc = 0;
|
||||
u8_t eaten = 0;
|
||||
|
||||
iphdr = p->payload;
|
||||
proto = IPH_PROTO(iphdr);
|
||||
|
||||
for(pcb = raw_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
pcb = raw_pcbs;
|
||||
/* loop through all raw pcbs until the packet is eaten by one */
|
||||
/* this allows multiple pcbs to match against the packet by design */
|
||||
while ((eaten == 0) && (pcb != NULL)) {
|
||||
if (pcb->protocol == proto) {
|
||||
if (pcb->recv) {
|
||||
if (!pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)))
|
||||
return 0;
|
||||
/* receive callback function available? */
|
||||
if (pcb->recv != NULL) {
|
||||
/* the receive callback function did not eat the packet? */
|
||||
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)
|
||||
{
|
||||
/* receive function ate the packet */
|
||||
p = NULL;
|
||||
eaten = 1;
|
||||
}
|
||||
}
|
||||
pbuf_free(p);
|
||||
rc = 1;
|
||||
break;
|
||||
/* no receive callback function was set for this raw PCB */
|
||||
/* drop the packet */
|
||||
}
|
||||
pcb = pcb->next;
|
||||
}
|
||||
return rc;
|
||||
return eaten;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +125,7 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||
*
|
||||
* @return lwIP error code.
|
||||
* - ERR_OK. Successful. No error occured.
|
||||
* - ERR_USE. The specified ipaddr is already bound to by
|
||||
* - ERR_USE. The specified IP address is already bound to by
|
||||
* another RAW PCB.
|
||||
*
|
||||
* @see raw_disconnect()
|
||||
@@ -130,7 +139,7 @@ raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
||||
|
||||
/**
|
||||
* Connect an RAW PCB. This function is required by upper layers
|
||||
* of lwip. Using the raw api you could use raw_send_to() instead
|
||||
* of lwip. Using the raw api you could use raw_sendto() instead
|
||||
*
|
||||
* This will associate the RAW PCB with the remote address.
|
||||
*
|
||||
@@ -139,7 +148,7 @@ raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
||||
*
|
||||
* @return lwIP error code
|
||||
*
|
||||
* @see raw_disconnect() and raw_send_to()
|
||||
* @see raw_disconnect() and raw_sendto()
|
||||
*/
|
||||
err_t
|
||||
raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
||||
@@ -150,14 +159,21 @@ raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
||||
|
||||
|
||||
/**
|
||||
* Set the callback function if a RAW packet with the pcb's protocol
|
||||
* is received. If the callback function returns a value unequal 0
|
||||
* the raw packet is "eaten" and not forwarded to any other raw pcb
|
||||
* including lwip itself
|
||||
* Set the callback function for received packets that match the
|
||||
* raw PCB's protocol and binding.
|
||||
*
|
||||
* The callback function MUST either
|
||||
* - eat the packet by calling pbuf_free() and returning non-zero. The
|
||||
* packet will not be passed to other raw PCBs or other protocol layers.
|
||||
* - not free the packet, and return zero. The packet will be matched
|
||||
* against further PCBs and/or forwarded to another protocol layers.
|
||||
*
|
||||
* @return non-zero if the packet was free()d, zero if the packet remains
|
||||
* available for others.
|
||||
*/
|
||||
void
|
||||
raw_recv(struct raw_pcb *pcb,
|
||||
int (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,
|
||||
u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,
|
||||
struct ip_addr *addr),
|
||||
void *recv_arg)
|
||||
{
|
||||
@@ -168,25 +184,25 @@ raw_recv(struct raw_pcb *pcb,
|
||||
|
||||
/**
|
||||
* Send the raw IP packet to the given address. Note that actually you cannot
|
||||
* modify the IP headers (this is inconsitent with the receive callback where
|
||||
* you actually get the IP headers), you can only specifiy the ip payload here.
|
||||
* It requires some more changes in LWIP. (there will be a raw_send() function
|
||||
* then)
|
||||
* modify the IP headers (this is inconsistent with the receive callback where
|
||||
* you actually get the IP headers), you can only specify the IP payload here.
|
||||
* It requires some more changes in lwIP. (there will be a raw_send() function
|
||||
* then.)
|
||||
*
|
||||
* @param pcb the raw pcb which to send
|
||||
* @param p the ip payload to send
|
||||
* @param ipaddr the destination address of the whole IP packet
|
||||
* @param p the IP payload to send
|
||||
* @param ipaddr the destination address of the IP packet
|
||||
*
|
||||
*/
|
||||
err_t
|
||||
raw_send_to(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
{
|
||||
err_t err;
|
||||
struct netif *netif;
|
||||
struct ip_addr *src_ip;
|
||||
struct pbuf *q; /* q will be sent down the stack */
|
||||
|
||||
LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_send_to\n"));
|
||||
LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_sendto\n"));
|
||||
|
||||
/* not enough space to add an IP header to first pbuf in given p chain? */
|
||||
if (pbuf_header(p, IP_HLEN)) {
|
||||
@@ -194,13 +210,13 @@ raw_send_to(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
|
||||
/* new header pbuf could not be allocated? */
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 2, ("raw_send_to: could not allocate header\n"));
|
||||
LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* chain header q in front of given pbuf p */
|
||||
pbuf_chain(q, p);
|
||||
/* { first pbuf q points to header pbuf } */
|
||||
LWIP_DEBUGF(RAW_DEBUG, ("raw_send_to: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
|
||||
LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
|
||||
} else {
|
||||
/* first pbuf q equals given pbuf */
|
||||
q = p;
|
||||
@@ -208,10 +224,11 @@ raw_send_to(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
}
|
||||
|
||||
if ((netif = ip_route(ipaddr)) == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_send_to: No route to 0x%lx\n", ipaddr->addr));
|
||||
LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%lx\n", ipaddr->addr));
|
||||
#if RAW_STATS
|
||||
/* ++lwip_stats.raw.rterr;*/
|
||||
#endif /* RAW_STATS */
|
||||
/* free any temporary header pbuf allocated by pbuf_header() */
|
||||
if (q != p) {
|
||||
pbuf_free(q);
|
||||
}
|
||||
@@ -240,14 +257,14 @@ raw_send_to(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
* Send the raw IP packet to the address given by raw_connect()
|
||||
*
|
||||
* @param pcb the raw pcb which to send
|
||||
* @param p the ip payload to send
|
||||
* @param ipaddr the destination address of the whole IP packet
|
||||
* @param p the IP payload to send
|
||||
* @param ipaddr the destination address of the IP packet
|
||||
*
|
||||
*/
|
||||
err_t
|
||||
raw_send(struct raw_pcb *pcb, struct pbuf *p)
|
||||
{
|
||||
return raw_send_to(pcb,p,&pcb->remote_ip);
|
||||
return raw_sendto(pcb, p, &pcb->remote_ip);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,7 +283,7 @@ raw_remove(struct raw_pcb *pcb)
|
||||
if (raw_pcbs == pcb) {
|
||||
/* make list start at 2nd pcb */
|
||||
raw_pcbs = raw_pcbs->next;
|
||||
/* pcb not 1st in list */
|
||||
/* pcb not 1st in list */
|
||||
} else for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
|
||||
/* find pcb in raw_pcbs list */
|
||||
if (pcb2->next != NULL && pcb2->next == pcb) {
|
||||
@@ -303,7 +320,6 @@ raw_new(u16_t proto) {
|
||||
pcb->next = raw_pcbs;
|
||||
raw_pcbs = pcb;
|
||||
}
|
||||
|
||||
return pcb;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
@@ -47,5 +48,68 @@ stats_init(void)
|
||||
{
|
||||
memset(&lwip_stats, 0, sizeof(struct stats_));
|
||||
}
|
||||
#if LWIP_STATS_DISPLAY
|
||||
void
|
||||
stats_display_proto(struct stats_proto *proto, char *name)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
|
||||
LWIP_PLATFORM_DIAG(("xmit: %d\n\t", proto->xmit));
|
||||
LWIP_PLATFORM_DIAG(("rexmit: %d\n\t", proto->rexmit));
|
||||
LWIP_PLATFORM_DIAG(("recv: %d\n\t", proto->recv));
|
||||
LWIP_PLATFORM_DIAG(("fw: %d\n\t", proto->fw));
|
||||
LWIP_PLATFORM_DIAG(("drop: %d\n\t", proto->drop));
|
||||
LWIP_PLATFORM_DIAG(("chkerr: %d\n\t", proto->chkerr));
|
||||
LWIP_PLATFORM_DIAG(("lenerr: %d\n\t", proto->lenerr));
|
||||
LWIP_PLATFORM_DIAG(("memerr: %d\n\t", proto->memerr));
|
||||
LWIP_PLATFORM_DIAG(("rterr: %d\n\t", proto->rterr));
|
||||
LWIP_PLATFORM_DIAG(("proterr: %d\n\t", proto->proterr));
|
||||
LWIP_PLATFORM_DIAG(("opterr: %d\n\t", proto->opterr));
|
||||
LWIP_PLATFORM_DIAG(("err: %d\n\t", proto->err));
|
||||
LWIP_PLATFORM_DIAG(("cachehit: %d\n", proto->cachehit));
|
||||
}
|
||||
|
||||
void
|
||||
stats_display_pbuf(struct stats_pbuf *pbuf)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\nPBUF\n\t"));
|
||||
LWIP_PLATFORM_DIAG(("avail: %d\n\t", pbuf->avail));
|
||||
LWIP_PLATFORM_DIAG(("used: %d\n\t", pbuf->used));
|
||||
LWIP_PLATFORM_DIAG(("max: %d\n\t", pbuf->max));
|
||||
LWIP_PLATFORM_DIAG(("err: %d\n\t", pbuf->err));
|
||||
LWIP_PLATFORM_DIAG(("alloc_locked: %d\n\t", pbuf->alloc_locked));
|
||||
LWIP_PLATFORM_DIAG(("refresh_locked: %d\n", pbuf->refresh_locked));
|
||||
}
|
||||
|
||||
void
|
||||
stats_display_mem(struct stats_mem *mem, char *name)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\n MEM %s\n\t", name));
|
||||
LWIP_PLATFORM_DIAG(("avail: %d\n\t", mem->avail));
|
||||
LWIP_PLATFORM_DIAG(("used: %d\n\t", mem->used));
|
||||
LWIP_PLATFORM_DIAG(("max: %d\n\t", mem->max));
|
||||
LWIP_PLATFORM_DIAG(("err: %d\n", mem->err));
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
stats_display(void)
|
||||
{
|
||||
int i;
|
||||
char * memp_names[] = {"PBUF", "RAW_PCB", "UDP_PCB", "TCP_PCB", "TCP_PCB_LISTEN",
|
||||
"TCP_SEG", "NETBUF", "NETCONN", "API_MSG", "TCP_MSG", "TIMEOUT"};
|
||||
stats_display_proto(&lwip_stats.link, "LINK");
|
||||
stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");
|
||||
stats_display_proto(&lwip_stats.ip, "IP");
|
||||
stats_display_proto(&lwip_stats.icmp, "ICMP");
|
||||
stats_display_proto(&lwip_stats.udp, "UDP");
|
||||
stats_display_proto(&lwip_stats.tcp, "TCP");
|
||||
stats_display_pbuf(&lwip_stats.pbuf);
|
||||
stats_display_mem(&lwip_stats.mem, "HEAP");
|
||||
for (i = 0; i < MEMP_MAX; i++) {
|
||||
stats_display_mem(&lwip_stats.memp[i], memp_names[i]);
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* LWIP_STATS_DISPLAY */
|
||||
#endif /* LWIP_STATS */
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
(void *)timeout, msecs, (void *)h, (void *)arg));
|
||||
|
||||
LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
|
||||
|
||||
if (timeouts->next == NULL) {
|
||||
timeouts->next = timeout;
|
||||
return;
|
||||
@@ -186,14 +187,13 @@ sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
} else {
|
||||
for(t = timeouts->next; t != NULL; t = t->next) {
|
||||
timeout->time -= t->time;
|
||||
if (t->next == NULL ||
|
||||
t->next->time > timeout->time) {
|
||||
if (t->next != NULL) {
|
||||
t->next->time -= timeout->time;
|
||||
}
|
||||
timeout->next = t->next;
|
||||
t->next = timeout;
|
||||
break;
|
||||
if (t->next == NULL || t->next->time > timeout->time) {
|
||||
if (t->next != NULL) {
|
||||
t->next->time -= timeout->time;
|
||||
}
|
||||
timeout->next = t->next;
|
||||
t->next = timeout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
211
src/core/tcp.c
211
src/core/tcp.c
@@ -2,6 +2,11 @@
|
||||
* @file
|
||||
*
|
||||
* Transmission Control Protocol for IP
|
||||
*
|
||||
* This file contains common functions for the TCP implementation, such as functinos
|
||||
* for manipulating the data structures and the TCP timer functions. TCP functions
|
||||
* related to input and output is found in tcp_in.c and tcp_out.c respectively.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -36,16 +41,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* tcp.c
|
||||
*
|
||||
* This file contains common functions for the TCP implementation, such as functinos
|
||||
* for manipulating the data structures and the TCP timer functions. TCP functions
|
||||
* related to input and output is found in tcp_input.c and tcp_output.c respectively.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
@@ -62,30 +58,28 @@ const u8_t tcp_backoff[13] =
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
|
||||
|
||||
/* The TCP PCB lists. */
|
||||
struct tcp_pcb_listen *tcp_listen_pcbs; /* List of all TCP PCBs in LISTEN state. */
|
||||
struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a
|
||||
state in which they accept or send
|
||||
data. */
|
||||
struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */
|
||||
|
||||
/** List of all TCP PCBs in LISTEN state */
|
||||
union tcp_listen_pcbs_t tcp_listen_pcbs;
|
||||
/** List of all TCP PCBs that are in a state in which
|
||||
* they accept or send data. */
|
||||
struct tcp_pcb *tcp_active_pcbs;
|
||||
/** List of all TCP PCBs in TIME-WAIT state */
|
||||
struct tcp_pcb *tcp_tw_pcbs;
|
||||
|
||||
struct tcp_pcb *tcp_tmp_pcb;
|
||||
|
||||
static u8_t tcp_timer;
|
||||
|
||||
static u16_t tcp_new_port(void);
|
||||
|
||||
|
||||
/*
|
||||
* tcp_init():
|
||||
*
|
||||
/**
|
||||
* Initializes the TCP layer.
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_init(void)
|
||||
{
|
||||
/* Clear globals. */
|
||||
tcp_listen_pcbs = NULL;
|
||||
tcp_listen_pcbs.listen_pcbs = NULL;
|
||||
tcp_active_pcbs = NULL;
|
||||
tcp_tw_pcbs = NULL;
|
||||
tcp_tmp_pcb = NULL;
|
||||
@@ -96,13 +90,10 @@ tcp_init(void)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_tmr():
|
||||
*
|
||||
/**
|
||||
* Called periodically to dispatch TCP timers.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_tmr(void)
|
||||
{
|
||||
@@ -116,13 +107,10 @@ tcp_tmr(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_close():
|
||||
*
|
||||
/**
|
||||
* Closes the connection held by the PCB.
|
||||
*
|
||||
*/
|
||||
|
||||
err_t
|
||||
tcp_close(struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -134,9 +122,21 @@ 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, pcb);
|
||||
tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);
|
||||
memp_free(MEMP_TCP_PCB_LISTEN, pcb);
|
||||
pcb = NULL;
|
||||
break;
|
||||
@@ -172,15 +172,12 @@ tcp_close(struct tcp_pcb *pcb)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_abort()
|
||||
*
|
||||
/**
|
||||
* Aborts a connection by sending a RST to the remote host and deletes
|
||||
* the local protocol control block. This is done when a connection is
|
||||
* killed because of shortage of memory.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_abort(struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -229,9 +226,7 @@ tcp_abort(struct tcp_pcb *pcb)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_bind():
|
||||
*
|
||||
/**
|
||||
* Binds the connection to a local portnumber and IP address. If the
|
||||
* IP address is not given (i.e., ipaddr == NULL), the IP address of
|
||||
* the outgoing network interface is used instead.
|
||||
@@ -242,16 +237,16 @@ err_t
|
||||
tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
{
|
||||
struct tcp_pcb *cpcb;
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
int reuse_port_all_set = 1;
|
||||
#endif /* SO_REUSE */
|
||||
|
||||
if (port == 0) {
|
||||
port = tcp_new_port();
|
||||
}
|
||||
#ifndef SO_REUSE
|
||||
#if SO_REUSE == 0
|
||||
/* Check if the address already is in use. */
|
||||
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs;
|
||||
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;
|
||||
cpcb != NULL; cpcb = cpcb->next) {
|
||||
if (cpcb->local_port == port) {
|
||||
if (ip_addr_isany(&(cpcb->local_ip)) ||
|
||||
@@ -284,7 +279,7 @@ tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
|
||||
When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
|
||||
address is already in use. */
|
||||
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs; cpcb != NULL; cpcb = cpcb->next) {
|
||||
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; cpcb != NULL; cpcb = cpcb->next) {
|
||||
if(cpcb->local_port == port) {
|
||||
if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
|
||||
if(pcb->so_options & SOF_REUSEPORT) {
|
||||
@@ -386,16 +381,13 @@ tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
|
||||
}
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
|
||||
/*
|
||||
* tcp_listen():
|
||||
*
|
||||
/**
|
||||
* Set the state of the connection to be LISTEN, which means that it
|
||||
* is able to accept incoming connections. The protocol control block
|
||||
* is reallocated in order to consume less memory. Setting the
|
||||
* connection to LISTEN is an irreversible process.
|
||||
*
|
||||
*/
|
||||
|
||||
struct tcp_pcb *
|
||||
tcp_listen(struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -421,19 +413,16 @@ tcp_listen(struct tcp_pcb *pcb)
|
||||
#if LWIP_CALLBACK_API
|
||||
lpcb->accept = tcp_accept_null;
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
TCP_REG(&tcp_listen_pcbs, lpcb);
|
||||
TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);
|
||||
return (struct tcp_pcb *)lpcb;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_recved():
|
||||
*
|
||||
/**
|
||||
* This function should be called by the application when it has
|
||||
* processed the data. The purpose is to advertise a larger window
|
||||
* when the data has been processed.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||
{
|
||||
@@ -444,20 +433,37 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||
}
|
||||
if (!(pcb->flags & TF_ACK_DELAY) &&
|
||||
!(pcb->flags & TF_ACK_NOW)) {
|
||||
/*
|
||||
* We send an ACK here (if one is not already pending, hence
|
||||
* the above tests) as tcp_recved() implies that the application
|
||||
* has processed some data, and so we can open the receiver's
|
||||
* window to allow more to be transmitted. This could result in
|
||||
* two ACKs being sent for each received packet in some limited cases
|
||||
* (where the application is only receiving data, and is slow to
|
||||
* process it) but it is necessary to guarantee that the sender can
|
||||
* continue to transmit.
|
||||
*/
|
||||
tcp_ack(pcb);
|
||||
}
|
||||
else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {
|
||||
/* If we can send a window update such that there is a full
|
||||
* segment available in the window, do so now. This is sort of
|
||||
* nagle-like in its goals, and tries to hit a compromise between
|
||||
* sending acks each time the window is updated, and only sending
|
||||
* window updates when a timer expires. The "threshold" used
|
||||
* above (currently TCP_WND/2) can be tuned to be more or less
|
||||
* aggressive */
|
||||
tcp_ack_now(pcb);
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %u bytes, wnd %u (%u).\n",
|
||||
len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_new_port():
|
||||
*
|
||||
/**
|
||||
* A nastly hack featuring 'goto' statements that allocates a
|
||||
* new TCP local port.
|
||||
*/
|
||||
|
||||
static u16_t
|
||||
tcp_new_port(void)
|
||||
{
|
||||
@@ -483,7 +489,7 @@ tcp_new_port(void)
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
if (pcb->local_port == port) {
|
||||
goto again;
|
||||
}
|
||||
@@ -491,14 +497,11 @@ tcp_new_port(void)
|
||||
return port;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_connect():
|
||||
*
|
||||
/**
|
||||
* Connects to another host. The function given as the "connected"
|
||||
* argument will be called when the connection has been established.
|
||||
*
|
||||
*/
|
||||
|
||||
err_t
|
||||
tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
|
||||
err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
|
||||
@@ -546,14 +549,11 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_slowtmr():
|
||||
*
|
||||
/**
|
||||
* Called every 500 ms and implements the retransmission timer and the timer that
|
||||
* removes PCBs that have been in TIME-WAIT for enough time. It also increments
|
||||
* various timers such as the inactivity timer in each PCB.
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_slowtmr(void)
|
||||
{
|
||||
@@ -569,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);
|
||||
@@ -598,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;
|
||||
@@ -608,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) {
|
||||
@@ -730,12 +734,9 @@ tcp_slowtmr(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_fasttmr():
|
||||
*
|
||||
/**
|
||||
* Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_fasttmr(void)
|
||||
{
|
||||
@@ -751,13 +752,10 @@ tcp_fasttmr(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_segs_free():
|
||||
*
|
||||
/**
|
||||
* Deallocates a list of TCP segments (tcp_seg structures).
|
||||
*
|
||||
*/
|
||||
|
||||
u8_t
|
||||
tcp_segs_free(struct tcp_seg *seg)
|
||||
{
|
||||
@@ -771,13 +769,10 @@ tcp_segs_free(struct tcp_seg *seg)
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_seg_free():
|
||||
*
|
||||
/**
|
||||
* Frees a TCP segment.
|
||||
*
|
||||
*/
|
||||
|
||||
u8_t
|
||||
tcp_seg_free(struct tcp_seg *seg)
|
||||
{
|
||||
@@ -795,13 +790,10 @@ tcp_seg_free(struct tcp_seg *seg)
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_setprio():
|
||||
*
|
||||
/**
|
||||
* Sets the priority of a connection.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
|
||||
{
|
||||
@@ -809,13 +801,10 @@ tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
|
||||
}
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
|
||||
/*
|
||||
* tcp_seg_copy():
|
||||
*
|
||||
/**
|
||||
* Returns a copy of the given TCP segment.
|
||||
*
|
||||
*/
|
||||
|
||||
struct tcp_seg *
|
||||
tcp_seg_copy(struct tcp_seg *seg)
|
||||
{
|
||||
@@ -951,12 +940,13 @@ tcp_alloc(u8_t prio)
|
||||
return pcb;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_new():
|
||||
*
|
||||
/**
|
||||
* Creates a new TCP protocol control block but doesn't place it on
|
||||
* any of the TCP PCB lists.
|
||||
*
|
||||
* @internal: Maybe there should be a idle TCP PCB list where these
|
||||
* PCBs are put on. We can then implement port reservation using
|
||||
* tcp_bind(). Currently, we lack this (BSD socket type of) feature.
|
||||
*/
|
||||
|
||||
struct tcp_pcb *
|
||||
@@ -980,14 +970,11 @@ tcp_arg(struct tcp_pcb *pcb, void *arg)
|
||||
}
|
||||
#if LWIP_CALLBACK_API
|
||||
|
||||
/*
|
||||
* tcp_recv():
|
||||
*
|
||||
/**
|
||||
* Used to specify the function that should be called when a TCP
|
||||
* connection receives data.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_recv(struct tcp_pcb *pcb,
|
||||
err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
|
||||
@@ -995,9 +982,7 @@ tcp_recv(struct tcp_pcb *pcb,
|
||||
pcb->recv = recv;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_sent():
|
||||
*
|
||||
/**
|
||||
* Used to specify the function that should be called when TCP data
|
||||
* has been successfully delivered to the remote host.
|
||||
*
|
||||
@@ -1010,14 +995,11 @@ tcp_sent(struct tcp_pcb *pcb,
|
||||
pcb->sent = sent;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_err():
|
||||
*
|
||||
/**
|
||||
* Used to specify the function that should be called when a fatal error
|
||||
* has occured on the connection.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_err(struct tcp_pcb *pcb,
|
||||
void (* errf)(void *arg, err_t err))
|
||||
@@ -1025,14 +1007,11 @@ tcp_err(struct tcp_pcb *pcb,
|
||||
pcb->errf = errf;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_accept():
|
||||
*
|
||||
/**
|
||||
* Used for specifying the function that should be called when a
|
||||
* LISTENing connection has been connected to another host.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_accept(struct tcp_pcb *pcb,
|
||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
|
||||
@@ -1042,15 +1021,12 @@ tcp_accept(struct tcp_pcb *pcb,
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
|
||||
|
||||
/*
|
||||
* tcp_poll():
|
||||
*
|
||||
/**
|
||||
* Used to specify the function that should be called periodically
|
||||
* from TCP. The interval is specified in terms of the TCP coarse
|
||||
* timer interval, which is called twice a second.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_poll(struct tcp_pcb *pcb,
|
||||
err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
|
||||
@@ -1061,13 +1037,10 @@ tcp_poll(struct tcp_pcb *pcb,
|
||||
pcb->pollinterval = interval;
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_pcb_purge():
|
||||
*
|
||||
/**
|
||||
* Purges a TCP PCB. Removes any buffered data and frees the buffer memory.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_pcb_purge(struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -1097,13 +1070,10 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_pcb_remove():
|
||||
*
|
||||
/**
|
||||
* Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -1123,13 +1093,10 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
|
||||
LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
|
||||
}
|
||||
|
||||
/*
|
||||
* tcp_next_iss():
|
||||
*
|
||||
/**
|
||||
* Calculates a new initial sequence number for new connections.
|
||||
*
|
||||
*/
|
||||
|
||||
u32_t
|
||||
tcp_next_iss(void)
|
||||
{
|
||||
@@ -1253,7 +1220,7 @@ tcp_debug_print_pcbs(void)
|
||||
tcp_debug_print_state(pcb->state);
|
||||
}
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
|
||||
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("Local port %u, foreign port %u snd_nxt %lu rcv_nxt %lu ",
|
||||
pcb->local_port, pcb->remote_port,
|
||||
pcb->snd_nxt, pcb->rcv_nxt));
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
* @file
|
||||
*
|
||||
* Transmission Control Protocol, incoming traffic
|
||||
*
|
||||
* The input processing functions of TCP.
|
||||
*
|
||||
* These functions are generally called in the order (ip_input() ->) tcp_input() ->
|
||||
* tcp_process() -> tcp_receive() (-> application).
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -36,21 +42,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* tcp_input.c
|
||||
*
|
||||
* The input processing functions of TCP.
|
||||
*
|
||||
* These functions are generally called in the order (ip_input() ->) tcp_input() ->
|
||||
* tcp_process() -> tcp_receive() (-> application).
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
@@ -102,7 +97,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
u8_t hdrlen;
|
||||
err_t err;
|
||||
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
struct tcp_pcb *pcb_temp;
|
||||
int reuse = 0;
|
||||
int reuse_port = 0;
|
||||
@@ -130,12 +125,13 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
|
||||
/* Don't even process incoming broadcasts/multicasts. */
|
||||
if (ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) ||
|
||||
ip_addr_ismulticast(&(iphdr->dest))) {
|
||||
if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||
|
||||
ip_addr_ismulticast(&(iphdr->dest))) {
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
#if CHECKSUM_CHECK_TCP
|
||||
/* Verify TCP checksum. */
|
||||
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
@@ -152,7 +148,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Move the payload pointer in the pbuf so that it points to the
|
||||
TCP data instead of the TCP header. */
|
||||
@@ -173,7 +169,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
for an active connection. */
|
||||
prev = NULL;
|
||||
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
pcb_temp = tcp_active_pcbs;
|
||||
|
||||
again_1:
|
||||
@@ -191,7 +187,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
|
||||
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
if(pcb->so_options & SOF_REUSEPORT) {
|
||||
if(reuse) {
|
||||
/* We processed one PCB already */
|
||||
@@ -255,7 +251,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
/* Finally, if we still did not get a match, we check all PCBs that
|
||||
are LISTENing for incoming connections. */
|
||||
prev = NULL;
|
||||
for(lpcb = tcp_listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
if ((ip_addr_isany(&(lpcb->local_ip)) ||
|
||||
ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&
|
||||
lpcb->local_port == tcphdr->dest) {
|
||||
@@ -265,9 +261,9 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
if (prev != NULL) {
|
||||
((struct tcp_pcb_listen *)prev)->next = lpcb->next;
|
||||
/* our successor is the remainder of the listening list */
|
||||
lpcb->next = tcp_listen_pcbs;
|
||||
lpcb->next = tcp_listen_pcbs.listen_pcbs;
|
||||
/* put this listening pcb at the head of the listening list */
|
||||
tcp_listen_pcbs = lpcb;
|
||||
tcp_listen_pcbs.listen_pcbs = lpcb;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
|
||||
@@ -355,13 +351,13 @@ 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);
|
||||
#endif /* TCP_DEBUG */
|
||||
#endif /* TCP_INPUT_DEBUG */
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
/* First socket should receive now */
|
||||
if(reuse_port) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: searching next PCB.\n"));
|
||||
@@ -373,7 +369,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
#endif /* SO_REUSE */
|
||||
|
||||
} else {
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
if(reuse) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: freeing PBUF with reference counter set to %i\n", p->ref));
|
||||
pbuf_free(p);
|
||||
@@ -392,7 +388,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
pbuf_free(p);
|
||||
}
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
end:
|
||||
#endif /* SO_REUSE */
|
||||
LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
|
||||
@@ -510,9 +506,11 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,8 +564,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
|
||||
@@ -676,6 +675,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) {
|
||||
@@ -703,43 +703,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. */
|
||||
@@ -760,86 +767,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
|
||||
@@ -848,20 +854,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;
|
||||
}
|
||||
@@ -872,290 +878,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);
|
||||
}
|
||||
}
|
||||
@@ -1189,7 +1214,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;
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
* @file
|
||||
*
|
||||
* Transmission Control Protocol, outgoing traffic
|
||||
*
|
||||
* The output functions of TCP.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
@@ -35,15 +39,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* tcp_output.c
|
||||
*
|
||||
* The output functions of TCP.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
@@ -51,6 +46,7 @@
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#include "lwip/inet.h"
|
||||
@@ -63,8 +59,6 @@
|
||||
/* Forward declarations.*/
|
||||
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)
|
||||
{
|
||||
@@ -72,6 +66,14 @@ tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 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().
|
||||
*/
|
||||
|
||||
err_t
|
||||
tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
|
||||
{
|
||||
@@ -400,9 +402,10 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
TCPH_HDRLEN_SET(tcphdr, 5);
|
||||
|
||||
tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
|
||||
#endif
|
||||
|
||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
@@ -459,8 +462,16 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
pcb->unacked = seg;
|
||||
useg = seg;
|
||||
} else {
|
||||
useg->next = seg;
|
||||
useg = useg->next;
|
||||
/* In the case of fast retransmit, the packet should not go to the end
|
||||
* of the unacked queue, but rather at the start. We need to check for
|
||||
* this case. -STJ Jul 27, 2004 */
|
||||
if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
|
||||
seg->next = pcb->unacked;
|
||||
pcb->unacked = seg;
|
||||
} else {
|
||||
useg->next = seg;
|
||||
useg = useg->next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tcp_seg_free(seg);
|
||||
@@ -518,10 +529,12 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
seg->p->payload = seg->tcphdr;
|
||||
|
||||
seg->tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
|
||||
&(pcb->local_ip),
|
||||
&(pcb->remote_ip),
|
||||
IP_PROTO_TCP, seg->p->tot_len);
|
||||
#endif
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
@@ -552,9 +565,10 @@ tcp_rst(u32_t seqno, u32_t ackno,
|
||||
TCPH_HDRLEN_SET(tcphdr, 5);
|
||||
|
||||
tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
|
||||
#endif
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
/* Send output with hardcoded TTL since we have no access to the pcb */
|
||||
ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
|
||||
@@ -563,7 +577,7 @@ tcp_rst(u32_t seqno, u32_t ackno,
|
||||
}
|
||||
|
||||
void
|
||||
tcp_rexmit(struct tcp_pcb *pcb)
|
||||
tcp_rexmit_rto(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct tcp_seg *seg;
|
||||
|
||||
@@ -573,13 +587,10 @@ tcp_rexmit(struct tcp_pcb *pcb)
|
||||
|
||||
/* Move all unacked segments to the unsent queue. */
|
||||
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
|
||||
|
||||
seg->next = pcb->unsent;
|
||||
pcb->unsent = pcb->unacked;
|
||||
|
||||
pcb->unacked = NULL;
|
||||
|
||||
|
||||
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
|
||||
|
||||
++pcb->nrtx;
|
||||
@@ -592,6 +603,34 @@ tcp_rexmit(struct tcp_pcb *pcb)
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
tcp_rexmit(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct tcp_seg *seg;
|
||||
|
||||
if (pcb->unacked == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move the first unacked segment to the unsent queue */
|
||||
seg = pcb->unacked->next;
|
||||
pcb->unacked->next = pcb->unsent;
|
||||
pcb->unsent = pcb->unacked;
|
||||
pcb->unacked = seg;
|
||||
|
||||
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
|
||||
|
||||
++pcb->nrtx;
|
||||
|
||||
/* Don't take any rtt measurements after retransmitting. */
|
||||
pcb->rttest = 0;
|
||||
|
||||
/* Do the actual retransmission. */
|
||||
tcp_output(pcb);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
tcp_keepalive(struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -602,7 +641,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);
|
||||
|
||||
@@ -621,8 +660,9 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
||||
TCPH_HDRLEN_SET(tcphdr, 5);
|
||||
|
||||
tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len);
|
||||
|
||||
#endif
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
/* Send output to IP */
|
||||
|
||||
135
src/core/udp.c
135
src/core/udp.c
@@ -42,15 +42,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
@@ -89,7 +91,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
struct ip_hdr *iphdr;
|
||||
u16_t src, dest;
|
||||
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
struct udp_pcb *pcb_temp;
|
||||
int reuse = 0;
|
||||
int reuse_port_1 = 0;
|
||||
@@ -128,16 +130,16 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
|
||||
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
|
||||
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
pcb_temp = udp_pcbs;
|
||||
|
||||
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",
|
||||
@@ -158,8 +160,8 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
/* PCB local IP address matches UDP destination IP address? */
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
|
||||
#ifdef SO_REUSE
|
||||
if(pcb->so_options & SOF_REUSEPORT) {
|
||||
#if SO_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"));
|
||||
@@ -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"));
|
||||
}
|
||||
@@ -187,14 +189,14 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
/* Iterate through the UDP PCB list for a pcb that matches
|
||||
the local address. */
|
||||
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
pcb_temp = udp_pcbs;
|
||||
|
||||
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),
|
||||
@@ -209,9 +211,9 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
/* ...matching interface address? */
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
|
||||
#ifdef SO_REUSE
|
||||
if(pcb->so_options & SOF_REUSEPORT) {
|
||||
if(reuse) {
|
||||
#if SO_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"));
|
||||
}
|
||||
@@ -246,6 +248,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
|
||||
#endif /* IPv4 */
|
||||
/* Do the UDP Lite checksum */
|
||||
#if CHECKSUM_CHECK_UDP
|
||||
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) {
|
||||
@@ -256,7 +259,9 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
pbuf_free(p);
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if CHECKSUM_CHECK_UDP
|
||||
if (udphdr->chksum != 0) {
|
||||
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
@@ -270,12 +275,13 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pbuf_header(p, -UDP_HLEN);
|
||||
if (pcb != NULL) {
|
||||
snmp_inc_udpindatagrams();
|
||||
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
/* First socket should receive now */
|
||||
if(reuse_port_1 || reuse_port_2) {
|
||||
/* We want to search on next socket after receiving */
|
||||
@@ -295,7 +301,7 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
#endif /* SO_REUSE */
|
||||
} else {
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
if(reuse) {
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: freeing PBUF with reference counter set to %i\n", p->ref));
|
||||
pbuf_free(p);
|
||||
@@ -305,10 +311,10 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n"));
|
||||
|
||||
/* No match was found, send ICMP destination port unreachable unless
|
||||
destination address was broadcast/multicast. */
|
||||
destination address was broadcast/multicast. */
|
||||
|
||||
if (!ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) &&
|
||||
!ip_addr_ismulticast(&iphdr->dest)) {
|
||||
if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&
|
||||
!ip_addr_ismulticast(&iphdr->dest)) {
|
||||
|
||||
/* adjust pbuf pointer */
|
||||
p->payload = iphdr;
|
||||
@@ -326,6 +332,46 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
PERF_STOP("udp_input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data to a specified address using UDP.
|
||||
*
|
||||
* @param pcb UDP PCB used to send the data.
|
||||
* @param pbuf chain of pbuf's to be sent.
|
||||
* @param dst_ip Destination IP address.
|
||||
* @param dst_port Destination UDP port.
|
||||
*
|
||||
* If the PCB already has a remote address association, it will
|
||||
* be restored after the data is sent.
|
||||
*
|
||||
* @return lwIP error code.
|
||||
* - ERR_OK. Successful. No error occured.
|
||||
* - ERR_MEM. Out of memory.
|
||||
* - ERR_RTE. Could not find route to destination address.
|
||||
*
|
||||
* @see udp_disconnect() udp_send()
|
||||
*/
|
||||
err_t
|
||||
udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
|
||||
struct ip_addr *dst_ip, u16_t dst_port)
|
||||
{
|
||||
err_t err;
|
||||
struct ip_addr pcb_remote_ip;
|
||||
u16_t pcb_remote_port;
|
||||
/* remember 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 */
|
||||
pcb->remote_ip.addr = dst_ip->addr;
|
||||
pcb->remote_port = dst_port;
|
||||
/* send to the packet destination address */
|
||||
err = udp_send(pcb, p);
|
||||
/* reset PCB remote peer address */
|
||||
pcb->remote_ip.addr = pcb_remote_ip.addr;
|
||||
pcb->remote_port = pcb_remote_port;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data using UDP.
|
||||
*
|
||||
@@ -335,10 +381,9 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
* @return lwIP error code.
|
||||
* - ERR_OK. Successful. No error occured.
|
||||
* - ERR_MEM. Out of memory.
|
||||
* - ERR_USE. The specified ipaddr and port are already bound to by
|
||||
* another UDP PCB.
|
||||
* - ERR_RTE. Could not find route to destination address.
|
||||
*
|
||||
* @see udp_disconnect()
|
||||
* @see udp_disconnect() udp_sendto()
|
||||
*/
|
||||
err_t
|
||||
udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
@@ -363,7 +408,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
|
||||
/* not enough space to add an UDP header to first pbuf in given p chain? */
|
||||
if (pbuf_header(p, UDP_HLEN)) {
|
||||
/* allocate header in new pbuf */
|
||||
/* allocate header in a seperate new pbuf */
|
||||
q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
|
||||
/* new header pbuf could not be allocated? */
|
||||
if (q == NULL) {
|
||||
@@ -375,23 +420,25 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
/* { first pbuf q points to header pbuf } */
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
|
||||
/* adding a header within p succeeded */
|
||||
} else {
|
||||
} else {
|
||||
/* first pbuf q equals given pbuf */
|
||||
q = p;
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
|
||||
}
|
||||
/* { q now represents the packet to be sent */
|
||||
/* { q now represents the packet to be sent } */
|
||||
udphdr = q->payload;
|
||||
udphdr->src = htons(pcb->local_port);
|
||||
udphdr->dest = htons(pcb->remote_port);
|
||||
udphdr->chksum = 0x0000;
|
||||
/* in UDP, 0 checksum means 'no checksum' */
|
||||
udphdr->chksum = 0x0000;
|
||||
|
||||
/* find the outgoing network interface for this packet */
|
||||
if ((netif = ip_route(&(pcb->remote_ip))) == 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;
|
||||
}
|
||||
/* using IP_ANY_ADDR? */
|
||||
/* PCB local address is IP_ANY_ADDR? */
|
||||
if (ip_addr_isany(&pcb->local_ip)) {
|
||||
/* use outgoing network interface IP address as source address */
|
||||
src_ip = &(netif->ip_addr);
|
||||
@@ -408,34 +455,44 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
/* set UDP message length in UDP header */
|
||||
udphdr->len = htons(pcb->chksum_len);
|
||||
/* calculate checksum */
|
||||
#if CHECKSUM_GEN_UDP
|
||||
udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip),
|
||||
IP_PROTO_UDP, pcb->chksum_len);
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
|
||||
#else
|
||||
udphdr->chksum = 0x0000;
|
||||
#endif
|
||||
/* output to IP */
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
|
||||
err = ip_output_if (q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
|
||||
snmp_inc_udpoutdatagrams();
|
||||
/* UDP */
|
||||
} else {
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %u\n", q->tot_len));
|
||||
udphdr->len = htons(q->tot_len);
|
||||
/* calculate checksum */
|
||||
#if CHECKSUM_GEN_UDP
|
||||
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
|
||||
udphdr->chksum = inet_chksum_pseudo(q, src_ip, &pcb->remote_ip, IP_PROTO_UDP, q->tot_len);
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
|
||||
}
|
||||
#else
|
||||
udphdr->chksum = 0x0000;
|
||||
#endif
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04x\n", udphdr->chksum));
|
||||
snmp_inc_udpoutdatagrams();
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
|
||||
/* output to IP */
|
||||
err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
|
||||
}
|
||||
/* TODO: must this be increased even if error occured? */
|
||||
snmp_inc_udpoutdatagrams();
|
||||
|
||||
/* did we chain a header earlier? */
|
||||
/* did we chain a seperate header pbuf earlier? */
|
||||
if (q != p) {
|
||||
/* free the header */
|
||||
/* p is also still referenced by the caller, and will live on */
|
||||
pbuf_free(q);
|
||||
/* free the header pbuf */
|
||||
pbuf_free(q); q = NULL;
|
||||
/* { p is still referenced by the caller, and will live on } */
|
||||
}
|
||||
|
||||
UDP_STATS_INC(udp.xmit);
|
||||
@@ -462,7 +519,7 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
{
|
||||
struct udp_pcb *ipcb;
|
||||
u8_t rebind;
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
int reuse_port_all_set = 1;
|
||||
#endif /* SO_REUSE */
|
||||
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = "));
|
||||
@@ -480,7 +537,7 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
rebind = 1;
|
||||
}
|
||||
|
||||
#ifndef SO_REUSE
|
||||
#if SO_REUSE == 0
|
||||
/* this code does not allow upper layer to share a UDP port for
|
||||
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
|
||||
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
|
||||
@@ -534,7 +591,7 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
|
||||
}
|
||||
|
||||
#ifdef SO_REUSE
|
||||
#if SO_REUSE
|
||||
/* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then
|
||||
{IP, port} can't be reused. */
|
||||
if(!reuse_port_all_set) {
|
||||
@@ -647,6 +704,10 @@ udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
void
|
||||
udp_disconnect(struct udp_pcb *pcb)
|
||||
{
|
||||
/* reset remote address association */
|
||||
ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);
|
||||
pcb->remote_port = 0;
|
||||
/* mark PCB as unconnected */
|
||||
pcb->flags &= ~UDP_FLAGS_CONNECTED;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#define ICMP_ER 0 /* echo reply */
|
||||
|
||||
@@ -46,7 +46,7 @@ u16_t inet_chksum_pseudo(struct pbuf *p,
|
||||
|
||||
u32_t inet_addr(const char *cp);
|
||||
int inet_aton(const char *cp, struct in_addr *addr);
|
||||
u8_t *inet_ntoa(u32_t addr); /* returns ptr to static buffer; not reentrant! */
|
||||
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
|
||||
|
||||
#ifdef htons
|
||||
#undef htons
|
||||
|
||||
@@ -128,7 +128,7 @@ PACK_STRUCT_END
|
||||
|
||||
#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)
|
||||
|
||||
@@ -34,6 +34,40 @@
|
||||
|
||||
#include "lwip/arch.h"
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_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 {
|
||||
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 {
|
||||
u32_t s_addr;
|
||||
};
|
||||
|
||||
struct netif;
|
||||
|
||||
extern const struct ip_addr ip_addr_any;
|
||||
extern const struct ip_addr ip_addr_broadcast;
|
||||
|
||||
/** IP_ADDR_ can be used as a fixed IP address
|
||||
* for the wildcard and the broadcast address
|
||||
*/
|
||||
@@ -76,32 +110,13 @@
|
||||
|
||||
#define IN_LOOPBACKNET 127 /* official! */
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_addr {
|
||||
PACK_STRUCT_FIELD(u32_t addr);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* For compatibility with BSD code */
|
||||
struct in_addr {
|
||||
u32_t s_addr;
|
||||
};
|
||||
|
||||
extern const struct ip_addr ip_addr_any;
|
||||
extern const struct ip_addr ip_addr_broadcast;
|
||||
|
||||
#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = htonl(((u32_t)(a & 0xff) << 24) | ((u32_t)(b & 0xff) << 16) | \
|
||||
((u32_t)(c & 0xff) << 8) | (u32_t)(d & 0xff))
|
||||
|
||||
#define ip_addr_set(dest, src) (dest)->addr = \
|
||||
((src) == NULL? 0:\
|
||||
((struct ip_addr *)src)->addr)
|
||||
(src)->addr)
|
||||
#define ip_addr_maskcmp(addr1, addr2, mask) (((addr1)->addr & \
|
||||
(mask)->addr) == \
|
||||
((addr2)->addr & \
|
||||
@@ -110,10 +125,7 @@ extern const struct ip_addr ip_addr_broadcast;
|
||||
|
||||
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)
|
||||
|
||||
#define ip_addr_isbroadcast(addr1, mask) (((((addr1)->addr) & ~((mask)->addr)) == \
|
||||
(0xffffffff & ~((mask)->addr))) || \
|
||||
((addr1)->addr == 0xffffffff) || \
|
||||
((addr1)->addr == 0x00000000))
|
||||
u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
|
||||
|
||||
#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000)) == ntohl(0xe0000000))
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,38 +1,6 @@
|
||||
/** @file
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LWIP_DHCP_H__
|
||||
#define __LWIP_DHCP_H__
|
||||
|
||||
@@ -75,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) */
|
||||
@@ -102,10 +74,10 @@ struct dhcp_msg
|
||||
PACK_STRUCT_FIELD(u32_t xid);
|
||||
PACK_STRUCT_FIELD(u16_t secs);
|
||||
PACK_STRUCT_FIELD(u16_t flags);
|
||||
PACK_STRUCT_FIELD(u32_t ciaddr);
|
||||
PACK_STRUCT_FIELD(u32_t yiaddr);
|
||||
PACK_STRUCT_FIELD(u32_t siaddr);
|
||||
PACK_STRUCT_FIELD(u32_t giaddr);
|
||||
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
|
||||
PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
|
||||
#define DHCP_SNAME_LEN 64U
|
||||
@@ -206,7 +178,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
|
||||
|
||||
@@ -59,6 +59,7 @@ typedef s8_t err_t;
|
||||
#define ERR_USE -10 /* Address in use. */
|
||||
|
||||
#define ERR_IF -11 /* Low-level netif error */
|
||||
#define ERR_ISCONN -12 /* Already connected. */
|
||||
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/dhcp.h"
|
||||
#if LWIP_DHCP
|
||||
# include "lwip/dhcp.h"
|
||||
#endif
|
||||
|
||||
/** must be the maximum of all used hardware address lengths
|
||||
across all types of interfaces in use */
|
||||
@@ -50,7 +52,8 @@
|
||||
|
||||
/** whether the network interface is 'up'. this is
|
||||
* a software flag used to control whether this network
|
||||
* interface is enabled and processes traffic */
|
||||
* interface is enabled and processes traffic.
|
||||
*/
|
||||
#define NETIF_FLAG_UP 0x1U
|
||||
/** if set, the netif has broadcast capability */
|
||||
#define NETIF_FLAG_BROADCAST 0x2U
|
||||
@@ -59,35 +62,36 @@
|
||||
/** if set, the interface is configured using DHCP */
|
||||
#define NETIF_FLAG_DHCP 0x08U
|
||||
/** if set, the interface has an active link
|
||||
* (set by the interface) */
|
||||
* (set by the network interface driver) */
|
||||
#define NETIF_FLAG_LINK_UP 0x10U
|
||||
|
||||
/** generic data structure used for all lwIP network interfaces */
|
||||
/** Generic data structure used for all lwIP network interfaces.
|
||||
* The following fields should be filled in by the initialization
|
||||
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
|
||||
|
||||
struct netif {
|
||||
/** pointer to next in linked list */
|
||||
struct netif *next;
|
||||
/** The following fields should be filled in by the
|
||||
initialization function for the device driver. */
|
||||
|
||||
|
||||
/** IP address configuration in network byte order */
|
||||
struct ip_addr ip_addr;
|
||||
struct ip_addr netmask;
|
||||
struct ip_addr gw;
|
||||
|
||||
/** This function is called by the network device driver
|
||||
to pass a packet up the TCP/IP stack. */
|
||||
* to pass a packet up the TCP/IP stack. */
|
||||
err_t (* input)(struct pbuf *p, struct netif *inp);
|
||||
/** This function is called by the IP module when it wants
|
||||
to send a packet on the interface. This function typically
|
||||
first resolves the hardware address, then sends the packet. */
|
||||
* to send a packet on the interface. This function typically
|
||||
* first resolves the hardware address, then sends the packet. */
|
||||
err_t (* output)(struct netif *netif, struct pbuf *p,
|
||||
struct ip_addr *ipaddr);
|
||||
/** This function is called by the ARP module when it wants
|
||||
to send a packet on the interface. This function outputs
|
||||
the pbuf as-is on the link medium. */
|
||||
* to send a packet on the interface. This function outputs
|
||||
* the pbuf as-is on the link medium. */
|
||||
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
|
||||
/** This field can be set by the device driver and could point
|
||||
to state information for the device. */
|
||||
* to state information for the device. */
|
||||
void *state;
|
||||
#if LWIP_DHCP
|
||||
/** the DHCP client state information for this netif */
|
||||
@@ -99,12 +103,14 @@ struct netif {
|
||||
unsigned char hwaddr[NETIF_MAX_HWADDR_LEN];
|
||||
/** maximum transfer unit (in bytes) */
|
||||
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 */
|
||||
u8_t num;
|
||||
/** NETIF_FLAG_* */
|
||||
u8_t flags;
|
||||
};
|
||||
|
||||
/** The list of network interfaces. */
|
||||
@@ -137,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__ */
|
||||
|
||||
@@ -67,6 +67,10 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
#define MEM_SIZE 1600
|
||||
#endif
|
||||
|
||||
#ifndef MEMP_SANITY_CHECK
|
||||
#define MEMP_SANITY_CHECK 0
|
||||
#endif
|
||||
|
||||
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
|
||||
sends a lot of data out of ROM (or other static memory), this
|
||||
should be set high. */
|
||||
@@ -142,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
|
||||
|
||||
|
||||
@@ -164,21 +168,15 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
#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
|
||||
/**
|
||||
* If defined to 1, cache entries are updated or added for every kind of ARP traffic
|
||||
* or broadcast IP traffic. Recommended for routers.
|
||||
* If defined to 0, only existing cache entries are updated. Entries are added when
|
||||
* lwIP is sending to them. Recommended for embedded devices.
|
||||
*/
|
||||
#ifndef ETHARP_ALWAYS_INSERT
|
||||
#define ETHARP_ALWAYS_INSERT 1
|
||||
|
||||
/* This option is removed to comply with the ARP standard */
|
||||
#ifdef ETHARP_ALWAYS_INSERT
|
||||
#error ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h.
|
||||
#endif
|
||||
|
||||
/* ---------- IP options ---------- */
|
||||
@@ -218,6 +216,10 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
|
||||
/* ---------- RAW options ---------- */
|
||||
|
||||
#ifndef LWIP_RAW
|
||||
#define LWIP_RAW 1
|
||||
#endif
|
||||
|
||||
#ifndef RAW_TTL
|
||||
#define RAW_TTL 255
|
||||
#endif
|
||||
@@ -348,6 +350,10 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
|
||||
#if LWIP_STATS
|
||||
|
||||
#ifndef LWIP_STATS_DISPLAY
|
||||
#define LWIP_STATS_DISPLAY 0
|
||||
#endif
|
||||
|
||||
#ifndef LINK_STATS
|
||||
#define LINK_STATS 1
|
||||
#endif
|
||||
@@ -405,6 +411,7 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
#define PBUF_STATS 0
|
||||
#define SYS_STATS 0
|
||||
#define RAW_STATS 0
|
||||
#define LWIP_STATS_DISPLAY 0
|
||||
|
||||
#endif /* LWIP_STATS */
|
||||
|
||||
@@ -495,6 +502,31 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
|
||||
#endif /* PPP_SUPPORT */
|
||||
|
||||
/* checksum options - set to zero for hardware checksum support */
|
||||
|
||||
#ifndef CHECKSUM_GEN_IP
|
||||
#define CHECKSUM_GEN_IP 1
|
||||
#endif
|
||||
|
||||
#ifndef CHECKSUM_GEN_UDP
|
||||
#define CHECKSUM_GEN_UDP 1
|
||||
#endif
|
||||
|
||||
#ifndef CHECKSUM_GEN_TCP
|
||||
#define CHECKSUM_GEN_TCP 1
|
||||
#endif
|
||||
|
||||
#ifndef CHECKSUM_CHECK_IP
|
||||
#define CHECKSUM_CHECK_IP 1
|
||||
#endif
|
||||
|
||||
#ifndef CHECKSUM_CHECK_UDP
|
||||
#define CHECKSUM_CHECK_UDP 1
|
||||
#endif
|
||||
|
||||
#ifndef CHECKSUM_CHECK_TCP
|
||||
#define CHECKSUM_CHECK_TCP 1
|
||||
#endif
|
||||
|
||||
/* Debugging options all default to off */
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@ typedef enum {
|
||||
PBUF_POOL
|
||||
} pbuf_flag;
|
||||
|
||||
/* Definitions for the pbuf flag field (these are not the flags that
|
||||
are passed to pbuf_alloc()). */
|
||||
/* Definitions for the pbuf flag field. These are NOT the flags that
|
||||
* are passed to pbuf_alloc(). */
|
||||
#define PBUF_FLAG_RAM 0x00U /* Flags that pbuf data is stored in RAM */
|
||||
#define PBUF_FLAG_ROM 0x01U /* Flags that pbuf data is stored in ROM */
|
||||
#define PBUF_FLAG_POOL 0x02U /* Flags that the pbuf comes from the pbuf pool */
|
||||
@@ -79,10 +79,10 @@ struct pbuf {
|
||||
*/
|
||||
u16_t tot_len;
|
||||
|
||||
/* length of this buffer */
|
||||
/** length of this buffer */
|
||||
u16_t len;
|
||||
|
||||
/* flags telling the type of pbuf */
|
||||
/** flags telling the type of pbuf, see PBUF_FLAG_ */
|
||||
u16_t flags;
|
||||
|
||||
/**
|
||||
@@ -94,11 +94,6 @@ struct pbuf {
|
||||
|
||||
};
|
||||
|
||||
/* pbuf_init():
|
||||
|
||||
Initializes the pbuf module. The num parameter determines how many
|
||||
pbufs that should be allocated to the pbuf pool, and the size
|
||||
parameter specifies the size of the data allocated to those. */
|
||||
void pbuf_init(void);
|
||||
|
||||
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag);
|
||||
@@ -112,5 +107,7 @@ void pbuf_cat(struct pbuf *h, struct pbuf *t);
|
||||
void pbuf_chain(struct pbuf *h, struct pbuf *t);
|
||||
struct pbuf *pbuf_take(struct pbuf *f);
|
||||
struct pbuf *pbuf_dechain(struct pbuf *p);
|
||||
void pbuf_queue(struct pbuf *p, struct pbuf *n);
|
||||
struct pbuf * pbuf_dequeue(struct pbuf *p);
|
||||
|
||||
#endif /* __LWIP_PBUF_H__ */
|
||||
|
||||
@@ -46,7 +46,7 @@ struct raw_pcb {
|
||||
|
||||
u16_t protocol;
|
||||
|
||||
int (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
|
||||
u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
|
||||
struct ip_addr *addr);
|
||||
void *recv_arg;
|
||||
};
|
||||
@@ -59,15 +59,15 @@ err_t raw_bind (struct raw_pcb *pcb, struct ip_addr *ipaddr);
|
||||
err_t raw_connect (struct raw_pcb *pcb, struct ip_addr *ipaddr);
|
||||
|
||||
void raw_recv (struct raw_pcb *pcb,
|
||||
int (* recv)(void *arg, struct raw_pcb *pcb,
|
||||
u8_t (* recv)(void *arg, struct raw_pcb *pcb,
|
||||
struct pbuf *p,
|
||||
struct ip_addr *addr),
|
||||
void *recv_arg);
|
||||
err_t raw_send_to (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);
|
||||
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);
|
||||
err_t raw_send (struct raw_pcb *pcb, struct pbuf *p);
|
||||
|
||||
/* The following functions are the lower layer interface to RAW. */
|
||||
int raw_input (struct pbuf *p, struct netif *inp);
|
||||
u8_t raw_input (struct pbuf *p, struct netif *inp);
|
||||
void raw_init (void);
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
|
||||
* Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.
|
||||
* Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>
|
||||
* Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
@@ -205,10 +205,20 @@ struct linger {
|
||||
unsigned char fd_bits [(FD_SETSIZE+7)/8];
|
||||
} fd_set;
|
||||
|
||||
/*
|
||||
* only define this in sockets.c so it does not interfere
|
||||
* with other projects namespaces where timeval is present
|
||||
*/
|
||||
#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 */
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -144,6 +144,13 @@ void stats_init(void);
|
||||
#define LINK_STATS_INC(x)
|
||||
#endif
|
||||
|
||||
/* Display of statistics */
|
||||
#if LWIP_STATS_DISPLAY
|
||||
void stats_display(void);
|
||||
#else
|
||||
#define stats_display()
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_STATS_H__ */
|
||||
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/icmp.h"
|
||||
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
struct tcp_pcb;
|
||||
@@ -107,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);
|
||||
|
||||
|
||||
|
||||
@@ -114,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
|
||||
@@ -377,7 +380,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)))
|
||||
@@ -457,7 +460,11 @@ void tcp_timer_needed(void);
|
||||
#endif
|
||||
|
||||
/* The TCP PCB lists. */
|
||||
extern struct tcp_pcb_listen *tcp_listen_pcbs; /* List of all TCP PCBs in LISTEN state. */
|
||||
union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */
|
||||
struct tcp_pcb_listen *listen_pcbs;
|
||||
struct tcp_pcb *pcbs;
|
||||
};
|
||||
extern union tcp_listen_pcbs_t tcp_listen_pcbs;
|
||||
extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a
|
||||
state in which they accept or send
|
||||
data. */
|
||||
|
||||
@@ -84,12 +84,12 @@ void udp_recv (struct udp_pcb *pcb,
|
||||
struct ip_addr *addr,
|
||||
u16_t port),
|
||||
void *recv_arg);
|
||||
err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port);
|
||||
err_t udp_send (struct udp_pcb *pcb, struct pbuf *p);
|
||||
|
||||
#define udp_flags(pcb) ((pcb)->flags)
|
||||
#define udp_setflags(pcb, f) ((pcb)->flags = (f))
|
||||
|
||||
|
||||
/* The following functions are the lower layer interface to UDP. */
|
||||
void udp_input (struct pbuf *p, struct netif *inp);
|
||||
void udp_init (void);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
|
||||
* Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -33,6 +35,10 @@
|
||||
#ifndef __NETIF_ETHARP_H__
|
||||
#define __NETIF_ETHARP_H__
|
||||
|
||||
#ifndef ETH_PAD_SIZE
|
||||
#define ETH_PAD_SIZE 0
|
||||
#endif
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
@@ -46,15 +52,30 @@ struct eth_addr {
|
||||
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
|
||||
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
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
/** the ARP message */
|
||||
struct etharp_hdr {
|
||||
@@ -64,17 +85,24 @@ struct etharp_hdr {
|
||||
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_addr sipaddr);
|
||||
PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
|
||||
PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
|
||||
PACK_STRUCT_FIELD(struct ip_addr dipaddr);
|
||||
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 {
|
||||
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
|
||||
@@ -86,13 +114,12 @@ struct ethip_hdr {
|
||||
|
||||
void etharp_init(void);
|
||||
void etharp_tmr(void);
|
||||
struct pbuf *etharp_ip_input(struct netif *netif, struct pbuf *p);
|
||||
struct pbuf *etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
|
||||
void etharp_ip_input(struct netif *netif, struct pbuf *p);
|
||||
void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
|
||||
struct pbuf *p);
|
||||
struct pbuf *etharp_output(struct netif *netif, struct ip_addr *ipaddr,
|
||||
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__ */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2001, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,8 +35,6 @@
|
||||
* drivers for lwIP. Add code to the low_level functions and do a
|
||||
* search-and-replace for the word "ethernetif" to replace it with
|
||||
* something that better describes your network interface.
|
||||
*
|
||||
* THIS CODE NEEDS TO BE FIXED - IT IS NOT In SYNC WITH CURRENT ETHARP API
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
@@ -45,11 +43,11 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "netif/arp.h"
|
||||
#include "netif/etharp.h"
|
||||
|
||||
/* Define those to better describe your network interface. */
|
||||
#define IFNAME0 'e'
|
||||
#define IFNAME1 't'
|
||||
#define IFNAME1 'n'
|
||||
|
||||
struct ethernetif {
|
||||
struct eth_addr *ethaddr;
|
||||
@@ -63,13 +61,10 @@ static void ethernetif_input(struct netif *netif);
|
||||
static err_t ethernetif_output(struct netif *netif, struct pbuf *p,
|
||||
struct ip_addr *ipaddr);
|
||||
|
||||
|
||||
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;
|
||||
@@ -77,7 +72,7 @@ low_level_init(struct netif *netif)
|
||||
/* set MAC hardware address */
|
||||
netif->hwaddr[0] = ;
|
||||
...
|
||||
netif->hwaddr[6] = ;
|
||||
netif->hwaddr[5] = ;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
@@ -97,14 +92,18 @@ 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();
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
|
||||
#endif
|
||||
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
/* Send the data from the pbuf to the interface, one pbuf at a
|
||||
time. The size of the data in each pbuf is kept in the ->len
|
||||
@@ -113,6 +112,10 @@ low_level_output(struct ethernetif *ethernetif, struct pbuf *p)
|
||||
}
|
||||
|
||||
signal that packet should be sent();
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
|
||||
#ifdef LINK_STATS
|
||||
lwip_stats.link.xmit++;
|
||||
@@ -130,8 +133,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;
|
||||
|
||||
@@ -139,19 +143,33 @@ low_level_input(struct ethernetif *ethernetif)
|
||||
variable. */
|
||||
len = ;
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
|
||||
#endif
|
||||
|
||||
/* We allocate a pbuf chain of pbufs from the pool. */
|
||||
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
||||
|
||||
if (p != NULL) {
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
|
||||
#endif
|
||||
|
||||
/* We iterate over the pbuf chain until we have read the entire
|
||||
packet into the pbuf. */
|
||||
* packet into the pbuf. */
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
/* Read enough bytes to fill this pbuf in the chain. The
|
||||
available data in the pbuf is given by the q->len
|
||||
variable. */
|
||||
* available data in the pbuf is given by the q->len
|
||||
* variable. */
|
||||
read data into(q->payload, q->len);
|
||||
}
|
||||
acknowledge that packet has been read();
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
|
||||
#ifdef LINK_STATS
|
||||
lwip_stats.link.recv++;
|
||||
#endif /* LINK_STATS */
|
||||
@@ -171,7 +189,7 @@ low_level_input(struct ethernetif *ethernetif)
|
||||
*
|
||||
* This function is called by the TCP/IP stack when an IP packet
|
||||
* should be sent. It calls the function called low_level_output() to
|
||||
* do the actuall transmission of the packet.
|
||||
* do the actual transmission of the packet.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -179,90 +197,10 @@ static err_t
|
||||
ethernetif_output(struct netif *netif, struct pbuf *p,
|
||||
struct ip_addr *ipaddr)
|
||||
{
|
||||
struct ethernetif *ethernetif;
|
||||
struct pbuf *q;
|
||||
struct eth_hdr *ethhdr;
|
||||
struct eth_addr *dest, mcastaddr;
|
||||
struct ip_addr *queryaddr;
|
||||
err_t err;
|
||||
u8_t i;
|
||||
|
||||
ethernetif = netif->state;
|
||||
|
||||
/* Make room for Ethernet header. */
|
||||
if (pbuf_header(p, 14) != 0) {
|
||||
/* The pbuf_header() call shouldn't fail, but we allocate an extra
|
||||
pbuf just in case. */
|
||||
q = pbuf_alloc(PBUF_LINK, 14, PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
#ifdef LINK_STATS
|
||||
lwip_stats.link.drop++;
|
||||
lwip_stats.link.memerr++;
|
||||
#endif /* LINK_STATS */
|
||||
return ERR_MEM;
|
||||
}
|
||||
pbuf_chain(q, p);
|
||||
p = q;
|
||||
}
|
||||
|
||||
/* Construct Ethernet header. Start with looking up deciding which
|
||||
MAC address to use as a destination address. Broadcasts and
|
||||
multicasts are special, all other addresses are looked up in the
|
||||
ARP table. */
|
||||
queryaddr = ipaddr;
|
||||
if (ip_addr_isany(ipaddr) ||
|
||||
ip_addr_isbroadcast(ipaddr, &(netif->netmask))) {
|
||||
dest = (struct eth_addr *)ðbroadcast;
|
||||
} else if (ip_addr_ismulticast(ipaddr)) {
|
||||
/* Hash IP multicast address to MAC address. */
|
||||
mcastaddr.addr[0] = 0x01;
|
||||
mcastaddr.addr[1] = 0x0;
|
||||
mcastaddr.addr[2] = 0x5e;
|
||||
mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
|
||||
mcastaddr.addr[4] = ip4_addr3(ipaddr);
|
||||
mcastaddr.addr[5] = ip4_addr4(ipaddr);
|
||||
dest = &mcastaddr;
|
||||
} else {
|
||||
|
||||
if (ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
|
||||
/* Use destination IP address if the destination is on the same
|
||||
subnet as we are. */
|
||||
queryaddr = ipaddr;
|
||||
} else {
|
||||
/* Otherwise we use the default router as the address to send
|
||||
the Ethernet frame to. */
|
||||
queryaddr = &(netif->gw);
|
||||
}
|
||||
dest = arp_lookup(queryaddr);
|
||||
}
|
||||
|
||||
|
||||
/* If the arp_lookup() didn't find an address, we send out an ARP
|
||||
query for the IP address. */
|
||||
if (dest == NULL) {
|
||||
q = arp_query(netif, ethernetif->ethaddr, queryaddr);
|
||||
if (q != NULL) {
|
||||
err = low_level_output(ethernetif, q);
|
||||
pbuf_free(q);
|
||||
return err;
|
||||
}
|
||||
#ifdef LINK_STATS
|
||||
lwip_stats.link.drop++;
|
||||
lwip_stats.link.memerr++;
|
||||
#endif /* LINK_STATS */
|
||||
return ERR_MEM;
|
||||
}
|
||||
ethhdr = p->payload;
|
||||
|
||||
for(i = 0; i < 6; i++) {
|
||||
ethhdr->dest.addr[i] = dest->addr[i];
|
||||
ethhdr->src.addr[i] = ethernetif->ethaddr->addr[i];
|
||||
}
|
||||
|
||||
ethhdr->type = htons(ETHTYPE_IP);
|
||||
|
||||
return low_level_output(ethernetif, p);
|
||||
|
||||
/* resolve hardware address, then send (or queue) packet */
|
||||
return etharp_output(netif, ipaddr, p);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -282,43 +220,47 @@ ethernetif_input(struct netif *netif)
|
||||
struct eth_hdr *ethhdr;
|
||||
struct pbuf *p;
|
||||
|
||||
|
||||
ethernetif = netif->state;
|
||||
|
||||
p = low_level_input(ethernetif);
|
||||
|
||||
if (p != NULL) {
|
||||
/* move received packet into a new pbuf */
|
||||
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
|
||||
lwip_stats.link.recv++;
|
||||
lwip_stats.link.recv++;
|
||||
#endif /* LINK_STATS */
|
||||
|
||||
ethhdr = p->payload;
|
||||
ethhdr = p->payload;
|
||||
|
||||
switch (htons(ethhdr->type)) {
|
||||
case ETHTYPE_IP:
|
||||
arp_ip_input(netif, p);
|
||||
pbuf_header(p, -14);
|
||||
netif->input(p, netif);
|
||||
break;
|
||||
switch (htons(ethhdr->type)) {
|
||||
/* IP packet? */
|
||||
case ETHTYPE_IP:
|
||||
/* update ARP table */
|
||||
etharp_ip_input(netif, p);
|
||||
/* skip Ethernet header */
|
||||
pbuf_header(p, -sizeof(struct eth_hdr));
|
||||
/* pass to network layer */
|
||||
netif->input(p, netif);
|
||||
break;
|
||||
|
||||
case ETHTYPE_ARP:
|
||||
p = arp_arp_input(netif, ethernetif->ethaddr, p);
|
||||
if (p != NULL) {
|
||||
low_level_output(ethernetif, p);
|
||||
pbuf_free(p);
|
||||
}
|
||||
/* pass p to ARP module */
|
||||
etharp_arp_input(netif, ethernetif->ethaddr, p);
|
||||
break;
|
||||
default:
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
arp_timer(void *arg)
|
||||
{
|
||||
arp_tmr();
|
||||
etharp_tmr();
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
}
|
||||
|
||||
@@ -331,12 +273,19 @@ arp_timer(void *arg)
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
err_t
|
||||
ethernetif_init(struct netif *netif)
|
||||
{
|
||||
struct ethernetif *ethernetif;
|
||||
|
||||
ethernetif = mem_malloc(sizeof(struct ethernetif));
|
||||
|
||||
if (ethernetif == NULL)
|
||||
{
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
netif->state = ethernetif;
|
||||
netif->name[0] = IFNAME0;
|
||||
netif->name[1] = IFNAME1;
|
||||
@@ -346,8 +295,11 @@ ethernetif_init(struct netif *netif)
|
||||
ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
|
||||
|
||||
low_level_init(netif);
|
||||
arp_init();
|
||||
|
||||
etharp_init();
|
||||
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* $Id: chpms.h,v 1.1.6.1 2003/09/02 12:00:48 jani Exp $
|
||||
* $Id: chpms.h,v 1.3 2004/02/07 00:30:03 likewise Exp $
|
||||
*/
|
||||
|
||||
#ifndef CHPMS_H
|
||||
|
||||
@@ -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"
|
||||
@@ -178,6 +180,20 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
|
||||
/*** LOCAL FUNCTION DEFINITIONS ***/
|
||||
/**********************************/
|
||||
|
||||
/*
|
||||
* Non-standard inet_ntoa left here for compat with original ppp
|
||||
* sources. Assumes u32_t instead of struct in_addr.
|
||||
*/
|
||||
|
||||
char * _inet_ntoa(u32_t n)
|
||||
{
|
||||
struct in_addr ia;
|
||||
ia.s_addr = n;
|
||||
return inet_ntoa(ia);
|
||||
}
|
||||
|
||||
#define inet_ntoa _inet_ntoa
|
||||
|
||||
/*
|
||||
* ipcp_init - Initialize IPCP.
|
||||
*/
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Definitions for tcp compression routines.
|
||||
*
|
||||
* $Id: vj.h,v 1.2.6.1 2003/10/28 11:44:45 jani Exp $
|
||||
* $Id: vj.h,v 1.4 2004/02/07 00:30:03 likewise Exp $
|
||||
*
|
||||
* Copyright (c) 1989 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
|
||||
@@ -199,6 +199,7 @@ slipif_init(struct netif *netif)
|
||||
netif->name[1] = 'l';
|
||||
netif->output = slipif_output;
|
||||
netif->mtu = 1500;
|
||||
netif->flags = NETIF_FLAG_POINTTOPOINT;
|
||||
|
||||
netif->state = sio_open(netif->num);
|
||||
if (!netif->state)
|
||||
|
||||
Reference in New Issue
Block a user