--- tcp_in_o.c	2009-11-19 18:19:09.765625000 +0100
+++ tcp_in.c	2009-11-20 17:08:38.921875000 +0100
@@ -1277,13 +1277,23 @@
                   } 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);
+                  if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
+                    cseg->next = NULL;
+                    while (next != NULL) {
+                      struct tcp_seg *old_seg = next;
+                      next = next->next;
+                      memp_free(MEMP_TCP_SEG, old_seg);
+                    }               
+                  }
+                  else {
+                    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);
+                      }
                     }
                   }
                 }
@@ -1302,10 +1312,20 @@
                      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);
+                  if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
+                    cseg->next = NULL;
+                    while (next != NULL) {
+                      struct tcp_seg *old_seg = next;
+                      next = next->next;
+                      memp_free(MEMP_TCP_SEG, old_seg);
+                    }               
+                  }
+                  else {
+                    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) {
@@ -1323,21 +1343,39 @@
                    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);
                   }
+                  prev->next = cseg;
+                  if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
+                    cseg->next = NULL;
+                    while (next != NULL) {
+                      struct tcp_seg *old_seg = next;
+                      next = next->next;
+                      memp_free(MEMP_TCP_SEG, old_seg);
+                    }               
+                  }
+                  else {
+                    /* delete some segments */
+                    while (next &&
+                           TCP_SEQ_GT((seqno + cseg->len),
+                                      (next->tcphdr->seqno + next->len))) {
+                      struct tcp_seg *old_seg = next;
+                      next = next->next;
+                      memp_free(MEMP_TCP_SEG, 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;
+                  }
                 }
                 break;
               }
