mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-02 12:52:10 +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:
|
++ 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
|
2009-11-29: Simon Goldschmidt
|
||||||
* pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by
|
* 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
|
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;
|
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
|
* 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
|
* 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) {
|
while (pcb->ooseq != NULL) {
|
||||||
struct tcp_seg *old_ooseq = pcb->ooseq;
|
struct tcp_seg *old_ooseq = pcb->ooseq;
|
||||||
pcb->ooseq = pcb->ooseq->next;
|
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)) {
|
} else if (TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + tcplen)) {
|
||||||
if (pcb->ooseq->len > 0) {
|
if (pcb->ooseq->len > 0) {
|
||||||
@ -1157,7 +1191,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
(TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {
|
(TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {
|
||||||
struct tcp_seg *old_ooseq = pcb->ooseq;
|
struct tcp_seg *old_ooseq = pcb->ooseq;
|
||||||
pcb->ooseq = pcb->ooseq->next;
|
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;
|
pcb->ooseq = cseg->next;
|
||||||
tcp_seg_free(cseg);
|
tcp_seg_free(cseg);
|
||||||
}
|
}
|
||||||
@ -1266,25 +1299,16 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
discard. */
|
discard. */
|
||||||
if (inseg.len > next->len) {
|
if (inseg.len > next->len) {
|
||||||
/* The incoming segment is larger than the old
|
/* 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. */
|
one. */
|
||||||
cseg = tcp_seg_copy(&inseg);
|
cseg = tcp_seg_copy(&inseg);
|
||||||
if (cseg != NULL) {
|
if (cseg != NULL) {
|
||||||
cseg->next = next->next;
|
|
||||||
if (prev != NULL) {
|
if (prev != NULL) {
|
||||||
prev->next = cseg;
|
prev->next = cseg;
|
||||||
} else {
|
} else {
|
||||||
pcb->ooseq = cseg;
|
pcb->ooseq = cseg;
|
||||||
}
|
}
|
||||||
tcp_seg_free(next);
|
tcp_oos_insert_segment(cseg, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
@ -1300,51 +1324,44 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
than the sequence number of the first segment on the
|
than the sequence number of the first segment on the
|
||||||
queue. We put the incoming segment first on the
|
queue. We put the incoming segment first on the
|
||||||
queue. */
|
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);
|
cseg = tcp_seg_copy(&inseg);
|
||||||
if (cseg != NULL) {
|
if (cseg != NULL) {
|
||||||
cseg->next = next;
|
|
||||||
pcb->ooseq = cseg;
|
pcb->ooseq = cseg;
|
||||||
|
tcp_oos_insert_segment(cseg, next);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
/*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
|
/*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
|
||||||
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
|
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
|
||||||
if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){
|
if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
|
||||||
/* The sequence number of the incoming segment is in
|
/* The sequence number of the incoming segment is in
|
||||||
between the sequence numbers of the previous and
|
between the sequence numbers of the previous and
|
||||||
the next segment on ->ooseq. We trim and insert the
|
the next segment on ->ooseq. We trim trim the previous
|
||||||
incoming segment and trim the previous segment, if
|
segment, delete next segments that included in received segment
|
||||||
needed. */
|
and trim received, if needed. */
|
||||||
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
cseg = tcp_seg_copy(&inseg);
|
||||||
/* We need to trim the incoming segment. */
|
if (cseg != NULL) {
|
||||||
inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
|
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
|
||||||
pbuf_realloc(inseg.p, inseg.len);
|
/* We need to trim the prev segment. */
|
||||||
}
|
prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
|
||||||
|
pbuf_realloc(prev->p, prev->len);
|
||||||
cseg = tcp_seg_copy(&inseg);
|
}
|
||||||
if (cseg != NULL) {
|
prev->next = cseg;
|
||||||
cseg->next = next;
|
tcp_oos_insert_segment(cseg, 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);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
/* If the "next" segment is the last segment on the
|
/* If the "next" segment is the last segment on the
|
||||||
ooseq queue, we add the incoming segment to the end
|
ooseq queue, we add the incoming segment to the end
|
||||||
of the list. */
|
of the list. */
|
||||||
if (next->next == NULL &&
|
if (next->next == NULL &&
|
||||||
TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
|
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);
|
next->next = tcp_seg_copy(&inseg);
|
||||||
if (next->next != NULL) {
|
if (next->next != NULL) {
|
||||||
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
|
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user