mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-11-04 14:29:39 +00:00
Fixed bug #28054: Two segments with FIN flag on the out-of-sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code
This commit is contained in:
parent
c5d2e536cf
commit
59a5fb7ce8
@ -46,6 +46,10 @@ HISTORY
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2009-11-29: Simon Goldschmidt
|
||||
* tcp_in.c: Fixed bug #28054: Two segments with FIN flag on the out-of-
|
||||
sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code
|
||||
|
||||
2009-11-29: Simon Goldschmidt
|
||||
* pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by
|
||||
queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty
|
||||
|
@ -735,6 +735,40 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
/**
|
||||
* Insert segment into the list (segments covered with new one will be deleted)
|
||||
*
|
||||
* Called from tcp_receive()
|
||||
*/
|
||||
static void
|
||||
tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
|
||||
{
|
||||
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
|
||||
/* received segment overlaps all following segments */
|
||||
tcp_segs_free(next);
|
||||
next = NULL;
|
||||
}
|
||||
else {
|
||||
/* delete some following segments */
|
||||
while (next &&
|
||||
TCP_SEQ_GT((seqno + cseg->len),
|
||||
(next->tcphdr->seqno + next->len))) {
|
||||
struct tcp_seg *old_seg = next;
|
||||
next = next->next;
|
||||
tcp_seg_free(old_seg);
|
||||
}
|
||||
if (next &&
|
||||
TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
|
||||
/* We need to trim the incoming segment. */
|
||||
cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(cseg->p, cseg->len);
|
||||
}
|
||||
}
|
||||
cseg->next = next;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Called by tcp_process. Checks if the given segment is an ACK for outstanding
|
||||
* data, and if so frees the memory of the buffered data. Next, is places the
|
||||
@ -1135,7 +1169,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
while (pcb->ooseq != NULL) {
|
||||
struct tcp_seg *old_ooseq = pcb->ooseq;
|
||||
pcb->ooseq = pcb->ooseq->next;
|
||||
memp_free(MEMP_TCP_SEG, old_ooseq);
|
||||
tcp_seg_free(old_ooseq);
|
||||
}
|
||||
} else if (TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + tcplen)) {
|
||||
if (pcb->ooseq->len > 0) {
|
||||
@ -1157,7 +1191,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
(TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {
|
||||
struct tcp_seg *old_ooseq = pcb->ooseq;
|
||||
pcb->ooseq = pcb->ooseq->next;
|
||||
memp_free(MEMP_TCP_SEG, old_ooseq);
|
||||
tcp_seg_free(old_ooseq);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1227,7 +1261,6 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pcb->ooseq = cseg->next;
|
||||
tcp_seg_free(cseg);
|
||||
}
|
||||
@ -1266,25 +1299,16 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
discard. */
|
||||
if (inseg.len > next->len) {
|
||||
/* The incoming segment is larger than the old
|
||||
segment. We replace the old segment with the new
|
||||
segment. We replace some segments with the new
|
||||
one. */
|
||||
cseg = tcp_seg_copy(&inseg);
|
||||
if (cseg != NULL) {
|
||||
cseg->next = next->next;
|
||||
if (prev != NULL) {
|
||||
prev->next = cseg;
|
||||
} else {
|
||||
pcb->ooseq = cseg;
|
||||
}
|
||||
tcp_seg_free(next);
|
||||
if (cseg->next != NULL) {
|
||||
next = cseg->next;
|
||||
if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
|
||||
/* We need to trim the incoming segment. */
|
||||
cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(cseg->p, cseg->len);
|
||||
}
|
||||
}
|
||||
tcp_oos_insert_segment(cseg, next);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
@ -1300,51 +1324,44 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
than the sequence number of the first segment on the
|
||||
queue. We put the incoming segment first on the
|
||||
queue. */
|
||||
|
||||
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
||||
/* We need to trim the incoming segment. */
|
||||
inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(inseg.p, inseg.len);
|
||||
}
|
||||
cseg = tcp_seg_copy(&inseg);
|
||||
if (cseg != NULL) {
|
||||
cseg->next = next;
|
||||
pcb->ooseq = cseg;
|
||||
tcp_oos_insert_segment(cseg, next);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} 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
|
||||
incoming segment and trim the previous segment, if
|
||||
needed. */
|
||||
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
||||
/* We need to trim the incoming segment. */
|
||||
inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
|
||||
pbuf_realloc(inseg.p, inseg.len);
|
||||
}
|
||||
|
||||
cseg = tcp_seg_copy(&inseg);
|
||||
if (cseg != NULL) {
|
||||
cseg->next = next;
|
||||
prev->next = cseg;
|
||||
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
|
||||
/* We need to trim the prev segment. */
|
||||
prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
|
||||
pbuf_realloc(prev->p, prev->len);
|
||||
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 trim the previous
|
||||
segment, delete next segments that included in received segment
|
||||
and trim received, if needed. */
|
||||
cseg = tcp_seg_copy(&inseg);
|
||||
if (cseg != NULL) {
|
||||
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
|
||||
/* We need to trim the prev segment. */
|
||||
prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
|
||||
pbuf_realloc(prev->p, prev->len);
|
||||
}
|
||||
prev->next = cseg;
|
||||
tcp_oos_insert_segment(cseg, next);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* If the "next" segment is the last segment on the
|
||||
ooseq queue, we add the incoming segment to the end
|
||||
of the list. */
|
||||
if (next->next == NULL &&
|
||||
TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
|
||||
if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
|
||||
/* segment "next" already contains all data */
|
||||
break;
|
||||
}
|
||||
next->next = tcp_seg_copy(&inseg);
|
||||
if (next->next != NULL) {
|
||||
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
|
||||
|
Loading…
Reference in New Issue
Block a user