Compare commits
57 Commits
STABLE-1_0
...
STABLE-1_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec0c2bea6e | ||
|
|
1b3682cfa9 | ||
|
|
2a9ee35411 | ||
|
|
0e0a7d82de | ||
|
|
dfa96852f0 | ||
|
|
a549ec0382 | ||
|
|
c61f01b206 | ||
|
|
15257f4524 | ||
|
|
089378ef87 | ||
|
|
805f495d84 | ||
|
|
928dd94ba6 | ||
|
|
b429918b32 | ||
|
|
62a37a4876 | ||
|
|
0e96ece6c6 | ||
|
|
f1eca32536 | ||
|
|
ed59dc1ada | ||
|
|
a5cd3fcafd | ||
|
|
f3def542ee | ||
|
|
aa249922df | ||
|
|
37a0c57bed | ||
|
|
90b7e68b4e | ||
|
|
1a0c497007 | ||
|
|
fd49ee3c8d | ||
|
|
3488a5c3c4 | ||
|
|
ae4955f59e | ||
|
|
fab107a9df | ||
|
|
bb87d19e84 | ||
|
|
4e309b7992 | ||
|
|
64aa4c716d | ||
|
|
6b0852a21f | ||
|
|
8afd3e882e | ||
|
|
791fa28817 | ||
|
|
3fab752640 | ||
|
|
67dd939d83 | ||
|
|
ec9b447be1 | ||
|
|
99e3fe9ae1 | ||
|
|
eb99d21022 | ||
|
|
793cbcdff8 | ||
|
|
751557bcbf | ||
|
|
252dcd8626 | ||
|
|
0ad7ea16d2 | ||
|
|
79842d4fdd | ||
|
|
1e1f5d5462 | ||
|
|
19d8ffe177 | ||
|
|
4cb8192c1d | ||
|
|
2ed5bc5195 | ||
|
|
fae1397468 | ||
|
|
e871548772 | ||
|
|
a3d27e30e0 | ||
|
|
89abd1f58e | ||
|
|
fae709d9ea | ||
|
|
36df79b207 | ||
|
|
b9ebcd7738 | ||
|
|
515fb5a3fd | ||
|
|
785f90d9fa | ||
|
|
22ac311496 | ||
|
|
0e31ca73c0 |
75
CHANGELOG
75
CHANGELOG
@@ -5,16 +5,89 @@ FUTURE
|
||||
problems with exoteric (/DSP) architectures showing these problems.
|
||||
We still have to fix some of these issues neatly.
|
||||
|
||||
* TODO: the ARP layer is not protected against concurrent access. If
|
||||
you run from a multitasking OS, serialize access to ARP (called from
|
||||
your network device driver and from a timeout thread.)
|
||||
|
||||
HISTORY
|
||||
|
||||
(HEAD)
|
||||
|
||||
2004-12-28 Leon Woestenberg <leon.woestenberg@gmx.net>
|
||||
* etharp.*: Disabled multiple packets on the ARP queue.
|
||||
This clashes with TCP queueing.
|
||||
|
||||
2004-11-28 Leon Woestenberg <leon.woestenberg@gmx.net>
|
||||
* etharp.*: Fixed race condition from ARP request to ARP timeout.
|
||||
Halved the ARP period, doubled the period counts.
|
||||
ETHARP_MAX_PENDING now should be at least 2. This prevents
|
||||
the counter from reaching 0 right away (which would allow
|
||||
too little time for ARP responses to be received).
|
||||
|
||||
2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net>
|
||||
* dhcp.c: Decline messages were not multicast but unicast.
|
||||
* etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD.
|
||||
Do not try hard to insert arbitrary packet's source address,
|
||||
etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD.
|
||||
etharp_query() now always DOES call ETHARP_TRY_HARD so that users
|
||||
querying an address will see it appear in the cache (DHCP could
|
||||
suffer from this when a server invalidly gave an in-use address.)
|
||||
* ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are
|
||||
comparing network addresses (identifiers), not the network masks
|
||||
themselves.
|
||||
* ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given
|
||||
IP address actually belongs to the network of the given interface.
|
||||
|
||||
2004-11-24 Kieran Mansley <kjm25@cam.ac.uk>
|
||||
* tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state.
|
||||
|
||||
(STABLE-1_1_0-RC1)
|
||||
|
||||
2004-10-16 Kieran Mansley <kjm25@cam.ac.uk>
|
||||
* tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately,
|
||||
even if one is already pending, if the rcv_wnd is above a threshold
|
||||
(currently TCP_WND/2). This avoids waiting for a timer to expire to send a
|
||||
delayed ACK in order to open the window if the stack is only receiving data.
|
||||
|
||||
2004-09-12 Kieran Mansley <kjm25@cam.ac.uk>
|
||||
* tcp*.*: Retransmit time-out handling improvement by Sam Jansen.
|
||||
|
||||
2004-08-20 Tony Mountifield <tony@softins.co.uk>
|
||||
* etharp.c: Make sure the first pbuf queued on an ARP entry
|
||||
is properly ref counted.
|
||||
|
||||
2004-07-27 Tony Mountifield <tony@softins.co.uk>
|
||||
* debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler
|
||||
warnings about comparison.
|
||||
* pbuf.c: Stopped compiler complaining of empty if statement
|
||||
when LWIP_DEBUGF() empty. Closed an unclosed comment.
|
||||
* tcp.c: Stopped compiler complaining of empty if statement
|
||||
when LWIP_DEBUGF() empty.
|
||||
* ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons().
|
||||
* inet.c: Added a couple of casts to quiet the compiler.
|
||||
No need to test isascii(c) before isdigit(c) or isxdigit(c).
|
||||
|
||||
2004-07-22 Tony Mountifield <tony@softins.co.uk>
|
||||
* inet.c: Made data types consistent in inet_ntoa().
|
||||
Added casts for return values of checksum routines, to pacify compiler.
|
||||
* ip_frag.c, tcp_out.c, sockets.c, pbuf.c
|
||||
Small corrections to some debugging statements, to pacify compiler.
|
||||
|
||||
2004-07-21 Tony Mountifield <tony@softins.co.uk>
|
||||
* etharp.c: Removed spurious semicolon and added missing end-of-comment.
|
||||
* ethernetif.c Updated low_level_output() to match prototype for
|
||||
netif->linkoutput and changed low_level_input() similarly for consistency.
|
||||
* api_msg.c: Changed recv_raw() from int to u8_t, to match prototype
|
||||
of raw_recv() in raw.h and so avoid compiler error.
|
||||
* sockets.c: Added trivial (int) cast to keep compiler happier.
|
||||
* ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros.
|
||||
|
||||
(STABLE-1_0_0)
|
||||
|
||||
++ Changes:
|
||||
|
||||
2004-07-05 Leon Woestenberg <leon.woestenberg@gmx.net>
|
||||
* sockets.* Restructured LWIP_PRIVATE_TIMEVAL. Make sure
|
||||
* 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.
|
||||
|
||||
@@ -27,7 +27,7 @@ features of Savannah help us not lose users' input.
|
||||
|
||||
1. JavaDoc compliant and Doxygen compatible.
|
||||
2. Function documentation above functions in .c files, not .h files.
|
||||
(This forces you to synchronize documentation and behaviour.)
|
||||
(This forces you to synchronize documentation and implementation.)
|
||||
3. Use current documentation style as further reference.
|
||||
|
||||
2.3 Bug reports and patches:
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
Raw TCP/IP interface for lwIP 0.5
|
||||
Raw TCP/IP interface for lwIP
|
||||
|
||||
Author: Adam Dunkels
|
||||
Authors: Adam Dunkels, Leon Woestenberg
|
||||
|
||||
lwIP provides two Application Program's Interfaces (APIs) for programs
|
||||
to use for communication with the TCP/IP code: the sequential API
|
||||
(often just called "the API") and the raw TCP/IP interface. This
|
||||
document is intended as a description of the latter. For lwIP versions
|
||||
lower than 0.5, this API was not documented.
|
||||
to use for communication with the TCP/IP code:
|
||||
* low-level "core" / "callback" or "raw" API.
|
||||
* higher-level "sequential" API.
|
||||
|
||||
The sequential API provides a way for ordinary, sequential, programs
|
||||
to use the lwIP stack. It is quite similar to the BSD socket API. The
|
||||
model of execution is based on the open-read-write-close
|
||||
model of execution is based on the blocking open-read-write-close
|
||||
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
|
||||
code and the application program must reside in different execution
|
||||
contexts (threads).
|
||||
|
||||
** The remainder of this document discusses the "raw" API. **
|
||||
|
||||
The raw TCP/IP interface allows the application program to integrate
|
||||
better with the TCP/IP code. Program execution is event based by
|
||||
having callback functions being called from within the TCP/IP
|
||||
@@ -34,7 +35,6 @@ Both APIs can be used simultaneously by different application
|
||||
programs. In fact, the sequential API is implemented as an application
|
||||
program using the raw TCP/IP interface.
|
||||
|
||||
|
||||
--- Callbacks
|
||||
|
||||
Program execution is driven by callbacks. Each callback is an ordinary
|
||||
|
||||
@@ -115,40 +115,16 @@ tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
|
||||
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
|
||||
zip -r lwip-0.6.3.zip lwip-0.6.3
|
||||
|
||||
First, make a local release directory to work in, I use "lwip-releases":
|
||||
Now, sign the archives with a detached GPG binary signature as follows:
|
||||
|
||||
mkdir lwip-releases
|
||||
cd lwip-releases
|
||||
gpg -b lwip-0.6.3.tar.gz
|
||||
gpg -b lwip-0.6.3.tar.bz2
|
||||
gpg -b lwip-0.6.3.zip
|
||||
|
||||
Now, make a new release by creating a new directory for it (these are
|
||||
Savannah conventions so that it shows up in the Files list real nice):
|
||||
Upload these files using anonymous FTP:
|
||||
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
|
||||
|
||||
mkdir stable.pkg
|
||||
mkdir stable.pkg 0.6.3
|
||||
|
||||
We can now copy the tar archive we made earlier into the release directory:
|
||||
|
||||
cp ../../../lwip-0.6.3.tar.gz .
|
||||
|
||||
Finally, synchronize this directory upwards to Savannah:
|
||||
|
||||
rsync -n -e "ssh -1" -t -u -v -r *.pkg likewise@savannah.nongnu.org:/upload/lwip
|
||||
|
||||
This does a "dry run": no files are modified! After you have confirmed that
|
||||
this is what you intended to do, remove "-n" and actually synchronize for
|
||||
real. The release should now be available here:
|
||||
|
||||
http://savannah.nongnu.org/files/?group=lwip
|
||||
|
||||
---
|
||||
Explanation of rsync options used:
|
||||
|
||||
-t: preserve file timestamps
|
||||
-u: do not overwrite existing files, unless they are older
|
||||
-v: be verbose (long format file attributes)
|
||||
-r: recurse into directories
|
||||
-n: dry-run, do not modify anything.
|
||||
---
|
||||
ncftp>mput *0.6.3.*
|
||||
|
||||
Additionally, you may post a news item on Savannah, like this:
|
||||
|
||||
|
||||
10
src/FILES
10
src/FILES
@@ -1,11 +1,13 @@
|
||||
api/ - The code for the API.
|
||||
api/ - The code for the high-level wrapper API. Not needed if
|
||||
you use the lowel-level call-back/raw API.
|
||||
|
||||
core/ - The core files including protocol implementations, memory
|
||||
and buffer management etc.
|
||||
core/ - The core of the TPC/IP stack; protocol implementations,
|
||||
memory and buffer management, and the low-level raw API.
|
||||
|
||||
include/ - lwIP include files.
|
||||
|
||||
netif/ - Generic network interface device drivers are kept here.
|
||||
netif/ - Generic network interface device drivers are kept here,
|
||||
as well as the ARP module.
|
||||
|
||||
For more information on the various subdirectories, check the FILES
|
||||
file in each directory.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -418,7 +418,7 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
|
||||
ip_addr_debug_print(SOCKETS_DEBUG, addr);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
|
||||
} else {
|
||||
#if SOCKETS_DEBUG != 0
|
||||
#if SOCKETS_DEBUG
|
||||
addr = netbuf_fromaddr(buf);
|
||||
port = netbuf_fromport(buf);
|
||||
|
||||
|
||||
@@ -46,11 +46,10 @@
|
||||
static void (* tcpip_init_done)(void *arg) = NULL;
|
||||
static void *tcpip_init_done_arg;
|
||||
static sys_mbox_t mbox;
|
||||
|
||||
#if LWIP_TCP
|
||||
static int tcpip_tcp_timer_active = 0;
|
||||
|
||||
|
||||
|
||||
static void
|
||||
tcpip_tcp_timer(void *arg)
|
||||
{
|
||||
@@ -68,6 +67,7 @@ tcpip_tcp_timer(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
#if !NO_SYS
|
||||
void
|
||||
tcp_timer_needed(void)
|
||||
{
|
||||
@@ -78,6 +78,7 @@ tcp_timer_needed(void)
|
||||
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
|
||||
}
|
||||
}
|
||||
#endif /* !NO_SYS */
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
static void
|
||||
|
||||
@@ -85,7 +85,8 @@
|
||||
#if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */
|
||||
|
||||
/** global transaction identifier, must be
|
||||
* unique for each DHCP request. */
|
||||
* unique for each DHCP request. We simply increment, starting
|
||||
* with this value (easy to match with a packet analyzer) */
|
||||
static u32_t xid = 0xABCD0000;
|
||||
|
||||
/** DHCP client state machine functions */
|
||||
@@ -99,7 +100,6 @@ static void dhcp_check(struct netif *netif);
|
||||
static void dhcp_bind(struct netif *netif);
|
||||
static err_t dhcp_decline(struct netif *netif);
|
||||
static err_t dhcp_rebind(struct netif *netif);
|
||||
static err_t dhcp_release(struct netif *netif);
|
||||
static void dhcp_set_state(struct dhcp *dhcp, unsigned char new_state);
|
||||
|
||||
/** receive, unfold, parse and free incoming messages */
|
||||
@@ -679,8 +679,10 @@ static err_t dhcp_decline(struct netif *netif)
|
||||
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
|
||||
|
||||
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
|
||||
udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
|
||||
udp_send(dhcp->pcb, dhcp->p_out);
|
||||
/* @todo: should we really connect here? we are performing sendto() */
|
||||
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
/* per section 4.4.4, broadcast DECLINE messages */
|
||||
udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
|
||||
dhcp_delete_request(netif);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
|
||||
} else {
|
||||
@@ -805,6 +807,8 @@ static void dhcp_bind(struct netif *netif)
|
||||
netif_set_netmask(netif, &sn_mask);
|
||||
LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08lx\n", gw_addr.addr));
|
||||
netif_set_gw(netif, &gw_addr);
|
||||
/* bring the interface up */
|
||||
netif_set_up(netif);
|
||||
/* netif is now bound to DHCP leased address */
|
||||
dhcp_set_state(dhcp, DHCP_BOUND);
|
||||
}
|
||||
@@ -922,7 +926,7 @@ static err_t dhcp_rebind(struct netif *netif)
|
||||
*
|
||||
* @param netif network interface which must release its lease
|
||||
*/
|
||||
static err_t dhcp_release(struct netif *netif)
|
||||
err_t dhcp_release(struct netif *netif)
|
||||
{
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
err_t result;
|
||||
@@ -960,10 +964,13 @@ static err_t dhcp_release(struct netif *netif)
|
||||
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));
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -136,7 +148,7 @@ 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
case ICMP_ECHO:
|
||||
/* broadcast or multicast destination address? */
|
||||
if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("Smurf.\n"));
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
pbuf_free(p);
|
||||
return;
|
||||
|
||||
@@ -85,7 +85,7 @@ ip_route(struct ip_addr *dest)
|
||||
/* iterate through netifs */
|
||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
/* network mask matches? */
|
||||
if (ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||
/* return netif on which to forward IP packet */
|
||||
return netif;
|
||||
}
|
||||
@@ -238,11 +238,8 @@ ip_input(struct pbuf *p, struct netif *inp) {
|
||||
{
|
||||
/* unicast to this interface address? */
|
||||
if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
|
||||
/* or broadcast matching this interface network address? */
|
||||
(ip_addr_isbroadcast(&(iphdr->dest), netif) &&
|
||||
ip_addr_maskcmp(&(iphdr->dest), &(netif->ip_addr), &(netif->netmask))) ||
|
||||
/* or restricted broadcast? */
|
||||
ip_addr_cmp(&(iphdr->dest), IP_ADDR_BROADCAST)) {
|
||||
/* or broadcast on this interface network address? */
|
||||
ip_addr_isbroadcast(&(iphdr->dest), netif)) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
|
||||
netif->name[0], netif->name[1]));
|
||||
/* break out of for loop */
|
||||
|
||||
@@ -60,9 +60,12 @@ u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
|
||||
/* address matches network interface address exactly? => no broadcast */
|
||||
else if (addr->addr == netif->ip_addr.addr)
|
||||
return 0;
|
||||
/* host identifier bits are all ones? => network broadcast address */
|
||||
else if ((addr->addr & ~netif->netmask.addr) ==
|
||||
(ip_addr_broadcast.addr & ~netif->netmask.addr))
|
||||
/* on the same (sub) network... */
|
||||
else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
|
||||
/* ...and host identifier bits are all ones? =>... */
|
||||
&& ((addr->addr & ~netif->netmask.addr) ==
|
||||
(ip_addr_broadcast.addr & ~netif->netmask.addr)))
|
||||
/* => network broadcast address */
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
@@ -77,7 +77,7 @@ ip_route(struct ip_addr *dest)
|
||||
struct netif *netif;
|
||||
|
||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
|
||||
int
|
||||
ip_addr_maskcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
struct ip_addr *mask)
|
||||
{
|
||||
return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&
|
||||
|
||||
@@ -183,7 +183,7 @@ pbuf_pool_alloc(void)
|
||||
|
||||
|
||||
/**
|
||||
* Allocates a pbuf.
|
||||
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
|
||||
*
|
||||
* The actual memory allocated for the pbuf is determined by the
|
||||
* layer at which the pbuf is allocated and the requested size
|
||||
@@ -319,7 +319,7 @@ pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
|
||||
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
|
||||
((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||
break;
|
||||
/* pbuf references existing (static constant) ROM payload? */
|
||||
/* pbuf references existing (non-volatile static constant) ROM payload? */
|
||||
case PBUF_ROM:
|
||||
/* pbuf references existing (externally allocated) RAM payload? */
|
||||
case PBUF_REF:
|
||||
@@ -664,8 +664,8 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
|
||||
{
|
||||
struct pbuf *p;
|
||||
|
||||
LWIP_ASSERT("h != NULL", h != NULL);
|
||||
LWIP_ASSERT("t != NULL", t != NULL);
|
||||
LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);
|
||||
LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL);
|
||||
if ((h == NULL) || (t == NULL)) return;
|
||||
|
||||
/* proceed to last pbuf of chain */
|
||||
@@ -675,10 +675,14 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
|
||||
}
|
||||
/* { p is last pbuf of first h chain, p->next == NULL } */
|
||||
LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
|
||||
LWIP_ASSERT("p->next == NULL", p->next == NULL);
|
||||
/* add total length of second chain to last pbuf total of first chain */
|
||||
p->tot_len += t->tot_len;
|
||||
/* chain last pbuf of head (p) with first of tail (t) */
|
||||
p->next = t;
|
||||
/* p->next now references t, but the caller will drop its reference to t,
|
||||
* so netto there is no change to the reference count of t.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -706,8 +710,8 @@ pbuf_chain(struct pbuf *h, struct pbuf *t)
|
||||
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
|
||||
}
|
||||
|
||||
/* For packet queueing. Note that queued packets must be dequeued first
|
||||
* before calling any pbuf functions. */
|
||||
/* For packet queueing. Note that queued packets MUST be dequeued first
|
||||
* using pbuf_dequeue() before calling other pbuf_() functions. */
|
||||
#if ARP_QUEUEING
|
||||
/**
|
||||
* Add a packet to the end of a queue.
|
||||
@@ -715,6 +719,7 @@ pbuf_chain(struct pbuf *h, struct pbuf *t)
|
||||
* @param q pointer to first packet on the queue
|
||||
* @param n packet to be queued
|
||||
*
|
||||
* Both packets MUST be given, and must be different.
|
||||
*/
|
||||
void
|
||||
pbuf_queue(struct pbuf *p, struct pbuf *n)
|
||||
@@ -723,9 +728,13 @@ pbuf_queue(struct pbuf *p, struct pbuf *n)
|
||||
struct pbuf *q = p;
|
||||
#endif
|
||||
/* programmer stupidity checks */
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
LWIP_ASSERT("n != NULL", n != NULL);
|
||||
if ((p == NULL) || (n == NULL)) return;
|
||||
LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);
|
||||
LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);
|
||||
LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);
|
||||
if ((p == NULL) || (n == NULL) || (p == n)){
|
||||
LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* iterate through all packets on queue */
|
||||
while (p->next != NULL) {
|
||||
@@ -787,7 +796,7 @@ pbuf_dequeue(struct pbuf *p)
|
||||
/* { 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 */
|
||||
/* dequeue packet p from queue */
|
||||
p->next = NULL;
|
||||
/* any next packet on queue? */
|
||||
if (q != NULL) {
|
||||
|
||||
@@ -444,6 +444,16 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||
* continue to transmit.
|
||||
*/
|
||||
tcp_ack(pcb);
|
||||
}
|
||||
else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {
|
||||
/* If we can send a window update such that there is a full
|
||||
* segment available in the window, do so now. This is sort of
|
||||
* nagle-like in its goals, and tries to hit a compromise between
|
||||
* sending acks each time the window is updated, and only sending
|
||||
* window updates when a timer expires. The "threshold" used
|
||||
* above (currently TCP_WND/2) can be tuned to be more or less
|
||||
* aggressive */
|
||||
tcp_ack_now(pcb);
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %u bytes, wnd %u (%u).\n",
|
||||
@@ -590,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;
|
||||
@@ -600,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) {
|
||||
@@ -846,7 +858,7 @@ tcp_kill_prio(u8_t prio)
|
||||
}
|
||||
}
|
||||
if (inactive != NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB 0x%p (%ld)\n",
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%ld)\n",
|
||||
(void *)inactive, inactivity));
|
||||
tcp_abort(inactive);
|
||||
}
|
||||
@@ -868,7 +880,7 @@ tcp_kill_timewait(void)
|
||||
}
|
||||
}
|
||||
if (inactive != NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB 0x%p (%ld)\n",
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%ld)\n",
|
||||
(void *)inactive, inactivity));
|
||||
tcp_abort(inactive);
|
||||
}
|
||||
|
||||
@@ -503,12 +503,14 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
/* First, determine if the reset is acceptable. */
|
||||
if (pcb->state == SYN_SENT) {
|
||||
if (ackno == pcb->snd_nxt) {
|
||||
acceptable = 1;
|
||||
acceptable = 1;
|
||||
}
|
||||
} else {
|
||||
if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
|
||||
TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
|
||||
acceptable = 1;
|
||||
/*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
|
||||
TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
|
||||
*/
|
||||
if(TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)){
|
||||
acceptable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,6 +540,7 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
|
||||
if ((flags & TCP_ACK) && (flags & TCP_SYN)
|
||||
&& ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
|
||||
pcb->snd_buf ++;
|
||||
pcb->rcv_nxt = seqno + 1;
|
||||
pcb->lastack = ackno;
|
||||
pcb->snd_wnd = tcphdr->wnd;
|
||||
@@ -562,8 +565,9 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
case SYN_RCVD:
|
||||
if (flags & TCP_ACK &&
|
||||
!(flags & TCP_RST)) {
|
||||
if (TCP_SEQ_LT(pcb->lastack, ackno) &&
|
||||
TCP_SEQ_LEQ(ackno, pcb->snd_nxt)) {
|
||||
/*if (TCP_SEQ_LT(pcb->lastack, ackno) &&
|
||||
TCP_SEQ_LEQ(ackno, pcb->snd_nxt)) { */
|
||||
if(TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
|
||||
pcb->state = ESTABLISHED;
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %u -> %u.\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
#if LWIP_CALLBACK_API
|
||||
@@ -732,8 +736,10 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
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
|
||||
@@ -813,17 +819,14 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
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. */
|
||||
/* KJM 13th July 2004
|
||||
I don't think is is necessary as we no longer move all unacked
|
||||
segments on the unsent queue when performing retransmit */
|
||||
#if 0
|
||||
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_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)));
|
||||
ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
|
||||
TCP_TCPLEN(pcb->unsent)));
|
||||
|
||||
next = pcb->unsent;
|
||||
pcb->unsent = pcb->unsent->next;
|
||||
@@ -840,7 +843,6 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* End of ACK for new data processing. */
|
||||
|
||||
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %u rtseq %lu ackno %lu\n",
|
||||
@@ -903,55 +905,57 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
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;
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
/* 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;
|
||||
pbuf_header(p, -off);
|
||||
} else {
|
||||
pbuf_header(inseg.p, -off);
|
||||
}
|
||||
else{
|
||||
/* 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);
|
||||
}
|
||||
@@ -960,8 +964,9 @@ tcp_receive(struct tcp_pcb *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
|
||||
we have to trim the end of the segment and update rcv_nxt
|
||||
@@ -1115,8 +1120,10 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
|
||||
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
|
||||
} 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
|
||||
@@ -1162,12 +1169,19 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@@ -1201,7 +1215,7 @@ tcp_parseopt(struct tcp_pcb *pcb)
|
||||
++c;
|
||||
/* NOP option. */
|
||||
} else if (opt == 0x02 &&
|
||||
opts[c + 1] == 0x04) {
|
||||
opts[c + 1] == 0x04) {
|
||||
/* An MSS option with the right option length. */
|
||||
mss = (opts[c + 2] << 8) | opts[c + 3];
|
||||
pcb->mss = mss > TCP_MSS? TCP_MSS: mss;
|
||||
|
||||
@@ -62,16 +62,21 @@ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
|
||||
err_t
|
||||
tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
|
||||
{
|
||||
/* no data, no length, flags, copy=1, no optdata, no optdatalen */
|
||||
return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* NB. tcp_write() enqueues data for sending, but does not send it
|
||||
* straight away. It waits in the expectation of more data being sent
|
||||
* soon (as it can send them more efficiently by combining them
|
||||
* together). To prompt the system to send data now, call
|
||||
* tcp_output() after calling tcp_write().
|
||||
/**
|
||||
* Write data for sending (but does not send it immediately).
|
||||
*
|
||||
* It waits in the expectation of more data being sent soon (as
|
||||
* it can send them more efficiently by combining them together).
|
||||
* To prompt the system to send data now, call tcp_output() after
|
||||
* calling tcp_write().
|
||||
*
|
||||
* @arg pcb Protocol control block of the TCP connection to enqueue data for.
|
||||
*
|
||||
* @see tcp_write()
|
||||
*/
|
||||
|
||||
err_t
|
||||
@@ -79,10 +84,11 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
|
||||
{
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb,
|
||||
arg, len, (unsigned int)copy));
|
||||
if (pcb->state == SYN_SENT ||
|
||||
pcb->state == SYN_RCVD ||
|
||||
pcb->state == ESTABLISHED ||
|
||||
pcb->state == CLOSE_WAIT) {
|
||||
/* connection is in valid state for data transmission? */
|
||||
if (pcb->state == ESTABLISHED ||
|
||||
pcb->state == CLOSE_WAIT ||
|
||||
pcb->state == SYN_SENT ||
|
||||
pcb->state == SYN_RCVD) {
|
||||
if (len > 0) {
|
||||
return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
|
||||
}
|
||||
@@ -93,10 +99,24 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue either data or TCP options (but not both) for tranmission
|
||||
*
|
||||
*
|
||||
*
|
||||
* @arg pcb Protocol control block for the TCP connection to enqueue data for.
|
||||
* @arg arg Pointer to the data to be enqueued for sending.
|
||||
* @arg len Data length in bytes
|
||||
* @arg flags
|
||||
* @arg copy 1 if data must be copied, 0 if data is non-volatile and can be
|
||||
* referenced.
|
||||
* @arg optdata
|
||||
* @arg optlen
|
||||
*/
|
||||
err_t
|
||||
tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
u8_t flags, u8_t copy,
|
||||
u8_t *optdata, u8_t optlen)
|
||||
u8_t flags, u8_t copy,
|
||||
u8_t *optdata, u8_t optlen)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_seg *seg, *useg, *queue;
|
||||
@@ -107,39 +127,43 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%u)\n",
|
||||
(void *)pcb, arg, len, (unsigned int)flags, (unsigned int)copy));
|
||||
left = len;
|
||||
ptr = arg;
|
||||
LWIP_ASSERT("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",
|
||||
len == 0 || optlen == 0);
|
||||
LWIP_ASSERT("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",
|
||||
arg == NULL || optdata == NULL);
|
||||
/* fail on too much data */
|
||||
if (len > pcb->snd_buf) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%u > snd_buf=%u)\n", len, pcb->snd_buf));
|
||||
return ERR_MEM;
|
||||
}
|
||||
left = len;
|
||||
ptr = arg;
|
||||
|
||||
/* seqno will be the sequence number of the first segment enqueued
|
||||
* by the call to this function. */
|
||||
seqno = pcb->snd_lbb;
|
||||
|
||||
queue = NULL;
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %u\n", (unsigned int)pcb->snd_queuelen));
|
||||
|
||||
/* Check if the queue length exceeds the configured maximum queue
|
||||
* length. If so, we return an error. */
|
||||
/* If total number of pbufs on the unsent/unacked queues exceeds the
|
||||
* configured maximum, return an error */
|
||||
queuelen = pcb->snd_queuelen;
|
||||
if (queuelen >= TCP_SND_QUEUELEN) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %u (max %u)\n", queuelen, TCP_SND_QUEUELEN));
|
||||
goto memerr;
|
||||
}
|
||||
|
||||
if (pcb->snd_queuelen != 0) {
|
||||
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
|
||||
pcb->unsent != NULL);
|
||||
if (queuelen != 0) {
|
||||
LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",
|
||||
pcb->unacked != NULL || pcb->unsent != NULL);
|
||||
} else {
|
||||
LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",
|
||||
pcb->unacked == NULL && pcb->unsent == NULL);
|
||||
}
|
||||
|
||||
seg = useg = NULL;
|
||||
seglen = 0;
|
||||
|
||||
/* First, break up the data into segments and tuck them together in
|
||||
* the local "queue" variable. */
|
||||
useg = queue = seg = NULL;
|
||||
seglen = 0;
|
||||
while (queue == NULL || left > 0) {
|
||||
|
||||
/* The segment length should be the MSS if the data to be enqueued
|
||||
@@ -155,20 +179,25 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
seg->next = NULL;
|
||||
seg->p = NULL;
|
||||
|
||||
/* first segment of to-be-queued data? */
|
||||
if (queue == NULL) {
|
||||
useg = queue = seg;
|
||||
queue = seg;
|
||||
}
|
||||
/* subsequent segments of to-be-queued data */
|
||||
else {
|
||||
/* Attach the segment to the end of the queued segments. */
|
||||
/* Attach the segment to the end of the queued segments */
|
||||
LWIP_ASSERT("useg != NULL", useg != NULL);
|
||||
useg->next = seg;
|
||||
useg = seg;
|
||||
}
|
||||
/* remember last segment of to-be-queued data for next iteration */
|
||||
useg = seg;
|
||||
|
||||
/* If copy is set, memory should be allocated
|
||||
* and data copied into pbuf, otherwise data comes from
|
||||
* ROM or other static memory, and need not be copied. If
|
||||
* optdata is != NULL, we have options instead of data. */
|
||||
|
||||
/* options? */
|
||||
if (optdata != NULL) {
|
||||
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
|
||||
goto memerr;
|
||||
@@ -176,6 +205,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
++queuelen;
|
||||
seg->dataptr = seg->p->payload;
|
||||
}
|
||||
/* copy from volatile memory? */
|
||||
else if (copy) {
|
||||
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %u\n", seglen));
|
||||
@@ -189,8 +219,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
}
|
||||
/* do not copy data */
|
||||
else {
|
||||
|
||||
/* first, allocate a pbuf for holding the data.
|
||||
/* First, allocate a pbuf for holding the data.
|
||||
* since the referenced data is available at least until it is sent out on the
|
||||
* link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
|
||||
* instead of PBUF_REF here.
|
||||
@@ -200,6 +229,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
goto memerr;
|
||||
}
|
||||
++queuelen;
|
||||
/* reference the non-volatile payload data */
|
||||
p->payload = ptr;
|
||||
seg->dataptr = ptr;
|
||||
|
||||
@@ -214,7 +244,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
++queuelen;
|
||||
|
||||
/* Concatenate the headers and data pbufs together. */
|
||||
pbuf_cat(seg->p, p);
|
||||
pbuf_cat(seg->p/*header*/, p/*data*/);
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
@@ -226,16 +256,10 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
}
|
||||
|
||||
seg->len = seglen;
|
||||
#if 0 /* Was commented out. TODO: can someone say why this is here? */
|
||||
if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
|
||||
++seg->len;
|
||||
}
|
||||
#endif
|
||||
/* Build TCP header. */
|
||||
|
||||
/* build TCP header */
|
||||
if (pbuf_header(seg->p, TCP_HLEN)) {
|
||||
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
|
||||
|
||||
TCP_STATS_INC(tcp.err);
|
||||
goto memerr;
|
||||
}
|
||||
@@ -268,7 +292,6 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
ptr = (void *)((char *)ptr + seglen);
|
||||
}
|
||||
|
||||
|
||||
/* Now that the data to be enqueued has been broken up into TCP
|
||||
segments in the queue variable, we add them to the end of the
|
||||
pcb->unsent queue. */
|
||||
@@ -278,6 +301,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
else {
|
||||
for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
|
||||
}
|
||||
/* { useg is last segment on the unsent queue, NULL if list is empty } */
|
||||
|
||||
/* If there is room in the last pbuf on the unsent queue,
|
||||
chain the first pbuf on the queue together with that. */
|
||||
@@ -285,24 +309,27 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
TCP_TCPLEN(useg) != 0 &&
|
||||
!(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
|
||||
!(flags & (TCP_SYN | TCP_FIN)) &&
|
||||
/* fit within max seg size */
|
||||
useg->len + queue->len <= pcb->mss) {
|
||||
/* Remove TCP header from first segment. */
|
||||
/* Remove TCP header from first segment of our to-be-queued list */
|
||||
pbuf_header(queue->p, -TCP_HLEN);
|
||||
pbuf_cat(useg->p, queue->p);
|
||||
useg->len += queue->len;
|
||||
useg->next = queue->next;
|
||||
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining, new len %u\n", useg->len));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %u\n", useg->len));
|
||||
if (seg == queue) {
|
||||
seg = NULL;
|
||||
}
|
||||
memp_free(MEMP_TCP_SEG, queue);
|
||||
}
|
||||
else {
|
||||
/* empty list */
|
||||
if (useg == NULL) {
|
||||
/* initialize list with this segment */
|
||||
pcb->unsent = queue;
|
||||
|
||||
}
|
||||
/* enqueue segment */
|
||||
else {
|
||||
useg->next = queue;
|
||||
}
|
||||
@@ -312,12 +339,12 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
}
|
||||
pcb->snd_lbb += len;
|
||||
pcb->snd_buf -= len;
|
||||
/* update number of segments on the queues */
|
||||
pcb->snd_queuelen = queuelen;
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));
|
||||
if (pcb->snd_queuelen != 0) {
|
||||
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
|
||||
pcb->unsent != NULL);
|
||||
|
||||
LWIP_ASSERT("tcp_enqueue: valid queue length",
|
||||
pcb->unacked != NULL || pcb->unsent != NULL);
|
||||
}
|
||||
|
||||
/* Set the PSH flag in the last segment that we enqueued, but only
|
||||
@@ -336,7 +363,6 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
if (pcb->snd_queuelen != 0) {
|
||||
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
|
||||
pcb->unsent != NULL);
|
||||
|
||||
}
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));
|
||||
return ERR_MEM;
|
||||
@@ -364,7 +390,6 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
|
||||
wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
|
||||
|
||||
|
||||
seg = pcb->unsent;
|
||||
|
||||
/* useg should point to last segment on unacked queue */
|
||||
@@ -372,24 +397,24 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
if (useg != NULL) {
|
||||
for (; useg->next != NULL; useg = useg->next);
|
||||
}
|
||||
|
||||
|
||||
/* If the TF_ACK_NOW flag is set, we check if there is data that is
|
||||
to be sent. If data is to be sent out, we'll just piggyback our
|
||||
acknowledgement with the outgoing segment. If no data will be
|
||||
sent (either because the ->unsent queue is empty or because the
|
||||
window doesn't allow it) we'll have to construct an empty ACK
|
||||
segment and send it. */
|
||||
/* If the TF_ACK_NOW flag is set and no data will be sent (either
|
||||
* because the ->unsent queue is empty or because the window does
|
||||
* not allow it), construct an empty ACK segment and send it.
|
||||
*
|
||||
* If data is to be sent, we will just piggyback the ACK (see below).
|
||||
*/
|
||||
if (pcb->flags & TF_ACK_NOW &&
|
||||
(seg == NULL ||
|
||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %lu\n", pcb->rcv_nxt));
|
||||
/* remove ACK flags from the PCB, as we send an empty ACK now */
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
|
||||
tcphdr = p->payload;
|
||||
tcphdr->src = htons(pcb->local_port);
|
||||
@@ -406,7 +431,6 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
#endif
|
||||
|
||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
pbuf_free(p);
|
||||
@@ -431,7 +455,7 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
ntohl(seg->tcphdr->seqno), pcb->lastack));
|
||||
}
|
||||
#endif /* TCP_CWND_DEBUG */
|
||||
|
||||
/* data available and window allows it to be sent? */
|
||||
while (seg != NULL &&
|
||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
|
||||
#if TCP_CWND_DEBUG
|
||||
@@ -458,13 +482,26 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
/* put segment on unacknowledged list if length > 0 */
|
||||
if (TCP_TCPLEN(seg) > 0) {
|
||||
seg->next = NULL;
|
||||
/* unacked list is empty? */
|
||||
if (pcb->unacked == NULL) {
|
||||
pcb->unacked = seg;
|
||||
useg = seg;
|
||||
/* unacked list is not empty? */
|
||||
} else {
|
||||
useg->next = seg;
|
||||
useg = useg->next;
|
||||
/* In the case of fast retransmit, the packet should not go to the tail
|
||||
* of the unacked queue, but rather at the head. We need to check for
|
||||
* this case. -STJ Jul 27, 2004 */
|
||||
if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
|
||||
/* add segment to head of unacked list */
|
||||
seg->next = pcb->unacked;
|
||||
pcb->unacked = seg;
|
||||
} else {
|
||||
/* add segment to tail of unacked list */
|
||||
useg->next = seg;
|
||||
useg = useg->next;
|
||||
}
|
||||
}
|
||||
/* do not queue empty segments on the unacked list */
|
||||
} else {
|
||||
tcp_seg_free(seg);
|
||||
}
|
||||
@@ -473,6 +510,9 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually send a TCP segment over IP
|
||||
*/
|
||||
static void
|
||||
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -568,6 +608,36 @@ tcp_rst(u32_t seqno, u32_t ackno,
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));
|
||||
}
|
||||
|
||||
/* requeue all unacked segments for retransmission */
|
||||
void
|
||||
tcp_rexmit_rto(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct tcp_seg *seg;
|
||||
|
||||
if (pcb->unacked == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move all unacked segments to the head of the unsent queue */
|
||||
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
|
||||
/* concatenate unsent queue after unacked queue */
|
||||
seg->next = pcb->unsent;
|
||||
/* unsent queue is the concatenated queue (of unacked, unsent) */
|
||||
pcb->unsent = pcb->unacked;
|
||||
/* unacked queue is now empty */
|
||||
pcb->unacked = NULL;
|
||||
|
||||
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
|
||||
/* increment number of retransmissions */
|
||||
++pcb->nrtx;
|
||||
|
||||
/* Don't take any RTT measurements after retransmitting. */
|
||||
pcb->rttest = 0;
|
||||
|
||||
/* Do the actual retransmission */
|
||||
tcp_output(pcb);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_rexmit(struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -595,6 +665,7 @@ tcp_rexmit(struct tcp_pcb *pcb)
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
tcp_keepalive(struct tcp_pcb *pcb)
|
||||
{
|
||||
|
||||
@@ -356,9 +356,10 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
|
||||
struct ip_addr *dst_ip, u16_t dst_port)
|
||||
{
|
||||
err_t err;
|
||||
/* temporary space for current PCB remote address */
|
||||
struct ip_addr pcb_remote_ip;
|
||||
u16_t pcb_remote_port;
|
||||
/* remember remote peer address of PCB */
|
||||
/* remember current remote peer address of PCB */
|
||||
pcb_remote_ip.addr = pcb->remote_ip.addr;
|
||||
pcb_remote_port = pcb->remote_port;
|
||||
/* copy packet destination address to PCB remote peer address */
|
||||
@@ -366,7 +367,7 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
|
||||
pcb->remote_port = dst_port;
|
||||
/* send to the packet destination address */
|
||||
err = udp_send(pcb, p);
|
||||
/* reset PCB remote peer address */
|
||||
/* restore PCB remote peer address */
|
||||
pcb->remote_ip.addr = pcb_remote_ip.addr;
|
||||
pcb->remote_port = pcb_remote_port;
|
||||
return err;
|
||||
@@ -433,7 +434,9 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
udphdr->chksum = 0x0000;
|
||||
|
||||
/* find the outgoing network interface for this packet */
|
||||
if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
|
||||
netif = ip_route(&(pcb->remote_ip));
|
||||
/* no outgoing network interface could be found? */
|
||||
if (netif == NULL) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%lx\n", pcb->remote_ip.addr));
|
||||
UDP_STATS_INC(udp.rterr);
|
||||
return ERR_RTE;
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
struct netif;
|
||||
|
||||
void ip_init(void);
|
||||
struct netif *ip_route(struct ip_addr *dest);
|
||||
|
||||
@@ -117,7 +117,15 @@ extern const struct ip_addr ip_addr_broadcast;
|
||||
#define ip_addr_set(dest, src) (dest)->addr = \
|
||||
((src) == NULL? 0:\
|
||||
(src)->addr)
|
||||
#define ip_addr_maskcmp(addr1, addr2, mask) (((addr1)->addr & \
|
||||
/**
|
||||
* Determine if two address are on the same network.
|
||||
*
|
||||
* @arg addr1 IP address 1
|
||||
* @arg addr2 IP address 2
|
||||
* @arg mask network identifier mask
|
||||
* @return !0 if the network identifiers of both address match
|
||||
*/
|
||||
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
|
||||
(mask)->addr) == \
|
||||
((addr2)->addr & \
|
||||
(mask)->addr))
|
||||
|
||||
@@ -45,7 +45,7 @@ struct ip_addr {
|
||||
(ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \
|
||||
(ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)
|
||||
|
||||
int ip_addr_maskcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
int ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
struct ip_addr *mask);
|
||||
int ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2);
|
||||
void ip_addr_set(struct ip_addr *dest, struct ip_addr *src);
|
||||
|
||||
@@ -86,8 +86,12 @@ struct dhcp_msg
|
||||
PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
|
||||
PACK_STRUCT_FIELD(u32_t cookie);
|
||||
#define DHCP_MIN_OPTIONS_LEN 68U
|
||||
/** make sure user does not configure this too small */
|
||||
#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
|
||||
# undef DHCP_OPTIONS_LEN
|
||||
#endif
|
||||
/** allow this to be configured in lwipopts.h, but not too small */
|
||||
#if ((!defined(DHCP_OPTIONS_LEN)) || (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
|
||||
#if (!defined(DHCP_OPTIONS_LEN))
|
||||
/** set this to be sufficient for your options in outgoing DHCP msgs */
|
||||
# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN
|
||||
#endif
|
||||
@@ -100,11 +104,13 @@ PACK_STRUCT_END
|
||||
|
||||
/** start DHCP configuration */
|
||||
err_t dhcp_start(struct netif *netif);
|
||||
/** enforce early lease renewal (not needed normally)*/
|
||||
err_t dhcp_renew(struct netif *netif);
|
||||
/** release the DHCP lease, usually called before dhcp_stop()*/
|
||||
err_t dhcp_release(struct netif *netif);
|
||||
/** stop DHCP configuration */
|
||||
void dhcp_stop(struct netif *netif);
|
||||
/** enforce lease renewal */
|
||||
err_t dhcp_renew(struct netif *netif);
|
||||
/** inform server of our IP address */
|
||||
/** inform server of our manual IP address */
|
||||
void dhcp_inform(struct netif *netif);
|
||||
|
||||
/** if enabled, check whether the offered IP address is not in use, using ARP */
|
||||
|
||||
@@ -146,10 +146,10 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
#endif
|
||||
|
||||
/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
|
||||
link level header. */
|
||||
link level header. Defaults to 14 for Ethernet. */
|
||||
|
||||
#ifndef PBUF_LINK_HLEN
|
||||
#define PBUF_LINK_HLEN 0
|
||||
#define PBUF_LINK_HLEN 14
|
||||
#endif
|
||||
|
||||
|
||||
@@ -163,7 +163,15 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
|
||||
/**
|
||||
* If enabled, outgoing packets are queued during hardware address
|
||||
* resolution. The etharp.c implementation queues 1 packet only.
|
||||
* resolution.
|
||||
*
|
||||
* This feature has not stabilized yet. Single-packet queueing is
|
||||
* believed to be stable, multi-packet queueing is believed to
|
||||
* clash with the TCP segment queueing.
|
||||
*
|
||||
* As multi-packet-queueing is currently disabled, enabling this
|
||||
* _should_ work, but we need your testing feedback on lwip-users.
|
||||
*
|
||||
*/
|
||||
#ifndef ARP_QUEUEING
|
||||
#define ARP_QUEUEING 1
|
||||
@@ -339,7 +347,7 @@ a lot of data that needs to be copied, this should be set high. */
|
||||
/* ---------- Socket Options ---------- */
|
||||
/* Enable SO_REUSEADDR and SO_REUSEPORT options */
|
||||
#ifndef SO_REUSE
|
||||
# define SO_REUSE 1
|
||||
# define SO_REUSE 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ void tcp_input (struct pbuf *p, struct netif *inp);
|
||||
/* Used within the TCP code only: */
|
||||
err_t tcp_output (struct tcp_pcb *pcb);
|
||||
void tcp_rexmit (struct tcp_pcb *pcb);
|
||||
void tcp_rexmit_rto (struct tcp_pcb *pcb);
|
||||
|
||||
|
||||
|
||||
@@ -112,7 +113,11 @@ void tcp_rexmit (struct tcp_pcb *pcb);
|
||||
#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
|
||||
#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
|
||||
#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0)
|
||||
|
||||
/* is b<=a<=c? */
|
||||
#if 0 /* see bug #10548 */
|
||||
#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
|
||||
#endif
|
||||
#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))
|
||||
#define TCP_FIN 0x01U
|
||||
#define TCP_SYN 0x02U
|
||||
#define TCP_RST 0x04U
|
||||
@@ -208,18 +213,13 @@ enum tcp_state {
|
||||
TIME_WAIT = 10
|
||||
};
|
||||
|
||||
|
||||
/* the TCP protocol control block */
|
||||
struct tcp_pcb {
|
||||
/* Common members of all PCB types */
|
||||
/** common PCB members */
|
||||
IP_PCB;
|
||||
|
||||
/* Protocol specific PCB members */
|
||||
|
||||
struct tcp_pcb *next; /* for the linked list */
|
||||
|
||||
enum tcp_state state; /* TCP state */
|
||||
|
||||
/** protocol specific PCB members */
|
||||
struct tcp_pcb *next; /* for the linked list */
|
||||
enum tcp_state state; /* TCP state */
|
||||
u8_t prio;
|
||||
void *callback_arg;
|
||||
|
||||
@@ -235,7 +235,7 @@ struct tcp_pcb {
|
||||
#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
|
||||
#define TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */
|
||||
|
||||
/* receiver varables */
|
||||
/* receiver variables */
|
||||
u32_t rcv_nxt; /* next seqno expected */
|
||||
u16_t rcv_wnd; /* receiver window */
|
||||
|
||||
@@ -248,10 +248,10 @@ struct tcp_pcb {
|
||||
|
||||
u16_t mss; /* maximum segment size */
|
||||
|
||||
/* RTT estimation variables. */
|
||||
u16_t rttest; /* RTT estimate in 500ms ticks */
|
||||
/* RTT (round trip time) estimation variables */
|
||||
u32_t rttest; /* RTT estimate in 500ms ticks */
|
||||
u32_t rtseq; /* sequence number being timed */
|
||||
s16_t sa, sv;
|
||||
s16_t sa, sv; /* @todo document this */
|
||||
|
||||
u16_t rto; /* retransmission time-out */
|
||||
u8_t nrtx; /* number of retransmissions */
|
||||
@@ -375,7 +375,7 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
|
||||
#define TCP_EVENT_RECV(pcb,p,err,ret) \
|
||||
if((pcb)->recv != NULL) \
|
||||
{ ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \
|
||||
pbuf_free(p); }
|
||||
if (p) pbuf_free(p); }
|
||||
#define TCP_EVENT_CONNECTED(pcb,err,ret) \
|
||||
if((pcb)->connected != NULL) \
|
||||
(ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))
|
||||
@@ -387,7 +387,7 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
|
||||
(errf)((arg),(err))
|
||||
#endif /* LWIP_EVENT_API */
|
||||
|
||||
/* This structure is used to repressent TCP segments when queued. */
|
||||
/* This structure represents a TCP segment on the unsent and unacked queues */
|
||||
struct tcp_seg {
|
||||
struct tcp_seg *next; /* used when putting segements on a queue */
|
||||
struct pbuf *p; /* buffer containing data + TCP header */
|
||||
|
||||
@@ -52,7 +52,13 @@ 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
|
||||
@@ -63,7 +69,13 @@ struct eth_hdr {
|
||||
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 {
|
||||
@@ -78,17 +90,25 @@ struct etharp_hdr {
|
||||
PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ethip_hdr {
|
||||
PACK_STRUCT_FIELD(struct eth_hdr eth);
|
||||
PACK_STRUCT_FIELD(struct ip_hdr ip);
|
||||
};
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define ARP_TMR_INTERVAL 10000
|
||||
#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
|
||||
|
||||
/** 5 seconds period */
|
||||
#define ARP_TMR_INTERVAL 5000
|
||||
|
||||
#define ETHTYPE_ARP 0x0806
|
||||
#define ETHTYPE_IP 0x0800
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
This directory contains generic network interface device drivers that
|
||||
don't contain any hardware or architecture specific code. The files
|
||||
do not contain any hardware or architecture specific code. The files
|
||||
are:
|
||||
|
||||
etharp.c
|
||||
Implements the ARP (Address Resolution Protocol) over
|
||||
Ethernet. The code in this file should be used together with
|
||||
Ethernet device drivers.
|
||||
Ethernet device drivers. Note that this module has been
|
||||
largely made Ethernet independent so you should be able to
|
||||
adapt this for other link layers (such as Firewire).
|
||||
|
||||
ethernetif.c
|
||||
An example of how an Ethernet device driver could look. This
|
||||
file can be used as a "skeleton" for developing new Ethernet
|
||||
network device drivers. It uses the etharp.c ARP code.
|
||||
!!!THIS FILE IS NOT IN SYNC WITH CURRENT CODE !!!!
|
||||
|
||||
loopif.c
|
||||
An example network interface that shows how a "loopback"
|
||||
|
||||
@@ -55,10 +55,17 @@
|
||||
# include "lwip/dhcp.h"
|
||||
#endif
|
||||
|
||||
/** the time an ARP entry stays valid after its last update, (120 * 10) seconds = 20 minutes. */
|
||||
#define ARP_MAXAGE 120
|
||||
/** the time an ARP entry stays pending after first request, (1 * 10) seconds = 10 seconds. */
|
||||
#define ARP_MAXPENDING 1
|
||||
/** the time an ARP entry stays valid after its last update,
|
||||
* (240 * 5) seconds = 20 minutes.
|
||||
*/
|
||||
#define ARP_MAXAGE 240
|
||||
/** the time an ARP entry stays pending after first request,
|
||||
* (2 * 5) seconds = 10 seconds.
|
||||
*
|
||||
* @internal Keep this number at least 2, otherwise it might
|
||||
* run out instantly if the timeout occurs directly after a request.
|
||||
*/
|
||||
#define ARP_MAXPENDING 2
|
||||
|
||||
#define HWTYPE_ETHERNET 1
|
||||
|
||||
@@ -96,9 +103,11 @@ struct etharp_entry {
|
||||
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
|
||||
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
|
||||
|
||||
/** ask update_arp_entry() to create new entry instead of merely update existing */
|
||||
/** ask find_entry() to create new entry instead of merely finding existing */
|
||||
#define ETHARP_CREATE 1
|
||||
/**
|
||||
* Try hard to create a new entry - we want the IP address to appear in
|
||||
* the cache (even if this means removing an active entry or so). */
|
||||
#define ETHARP_TRY_HARD 1
|
||||
|
||||
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);
|
||||
static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
|
||||
/**
|
||||
@@ -121,7 +130,7 @@ etharp_init(void)
|
||||
/**
|
||||
* Clears expired entries in the ARP table.
|
||||
*
|
||||
* This function should be called every ETHARP_TMR_INTERVAL microseconds (10 seconds),
|
||||
* This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
|
||||
* in order to expire entries in the ARP table.
|
||||
*/
|
||||
void
|
||||
@@ -169,7 +178,7 @@ etharp_tmr(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the ARP table for a specific entry.
|
||||
* Search the ARP table for a matching or new entry.
|
||||
*
|
||||
* If an IP address is given, return a pending or stable ARP entry that matches
|
||||
* the address. If no match is found, create a new entry with this address set,
|
||||
@@ -179,28 +188,29 @@ etharp_tmr(void)
|
||||
* If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
|
||||
*
|
||||
* In all cases, attempt to create new entries from an empty entry. If no
|
||||
* empty entries are available and ETHARP_CREATE flag is set, recycle
|
||||
* empty entries are available and ETHARP_TRY_HARD flag is set, recycle
|
||||
* old entries. Heuristic choose the least important entry for recycling.
|
||||
*
|
||||
* @param ipaddr IP address to find in ARP cache, or to add if not found.
|
||||
* @param flags
|
||||
* - ETHARP_CREATE: Try hard to create a entry by allowing recycling.
|
||||
* - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
|
||||
* active (stable or pending) entries.
|
||||
*
|
||||
* @return The ARP entry index that matched or is created, ERR_MEM if no
|
||||
* entry is found or could be recycled.
|
||||
*/
|
||||
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
|
||||
{
|
||||
s8_t old_pending, old_stable, empty, i;
|
||||
u8_t age_pending, age_stable;
|
||||
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
|
||||
s8_t empty = ARP_TABLE_SIZE;
|
||||
u8_t i = 0, age_pending = 0, age_stable = 0;
|
||||
#if ARP_QUEUEING
|
||||
/* oldest entry with packets on queue */
|
||||
s8_t old_queue = ARP_TABLE_SIZE;
|
||||
/* its age */
|
||||
u8_t age_queue = 0;
|
||||
#endif
|
||||
|
||||
old_pending = old_stable = empty = ARP_TABLE_SIZE;
|
||||
age_pending = age_stable = 0;
|
||||
|
||||
/**
|
||||
* a) do a search through the cache, remember candidates
|
||||
* b) select candidate entry
|
||||
@@ -228,7 +238,7 @@ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
|
||||
/* if given, does IP address match IP address in ARP entry? */
|
||||
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %d\n", i));
|
||||
/* found match, simply bail out */
|
||||
/* found exact IP address match, simply bail out */
|
||||
return i;
|
||||
#if ARP_QUEUEING
|
||||
/* pending with queued packets? */
|
||||
@@ -251,7 +261,7 @@ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
|
||||
/* if given, does IP address match IP address in ARP entry? */
|
||||
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %d\n", i));
|
||||
/* found match, simply bail out */
|
||||
/* found exact IP address match, simply bail out */
|
||||
return i;
|
||||
/* remember entry with oldest stable entry in oldest, its age in maxtime */
|
||||
} else if (arp_table[i].ctime >= age_stable) {
|
||||
@@ -260,12 +270,21 @@ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* { we have no match } => try to create a new entry */
|
||||
|
||||
/* no empty entry found and not allowed to recycle? */
|
||||
if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))
|
||||
{
|
||||
return (s8_t)ERR_MEM;
|
||||
}
|
||||
|
||||
/* b) choose the least destructive entry to recycle:
|
||||
* 1) empty entry
|
||||
* 2) oldest stable entry
|
||||
* 3) oldest pending entry without queued packets
|
||||
* 4) oldest pending entry without queued packets
|
||||
*
|
||||
* { ETHARP_TRY_HARD is set at this point }
|
||||
*/
|
||||
|
||||
/* 1) empty entry available? */
|
||||
@@ -293,41 +312,26 @@ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
|
||||
/* recycle oldest pending */
|
||||
i = old_queue;
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %d, freeing packet queue %p\n", i, (void *)(arp_table[i].p)));
|
||||
/* no empty or recyclable entries found */
|
||||
pbuf_free(arp_table[i].p);
|
||||
arp_table[i].p = NULL;
|
||||
#endif
|
||||
/* no empty or recyclable entries found */
|
||||
} else {
|
||||
return ERR_MEM;
|
||||
return (s8_t)ERR_MEM;
|
||||
}
|
||||
|
||||
/* { empty or recyclable entry found } */
|
||||
LWIP_ASSERT("i >= 0", i >= 0);
|
||||
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
|
||||
|
||||
/* allowed to recycle a entry? */
|
||||
if (flags & ETHARP_CREATE) {
|
||||
/* recycle (no-op for an already empty entry) */
|
||||
arp_table[i].state = ETHARP_STATE_EMPTY;
|
||||
}
|
||||
/* recycle entry (no-op for an already empty entry) */
|
||||
arp_table[i].state = ETHARP_STATE_EMPTY;
|
||||
|
||||
/* empty entry found or created? */
|
||||
if (arp_table[i].state == ETHARP_STATE_EMPTY) {
|
||||
/* IP address given? */
|
||||
if (ipaddr != NULL) {
|
||||
/* set IP address */
|
||||
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
|
||||
}
|
||||
arp_table[i].ctime = 0;
|
||||
#if ARP_QUEUEING
|
||||
/* remove any queued packets */
|
||||
if (arp_table[i].p != NULL) pbuf_free(arp_table[i].p);
|
||||
arp_table[i].p = NULL;
|
||||
#endif
|
||||
/* no entry available */
|
||||
} else {
|
||||
/* return failure */
|
||||
i = (s8_t)ERR_MEM;
|
||||
/* IP address given? */
|
||||
if (ipaddr != NULL) {
|
||||
/* set IP address */
|
||||
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
|
||||
}
|
||||
|
||||
arp_table[i].ctime = 0;
|
||||
return (err_t)i;
|
||||
}
|
||||
|
||||
@@ -340,17 +344,17 @@ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
|
||||
* @param ipaddr IP address of the inserted ARP entry.
|
||||
* @param ethaddr Ethernet address of the inserted ARP entry.
|
||||
* @param flags Defines behaviour:
|
||||
* - ETHARP_CREATE Allows ARP to insert this as a new item. If not specified,
|
||||
* - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
|
||||
* only existing ARP entries will be updated.
|
||||
*
|
||||
* @return
|
||||
* - ERR_OK Succesfully updated ARP cache.
|
||||
* - ERR_MEM If we could not add a new ARP entry when ETHARP_CREATE was set.
|
||||
* - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.
|
||||
* - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
|
||||
*
|
||||
* @see pbuf_free()
|
||||
*/
|
||||
err_t
|
||||
static err_t
|
||||
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
|
||||
{
|
||||
s8_t i, k;
|
||||
@@ -385,10 +389,10 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
||||
/* this is where we will send out queued packets! */
|
||||
#if ARP_QUEUEING
|
||||
while (arp_table[i].p != NULL) {
|
||||
/* get the first packet on the queue (if any) */
|
||||
/* get the first packet on the queue */
|
||||
struct pbuf *p = arp_table[i].p;
|
||||
/* Ethernet header */
|
||||
struct eth_hdr *ethhdr = p->payload;;
|
||||
struct eth_hdr *ethhdr = p->payload;
|
||||
/* remember (and reference) remainder of queue */
|
||||
/* note: this will also terminate the p pbuf chain */
|
||||
arp_table[i].p = pbuf_dequeue(p);
|
||||
@@ -431,15 +435,17 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
|
||||
/* Only insert an entry if the source IP address of the
|
||||
incoming IP packet comes from a host on the local network. */
|
||||
hdr = p->payload;
|
||||
/* source is on local network? */
|
||||
if (!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
|
||||
/* source is not on the local network? */
|
||||
if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
|
||||
/* do nothing */
|
||||
return;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
|
||||
/* update ARP table, ask to insert entry */
|
||||
update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), ETHARP_CREATE);
|
||||
/* update ARP table */
|
||||
/* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
|
||||
* back soon (for example, if the destination IP address is ours. */
|
||||
update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -492,7 +498,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
if (for_us) {
|
||||
/* add IP address in ARP cache; assume requester wants to talk to us.
|
||||
* can result in directly sending the queued packets for this host. */
|
||||
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_CREATE);
|
||||
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
|
||||
/* ARP message not directed to us? */
|
||||
} else {
|
||||
/* update the source IP address in the cache, if present */
|
||||
@@ -548,8 +554,9 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
/* ARP reply. We already updated the ARP cache earlier. */
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
|
||||
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
|
||||
/* DHCP wants to know about ARP replies to our wanna-have-address */
|
||||
if (for_us) dhcp_arp_reply(netif, &sipaddr);
|
||||
/* When unconfigured, DHCP wants to know about ARP replies from the
|
||||
* address offered to us, as that means someone else uses it already! */
|
||||
if (netif->ip_addr.addr == 0) dhcp_arp_reply(netif, &sipaddr);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
@@ -563,36 +570,27 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
||||
/**
|
||||
* Resolve and fill-in Ethernet address header for outgoing packet.
|
||||
*
|
||||
* If ARP has the Ethernet address in cache, the given packet is
|
||||
* returned, ready to be sent.
|
||||
* For IP multicast and broadcast, corresponding Ethernet addresses
|
||||
* are selected and the packet is transmitted on the link.
|
||||
*
|
||||
* If ARP does not have the Ethernet address in cache the packet is
|
||||
* queued (if enabled and space available) and a ARP request is sent.
|
||||
* This ARP request is returned as a pbuf, which should be sent by
|
||||
* the caller.
|
||||
*
|
||||
* A returned non-NULL packet should be sent by the caller.
|
||||
*
|
||||
* If ARP failed to allocate resources, NULL is returned.
|
||||
* For unicast addresses, the packet is submitted to etharp_query(). In
|
||||
* case the IP address is outside the local network, the IP address of
|
||||
* the gateway is used.
|
||||
*
|
||||
* @param netif The lwIP network interface which the IP packet will be sent on.
|
||||
* @param ipaddr The IP address of the packet destination.
|
||||
* @param pbuf The pbuf(s) containing the IP packet to be sent.
|
||||
*
|
||||
* @return If non-NULL, a packet ready to be sent by caller.
|
||||
*
|
||||
* @return
|
||||
* - ERR_BUF Could not make room for Ethernet header.
|
||||
* - ERR_MEM Hardware address unknown, and no more ARP entries available
|
||||
* to query for address or queue the packet.
|
||||
* - ERR_RTE No route to destination (no gateway to external networks).
|
||||
* - ERR_RTE No route to destination (no gateway to external networks),
|
||||
* or the return type of either etharp_query() or netif->linkoutput().
|
||||
*/
|
||||
err_t
|
||||
etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
||||
{
|
||||
struct eth_addr *dest, *srcaddr, mcastaddr;
|
||||
struct eth_hdr *ethhdr;
|
||||
err_t result = ERR_OK;
|
||||
u8_t i;
|
||||
|
||||
/* make room for Ethernet header - should not fail */
|
||||
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
|
||||
@@ -607,13 +605,13 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
||||
/* Determine on destination hardware address. Broadcasts and multicasts
|
||||
* are special, other IP addresses are looked up in the ARP table. */
|
||||
|
||||
/* destination IP address is an IP broadcast address? */
|
||||
if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, netif)) {
|
||||
/* broadcast destination IP address? */
|
||||
if (ip_addr_isbroadcast(ipaddr, netif)) {
|
||||
/* broadcast on Ethernet also */
|
||||
dest = (struct eth_addr *)ðbroadcast;
|
||||
/* destination IP address is an IP multicast address? */
|
||||
/* multicast destination IP address? */
|
||||
} else if (ip_addr_ismulticast(ipaddr)) {
|
||||
/* Hash IP multicast address to MAC address. */
|
||||
/* Hash IP multicast address to MAC address.*/
|
||||
mcastaddr.addr[0] = 0x01;
|
||||
mcastaddr.addr[1] = 0x00;
|
||||
mcastaddr.addr[2] = 0x5e;
|
||||
@@ -622,17 +620,17 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
||||
mcastaddr.addr[5] = ip4_addr4(ipaddr);
|
||||
/* destination Ethernet address is multicast */
|
||||
dest = &mcastaddr;
|
||||
/* destination IP address is an IP unicast address */
|
||||
/* unicast destination IP address? */
|
||||
} else {
|
||||
/* outside local network? */
|
||||
if (!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
|
||||
if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
|
||||
/* interface has default gateway? */
|
||||
if (netif->gw.addr != 0) {
|
||||
/* send to hardware address of default gateway IP address */
|
||||
ipaddr = &(netif->gw);
|
||||
/* no default gateway available */
|
||||
} else {
|
||||
/* no route to destination error */
|
||||
/* no route to destination error (default gateway missing) */
|
||||
return ERR_RTE;
|
||||
}
|
||||
}
|
||||
@@ -640,23 +638,17 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
||||
return etharp_query(netif, ipaddr, q);
|
||||
}
|
||||
|
||||
/* destination Ethernet address known */
|
||||
if (dest != NULL) {
|
||||
u8_t i;
|
||||
/* obtain source Ethernet address of the given interface */
|
||||
srcaddr = (struct eth_addr *)netif->hwaddr;
|
||||
/* A valid IP->MAC address mapping was found, fill in the
|
||||
* Ethernet header for the outgoing packet */
|
||||
ethhdr = q->payload;
|
||||
for (i = 0; i < netif->hwaddr_len; i++) {
|
||||
ethhdr->dest.addr[i] = dest->addr[i];
|
||||
ethhdr->src.addr[i] = srcaddr->addr[i];
|
||||
}
|
||||
ethhdr->type = htons(ETHTYPE_IP);
|
||||
/* send packet */
|
||||
result = netif->linkoutput(netif, q);
|
||||
/* continuation for multicast/broadcast destinations */
|
||||
/* obtain source Ethernet address of the given interface */
|
||||
srcaddr = (struct eth_addr *)netif->hwaddr;
|
||||
ethhdr = q->payload;
|
||||
for (i = 0; i < netif->hwaddr_len; i++) {
|
||||
ethhdr->dest.addr[i] = dest->addr[i];
|
||||
ethhdr->src.addr[i] = srcaddr->addr[i];
|
||||
}
|
||||
return result;
|
||||
ethhdr->type = htons(ETHTYPE_IP);
|
||||
/* send packet directly on the link */
|
||||
return netif->linkoutput(netif, q);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -699,18 +691,23 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
||||
u8_t k; /* Ethernet address octet index */
|
||||
|
||||
/* non-unicast address? */
|
||||
if (ip_addr_isany(ipaddr) ||
|
||||
ip_addr_isbroadcast(ipaddr, netif) ||
|
||||
ip_addr_ismulticast(ipaddr)) {
|
||||
if (ip_addr_isbroadcast(ipaddr, netif) ||
|
||||
ip_addr_ismulticast(ipaddr) ||
|
||||
ip_addr_isany(ipaddr)) {
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
/* find entry in ARP cache, ask to create entry if queueing packet */
|
||||
i = find_entry(ipaddr, (q != NULL) ? ETHARP_CREATE : 0);
|
||||
i = find_entry(ipaddr, ETHARP_TRY_HARD);
|
||||
|
||||
/* could not find or create entry? */
|
||||
if (i < 0) return (err_t)i;
|
||||
if (i < 0)
|
||||
{
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
|
||||
if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));
|
||||
return (err_t)i;
|
||||
}
|
||||
|
||||
/* mark a fresh entry as pending (we just sent a request) */
|
||||
if (arp_table[i].state == ETHARP_STATE_EMPTY) {
|
||||
@@ -722,7 +719,7 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
||||
((arp_table[i].state == ETHARP_STATE_PENDING) ||
|
||||
(arp_table[i].state == ETHARP_STATE_STABLE)));
|
||||
|
||||
/* do we have a pending entry? */
|
||||
/* do we have a pending entry? or an implicit query request? */
|
||||
if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
|
||||
/* try to resolve it; send out ARP request */
|
||||
result = etharp_request(netif, ipaddr);
|
||||
@@ -752,8 +749,17 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
||||
p = pbuf_take(q);
|
||||
/* packet could be taken over? */
|
||||
if (p != NULL) {
|
||||
/* queue packet */
|
||||
pbuf_queue(arp_table[i].p, p);
|
||||
/* queue packet ... */
|
||||
if (arp_table[i].p == NULL) {
|
||||
/* ... in the empty queue */
|
||||
pbuf_ref(p);
|
||||
arp_table[i].p = p;
|
||||
#if 0 /* multi-packet-queueing disabled, see bug #11400 */
|
||||
} else {
|
||||
/* ... at tail of non-empty queue */
|
||||
pbuf_queue(arp_table[i].p, p);
|
||||
#endif
|
||||
}
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %d\n", (void *)q, i));
|
||||
result = ERR_OK;
|
||||
} else {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <lwip/stats.h>
|
||||
|
||||
#include "netif/etharp.h"
|
||||
|
||||
@@ -117,7 +118,7 @@ low_level_output(struct netif *netif, struct pbuf *p)
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
|
||||
#ifdef LINK_STATS
|
||||
#if LINK_STATS
|
||||
lwip_stats.link.xmit++;
|
||||
#endif /* LINK_STATS */
|
||||
|
||||
@@ -170,12 +171,12 @@ low_level_input(struct netif *netif)
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
|
||||
#ifdef LINK_STATS
|
||||
#if LINK_STATS
|
||||
lwip_stats.link.recv++;
|
||||
#endif /* LINK_STATS */
|
||||
} else {
|
||||
drop packet();
|
||||
#ifdef LINK_STATS
|
||||
#if LINK_STATS
|
||||
lwip_stats.link.memerr++;
|
||||
lwip_stats.link.drop++;
|
||||
#endif /* LINK_STATS */
|
||||
@@ -229,7 +230,7 @@ ethernetif_input(struct netif *netif)
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = p->payload;
|
||||
|
||||
#ifdef LINK_STATS
|
||||
#if LINK_STATS
|
||||
lwip_stats.link.recv++;
|
||||
#endif /* LINK_STATS */
|
||||
|
||||
@@ -273,7 +274,7 @@ arp_timer(void *arg)
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
err_t
|
||||
ethernetif_init(struct netif *netif)
|
||||
{
|
||||
struct ethernetif *ethernetif;
|
||||
@@ -299,5 +300,7 @@ ethernetif_init(struct netif *netif)
|
||||
etharp_init();
|
||||
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1236,7 +1236,7 @@ static void pppMain(void *arg)
|
||||
pppInProc(pd, p->payload, c);
|
||||
} else {
|
||||
PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
|
||||
sys_msleep(250); /* give other tasks a chance to run */
|
||||
sys_msleep(1); /* give other tasks a chance to run */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user