lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lwip-users] Patch for persist timer and silly window bug


From: Per-Henrik Lundblom
Subject: [lwip-users] Patch for persist timer and silly window bug
Date: Tue, 18 Dec 2007 14:40:33 +0100
User-agent: Mutt/1.5.13 (2006-08-11)

Hi,

I guess it is about time to commit the mods and fixes we have done on
the lwIP stack. I have included and attached one large patch (I know
it's bad with one patch to fix several problems but take it or leave
it). The patch was made against a CVS copy from 2007-09-20.

The patch should fix the following things:

- Silly window problem (bug #20199)

- Implementation of the TCP persist timer which lwIP curretly lacks. The
  persist timer is MANDATORY for any TCP implementation. This
  implementation can be slimmed down. This implementation doesn't share
  any code with the retransmit timer even though it should be possible.
  Also, the tcp_split_unsent_seq() function has code copied from other
  tcp_*() functions. I guess you could leave out the split part of the
  persist timer if you want to reduce code size but then you don't fully
  implement the functionality for the persist timer.

Note that this code was 100% written during work time at connectBlue AB
(www.connectblue.se) but is released under the same license as the rest
of lwIP. We really hope it will find its way into the the trunk and that
others will find it useful.

Merry Christmas to all of you!

/PH


diff -ru lwip/src/core/pbuf.c lwip.trunk/src/core/pbuf.c
--- lwip/src/core/pbuf.c        2007-09-10 20:25:15.000000000 +0200
+++ lwip.trunk/src/core/pbuf.c  2007-12-18 11:29:24.703125000 +0100
@@ -617,6 +642,38 @@
 }
 
 /**
+ * Split two pbufs (or pbuf chains) from each other.
+ * 
+ * The caller must keep references to head and tail.
+ *
+ * @param h head pbuf (chain)
+ * @param t tail pbuf (chain)
+ *
+ * The ->tot_len fields of all pbufs of the head chain are adjusted.
+ * The ->next field of the last pbuf of the head chain is adjusted.
+ *
+ */
+void
+pbuf_split(struct pbuf *h, struct pbuf *t)
+{
+  struct pbuf *p, *q;
+  q = NULL;
+
+  LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);
+  if ((h == NULL) || (t == NULL)) return;
+
+  for (p = h; p != t && p != NULL; p = p->next);
+  
+  if (p == t) {
+    for (p = h; p != t; p = p->next) {
+      p->tot_len -= t->tot_len;
+      q = p;
+    }
+    q->next = NULL;
+  }
+}
+
+/**
  * Dechains the first pbuf from its succeeding pbufs in the chain.
  *
  * Makes p->tot_len field equal to p->len.
diff -ru lwip/src/core/tcp.c lwip.trunk/src/core/tcp.c
--- lwip/src/core/tcp.c 2007-09-08 01:02:00.000000000 +0200
+++ lwip.trunk/src/core/tcp.c   2007-12-18 11:29:25.234375000 +0100
@@ -56,6 +56,8 @@
 u32_t tcp_ticks;
 const u8_t tcp_backoff[13] =
     { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
+/* Also seen 1.5, 3, 6, 12, 25, 48, 60 */
+const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; /* Times 
per slowtmr hits */
 
 /* The TCP PCB lists. */
 
@@ -390,9 +392,14 @@
 {
   if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {
     pcb->rcv_wnd = TCP_WND;
+    pcb->rcv_ann_wnd = TCP_WND;
   } else {
     pcb->rcv_wnd += len;
+    if (pcb->rcv_wnd >= pcb->mss) {
+      pcb->rcv_ann_wnd = pcb->rcv_wnd;
+    }
   }
+
   if (!(pcb->flags & TF_ACK_DELAY) &&
      !(pcb->flags & TF_ACK_NOW)) {
     /*
@@ -497,6 +504,7 @@
   pcb->lastack = iss - 1;
   pcb->snd_lbb = iss - 1;
   pcb->rcv_wnd = TCP_WND;
+  pcb->rcv_ann_wnd = TCP_WND;
   pcb->snd_wnd = TCP_WND;
   pcb->mss = TCP_MSS;
   pcb->cwnd = 1;
@@ -564,36 +572,56 @@
       ++pcb_remove;
       LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
     } else {
-      /* Increase the retransmission timer if it is running */
-      if(pcb->rtime >= 0)
-        ++pcb->rtime;
-
-      if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
-        /* Time for a retransmission. */
-        LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F" pcb->rto 
%"S16_F"\n",
-                                    pcb->rtime, pcb->rto));
-
-        /* Double retransmission time-out unless we are trying to
-         * connect to somebody (i.e., we are in SYN_SENT). */
-        if (pcb->state != SYN_SENT) {
-          pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
-        }
-
-        /* Reset the retransmission timer. */
-        pcb->rtime = 0;
-
-        /* Reduce congestion window and ssthresh. */
-        eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
-        pcb->ssthresh = eff_wnd >> 1;
-        if (pcb->ssthresh < pcb->mss) {
-          pcb->ssthresh = pcb->mss * 2;
+      if (pcb->persist_backoff > 0) {
+        /* If snd_wnd is zero, use persist timer to send 1 byte probes
+         * instead of using the standard retransmission mechanism. */
+        pcb->persist_cnt++;
+        if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {
+          pcb->persist_cnt = 0;
+          if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {
+            pcb->persist_backoff++;
+          }
+          pcb->persist_probe++;
+          if (pcb->unacked != NULL) {
+            /* XXX: can we really assume there's only the 1 byte probe
+             * in the unacked queue? */
+            tcp_rexmit(pcb);
+          } else {
+            tcp_output(pcb);
+          }
         }
-        pcb->cwnd = pcb->mss;
-        LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh 
%"U16_F"\n",
-                                     pcb->cwnd, pcb->ssthresh));
+      } else {
+        /* Increase the retransmission timer if it is running */
+        if(pcb->rtime >= 0)
+          ++pcb->rtime;
+        if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
+
+          /* Time for a retransmission. */
+          LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F" pcb->rto 
%"S16_F"\n",
+            pcb->rtime, pcb->rto));
+
+          /* Double retransmission time-out unless we are trying to
+           * connect to somebody (i.e., we are in SYN_SENT). */
+          if (pcb->state != SYN_SENT) {
+            pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
+          }
+
+          /* Reset the retransmission timer. */
+          pcb->rtime = 0;
+
+          /* Reduce congestion window and ssthresh. */
+          eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
+          pcb->ssthresh = eff_wnd >> 1;
+          if (pcb->ssthresh < 2 * pcb->mss) {
+            pcb->ssthresh = pcb->mss * 2;
+          }
+          pcb->cwnd = pcb->mss;
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh 
%"U16_F"\n",
+                                  pcb->cwnd, pcb->ssthresh));
  
-        /* The following needs to be called AFTER cwnd is set to one mss - STJ 
*/
-        tcp_rexmit_rto(pcb);
+          /* The following needs to be called AFTER cwnd is set to one mss - 
STJ */
+          tcp_rexmit_rto(pcb);
+        }
       }
     }
     /* Check if this PCB has stayed too long in FIN-WAIT-2 */
@@ -938,6 +966,7 @@
     pcb->snd_buf = TCP_SND_BUF;
     pcb->snd_queuelen = 0;
     pcb->rcv_wnd = TCP_WND;
+    pcb->rcv_ann_wnd = TCP_WND;
     pcb->tos = 0;
     pcb->ttl = TCP_TTL;
     pcb->mss = TCP_MSS;
diff -ru lwip/src/core/tcp_in.c lwip.trunk/src/core/tcp_in.c
--- lwip/src/core/tcp_in.c      2007-09-08 01:02:00.000000000 +0200
+++ lwip.trunk/src/core/tcp_in.c        2007-12-18 11:29:25.296875000 +0100
@@ -479,7 +484,7 @@
       /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
           TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
       */
-      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
+      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_ann_wnd)) 
{
         acceptable = 1;
       }
     }
@@ -539,7 +544,7 @@
       /* Call the user specified function to call when sucessfully
        * connected. */
       TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
-      tcp_ack(pcb);
+      tcp_ack_now(pcb);
     }
     /* received ACK? possibly a half-open connection */
     else if (flags & TCP_ACK) {
@@ -689,6 +694,9 @@
       pcb->snd_wnd = tcphdr->wnd;
       pcb->snd_wl1 = seqno;
       pcb->snd_wl2 = ackno;
+      if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
+          pcb->persist_backoff = 0;
+      }
       LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", 
pcb->snd_wnd));
 #if TCP_WND_DEBUG
     } else {
@@ -990,7 +998,7 @@
        processed. */
     /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
       TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
-    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){
+    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_ann_wnd - 
1)){
       if (pcb->rcv_nxt == seqno) {
         accepted_inseq = 1; 
         /* The incoming segment is the next in sequence. We check if
@@ -1017,11 +1025,11 @@
 
         /* Update the receiver's (our) window. */
         if (pcb->rcv_wnd < tcplen) {
-          pcb->rcv_wnd = 0;
+          pcb->rcv_wnd = 0;          
         } else {
-          pcb->rcv_wnd -= tcplen;
+          pcb->rcv_wnd -= tcplen;          
         }
-
+        pcb->rcv_ann_wnd = pcb->rcv_wnd;
         /* If there is data in the segment, we make preparations to
            pass this up to the application. The ->recv_data variable
            is used for holding the pbuf that goes to the
@@ -1055,8 +1063,10 @@
           pcb->rcv_nxt += TCP_TCPLEN(cseg);
           if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
             pcb->rcv_wnd = 0;
+            pcb->rcv_ann_wnd = 0;
           } else {
             pcb->rcv_wnd -= TCP_TCPLEN(cseg);
+            pcb->rcv_ann_wnd -= TCP_TCPLEN(cseg);
           }
           if (cseg->p->tot_len > 0) {
             /* Chain this pbuf onto the pbuf that we will pass to
@@ -1214,7 +1224,7 @@
     } else {
       /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
         TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
-      if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
+      if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + 
pcb->rcv_ann_wnd-1)){
         tcp_ack_now(pcb);
       }
     }
@@ -1223,7 +1233,8 @@
        fall out of the window are ACKed. */
     /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
       TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
-    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
+    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + 
pcb->rcv_ann_wnd-1) &&
+       !(pcb->snd_wnd == 0)) {
       tcp_ack_now(pcb);
     }
   }
diff -ru lwip/src/core/tcp_out.c lwip.trunk/src/core/tcp_out.c
--- lwip/src/core/tcp_out.c     2007-09-08 01:02:00.000000000 +0200
+++ lwip.trunk/src/core/tcp_out.c       2007-12-18 11:29:25.343750000 +0100
@@ -57,6 +57,7 @@
 
 /* Forward declarations.*/
 static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
+static err_t tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t len);
 
 /**
  * Called by tcp_close() to send a segment including flags but not data.
@@ -451,7 +452,7 @@
     tcphdr->seqno = htonl(pcb->snd_nxt);
     tcphdr->ackno = htonl(pcb->rcv_nxt);
     TCPH_FLAGS_SET(tcphdr, TCP_ACK);
-    tcphdr->wnd = htons(pcb->rcv_wnd);
+    tcphdr->wnd = htons(pcb->rcv_ann_wnd);
     tcphdr->urgp = 0;
     TCPH_HDRLEN_SET(tcphdr, 5);
 
@@ -497,9 +498,32 @@
                             ntohl(seg->tcphdr->seqno), pcb->lastack));
   }
 #endif /* TCP_CWND_DEBUG */
+  /* If the next segment in the unsent queue doesn't fit into the sending 
window,
+   * then split it.
+   */
+  if (seg != NULL && ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > 
wnd) {    
+    if (pcb->snd_wnd == 0) {
+      if (pcb->persist_backoff == 0) {          
+        /* prepare for persist timer */
+        if (tcp_split_unsent_seg(pcb, 1) == ERR_OK) {
+          /* delay 1 byte probe by starting the presist timer */
+          seg = pcb->unsent;
+          pcb->persist_cnt = 0;
+          pcb->persist_backoff = 1;
+          pcb->persist_probe = 0;
+        }
+      }
+    } else {
+      tcp_split_unsent_seg(pcb, wnd);
+      /* pcb->unsent is updated */
+      seg = pcb->unsent;
+    }
+  }
+
   /* data available and window allows it to be sent? */
   while (seg != NULL &&
-  ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
+  ((ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) ||
+  pcb->persist_probe)) {
 #if TCP_CWND_DEBUG
     LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", 
wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
                             pcb->snd_wnd, pcb->cwnd, wnd,
@@ -508,7 +532,9 @@
                             ntohl(seg->tcphdr->seqno), pcb->lastack, i));
     ++i;
 #endif /* TCP_CWND_DEBUG */
-
+    if (pcb->persist_probe) {      
+      pcb->persist_probe = 0;
+    }
     pcb->unsent = seg->next;
 
     if (pcb->state != SYN_SENT) {
@@ -571,13 +597,7 @@
    wnd fields remain. */
   seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
 
-  /* silly window avoidance */
-  if (pcb->rcv_wnd < pcb->mss) {
-    seg->tcphdr->wnd = 0;
-  } else {
-    /* advertise our receive window size in this TCP segment */
-    seg->tcphdr->wnd = htons(pcb->rcv_wnd);
-  }
+  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
 
   /* If we don't have a local IP address, we get one by
      calling ip_route(). */
@@ -799,7 +819,7 @@
    tcphdr->seqno = htonl(pcb->snd_nxt - 1);
    tcphdr->ackno = htonl(pcb->rcv_nxt);
    TCPH_FLAGS_SET(tcphdr, 0);
-   tcphdr->wnd = htons(pcb->rcv_wnd);
+   tcphdr->wnd = htons(pcb->rcv_ann_wnd);
    tcphdr->urgp = 0;
    TCPH_HDRLEN_SET(tcphdr, 5);
 
@@ -830,4 +850,189 @@
   LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno 
%"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt));
 }
 
+
+static err_t
+tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t len)
+{
+  struct tcp_seg *seg, *useg;
+  struct pbuf *p, *q, *before_p;
+  u8_t *ptr;
+  u16_t offset, shrink;
+  u8_t queuelen;
+  u8_t method = 0;
+
+  useg = pcb->unsent;
+  if (useg == NULL) {
+    return ERR_MEM;
+  }
+
+  if (len == 0 || useg->len <= len) {
+    return ERR_OK;
+  }
+
+  LWIP_ASSERT("len <= mss", len <= pcb->mss);
+  LWIP_ASSERT("pcb->unsent->len > 0", pcb->unsent->len > 0);
+
+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: split_unsent_seg: %u\n", 
(unsigned int)pcb->snd_queuelen));
+
+  /* We should check that we don't exceed TCP_SND_QUEUELEN but we need
+   * to split this packet so we may actually exceed the max value by 
+   * one!
+   */
+  queuelen = pcb->snd_queuelen;
+
+  /* Allocate memory for tcp_seg, and fill in fields. */
+  seg = memp_malloc(MEMP_TCP_SEG);
+  if (seg == NULL) {
+    LWIP_DEBUGF(TCP_RESIZE_DEBUG | 2, ("tcp_split_unsent_seg: could not 
allocate memory for tcp_seg\n"));
+    goto memerr;
+  }
+  seg->p = NULL;
+
+  /* copy from volatile memory? */
+  if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM)) == NULL) {
+    LWIP_DEBUGF(TCP_RESIZE_DEBUG | 2, ("tcp_split_unsent_seg: could not 
allocate memory for pbuf copy size %u\n", len));
+    goto memerr;
+  }
+  ptr = (u8_t*) seg->p->payload;
+  /* Shrink original packet, this is somewhat messy.
+   * We know the first pbuf in chain contains the complete TCP
+   * header and eventually the start of the TCP data.
+   */
+  shrink = len;
+  
+  /* Find pbuf holding the first TCP data byte. Necessacy because this
+   * packet can have been split before and therefore only tcp headers 
+   * may be present int the first pbuf */
+  p = useg->p;
+  before_p = NULL;
+  while (!((u8_t*)useg->dataptr >= (u8_t*)p->payload && (u8_t*)useg->dataptr < 
((u8_t*)p->payload + p->len))) {
+    before_p = p;
+    p = p->next;
+    LWIP_ASSERT("Chain contains data", p != NULL);
+  }
+  offset = (u8_t*)useg->dataptr - (u8_t*)p->payload;
+
+  while (p != NULL && shrink > 0) {
+    if (p->len == 0 || shrink >= p->len - offset) {
+      /* Remove pbuf, update related pbufs in chain */
+      if (offset > 0) {
+        /* Keep header in pbuf, this is the first pbuf in the segment */
+        LWIP_ASSERT("TCP header in first pbuf", before_p == NULL);
+        method |= 0x01;
+        q = p->next;
+        pbuf_split(useg->p, q);
+        MEMCPY(ptr, (u8_t*)p->payload + offset, p->len - offset);
+        ptr += p->len - offset;
+        shrink -= p->len - offset;
+        pbuf_realloc(p, offset); /* p now only contains headers */
+        LWIP_ASSERT("TCP data in next chain", q != NULL);
+        pbuf_cat(useg->p, q);
+        useg->dataptr = q->payload;
+        before_p = p;
+      } else {
+        /* Remove complete pbuf */
+        method |= 0x02;
+        LWIP_ASSERT("Don't remove TCP header in first pbuf", before_p != NULL);
+        pbuf_split(useg->p, p);
+        q = p->next;
+        pbuf_split(p, q);
+        MEMCPY(ptr, (u8_t*)p->payload, p->len);
+        ptr += p->len;
+        shrink -= p->len;
+        pbuf_free(p);
+        queuelen--;
+        LWIP_ASSERT("Don't remove all data", q != NULL);
+        pbuf_cat(useg->p, q);
+        useg->dataptr = q->payload;
+      }
+      p = q;
+      LWIP_ASSERT("No pbuf/data length mismatch", !(p == NULL && shrink > 0));
+    } else {
+      /* Resize pbuf */
+      method |= 0x04;
+      q = p->next;
+      pbuf_split(useg->p, q);
+      MEMCPY(ptr, (u8_t*)p->payload + offset, shrink);
+      ptr += shrink;
+      MEMCPY((u8_t*)p->payload + offset, (u8_t*)p->payload + offset + shrink, 
p->len - offset - shrink);
+      if (before_p != NULL) {
+        LWIP_ASSERT("before_p is updated", before_p->next == p);
+        pbuf_split(useg->p, p);
+      }
+      pbuf_realloc(p, p->len - shrink);
+      if (before_p != NULL) {
+        pbuf_cat(useg->p, p);
+      }
+      if (q != NULL) {
+        pbuf_cat(useg->p, q);
+      }
+      useg->dataptr = (u8_t*)p->payload + offset;
+      p = q;
+      shrink = 0;
+    }
+    offset = 0; /* Offset is in first pbuf so it's not relevant any more */
+  }
+  LWIP_ASSERT("All data removed from original pbuf", shrink == 0);
+  LWIP_ASSERT("All removed data copied to new segment", ptr == 
(u8_t*)seg->p->payload + len);
+
+  useg->len -= len;
+
+  seg->len = len;
+  seg->dataptr = seg->p->payload;
+  queuelen++;
+
+  /* build TCP header */
+  if (pbuf_header(seg->p, TCP_HLEN)) {
+    LWIP_DEBUGF(TCP_RESIZE_DEBUG | 2, ("tcp_enqueue: no room for TCP header in 
pbuf.\n"));
+    TCP_STATS_INC(tcp.err);
+    goto memerr;
+  }
+  seg->tcphdr = seg->p->payload;
+  seg->tcphdr->src = htons(pcb->local_port);
+  seg->tcphdr->dest = htons(pcb->remote_port);
+  seg->tcphdr->seqno = pcb->unsent->tcphdr->seqno;
+  seg->tcphdr->urgp = 0;
+  TCPH_FLAGS_SET(seg->tcphdr, 0);
+  /* don't fill in tcphdr->ackno and tcphdr->wnd until later */
+
+  TCPH_HDRLEN_SET(seg->tcphdr, 5);
+
+  /* We don't have to touch pcb->snd_buf because the total amount of 
+   * data is constant when packet is split */
+
+  /* update number of segments on the queues. Note that length now may 
+   * exceed TCP_SND_QUEUELEN! */
+  pcb->snd_queuelen = queuelen;
+
+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_split_unsent_seg: %d (after enqueued)\n", 
pcb->snd_queuelen));
+  if (pcb->snd_queuelen != 0) {
+    LWIP_ASSERT("tcp_split_unsent_seg: valid queue length",
+        pcb->unacked != NULL || pcb->unsent != NULL);
+  }
+
+  /* Set the PSH flag in the last segment that we enqueued, but only
+     if the segment has data (indicated by seglen > 0). */
+  if (seg->tcphdr != NULL) {
+    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
+  }
+
+  /* Update original segment with a new sequence number */
+  pcb->unsent->tcphdr->seqno = htonl(ntohl(pcb->unsent->tcphdr->seqno) + len);
+
+  /* Finally insert new segment first in queue */
+  seg->next = pcb->unsent;
+  pcb->unsent = seg;
+
+  return ERR_OK;
+memerr:
+  TCP_STATS_INC(tcp.memerr);
+
+  if (pcb->snd_queuelen != 0) {
+    LWIP_ASSERT("tcp_split_unsent_seg: valid queue length", pcb->unacked != 
NULL ||
+        pcb->unsent != NULL);
+  }
+  LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_split_unsent_seg: %d (with mem 
err)\n", pcb->snd_queuelen));
+  return ERR_MEM;
+}
 #endif /* LWIP_TCP */
diff -ru lwip/src/include/lwip/opt.h lwip.trunk/src/include/lwip/opt.h
--- lwip/src/include/lwip/opt.h 2007-09-10 20:12:13.000000000 +0200
+++ lwip.trunk/src/include/lwip/opt.h   2007-12-18 11:29:26.687500000 +0100
@@ -1422,6 +1425,13 @@
 #endif
 
 /**
+ * TCP_RESIZE_DEBUG: Enable debugging for resizing of TCP packets in send 
queue.
+ */
+#ifndef TCP_RESIZE_DEBUG
+#define TCP_RESIZE_DEBUG                LWIP_DBG_OFF
+#endif
+
+/**
  * UDP_DEBUG: Enable debugging in UDP.
  */
 #ifndef UDP_DEBUG
diff -ru lwip/src/include/lwip/pbuf.h lwip.trunk/src/include/lwip/pbuf.h
--- lwip/src/include/lwip/pbuf.h        2007-09-08 01:02:03.000000000 +0200
+++ lwip.trunk/src/include/lwip/pbuf.h  2007-12-18 11:29:26.734375000 +0100
@@ -107,6 +110,7 @@
 u8_t pbuf_clen(struct pbuf *p);  
 void pbuf_cat(struct pbuf *h, struct pbuf *t);
 void pbuf_chain(struct pbuf *h, struct pbuf *t);
+void pbuf_split(struct pbuf *h, struct pbuf *t);
 struct pbuf *pbuf_dechain(struct pbuf *p);
 err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
 u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t 
offset);
diff -ru lwip/src/include/lwip/tcp.h lwip.trunk/src/include/lwip/tcp.h
--- lwip/src/include/lwip/tcp.h 2007-09-13 19:46:13.000000000 +0200
+++ lwip.trunk/src/include/lwip/tcp.h   2007-12-18 11:29:27.218750000 +0100
@@ -266,6 +266,7 @@
   /* receiver variables */
   u32_t rcv_nxt;   /* next seqno expected */
   u16_t rcv_wnd;   /* receiver window */
+  u16_t rcv_ann_wnd; /* the window announced to the other part */
   
   /* Timers */
   u32_t tmr;
@@ -378,6 +379,15 @@
   
   /* KEEPALIVE counter */
   u8_t keep_cnt_sent;
+
+  /* Persist timer back-off */
+  u8_t persist_backoff;
+
+  /* Persist timer send probe flag*/
+  u8_t persist_probe;
+
+  /* Persist timer counter */
+  u32_t persist_cnt;
 };
 
 struct tcp_pcb_listen {  

--
Per-Henrik Lundblom           epost: address@hidden
telefon: 0733-20 71 26        hemsida: www.whatever.nu

Attachment: lwip_working.diff
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]