diff --git a/CHANGELOG b/CHANGELOG index 263d19e7..82e007f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -321,6 +321,11 @@ HISTORY ++ Bugfixes: + 2016-07-21: Simon Goldschmidt (patch by Ambroz Bizjak) + * tcp_in.c, tcp_out.c: fixed bug #48543 (TCP sent callback may prematurely + report sent data when only part of a segment is acked) and don't include + SYN/FIN in snd_buf counter + 2016-07-19: Simon Goldschmidt * etharp.c: fixed bug #48477 (ARP input packet might update static entry) diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 7778918d..80e47ba7 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -752,7 +752,6 @@ tcp_process(struct tcp_pcb *pcb) /* received SYN ACK with expected sequence number? */ if ((flags & TCP_ACK) && (flags & TCP_SYN) && (ackno == pcb->lastack + 1)) { - pcb->snd_buf++; pcb->rcv_nxt = seqno + 1; pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->lastack = ackno; @@ -1070,7 +1069,6 @@ tcp_receive(struct tcp_pcb *pcb) /* Clause 1 */ if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { - recv_acked = 0; /* Clause 2 */ if (tcplen == 0) { /* Clause 3 */ @@ -1119,12 +1117,6 @@ tcp_receive(struct tcp_pcb *pcb) /* Reset the retransmission time-out. */ pcb->rto = (pcb->sa >> 3) + pcb->sv; - /* Update the send buffer space. Diff between the two can never exceed 64K - unless window scaling is used. */ - recv_acked = (tcpwnd_size_t)(ackno - pcb->lastack); - - pcb->snd_buf += recv_acked; - /* Reset the fast retransmit variables. */ pcb->dupacks = 0; pcb->lastack = ackno; @@ -1167,12 +1159,9 @@ tcp_receive(struct tcp_pcb *pcb) LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", (tcpwnd_size_t)pcb->snd_queuelen)); LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); - /* Prevent ACK for FIN to generate a sent event */ - if ((recv_acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { - recv_acked--; - } pcb->snd_queuelen -= pbuf_clen(next->p); + recv_acked += next->len; tcp_seg_free(next); LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unacked)\n", (tcpwnd_size_t)pcb->snd_queuelen)); @@ -1200,7 +1189,6 @@ tcp_receive(struct tcp_pcb *pcb) #endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ } else { /* Out of sequence ACK, didn't really ack anything */ - recv_acked = 0; tcp_send_empty_ack(pcb); } @@ -1227,10 +1215,8 @@ tcp_receive(struct tcp_pcb *pcb) LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", (tcpwnd_size_t)pcb->snd_queuelen)); LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); /* Prevent ACK for FIN to generate a sent event */ - if ((recv_acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { - recv_acked--; - } pcb->snd_queuelen -= pbuf_clen(next->p); + recv_acked += next->len; tcp_seg_free(next); LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unsent)\n", (tcpwnd_size_t)pcb->snd_queuelen)); if (pcb->snd_queuelen != 0) { @@ -1238,6 +1224,7 @@ tcp_receive(struct tcp_pcb *pcb) pcb->unacked != NULL || pcb->unsent != NULL); } } + pcb->snd_buf += recv_acked; /* End of ACK for new data processing. */ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 6d773303..30289791 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -788,16 +788,6 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) #endif /* LWIP_TCP_TIMESTAMPS */ optlen = LWIP_TCP_OPT_LENGTH(optflags); - /* tcp_enqueue_flags is always called with either SYN or FIN in flags. - * We need one available snd_buf byte to do that. - * This means we can't send FIN while snd_buf==0. A better fix would be to - * not include SYN and FIN sequence numbers in the snd_buf count. */ - if (pcb->snd_buf == 0) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_enqueue_flags: no send buffer available\n")); - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - /* Allocate pbuf with room for TCP header + options */ if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { pcb->flags |= TF_NAGLEMEMERR; @@ -839,7 +829,6 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) if ((flags & TCP_SYN) || (flags & TCP_FIN)) { pcb->snd_lbb++; /* optlen does not influence snd_buf */ - pcb->snd_buf--; } if (flags & TCP_FIN) { pcb->flags |= TF_FIN;