This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push: new 1e07b6d net/tcp(unbuffered): retransmit only one the earliest not acknowledged segment (according to RFC 6298 (5.4)). 1e07b6d is described below commit 1e07b6d528ab52dd179e6631991c683749c7635d Author: Alexander Lunev <alexanderlu...@mail.ru> AuthorDate: Tue Oct 12 07:15:54 2021 +0300 net/tcp(unbuffered): retransmit only one the earliest not acknowledged segment (according to RFC 6298 (5.4)). --- net/tcp/tcp.h | 3 +++ net/tcp/tcp_appsend.c | 18 +++++++++++++++++- net/tcp/tcp_send_unbuffered.c | 36 ++++++++++++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 7e55d36..245cba1 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -172,6 +172,9 @@ 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) + 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 c31a942..467d567 100644 --- a/net/tcp/tcp_appsend.c +++ b/net/tcp/tcp_appsend.c @@ -316,7 +316,23 @@ void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, #ifdef CONFIG_NET_TCP_WRITE_BUFFERS if (dev->d_sndlen > 0) #else - if (dev->d_sndlen > 0 && conn->tx_unacked > 0) + if ((result & TCP_REXMIT) != 0 && + dev->d_sndlen > 0 && conn->tx_unacked > 0) + { + uint32_t saveseq; + + /* 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); + + tcp_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen); + + tcp_setsequence(conn->sndseq, saveseq); + } + else if (dev->d_sndlen > 0 && conn->tx_unacked > 0) #endif { uint32_t seq; diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index c309e27..aa3605b 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -236,13 +236,41 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev, else if ((flags & TCP_REXMIT) != 0) { - /* Yes.. in this case, reset the number of bytes that have been sent - * to the number of bytes that have been ACKed. + /* According to RFC 6298 (5.4), retransmit the earliest segment + * that has not been acknowledged by the TCP receiver. */ - pstate->snd_sent = pstate->snd_acked; + /* Reconstruct the length of the earliest segment to be retransmitted */ - /* Fall through to re-send data from the last that was ACKed */ + uint32_t sndlen = pstate->snd_buflen - pstate->snd_acked; + + if (sndlen > conn->mss) + { + sndlen = conn->mss; + } + + conn->rexmit_seq = pstate->snd_isn + pstate->snd_acked; + +#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. + */ + + tcpsend_ipselect(dev, conn); +#endif + /* Then set-up to send that amount of data. (this won't actually + * happen until the polling cycle completes). + */ + + devif_send(dev, + &pstate->snd_buffer[pstate->snd_acked], + sndlen); + + /* Continue waiting */ + + return flags; } /* Check for a loss of connection */