[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RE : [lwip-users] Patch for persist timer and silly window bug
From: |
Frédéric BERNON |
Subject: |
RE : [lwip-users] Patch for persist timer and silly window bug |
Date: |
Tue, 18 Dec 2007 14:46:29 +0100 |
Can I copy/past your mail in the bug tracker and attach the patch file ?
====================================
Frédéric BERNON
HYMATOM SA
Chef de projet informatique
Microsoft Certified Professional
Tél. : +33 (0)4-67-87-61-10
Fax. : +33 (0)4-67-70-85-44
Email : address@hidden
Web Site : http://www.hymatom.fr
====================================
P Avant d'imprimer, penser à l'environnement
-----Message d'origine-----
De : address@hidden [mailto:address@hidden De la part de Per-Henrik Lundblom
Envoyé : mardi 18 décembre 2007 14:41
À : address@hidden
Objet : [lwip-users] Patch for persist timer and silly window bug
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
Frédéric BERNON.vcf
Description: Frédéric BERNON.vcf
- RE : [lwip-users] Patch for persist timer and silly window bug,
Frédéric BERNON <=