upgrade to lwip 2.0.0, beginning support for IPV6
This commit is contained in:
@@ -42,7 +42,7 @@
|
||||
|
||||
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
@@ -50,7 +50,8 @@
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
#include "lwip/sys.h"
|
||||
#endif
|
||||
@@ -76,9 +77,22 @@
|
||||
#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
|
||||
#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0
|
||||
#endif
|
||||
/* Allow to override the failure of sanity check from warning to e.g. hard failure */
|
||||
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
|
||||
#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL
|
||||
#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL(msg) LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, msg)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TCP_OVERSIZE
|
||||
/** The size of segment pbufs created when TCP_OVERSIZE is enabled */
|
||||
#ifndef TCP_OVERSIZE_CALC_LENGTH
|
||||
#define TCP_OVERSIZE_CALC_LENGTH(length) ((length) + TCP_OVERSIZE)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Forward declarations.*/
|
||||
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
|
||||
static err_t tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif);
|
||||
|
||||
/** Allocate a pbuf and create a tcphdr at p->payload, used for output
|
||||
* functions other than the default tcp_output -> tcp_output_segment
|
||||
@@ -105,7 +119,7 @@ tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
|
||||
tcphdr->seqno = seqno_be;
|
||||
tcphdr->ackno = htonl(pcb->rcv_nxt);
|
||||
TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
|
||||
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
||||
tcphdr->wnd = htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
|
||||
tcphdr->chksum = 0;
|
||||
tcphdr->urgp = 0;
|
||||
|
||||
@@ -162,13 +176,14 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
|
||||
u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
|
||||
|
||||
if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n"));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no memory.\n"));
|
||||
pbuf_free(p);
|
||||
return NULL;
|
||||
}
|
||||
seg->flags = optflags;
|
||||
seg->next = NULL;
|
||||
seg->p = p;
|
||||
LWIP_ASSERT("p->tot_len >= optlen", p->tot_len >= optlen);
|
||||
seg->len = p->tot_len - optlen;
|
||||
#if TCP_OVERSIZE_DBGCHECK
|
||||
seg->oversize_left = 0;
|
||||
@@ -183,7 +198,7 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
|
||||
|
||||
/* build TCP header */
|
||||
if (pbuf_header(p, TCP_HLEN)) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n"));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no room for TCP header in pbuf.\n"));
|
||||
TCP_STATS_INC(tcp.err);
|
||||
tcp_seg_free(seg);
|
||||
return NULL;
|
||||
@@ -212,7 +227,6 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
|
||||
* @param pcb The TCP connection that willo enqueue the pbuf.
|
||||
* @param apiflags API flags given to tcp_write.
|
||||
* @param first_seg true when this pbuf will be used in the first enqueued segment.
|
||||
* @param
|
||||
*/
|
||||
#if TCP_OVERSIZE
|
||||
static struct pbuf *
|
||||
@@ -248,7 +262,7 @@ tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
|
||||
(!first_seg ||
|
||||
pcb->unsent != NULL ||
|
||||
pcb->unacked != NULL))) {
|
||||
alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE));
|
||||
alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(TCP_OVERSIZE_CALC_LENGTH(length)));
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
@@ -306,20 +320,20 @@ tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
|
||||
|
||||
/* fail on too much data */
|
||||
if (len > pcb->snd_buf) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n",
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"TCPWNDSIZE_F")\n",
|
||||
len, pcb->snd_buf));
|
||||
pcb->flags |= TF_NAGLEMEMERR;
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
|
||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen));
|
||||
|
||||
/* If total number of pbufs on the unsent/unacked queues exceeds the
|
||||
* configured maximum, return an error */
|
||||
/* check for configured max queuelen and possible overflow */
|
||||
if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
|
||||
pcb->snd_queuelen, TCP_SND_QUEUELEN));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
|
||||
pcb->snd_queuelen, (u16_t)TCP_SND_QUEUELEN));
|
||||
TCP_STATS_INC(tcp.memerr);
|
||||
pcb->flags |= TF_NAGLEMEMERR;
|
||||
return ERR_MEM;
|
||||
@@ -335,6 +349,7 @@ tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup tcp_raw
|
||||
* Write data for sending (but does not send it immediately).
|
||||
*
|
||||
* It waits in the expectation of more data being sent soon (as
|
||||
@@ -347,7 +362,7 @@ tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
|
||||
* @param len Data length in bytes
|
||||
* @param apiflags combination of following flags :
|
||||
* - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
|
||||
* - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,
|
||||
* - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will not be set on last segment sent,
|
||||
* @return ERR_OK if enqueued, another err_t on error
|
||||
*/
|
||||
err_t
|
||||
@@ -370,10 +385,8 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
err_t err;
|
||||
/* don't allocate segments bigger than half the maximum window we ever received */
|
||||
u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2);
|
||||
|
||||
// Added to fix bug where mss_local was 0 - Joseph Henry
|
||||
mss_local = mss_local == 0 ? pcb->mss : mss_local;
|
||||
u16_t mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max/2));
|
||||
mss_local = mss_local ? mss_local : pcb->mss;
|
||||
|
||||
#if LWIP_NETIF_TX_SINGLE_PBUF
|
||||
/* Always copy to try to create single pbufs for TX */
|
||||
@@ -393,8 +406,12 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
if ((pcb->flags & TF_TIMESTAMP)) {
|
||||
/* Make sure the timestamp option is only included in data segments if we
|
||||
agreed about it with the remote host. */
|
||||
optflags = TF_SEG_OPTS_TS;
|
||||
optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
|
||||
/* ensure that segments can hold at least one data byte... */
|
||||
mss_local = LWIP_MAX(mss_local, LWIP_TCP_OPT_LEN_TS + 1);
|
||||
}
|
||||
#endif /* LWIP_TCP_TIMESTAMPS */
|
||||
|
||||
@@ -432,6 +449,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
|
||||
/* Usable space at the end of the last unsent segment */
|
||||
unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
|
||||
LWIP_ASSERT("mss_local is too small", mss_local >= last_unsent->len + unsent_optlen);
|
||||
space = mss_local - (last_unsent->len + unsent_optlen);
|
||||
|
||||
/*
|
||||
@@ -451,7 +469,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
if (oversize > 0) {
|
||||
LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
|
||||
seg = last_unsent;
|
||||
oversize_used = oversize < len ? oversize : len;
|
||||
oversize_used = LWIP_MIN(space, LWIP_MIN(oversize, len));
|
||||
pos += oversize_used;
|
||||
oversize -= oversize_used;
|
||||
space -= oversize_used;
|
||||
@@ -477,7 +495,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
if (apiflags & TCP_WRITE_FLAG_COPY) {
|
||||
/* Data is copied */
|
||||
if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
|
||||
seglen));
|
||||
goto memerr;
|
||||
@@ -485,25 +503,25 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
#if TCP_OVERSIZE_DBGCHECK
|
||||
last_unsent->oversize_left += oversize;
|
||||
#endif /* TCP_OVERSIZE_DBGCHECK */
|
||||
TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
|
||||
TCP_DATA_COPY2(concat_p->payload, (const u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
|
||||
#if TCP_CHECKSUM_ON_COPY
|
||||
concat_chksummed += seglen;
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
} else {
|
||||
/* Data is not copied */
|
||||
if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("tcp_write: could not allocate memory for zero-copy pbuf\n"));
|
||||
goto memerr;
|
||||
}
|
||||
#if TCP_CHECKSUM_ON_COPY
|
||||
/* calculate the checksum of nocopy-data */
|
||||
tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,
|
||||
tcp_seg_add_chksum(~inet_chksum((const u8_t*)arg + pos, seglen), seglen,
|
||||
&concat_chksum, &concat_chksum_swapped);
|
||||
concat_chksummed += seglen;
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
/* reference the non-volatile payload data */
|
||||
concat_p->payload = (u8_t*)arg + pos;
|
||||
((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos;
|
||||
}
|
||||
|
||||
pos += seglen;
|
||||
@@ -531,17 +549,17 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
u16_t chksum = 0;
|
||||
u8_t chksum_swapped = 0;
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
|
||||
|
||||
if (apiflags & TCP_WRITE_FLAG_COPY) {
|
||||
/* If copy is set, memory should be allocated and data copied
|
||||
* into pbuf */
|
||||
if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
|
||||
goto memerr;
|
||||
}
|
||||
LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
|
||||
(p->len >= seglen));
|
||||
TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
|
||||
TCP_DATA_COPY2((char *)p->payload + optlen, (const u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
|
||||
} else {
|
||||
/* Copy is not set: First allocate a pbuf for holding the data.
|
||||
* Since the referenced data is available at least until it is
|
||||
@@ -553,22 +571,26 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
LWIP_ASSERT("oversize == 0", oversize == 0);
|
||||
#endif /* TCP_OVERSIZE */
|
||||
if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
|
||||
goto memerr;
|
||||
}
|
||||
#if TCP_CHECKSUM_ON_COPY
|
||||
/* calculate the checksum of nocopy-data */
|
||||
chksum = ~inet_chksum((u8_t*)arg + pos, seglen);
|
||||
chksum = ~inet_chksum((const u8_t*)arg + pos, seglen);
|
||||
if (seglen & 1) {
|
||||
chksum_swapped = 1;
|
||||
chksum = SWAP_BYTES_IN_WORD(chksum);
|
||||
}
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
/* reference the non-volatile payload data */
|
||||
p2->payload = (u8_t*)arg + pos;
|
||||
((struct pbuf_rom*)p2)->payload = (const u8_t*)arg + pos;
|
||||
|
||||
/* Second, allocate a pbuf for the headers. */
|
||||
if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
|
||||
/* If allocation fails, we have to deallocate the data pbuf as
|
||||
* well. */
|
||||
pbuf_free(p2);
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n"));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: could not allocate memory for header pbuf\n"));
|
||||
goto memerr;
|
||||
}
|
||||
/* Concatenate the headers and data pbufs together. */
|
||||
@@ -581,7 +603,8 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
* length of the queue exceeds the configured maximum or
|
||||
* overflows. */
|
||||
if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n",
|
||||
queuelen, (int)TCP_SND_QUEUELEN));
|
||||
pbuf_free(p);
|
||||
goto memerr;
|
||||
}
|
||||
@@ -656,6 +679,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
||||
last_unsent->len += concat_p->tot_len;
|
||||
#if TCP_CHECKSUM_ON_COPY
|
||||
if (concat_chksummed) {
|
||||
/*if concat checksumm swapped - swap it back */
|
||||
if (concat_chksum_swapped) {
|
||||
concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum);
|
||||
}
|
||||
tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
|
||||
&last_unsent->chksum_swapped);
|
||||
last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
|
||||
@@ -718,8 +745,6 @@ memerr:
|
||||
*
|
||||
* @param pcb Protocol control block for the TCP connection.
|
||||
* @param flags TCP header flags to set in the outgoing segment.
|
||||
* @param optdata pointer to TCP options, or NULL.
|
||||
* @param optlen length of TCP options in bytes.
|
||||
*/
|
||||
err_t
|
||||
tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
|
||||
@@ -734,10 +759,11 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
|
||||
LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)",
|
||||
(flags & (TCP_SYN | TCP_FIN)) != 0);
|
||||
|
||||
/* check for configured max queuelen and possible overflow */
|
||||
if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
|
||||
pcb->snd_queuelen, TCP_SND_QUEUELEN));
|
||||
/* check for configured max queuelen and possible overflow (FIN flag should always come through!) */
|
||||
if (((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) &&
|
||||
((flags & TCP_FIN) == 0)) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
|
||||
pcb->snd_queuelen, (u16_t)TCP_SND_QUEUELEN));
|
||||
TCP_STATS_INC(tcp.memerr);
|
||||
pcb->flags |= TF_NAGLEMEMERR;
|
||||
return ERR_MEM;
|
||||
@@ -745,24 +771,23 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
|
||||
|
||||
if (flags & TCP_SYN) {
|
||||
optflags = TF_SEG_OPTS_MSS;
|
||||
#if LWIP_WND_SCALE
|
||||
if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_WND_SCALE)) {
|
||||
/* In a <SYN,ACK> (sent in state SYN_RCVD), the window scale option may only
|
||||
be sent if we received a window scale option from the remote host. */
|
||||
optflags |= TF_SEG_OPTS_WND_SCALE;
|
||||
}
|
||||
#endif /* LWIP_WND_SCALE */
|
||||
}
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
if ((pcb->flags & TF_TIMESTAMP)) {
|
||||
/* Make sure the timestamp option is only included in data segments if we
|
||||
agreed about it with the remote host. */
|
||||
optflags |= TF_SEG_OPTS_TS;
|
||||
}
|
||||
#endif /* LWIP_TCP_TIMESTAMPS */
|
||||
optlen = LWIP_TCP_OPT_LENGTH(optflags);
|
||||
|
||||
/* tcp_enqueue_flags is always called with either SYN or FIN in flags.
|
||||
* We need one available snd_buf byte to do that.
|
||||
* This means we can't send FIN while snd_buf==0. A better fix would be to
|
||||
* not include SYN and FIN sequence numbers in the snd_buf count. */
|
||||
if (pcb->snd_buf == 0) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));
|
||||
TCP_STATS_INC(tcp.memerr);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* Allocate pbuf with room for TCP header + options */
|
||||
if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
|
||||
pcb->flags |= TF_NAGLEMEMERR;
|
||||
@@ -778,7 +803,7 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
|
||||
TCP_STATS_INC(tcp.memerr);
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
|
||||
LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % LWIP_MIN(MEM_ALIGNMENT, 4)) == 0);
|
||||
LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
|
||||
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
|
||||
@@ -804,7 +829,6 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
|
||||
if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
|
||||
pcb->snd_lbb++;
|
||||
/* optlen does not influence snd_buf */
|
||||
pcb->snd_buf--;
|
||||
}
|
||||
if (flags & TCP_FIN) {
|
||||
pcb->flags |= TF_FIN;
|
||||
@@ -837,16 +861,34 @@ tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Send an ACK without data.
|
||||
#if LWIP_WND_SCALE
|
||||
/** Build a window scale option (3 bytes long) at the specified options pointer)
|
||||
*
|
||||
* @param opts option pointer where to store the window scale option
|
||||
*/
|
||||
static void
|
||||
tcp_build_wnd_scale_option(u32_t *opts)
|
||||
{
|
||||
/* Pad with one NOP option to make everything nicely aligned */
|
||||
opts[0] = PP_HTONL(0x01030300 | TCP_RCV_SCALE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Send an ACK without data.
|
||||
*
|
||||
* @param pcb Protocol control block for the TCP connection to send the ACK
|
||||
*/
|
||||
err_t
|
||||
tcp_send_empty_ack(struct tcp_pcb *pcb)
|
||||
{
|
||||
err_t err;
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
u8_t optlen = 0;
|
||||
struct netif *netif;
|
||||
#if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP
|
||||
struct tcp_hdr *tcphdr;
|
||||
#endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */
|
||||
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
if (pcb->flags & TF_TIMESTAMP) {
|
||||
@@ -856,16 +898,18 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
|
||||
|
||||
p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
|
||||
if (p == NULL) {
|
||||
/* let tcp_fasttmr retry sending this ACK */
|
||||
pcb->flags |= (TF_ACK_DELAY | TF_ACK_NOW);
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
#if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP
|
||||
tcphdr = (struct tcp_hdr *)p->payload;
|
||||
#endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
|
||||
("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
|
||||
/* remove ACK flags from the PCB, as we send an empty ACK now */
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
|
||||
/* NB. MSS option is only sent on SYNs, so ignore it here */
|
||||
/* NB. MSS and window scale options are only sent on SYNs, so ignore them here */
|
||||
#if LWIP_TCP_TIMESTAMPS
|
||||
pcb->ts_lastacksent = pcb->rcv_nxt;
|
||||
|
||||
@@ -874,23 +918,36 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
|
||||
}
|
||||
#endif
|
||||
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
|
||||
if (netif == NULL) {
|
||||
err = ERR_RTE;
|
||||
} else {
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) {
|
||||
tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len,
|
||||
&pcb->local_ip, &pcb->remote_ip);
|
||||
}
|
||||
#endif
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint));
|
||||
err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip,
|
||||
pcb->ttl, pcb->tos, IP_PROTO_TCP, netif);
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
}
|
||||
pbuf_free(p);
|
||||
|
||||
return ERR_OK;
|
||||
if (err != ERR_OK) {
|
||||
/* let tcp_fasttmr retry sending this ACK */
|
||||
pcb->flags |= (TF_ACK_DELAY | TF_ACK_NOW);
|
||||
} else {
|
||||
/* remove ACK flags from the PCB, as we sent an empty ACK now */
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup tcp_raw
|
||||
* Find out what we can send and send it
|
||||
*
|
||||
* @param pcb Protocol control block for the TCP connection to send data
|
||||
@@ -902,6 +959,8 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct tcp_seg *seg, *useg;
|
||||
u32_t wnd, snd_nxt;
|
||||
err_t err;
|
||||
struct netif *netif;
|
||||
#if TCP_CWND_DEBUG
|
||||
s16_t i = 0;
|
||||
#endif /* TCP_CWND_DEBUG */
|
||||
@@ -940,6 +999,20 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
for (; useg->next != NULL; useg = useg->next);
|
||||
}
|
||||
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
|
||||
if (netif == NULL) {
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
/* If we don't have a local IP address, we get one from netif */
|
||||
if (ip_addr_isany(&pcb->local_ip)) {
|
||||
const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, &pcb->remote_ip);
|
||||
if (local_ip == NULL) {
|
||||
return ERR_RTE;
|
||||
}
|
||||
ip_addr_copy(pcb->local_ip, *local_ip);
|
||||
}
|
||||
|
||||
#if TCP_OUTPUT_DEBUG
|
||||
if (seg == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
|
||||
@@ -948,13 +1021,13 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
#endif /* TCP_OUTPUT_DEBUG */
|
||||
#if TCP_CWND_DEBUG
|
||||
if (seg == NULL) {
|
||||
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
|
||||
", cwnd %"U16_F", wnd %"U32_F
|
||||
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F
|
||||
", cwnd %"TCPWNDSIZE_F", wnd %"U32_F
|
||||
", seg == NULL, ack %"U32_F"\n",
|
||||
pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
|
||||
} else {
|
||||
LWIP_DEBUGF(TCP_CWND_DEBUG,
|
||||
("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
|
||||
("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F
|
||||
", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
|
||||
pcb->snd_wnd, pcb->cwnd, wnd,
|
||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
|
||||
@@ -973,12 +1046,12 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
* either seg->next != NULL or pcb->unacked == NULL;
|
||||
* RST is no sent using tcp_write/tcp_output.
|
||||
*/
|
||||
if((tcp_do_output_nagle(pcb) == 0) &&
|
||||
((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){
|
||||
if ((tcp_do_output_nagle(pcb) == 0) &&
|
||||
((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) {
|
||||
break;
|
||||
}
|
||||
#if TCP_CWND_DEBUG
|
||||
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
|
||||
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
|
||||
pcb->snd_wnd, pcb->cwnd, wnd,
|
||||
ntohl(seg->tcphdr->seqno) + seg->len -
|
||||
pcb->lastack,
|
||||
@@ -986,14 +1059,23 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
++i;
|
||||
#endif /* TCP_CWND_DEBUG */
|
||||
|
||||
pcb->unsent = seg->next;
|
||||
|
||||
if (pcb->state != SYN_SENT) {
|
||||
TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
}
|
||||
|
||||
tcp_output_segment(seg, pcb);
|
||||
#if TCP_OVERSIZE_DBGCHECK
|
||||
seg->oversize_left = 0;
|
||||
#endif /* TCP_OVERSIZE_DBGCHECK */
|
||||
err = tcp_output_segment(seg, pcb, netif);
|
||||
if (err != ERR_OK) {
|
||||
/* segment could not be sent, for whatever reason */
|
||||
pcb->flags |= TF_NAGLEMEMERR;
|
||||
return err;
|
||||
}
|
||||
pcb->unsent = seg->next;
|
||||
if (pcb->state != SYN_SENT) {
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
}
|
||||
snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
|
||||
if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
|
||||
pcb->snd_nxt = snd_nxt;
|
||||
@@ -1047,33 +1129,48 @@ tcp_output(struct tcp_pcb *pcb)
|
||||
*
|
||||
* @param seg the tcp_seg to send
|
||||
* @param pcb the tcp_pcb for the TCP connection used to send the segment
|
||||
* @param netif the netif used to send the segment
|
||||
*/
|
||||
static void
|
||||
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
static err_t
|
||||
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif)
|
||||
{
|
||||
err_t err;
|
||||
u16_t len;
|
||||
struct netif *netif;
|
||||
u32_t *opts;
|
||||
|
||||
/** @bug Exclude retransmitted segments from this count. */
|
||||
snmp_inc_tcpoutsegs();
|
||||
if (seg->p->ref != 1) {
|
||||
/* This can happen if the pbuf of this segment is still referenced by the
|
||||
netif driver due to deferred transmission. Since this function modifies
|
||||
p->len, we must not continue in this case. */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* The TCP header has already been constructed, but the ackno and
|
||||
wnd fields remain. */
|
||||
seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
|
||||
|
||||
/* advertise our receive window size in this TCP segment */
|
||||
seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
|
||||
#if LWIP_WND_SCALE
|
||||
if (seg->flags & TF_SEG_OPTS_WND_SCALE) {
|
||||
/* The Window field in a SYN segment itself (the only type where we send
|
||||
the window scale option) is never scaled. */
|
||||
seg->tcphdr->wnd = htons(TCPWND_MIN16(pcb->rcv_ann_wnd));
|
||||
} else
|
||||
#endif /* LWIP_WND_SCALE */
|
||||
{
|
||||
seg->tcphdr->wnd = htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
|
||||
}
|
||||
|
||||
pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
|
||||
|
||||
/* Add any requested options. NB MSS option is only set on SYN
|
||||
packets, so ignore it here */
|
||||
/* cast through void* to get rid of alignment warnings */
|
||||
opts = (u32_t *)(void *)(seg->tcphdr + 1);
|
||||
if (seg->flags & TF_SEG_OPTS_MSS) {
|
||||
u16_t mss;
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
mss = tcp_eff_send_mss(TCP_MSS, &pcb->remote_ip);
|
||||
mss = tcp_eff_send_mss(TCP_MSS, &pcb->local_ip, &pcb->remote_ip);
|
||||
#else /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
mss = TCP_MSS;
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
@@ -1088,23 +1185,19 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
opts += 3;
|
||||
}
|
||||
#endif
|
||||
#if LWIP_WND_SCALE
|
||||
if (seg->flags & TF_SEG_OPTS_WND_SCALE) {
|
||||
tcp_build_wnd_scale_option(opts);
|
||||
opts += 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set retransmission timer running if it is not currently enabled
|
||||
This must be set before checking the route. */
|
||||
if (pcb->rtime == -1) {
|
||||
if (pcb->rtime < 0) {
|
||||
pcb->rtime = 0;
|
||||
}
|
||||
|
||||
/* If we don't have a local IP address, we get one by
|
||||
calling ip_route(). */
|
||||
if (ip_addr_isany(&(pcb->local_ip))) {
|
||||
netif = ip_route(&(pcb->remote_ip));
|
||||
if (netif == NULL) {
|
||||
return;
|
||||
}
|
||||
ip_addr_copy(pcb->local_ip, netif->ip_addr);
|
||||
}
|
||||
|
||||
if (pcb->rttest == 0) {
|
||||
pcb->rttest = tcp_ticks;
|
||||
pcb->rtseq = ntohl(seg->tcphdr->seqno);
|
||||
@@ -1116,6 +1209,10 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
seg->len));
|
||||
|
||||
len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
|
||||
if (len == 0) {
|
||||
/** Exclude retransmitted segments from this count. */
|
||||
MIB2_STATS_INC(mib2.tcpoutsegs);
|
||||
}
|
||||
|
||||
seg->p->len -= len;
|
||||
seg->p->tot_len -= len;
|
||||
@@ -1124,13 +1221,12 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
|
||||
seg->tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) {
|
||||
#if TCP_CHECKSUM_ON_COPY
|
||||
{
|
||||
u32_t acc;
|
||||
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
|
||||
u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
|
||||
&(pcb->remote_ip),
|
||||
IP_PROTO_TCP, seg->p->tot_len);
|
||||
u16_t chksum_slow = ip_chksum_pseudo(seg->p, IP_PROTO_TCP,
|
||||
seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip);
|
||||
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
|
||||
if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
|
||||
LWIP_ASSERT("data included but not checksummed",
|
||||
@@ -1138,9 +1234,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
}
|
||||
|
||||
/* rebuild TCP header checksum (TCP header changes for retransmissions!) */
|
||||
acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
|
||||
&(pcb->remote_ip),
|
||||
IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
|
||||
acc = ip_chksum_pseudo_partial(seg->p, IP_PROTO_TCP,
|
||||
seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4, &pcb->local_ip, &pcb->remote_ip);
|
||||
/* add payload checksum */
|
||||
if (seg->chksum_swapped) {
|
||||
seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
|
||||
@@ -1150,28 +1245,25 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
seg->tcphdr->chksum = FOLD_U32T(acc);
|
||||
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
|
||||
if (chksum_slow != seg->tcphdr->chksum) {
|
||||
LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
|
||||
TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL(
|
||||
("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
|
||||
seg->tcphdr->chksum, chksum_slow));
|
||||
seg->tcphdr->chksum = chksum_slow;
|
||||
}
|
||||
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
|
||||
}
|
||||
#else /* TCP_CHECKSUM_ON_COPY */
|
||||
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
|
||||
&(pcb->remote_ip),
|
||||
IP_PROTO_TCP, seg->p->tot_len);
|
||||
seg->tcphdr->chksum = ip_chksum_pseudo(seg->p, IP_PROTO_TCP,
|
||||
seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip);
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_TCP */
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint));
|
||||
err = ip_output_if(seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
|
||||
pcb->tos, IP_PROTO_TCP, netif);
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1196,15 +1288,16 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
*/
|
||||
void
|
||||
tcp_rst(u32_t seqno, u32_t ackno,
|
||||
ip_addr_t *local_ip, ip_addr_t *remote_ip,
|
||||
const ip_addr_t *local_ip, const ip_addr_t *remote_ip,
|
||||
u16_t local_port, u16_t remote_port)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
struct netif *netif;
|
||||
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
|
||||
return;
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
|
||||
(p->len >= sizeof(struct tcp_hdr)));
|
||||
@@ -1215,18 +1308,28 @@ tcp_rst(u32_t seqno, u32_t ackno,
|
||||
tcphdr->seqno = htonl(seqno);
|
||||
tcphdr->ackno = htonl(ackno);
|
||||
TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
|
||||
#if LWIP_WND_SCALE
|
||||
tcphdr->wnd = PP_HTONS(((TCP_WND >> TCP_RCV_SCALE) & 0xFFFF));
|
||||
#else
|
||||
tcphdr->wnd = PP_HTONS(TCP_WND);
|
||||
#endif
|
||||
tcphdr->chksum = 0;
|
||||
tcphdr->urgp = 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);
|
||||
snmp_inc_tcpoutrsts();
|
||||
/* 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);
|
||||
MIB2_STATS_INC(mib2.tcpoutrsts);
|
||||
|
||||
netif = ip_route(local_ip, remote_ip);
|
||||
if (netif != NULL) {
|
||||
#if CHECKSUM_GEN_TCP
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) {
|
||||
tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len,
|
||||
local_ip, remote_ip);
|
||||
}
|
||||
#endif
|
||||
/* Send output with hardcoded TTL/HL since we have no access to the pcb */
|
||||
ip_output_if(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP, netif);
|
||||
}
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
|
||||
}
|
||||
@@ -1251,11 +1354,16 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
|
||||
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
|
||||
/* concatenate unsent queue after unacked queue */
|
||||
seg->next = pcb->unsent;
|
||||
#if TCP_OVERSIZE_DBGCHECK
|
||||
/* if last unsent changed, we need to update unsent_oversize */
|
||||
if (pcb->unsent == NULL) {
|
||||
pcb->unsent_oversize = seg->oversize_left;
|
||||
}
|
||||
#endif /* TCP_OVERSIZE_DBGCHECK */
|
||||
/* unsent queue is the concatenated queue (of unacked, unsent) */
|
||||
pcb->unsent = pcb->unacked;
|
||||
/* unacked queue is now empty */
|
||||
pcb->unacked = NULL;
|
||||
/* last unsent hasn't changed, no need to reset unsent_oversize */
|
||||
|
||||
/* increment number of retransmissions */
|
||||
++pcb->nrtx;
|
||||
@@ -1270,7 +1378,7 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
|
||||
/**
|
||||
* Requeue the first unacked segment for retransmission
|
||||
*
|
||||
* Called by tcp_receive() for fast retramsmit.
|
||||
* Called by tcp_receive() for fast retransmit.
|
||||
*
|
||||
* @param pcb the tcp_pcb for which to retransmit the first unacked segment
|
||||
*/
|
||||
@@ -1309,7 +1417,7 @@ tcp_rexmit(struct tcp_pcb *pcb)
|
||||
pcb->rttest = 0;
|
||||
|
||||
/* Do the actual retransmission. */
|
||||
snmp_inc_tcpretranssegs();
|
||||
MIB2_STATS_INC(mib2.tcpretranssegs);
|
||||
/* No need to call tcp_output: we are always called from tcp_input()
|
||||
and thus tcp_output directly returns. */
|
||||
}
|
||||
@@ -1341,16 +1449,19 @@ tcp_rexmit_fast(struct tcp_pcb *pcb)
|
||||
}
|
||||
|
||||
/* The minimum value for ssthresh should be 2 MSS */
|
||||
if (pcb->ssthresh < 2*pcb->mss) {
|
||||
if (pcb->ssthresh < (2U * pcb->mss)) {
|
||||
LWIP_DEBUGF(TCP_FR_DEBUG,
|
||||
("tcp_receive: The minimum value for ssthresh %"U16_F
|
||||
("tcp_receive: The minimum value for ssthresh %"TCPWNDSIZE_F
|
||||
" should be min 2 mss %"U16_F"...\n",
|
||||
pcb->ssthresh, 2*pcb->mss));
|
||||
pcb->ssthresh, (u16_t)(2*pcb->mss)));
|
||||
pcb->ssthresh = 2*pcb->mss;
|
||||
}
|
||||
|
||||
pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
|
||||
pcb->flags |= TF_INFR;
|
||||
|
||||
/* Reset the retransmission timer to prevent immediate rto retransmissions */
|
||||
pcb->rtime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1363,45 +1474,49 @@ tcp_rexmit_fast(struct tcp_pcb *pcb)
|
||||
*
|
||||
* @param pcb the tcp_pcb for which to send a keepalive packet
|
||||
*/
|
||||
void
|
||||
err_t
|
||||
tcp_keepalive(struct tcp_pcb *pcb)
|
||||
{
|
||||
err_t err;
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
struct netif *netif;
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
|
||||
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to "));
|
||||
ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip);
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
|
||||
tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
|
||||
tcp_ticks, pcb->tmr, (u16_t)pcb->keep_cnt_sent));
|
||||
|
||||
p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
|
||||
if(p == NULL) {
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG,
|
||||
("tcp_keepalive: could not allocate memory for pbuf\n"));
|
||||
return;
|
||||
return ERR_MEM;
|
||||
}
|
||||
tcphdr = (struct tcp_hdr *)p->payload;
|
||||
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
|
||||
if (netif == NULL) {
|
||||
err = ERR_RTE;
|
||||
} else {
|
||||
#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 */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
|
||||
&(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) {
|
||||
struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload;
|
||||
tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len,
|
||||
&pcb->local_ip, &pcb->remote_ip);
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_TCP */
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
/* Send output to IP */
|
||||
NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint));
|
||||
err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, netif);
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
}
|
||||
pbuf_free(p);
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
|
||||
pcb->snd_nxt - 1, pcb->rcv_nxt));
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F" err %d.\n",
|
||||
pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -1413,33 +1528,34 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
||||
*
|
||||
* @param pcb the tcp_pcb for which to send a zero-window probe packet
|
||||
*/
|
||||
void
|
||||
err_t
|
||||
tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
{
|
||||
err_t err;
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
struct tcp_seg *seg;
|
||||
u16_t len;
|
||||
u8_t is_fin;
|
||||
struct netif *netif;
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG,
|
||||
("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
|
||||
U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
|
||||
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to "));
|
||||
ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip);
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG,
|
||||
("tcp_zero_window_probe: tcp_ticks %"U32_F
|
||||
" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
|
||||
tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
|
||||
tcp_ticks, pcb->tmr, (u16_t)pcb->keep_cnt_sent));
|
||||
|
||||
seg = pcb->unacked;
|
||||
|
||||
if(seg == NULL) {
|
||||
if (seg == NULL) {
|
||||
seg = pcb->unsent;
|
||||
}
|
||||
if(seg == NULL) {
|
||||
return;
|
||||
if (seg == NULL) {
|
||||
/* nothing to send, zero window probe not needed */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
|
||||
@@ -1447,9 +1563,9 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
len = is_fin ? 0 : 1;
|
||||
|
||||
p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
|
||||
if(p == NULL) {
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
|
||||
return;
|
||||
return ERR_MEM;
|
||||
}
|
||||
tcphdr = (struct tcp_hdr *)p->payload;
|
||||
|
||||
@@ -1465,24 +1581,30 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len);
|
||||
}
|
||||
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
|
||||
if (netif == NULL) {
|
||||
err = ERR_RTE;
|
||||
} else {
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) {
|
||||
tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len,
|
||||
&pcb->local_ip, &pcb->remote_ip);
|
||||
}
|
||||
#endif
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
/* Send output to IP */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
|
||||
&(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
/* Send output to IP */
|
||||
NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint));
|
||||
err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
|
||||
0, IP_PROTO_TCP, netif);
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
|
||||
" ackno %"U32_F".\n",
|
||||
pcb->snd_nxt - 1, pcb->rcv_nxt));
|
||||
" ackno %"U32_F" err %d.\n",
|
||||
pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err));
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
Reference in New Issue
Block a user