tcp: handle segmentation oversize during segment split (bug #52676)

This fixes a bug in tcp_split_unsent_seg where oversized segments were not
handled during the split, leading to pcb->unsent_oversized and
useg->oversize_left getting out of sync with the split segment

This would result in over-writing the pbuf if another call to tcp_write()
happened after the split, but before the remainder of the split was sent in
tcp_output

Now pcb->unsent_oversized is explicitly cleared (because the remainder at
the tail is never oversized) and useg->oversized_left is cleared after it is
trimmed

This also updates the test_tcp_persist_split unit test to explicitly check for
this case
This commit is contained in:
Joel Cunningham
2017-12-15 12:15:35 -06:00
parent 31c60775b6
commit 50a5d85f45
2 changed files with 50 additions and 26 deletions

View File

@@ -1902,6 +1902,10 @@ tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split)
pbuf_realloc(useg->p, useg->p->tot_len - remainder);
useg->len -= remainder;
TCPH_SET_FLAG(useg->tcphdr, split_flags);
#if TCP_OVERSIZE_DBGCHECK
/* By trimming, realloc may have actually shrunk the pbuf, so clear oversize_left */
useg->oversize_left = 0;
#endif /* TCP_OVERSIZE_DBGCHECK */
#if TCP_CHECKSUM_ON_COPY
/* The checksum on the split segment is now incorrect. We need to re-run it over the split */
@@ -1932,6 +1936,14 @@ tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split)
seg->next = useg->next;
useg->next = seg;
#if TCP_OVERSIZE
/* If remainder is last segment on the unsent, ensure we clear the oversize amount
* because the remainder is always sized to the exact remaining amount */
if (seg->next == NULL) {
pcb->unsent_oversize = 0;
}
#endif /* TCP_OVERSIZE */
return ERR_OK;
memerr:
TCP_STATS_INC(tcp.memerr);