diff --git a/CHANGELOG b/CHANGELOG index 84021054..11b9a93f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -526,6 +526,10 @@ HISTORY ++ Bug fixes: + 2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm) + * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling + of silly window avoidance and prevent lwIP from shrinking the window) + 2007-12-04 Simon Goldschmidt * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last data packet was lost): add assert that all segment lists are empty in diff --git a/src/core/tcp.c b/src/core/tcp.c index 40256d2e..93c4252e 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -385,9 +385,14 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len) { 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)) { /* @@ -494,6 +499,7 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, 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; /* The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; @@ -936,6 +942,7 @@ tcp_alloc(u8_t prio) 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; /* The send MSS is updated when an MSS option is received. */ diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 8c16bfb3..beffcff4 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -477,10 +477,8 @@ tcp_process(struct tcp_pcb *pcb) acceptable = 1; } } else { - /*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; } } @@ -549,7 +547,7 @@ tcp_process(struct tcp_pcb *pcb) /* 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) { @@ -1001,9 +999,8 @@ tcp_receive(struct tcp_pcb *pcb) /* The sequence number must be within the window (above rcv_nxt and below rcv_nxt + rcv_wnd) in order to be further 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 @@ -1045,6 +1042,12 @@ tcp_receive(struct tcp_pcb *pcb) pcb->rcv_wnd -= tcplen; } + if (pcb->rcv_ann_wnd < tcplen) { + pcb->rcv_ann_wnd = 0; + } else { + pcb->rcv_ann_wnd -= tcplen; + } + /* 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 @@ -1081,6 +1084,12 @@ tcp_receive(struct tcp_pcb *pcb) } else { pcb->rcv_wnd -= TCP_TCPLEN(cseg); } + if (pcb->rcv_ann_wnd < TCP_TCPLEN(cseg)) { + pcb->rcv_ann_wnd = 0; + } else { + pcb->rcv_ann_wnd -= TCP_TCPLEN(cseg); + } + if (cseg->p->tot_len > 0) { /* Chain this pbuf onto the pbuf that we will pass to the application. */ @@ -1235,9 +1244,8 @@ tcp_receive(struct tcp_pcb *pcb) } } 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); } } diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 0b1c0cbf..8457af90 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -460,7 +460,7 @@ tcp_output(struct tcp_pcb *pcb) 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); @@ -593,13 +593,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) 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); - } + /* advertise our receive window size in this TCP segment */ + seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd); /* If we don't have a local IP address, we get one by calling ip_route(). */ @@ -815,15 +810,15 @@ tcp_keepalive(struct tcp_pcb *pcb) LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", (p->len >= sizeof(struct tcp_hdr))); - tcphdr = p->payload; - tcphdr->src = htons(pcb->local_port); - tcphdr->dest = htons(pcb->remote_port); - 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->urgp = 0; - TCPH_HDRLEN_SET(tcphdr, 5); + tcphdr = p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dest = htons(pcb->remote_port); + tcphdr->seqno = htonl(pcb->snd_nxt - 1); + tcphdr->ackno = htonl(pcb->rcv_nxt); + TCPH_FLAGS_SET(tcphdr, 0); + tcphdr->wnd = htons(pcb->rcv_ann_wnd); + tcphdr->urgp = 0; + TCPH_HDRLEN_SET(tcphdr, 5); tcphdr->chksum = 0; #if CHECKSUM_GEN_TCP diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 6130d196..ebe7ed3d 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -281,7 +281,8 @@ struct tcp_pcb { /* receiver variables */ u32_t rcv_nxt; /* next seqno expected */ u16_t rcv_wnd; /* receiver window */ - + u16_t rcv_ann_wnd; /* announced receive window */ + /* Timers */ u32_t tmr; u8_t polltmr, pollinterval;