This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 2ce31c442f net/tcp:Added tcp zero window probe timer support
2ce31c442f is described below
commit 2ce31c442f2fa1309235026ead3d8fdbafb72de7
Author: wangyingdong <[email protected]>
AuthorDate: Tue Jun 20 19:43:37 2023 +0800
net/tcp:Added tcp zero window probe timer support
https://www.rfc-editor.org/rfc/rfc1122#page-92
Signed-off-by: wangyingdong <[email protected]>
---
net/tcp/tcp.h | 27 +++++++-
net/tcp/tcp_input.c | 36 +++++++++++
net/tcp/tcp_send_buffered.c | 4 ++
net/tcp/tcp_timer.c | 147 +++++++++++++++++++++++++++++++++++++-------
4 files changed, 192 insertions(+), 22 deletions(-)
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index 2907f63bd3..7398084f06 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -126,6 +126,9 @@
#define TCP_FAST_RETRANSMISSION_THRESH 3
+#define TCP_RTO_MAX 240 /* 120s,The unit is half a second */
+#define TCP_RTO_MIN 1 /* 0.5s */
+
/****************************************************************************
* Public Type Definitions
****************************************************************************/
@@ -355,6 +358,7 @@ struct tcp_conn_s
#if defined(CONFIG_NET_SENDFILE) && defined(CONFIG_NET_TCP_WRITE_BUFFERS)
bool sendfile; /* True if sendfile operation is in progress */
#endif
+ bool zero_probe; /* TCP zero window probe timer */
/* connevents is a list of callbacks for each socket the uses this
* connection (there can be more that one in the event that the the socket
@@ -760,7 +764,7 @@ void tcp_stop_monitor(FAR struct tcp_conn_s *conn, uint16_t
flags);
* Input Parameters:
* conn - The TCP connection of interest
* cb - devif callback structure
- * flags - Set of connection events events
+ * flags - Set of connection events
*
* Returned Value:
* None
@@ -2304,6 +2308,27 @@ void tcp_cc_recv_ack(FAR struct tcp_conn_s *conn, FAR
struct tcp_hdr_s *tcp);
}
#endif
+/****************************************************************************
+ * Name: tcp_set_zero_probe
+ *
+ * Description:
+ * Update the TCP probe timer for the provided TCP connection,
+ * The timeout is accurate
+ *
+ * Input Parameters:
+ * conn - The TCP "connection" to poll for TX data
+ * flags - Set of connection events
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * conn is not NULL.
+ *
+ ****************************************************************************/
+
+void tcp_set_zero_probe(FAR struct tcp_conn_s *conn, uint16_t flags);
+
#endif /* !CONFIG_NET_TCP_NO_STACK */
#endif /* CONFIG_NET_TCP */
#endif /* __NET_TCP_TCP_H */
diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c
index dd34cd369c..dcc16d9b07 100644
--- a/net/tcp/tcp_input.c
+++ b/net/tcp/tcp_input.c
@@ -633,6 +633,40 @@ static void tcp_parse_option(FAR struct net_driver_s *dev,
}
}
+/****************************************************************************
+ * Name: tcp_clear_zero_probe
+ *
+ * Description:
+ * clear the TCP zero window probe
+ *
+ * Input Parameters:
+ * conn - The TCP connection of interest
+ * tcp - Header of TCP structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void tcp_clear_zero_probe(FAR struct tcp_conn_s *conn,
+ FAR struct tcp_hdr_s *tcp)
+{
+ /* If the receive window is not 0,
+ * the zero window probe timer needs to be cleared
+ */
+
+ if ((tcp->wnd[0] || tcp->wnd[1]) && conn->zero_probe &&
+ (tcp->flags & TCP_ACK) != 0)
+ {
+ conn->zero_probe = false;
+ conn->nrtx = 0;
+ conn->timer = 0;
+ }
+}
+
/****************************************************************************
* Name: tcp_input
*
@@ -1155,6 +1189,8 @@ found:
tcp_update_retrantimer(conn, conn->rto);
}
+ tcp_clear_zero_probe(conn, tcp);
+
/* Update the connection's window size */
if ((tcp->flags & TCP_ACK) != 0 &&
diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c
index f911831a28..4b6f4ba53b 100644
--- a/net/tcp/tcp_send_buffered.c
+++ b/net/tcp/tcp_send_buffered.c
@@ -1119,6 +1119,10 @@ static uint16_t psock_send_eventhandler(FAR struct
net_driver_s *dev,
flags &= ~TCP_POLL;
}
}
+ else
+ {
+ tcp_set_zero_probe(conn, flags);
+ }
/* Continue waiting */
diff --git a/net/tcp/tcp_timer.c b/net/tcp/tcp_timer.c
index 591c884e12..c0b774c043 100644
--- a/net/tcp/tcp_timer.c
+++ b/net/tcp/tcp_timer.c
@@ -155,6 +155,50 @@ static void tcp_timer_expiry(FAR void *arg)
net_unlock();
}
+/****************************************************************************
+ * Name: tcp_xmit_probe
+ *
+ * Description:
+ * TCP retransmission probe packet
+ *
+ * Input Parameters:
+ * dev - The device driver structure to use in the send operation
+ * conn - The TCP "connection" to poll for TX data
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * dev is not NULL.
+ * conn is not NULL.
+ *
+ ****************************************************************************/
+
+static void tcp_xmit_probe(FAR struct net_driver_s *dev,
+ FAR struct tcp_conn_s *conn)
+{
+ /* And send the probe.
+ * The packet we send must have these properties:
+ *
+ * - TCP_ACK flag (only) is set.
+ * - Sequence number is the sequence number of
+ * previously ACKed data, i.e., the expected
+ * sequence number minus one.
+ *
+ * tcp_send() will send the TCP sequence number as
+ * conn->sndseq. Rather than creating a new
+ * interface, we spoof tcp_end() here:
+ */
+
+ uint16_t hdrlen = tcpip_hdrsize(conn);
+ uint32_t saveseq = tcp_getsequence(conn->sndseq);
+ tcp_setsequence(conn->sndseq, saveseq - 1);
+
+ tcp_send(dev, conn, TCP_ACK, hdrlen);
+
+ tcp_setsequence(conn->sndseq, saveseq);
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -292,6 +336,40 @@ void tcp_stop_timer(FAR struct tcp_conn_s *conn)
work_cancel(LPWORK, &conn->work);
}
+/****************************************************************************
+ * Name: tcp_set_zero_probe
+ *
+ * Description:
+ * Update the TCP probe timer for the provided TCP connection,
+ * The timeout is accurate
+ *
+ * Input Parameters:
+ * conn - The TCP "connection" to poll for TX data
+ * flags - Set of connection events
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * conn is not NULL.
+ *
+ ****************************************************************************/
+
+void tcp_set_zero_probe(FAR struct tcp_conn_s *conn, uint16_t flags)
+{
+ if ((conn->tcpstateflags & TCP_ESTABLISHED) &&
+ ((flags & TCP_NEWDATA) == 0) && conn->tx_unacked <= 0 &&
+ (flags & (TCP_POLL | TCP_REXMIT | TCP_ACKDATA)) &&
+#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
+ !(sq_empty(&conn->write_q)) &&
+#endif
+ !conn->timeout && !conn->zero_probe)
+ {
+ tcp_update_retrantimer(conn, TCP_RTO_MIN);
+ conn->zero_probe = true;
+ }
+}
+
/****************************************************************************
* Name: tcp_timer
*
@@ -616,8 +694,6 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct
tcp_conn_s *conn)
if (conn->keepalive)
{
- uint32_t saveseq;
-
/* Yes... has the idle period elapsed with no data or ACK
* received from the remote peer?
*/
@@ -643,25 +719,7 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct
tcp_conn_s *conn)
}
else
{
- /* And send the probe.
- * The packet we send must have these properties:
- *
- * - TCP_ACK flag (only) is set.
- * - Sequence number is the sequence number of
- * previously ACKed data, i.e., the expected
- * sequence number minus one.
- *
- * tcp_send() will send the TCP sequence number as
- * conn->sndseq. Rather than creating a new
- * interface, we spoof tcp_end() here:
- */
-
- saveseq = tcp_getsequence(conn->sndseq);
- tcp_setsequence(conn->sndseq, saveseq - 1);
-
- tcp_send(dev, conn, TCP_ACK, hdrlen);
-
- tcp_setsequence(conn->sndseq, saveseq);
+ tcp_xmit_probe(dev, conn);
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* Increment the un-ACKed sequence number */
@@ -679,6 +737,53 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct
tcp_conn_s *conn)
}
#endif
+ /* Is this an established connected with
+ * Zero window probe enabled?
+ */
+
+ if (conn->zero_probe)
+ {
+ if (conn->timer > hsec)
+ {
+ /* Will not yet decrement to zero */
+
+ conn->timer -= hsec;
+ }
+ else
+ {
+ /* Yes.. Has the retry count expired? */
+
+ if (conn->nrtx >= TCP_MAXRTX)
+ {
+ /* Yes... stop the network monitor, closing the
+ * connection and all sockets associated with the
+ * connection.
+ */
+
+ conn->zero_probe = false;
+ tcp_stop_monitor(conn, TCP_ABORT);
+ }
+ else
+ {
+ tcp_xmit_probe(dev, conn);
+
+#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
+ /* Increment the un-ACKed sequence number */
+
+ conn->sndseq_max++;
+#endif
+
+ /* Update for the next probe */
+
+ conn->nrtx++;
+ conn->timer = MIN((TCP_RTO_MIN << conn->nrtx),
+ TCP_RTO_MAX);
+ }
+
+ goto done;
+ }
+ }
+
#ifdef CONFIG_NET_TCP_DELAYED_ACK
/* Handle delayed acknowledgments. Is there a segment with a
* delayed acknowledgment?