[Top][All Lists]
[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
lwip_working.diff
Description: Text Data
- [lwip-users] Patch for persist timer and silly window bug,
Per-Henrik Lundblom <=