Skip to content

Commit

Permalink
Cherry-pick from the upstream lwip
Browse files Browse the repository at this point in the history
tcp: handle pcb->snd_queuelen and chained pbufs during segment split (bug #52692)

This fixes a bug in tcp_split_unsent_seg() where a chained pbuf was
not correctly updating pcb->snd_queuelen during trimming and snd_queuelen
would desynchronize if pbuf_realloc() freed some of the chain

Also, use pbuf_clen() for adding the new remaining segment rather than ++.
The new remaining segment should always be one pbuf due to the semantics
of PBUF_RAM, but this follows the best practice of using pbuf_clen()
  • Loading branch information
madeye committed Aug 20, 2019
1 parent 6e14849 commit 7bcb2e4
Showing 1 changed file with 7 additions and 1 deletion.
8 changes: 7 additions & 1 deletion lwip/src/core/tcp_out.c
Original file line number Diff line number Diff line change
Expand Up @@ -1875,12 +1875,18 @@ tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split)
seg->flags |= TF_SEG_DATA_CHECKSUMMED;
#endif /* TCP_CHECKSUM_ON_COPY */

/* Remove this segment from the queue since trimming it may free pbufs */
pcb->snd_queuelen -= pbuf_clen(useg->p);

/* Trim the original pbuf into our split size. At this point our remainder segment must be setup
successfully because we are modifying the original segment */
pbuf_realloc(useg->p, useg->p->tot_len - remainder);
useg->len -= remainder;
TCPH_SET_FLAG(useg->tcphdr, split_flags);

/* Add back to the queue with new trimmed pbuf */
pcb->snd_queuelen += pbuf_clen(useg->p);

#if TCP_CHECKSUM_ON_COPY
/* The checksum on the split segment is now incorrect. We need to re-run it over the split */
useg->chksum = 0;
Expand All @@ -1904,7 +1910,7 @@ tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split)
/* Update number of segments on the queues. Note that length now may
* exceed TCP_SND_QUEUELEN! We don't have to touch pcb->snd_buf
* because the total amount of data is constant when packet is split */
pcb->snd_queuelen++;
pcb->snd_queuelen += pbuf_clen(seg->p);

/* Finally insert remainder into queue after split (which stays head) */
seg->next = useg->next;
Expand Down

0 comments on commit 7bcb2e4

Please sign in to comment.