diff --git a/src/core/tcp.c b/src/core/tcp.c index 0fc70262..f8c1fd73 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -1344,6 +1344,9 @@ tcp_pcb_purge(struct tcp_pcb *pcb) tcp_segs_free(pcb->unsent); tcp_segs_free(pcb->unacked); pcb->unacked = pcb->unsent = NULL; +#if TCP_OVERSIZE + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ } } diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 6501fbe3..5abdfc9d 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -147,6 +147,9 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, seg->p = p; seg->dataptr = p->payload; seg->len = p->tot_len - optlen; +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ /* build TCP header */ if (pbuf_header(p, TCP_HLEN)) { @@ -355,11 +358,16 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) * function. */ #if TCP_OVERSIZE +#if TCP_OVERSIZE_DBGCHECK + /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */ + LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", + pcb->unsent_oversize == last_unsent->oversize_left); +#endif /* TCP_OVERSIZE_DBGCHECK */ oversize = pcb->unsent_oversize; if (oversize > 0) { + LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); seg = last_unsent; oversize_used = oversize < len ? oversize : len; - LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); pos += oversize_used; oversize -= oversize_used; space -= oversize_used; @@ -390,6 +398,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) seglen)); goto memerr; } +#if TCP_OVERSIZE_DBGCHECK + last_unsent->oversize_left = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ MEMCPY(concat_p->payload, (u8_t*)arg + pos, seglen); } else { /* Data is not copied */ @@ -404,6 +415,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) pos += seglen; queuelen += pbuf_clen(concat_p); } + } else { + LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", + pcb->unsent_oversize == 0); } /* @@ -435,6 +449,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) * party) we can safely use PBUF_ROM instead of PBUF_REF here. */ struct pbuf *p2; + LWIP_ASSERT("oversize == 0", oversize == 0); 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")); goto memerr; @@ -461,12 +476,16 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) * 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)); + pbuf_free(p); goto memerr; } if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { goto memerr; } +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ /* Fix dataptr for the nocopy case */ if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) { seg->dataptr = (u8_t*)arg + pos; @@ -511,6 +530,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) } } last_unsent->len += oversize_used; +#if TCP_OVERSIZE_DBGCHECK + last_unsent->oversize_left -= oversize_used; +#endif /* TCP_OVERSIZE_DBGCHECK */ } pcb->unsent_oversize = oversize; #endif /* TCP_OVERSIZE */ @@ -889,6 +911,12 @@ tcp_output(struct tcp_pcb *pcb) } seg = pcb->unsent; } +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + /* last unsent has been removed, reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ if (seg != NULL && pcb->persist_backoff == 0 && ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index 4283ab8b..bef4b9f7 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -253,12 +253,23 @@ PACK_STRUCT_END #endif /* LWIP_EVENT_API */ +#if TCP_OVERSIZE && defined(LWIP_DEBUG) +#define TCP_OVERSIZE_DBGCHECK 1 +#else +#define TCP_OVERSIZE_DBGCHECK 0 +#endif + /* 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 */ void *dataptr; /* pointer to the TCP data in the pbuf */ u16_t len; /* the TCP length of this segment */ +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_left; /* Extra bytes available at the end of the last + pbuf in unsent (used for asserting vs. + tcp_pcb.unsent_oversized only) */ +#endif /* TCP_OVERSIZE_DBGCHECK */ u8_t flags; #define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ #define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */