You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/11/10 18:21:14 UTC

[incubator-nuttx] branch master updated: net/tcp(unbuffered): retransmit only one the earliest not acknowledged segment (according to RFC 6298 (5.4)).

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 <al...@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 */