diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index c11550d742..78147ed352 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -175,10 +175,7 @@ struct tcp_conn_s uint8_t rcvseq[4]; /* The sequence number that we expect to * receive next */ uint8_t sndseq[4]; /* The sequence number that was last sent by us */ -#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || \ - defined(CONFIG_NET_SENDFILE) uint32_t rexmit_seq; /* The sequence number to be retrasmitted */ -#endif uint8_t crefs; /* Reference counts on this instance */ #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) uint8_t domain; /* IP domain: PF_INET or PF_INET6 */ diff --git a/net/tcp/tcp_appsend.c b/net/tcp/tcp_appsend.c index 1e8e58dbc2..39b120f3d8 100644 --- a/net/tcp/tcp_appsend.c +++ b/net/tcp/tcp_appsend.c @@ -322,30 +322,23 @@ void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, * new data in it, we must send out a packet. */ -#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_NET_SENDFILE) - if (conn->sendfile) -#endif + if ((result & TCP_REXMIT) != 0 && + dev->d_sndlen > 0 && conn->tx_unacked > 0) { -#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || defined(CONFIG_NET_SENDFILE) - if ((result & TCP_REXMIT) != 0 && - dev->d_sndlen > 0 && conn->tx_unacked > 0) - { - uint32_t saveseq; + uint32_t saveseq; - /* According to RFC 6298 (5.4), retransmit the earliest segment - * that has not been acknowledged by the TCP receiver. - */ + /* According to RFC 6298 (5.4), retransmit the earliest segment + * that has not been acknowledged by the TCP receiver. + */ - saveseq = tcp_getsequence(conn->sndseq); - tcp_setsequence(conn->sndseq, conn->rexmit_seq); + saveseq = tcp_getsequence(conn->sndseq); + tcp_setsequence(conn->sndseq, conn->rexmit_seq); - tcp_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen); + tcp_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen); - tcp_setsequence(conn->sndseq, saveseq); + tcp_setsequence(conn->sndseq, saveseq); - return; - } -#endif + return; } #if defined(CONFIG_NET_TCP_WRITE_BUFFERS) diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c index c5aac33db8..d00962c8ae 100644 --- a/net/tcp/tcp_send_buffered.c +++ b/net/tcp/tcp_send_buffered.c @@ -323,7 +323,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, */ FAR struct tcp_conn_s *conn = pvpriv; - bool rexmit = false; +#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT + uint32_t rexmitno = 0; +#endif /* Get the TCP connection pointer reliably from * the corresponding TCP socket. @@ -501,12 +503,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, { /* Do fast retransmit */ - rexmit = true; - } - else if ((TCP_WBNACK(wrb) > TCP_FAST_RETRANSMISSION_THRESH) && - TCP_WBNACK(wrb) == sq_count(&conn->unacked_q) - 1) - { - /* Reset the duplicate ack counter */ + rexmitno = ackno; + + /* Reset counter */ TCP_WBNACK(wrb) = 0; } @@ -573,14 +572,77 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, return flags; } +#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT + if (rexmitno != 0) + { + FAR struct tcp_wrbuffer_s *wrb; + FAR sq_entry_t *entry; + FAR sq_entry_t *next; + size_t sndlen; + + /* According to RFC 6298 (5.4), retransmit the earliest segment + * that has not been acknowledged by the TCP receiver. + */ + + for (entry = sq_peek(&conn->unacked_q); entry; entry = next) + { + wrb = (FAR struct tcp_wrbuffer_s *)entry; + next = sq_next(entry); + + if (rexmitno != TCP_WBSEQNO(wrb)) + { + continue; + } + + conn->rexmit_seq = rexmitno; + + /* Reconstruct the length of the earliest segment to be + * retransmitted. + */ + + sndlen = TCP_WBPKTLEN(wrb); + + if (sndlen > conn->mss) + { + sndlen = conn->mss; + } + + /* As we are retransmitting, the sequence number is expected + * already set for this write buffer. + */ + + DEBUGASSERT(TCP_WBSEQNO(wrb) != (unsigned)-1); + conn->rexmit_seq = TCP_WBSEQNO(wrb); + +#ifdef NEED_IPDOMAIN_SUPPORT + /* If both IPv4 and IPv6 support are enabled, then we will need to + * select which one to use when generating the outgoing packet. + * If only one domain is selected, then the setup is already in + * place and we need do nothing. + */ + + send_ipselect(dev, conn); +#endif + /* Then set-up to send that amount of data. (this won't actually + * happen until the polling cycle completes). + */ + + devif_iob_send(dev, TCP_WBIOB(wrb), sndlen, 0); + + /* Reset the retransmission timer. */ + + tcp_update_retrantimer(conn, conn->rto); + + /* Continue waiting */ + + return flags; + } + } +#endif + /* Check if we are being asked to retransmit data */ - else if ((flags & TCP_REXMIT) != 0) - { - rexmit = true; - } - - if (rexmit) + if ((flags & TCP_REXMIT) != 0) { FAR struct tcp_wrbuffer_s *wrb; FAR sq_entry_t *entry;