This commit adds an initial implemented of TCP delayed ACKs as specified in RFC 1122.

Squashed commit of the following:

    net/tmp:  Rename the unacked field of the tcp connection structure to tx_unacked.  Too confusing with the implementation of delayed RX ACKs.

    net/tcp:  Initial implementation of TCP delayed ACKs.

    net/tcp:  Add delayed ACK configuration selection.  Rename tcp_ack() to tcp_synack().  It may or may not send a ACK.  It will always send SYN or SYN/ACK.
This commit is contained in:
Gregory Nutt 2019-12-08 13:13:51 -06:00
parent 594734e0ae
commit 66ef6d143a
12 changed files with 174 additions and 71 deletions

View File

@ -164,7 +164,7 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* Check if all outstanding bytes have been ACKed */ /* Check if all outstanding bytes have been ACKed */
if (conn->unacked != 0 || !sq_empty(&conn->write_q)) if (conn->tx_unacked != 0 || !sq_empty(&conn->write_q))
{ {
/* No... we are still waiting for ACKs. Drop any received data, but /* No... we are still waiting for ACKs. Drop any received data, but
* do not yet report TCP_CLOSE in the response. * do not yet report TCP_CLOSE in the response.

View File

@ -557,7 +557,7 @@ static uint16_t tcp_send_eventhandler(FAR struct net_driver_s *dev,
/* Increment the count of bytes sent, the number of unacked bytes, /* Increment the count of bytes sent, the number of unacked bytes,
* and the total count of TCP packets sent. * and the total count of TCP packets sent.
* *
* NOTE: tcp_appsend() normally increments conn->unacked based on * NOTE: tcp_appsend() normally increments conn->tx_unacked based on
* the value of dev->d_sndlen. However, dev->d_len is always * the value of dev->d_sndlen. However, dev->d_len is always
* zero for 6LoWPAN since it does not send via the dev->d_buf * zero for 6LoWPAN since it does not send via the dev->d_buf
* but, rather, uses a backdoor frame interface with the IEEE * but, rather, uses a backdoor frame interface with the IEEE
@ -565,21 +565,21 @@ static uint16_t tcp_send_eventhandler(FAR struct net_driver_s *dev,
*/ */
sinfo->s_sent += sndlen; sinfo->s_sent += sndlen;
conn->unacked += sndlen; conn->tx_unacked += sndlen;
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* For compability with buffered send logic */ /* For compability with buffered send logic */
conn->sndseq_max = tcp_addsequence(conn->sndseq, conn->unacked); conn->sndseq_max = tcp_addsequence(conn->sndseq, conn->tx_unacked);
#endif #endif
#ifdef CONFIG_NET_STATISTICS #ifdef CONFIG_NET_STATISTICS
g_netstats.tcp.sent++; g_netstats.tcp.sent++;
#endif #endif
ninfo("Sent: acked=%d sent=%d buflen=%d unacked=%d\n", ninfo("Sent: acked=%d sent=%d buflen=%d tx_unacked=%d\n",
sinfo->s_acked, sinfo->s_sent, sinfo->s_buflen, sinfo->s_acked, sinfo->s_sent, sinfo->s_buflen,
conn->unacked); conn->tx_unacked);
} }
} }
@ -612,7 +612,7 @@ end_wait:
/* There are no outstanding, unacknowledged bytes */ /* There are no outstanding, unacknowledged bytes */
conn->unacked = 0; conn->tx_unacked = 0;
/* Wake up the waiting thread */ /* Wake up the waiting thread */
@ -710,7 +710,7 @@ static int sixlowpan_send_packet(FAR struct socket *psock,
* initial sequence number. * initial sequence number.
*/ */
conn->unacked = 0; conn->tx_unacked = 0;
/* Notify the IEEE802.15.4 MAC that we have data to send. */ /* Notify the IEEE802.15.4 MAC that we have data to send. */

View File

@ -20,6 +20,20 @@ config NET_TCP_NO_STACK
if NET_TCP && !NET_TCP_NO_STACK if NET_TCP && !NET_TCP_NO_STACK
config NET_TCP_DELAYED_ACK
bool "TCP/IP Delayed ACK"
default n
---help---
RFC 1122: A host that is receiving a stream of TCP data segments
can increase efficiency in both the Internet and the hosts
by sending fewer than one ACK (acknowledgment) segment per data
segment received; this is known as a "delayed ACK".
TCP should implement a delayed ACK, but an ACK should not be
excessively delayed; in particular, the delay MUST be less than
0.5 seconds, and in a stream of full-sized segments there should
be an ACK for at least every second segments.
config NET_TCP_KEEPALIVE config NET_TCP_KEEPALIVE
bool "TCP/IP Keep-alive support" bool "TCP/IP Keep-alive support"
default n default n

View File

@ -175,15 +175,19 @@ struct tcp_conn_s
uint8_t timer; /* The retransmission timer (units: half-seconds) */ uint8_t timer; /* The retransmission timer (units: half-seconds) */
uint8_t nrtx; /* The number of retransmissions for the last uint8_t nrtx; /* The number of retransmissions for the last
* segment sent */ * segment sent */
#ifdef CONFIG_NET_TCP_DELAYED_ACK
uint8_t rx_unackseg; /* Number of un-ACKed received segments */
uint8_t rx_acktimer; /* Time since last ACK sent (units: half-seconds) */
#endif
uint16_t lport; /* The local TCP port, in network byte order */ uint16_t lport; /* The local TCP port, in network byte order */
uint16_t rport; /* The remoteTCP port, in network byte order */ uint16_t rport; /* The remoteTCP port, in network byte order */
uint16_t mss; /* Current maximum segment size for the uint16_t mss; /* Current maximum segment size for the
* connection */ * connection */
uint16_t winsize; /* Current window size of the connection */ uint16_t winsize; /* Current window size of the connection */
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
uint32_t unacked; /* Number bytes sent but not yet ACKed */ uint32_t tx_unacked; /* Number bytes sent but not yet ACKed */
#else #else
uint16_t unacked; /* Number bytes sent but not yet ACKed */ uint16_t tx_unacked; /* Number bytes sent but not yet ACKed */
#endif #endif
/* If the TCP socket is bound to a local address, then this is /* If the TCP socket is bound to a local address, then this is
@ -941,7 +945,7 @@ ssize_t tcp_sendfile(FAR struct socket *psock, FAR struct file *infile,
void tcp_reset(FAR struct net_driver_s *dev); void tcp_reset(FAR struct net_driver_s *dev);
/**************************************************************************** /****************************************************************************
* Name: tcp_ack * Name: tcp_synack
* *
* Description: * Description:
* Send the SYN or SYNACK response. * Send the SYN or SYNACK response.
@ -959,7 +963,7 @@ void tcp_reset(FAR struct net_driver_s *dev);
* *
****************************************************************************/ ****************************************************************************/
void tcp_ack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, void tcp_synack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
uint8_t ack); uint8_t ack);
/**************************************************************************** /****************************************************************************

View File

@ -85,10 +85,49 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
{ {
uint8_t hdrlen; uint8_t hdrlen;
/* Handle the result based on the application response */ ninfo("result: %04x d_sndlen: %d conn->tx_unacked: %d\n",
result, dev->d_sndlen, conn->tx_unacked);
ninfo("result: %04x d_sndlen: %d conn->unacked: %d\n", #ifdef CONFIG_NET_TCP_DELAYED_ACK
result, dev->d_sndlen, conn->unacked); /* Did the caller request that an ACK be sent? */
if ((result & TCP_SNDACK) != 0)
{
/* Yes.. Handle delayed acknowledgments */
/* Reset the ACK timer in any event. */
conn->rx_acktimer = 0;
/* Per RFC 1122: "...there SHOULD be an ACK for at least every second
* segment."
*/
if (conn->rx_unackseg > 0)
{
/* Reset the delayed ACK state and send the ACK with this packet. */
conn->rx_unackseg = 0;
}
else
{
/* Indicate that there is one un-ACKed segment and don't send the
* ACK on this pack.
*/
result &= ~TCP_SNDACK;
conn->rx_unackseg = 1;
/* A special case is if there are not other flags and no TCP TX
* data payload. In this case, don't send anything.*/
if (result == 0 && dev->d_sndlen == 0)
{
return;
}
}
}
#endif
/* Get the IP header length associated with the IP domain configured for /* Get the IP header length associated with the IP domain configured for
* this TCP connection. * this TCP connection.
@ -143,7 +182,7 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
else if ((result & TCP_CLOSE) != 0) else if ((result & TCP_CLOSE) != 0)
{ {
conn->tcpstateflags = TCP_FIN_WAIT_1; conn->tcpstateflags = TCP_FIN_WAIT_1;
conn->unacked = 1; conn->tx_unacked = 1;
conn->nrtx = 0; conn->nrtx = 0;
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
conn->sndseq_max = tcp_getsequence(conn->sndseq) + 1; conn->sndseq_max = tcp_getsequence(conn->sndseq) + 1;
@ -172,10 +211,10 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
* do not go through this path. * do not go through this path.
*/ */
conn->unacked += dev->d_sndlen; conn->tx_unacked += dev->d_sndlen;
/* The application cannot send more than what is allowed by the /* The application cannot send more than what is allowed by the
* MSS (the minumum of the MSS and the available window). * MSS (the minimum of the MSS and the available window).
*/ */
DEBUGASSERT(dev->d_sndlen <= conn->mss); DEBUGASSERT(dev->d_sndlen <= conn->mss);
@ -183,6 +222,7 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
conn->nrtx = 0; conn->nrtx = 0;
#endif #endif
/* Then handle the rest of the operation just as for the rexmit case */ /* Then handle the rest of the operation just as for the rexmit case */
tcp_rexmit(dev, conn, result); tcp_rexmit(dev, conn, result);
@ -213,8 +253,8 @@ void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
{ {
uint8_t hdrlen; uint8_t hdrlen;
ninfo("result: %04x d_sndlen: %d conn->unacked: %d\n", ninfo("result: %04x d_sndlen: %d conn->tx_unacked: %d\n",
result, dev->d_sndlen, conn->unacked); result, dev->d_sndlen, conn->tx_unacked);
/* Get the IP header length associated with the IP domain configured for /* Get the IP header length associated with the IP domain configured for
* this TCP connection. * this TCP connection.
@ -247,7 +287,7 @@ void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
if (dev->d_sndlen > 0) if (dev->d_sndlen > 0)
#else #else
if (dev->d_sndlen > 0 && conn->unacked > 0) if (dev->d_sndlen > 0 && conn->tx_unacked > 0)
#endif #endif
{ {
/* We always set the ACK flag in response packets adding the length of /* We always set the ACK flag in response packets adding the length of

View File

@ -1008,7 +1008,7 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev,
conn->tcpstateflags = TCP_SYN_RCVD; conn->tcpstateflags = TCP_SYN_RCVD;
tcp_initsequence(conn->sndseq); tcp_initsequence(conn->sndseq);
conn->unacked = 1; conn->tx_unacked = 1;
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
conn->expired = 0; conn->expired = 0;
conn->isn = 0; conn->isn = 0;
@ -1243,7 +1243,7 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr)
conn->tcpstateflags = TCP_SYN_SENT; conn->tcpstateflags = TCP_SYN_SENT;
tcp_initsequence(conn->sndseq); tcp_initsequence(conn->sndseq);
conn->unacked = 1; /* TCP length of the SYN is one. */ conn->tx_unacked = 1; /* TCP length of the SYN is one. */
conn->nrtx = 0; conn->nrtx = 0;
conn->timer = 1; /* Send the SYN next time around. */ conn->timer = 1; /* Send the SYN next time around. */
conn->rto = TCP_RTO; conn->rto = TCP_RTO;

View File

@ -295,7 +295,7 @@ static void tcp_input(FAR struct net_driver_s *dev, uint8_t domain,
/* Our response will be a SYNACK. */ /* Our response will be a SYNACK. */
tcp_ack(dev, conn, TCP_ACK | TCP_SYN); tcp_synack(dev, conn, TCP_ACK | TCP_SYN);
return; return;
} }
} }
@ -416,7 +416,7 @@ found:
(tcp->flags & (TCP_SYN | TCP_FIN | TCP_RST)) == 0 && (tcp->flags & (TCP_SYN | TCP_FIN | TCP_RST)) == 0 &&
(conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED && (conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED &&
(dev->d_len == 0 || dev->d_len == 1) && (dev->d_len == 0 || dev->d_len == 1) &&
conn->unacked <= 0) conn->tx_unacked <= 0)
{ {
uint32_t ackseq; uint32_t ackseq;
uint32_t rcvseq; uint32_t rcvseq;
@ -471,20 +471,20 @@ found:
* data, calculate RTT estimations, and reset the retransmission timer. * data, calculate RTT estimations, and reset the retransmission timer.
*/ */
if ((tcp->flags & TCP_ACK) != 0 && conn->unacked > 0) if ((tcp->flags & TCP_ACK) != 0 && conn->tx_unacked > 0)
{ {
uint32_t unackseq; uint32_t unackseq;
uint32_t ackseq; uint32_t ackseq;
/* The next sequence number is equal to the current sequence /* The next sequence number is equal to the current sequence
* number (sndseq) plus the size of the outstanding, unacknowledged * number (sndseq) plus the size of the outstanding, unacknowledged
* data (unacked). * data (tx_unacked).
*/ */
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
unackseq = conn->sndseq_max; unackseq = conn->sndseq_max;
#else #else
unackseq = tcp_addsequence(conn->sndseq, conn->unacked); unackseq = tcp_addsequence(conn->sndseq, conn->tx_unacked);
#endif #endif
/* Get the sequence number of that has just been acknowledged by this /* Get the sequence number of that has just been acknowledged by this
@ -504,7 +504,7 @@ found:
{ {
/* Calculate the new number of outstanding, unacknowledged bytes */ /* Calculate the new number of outstanding, unacknowledged bytes */
conn->unacked = unackseq - ackseq; conn->tx_unacked = unackseq - ackseq;
} }
else else
{ {
@ -517,11 +517,11 @@ found:
if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED) if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED)
{ {
nwarn("WARNING: ackseq > unackseq\n"); nwarn("WARNING: ackseq > unackseq\n");
nwarn(" sndseq=%u unacked=%u unackseq=%u ackseq=%u\n", nwarn(" sndseq=%u tx_unacked=%u unackseq=%u ackseq=%u\n",
tcp_getsequence(conn->sndseq), conn->unacked, unackseq, tcp_getsequence(conn->sndseq), conn->tx_unacked, unackseq,
ackseq); ackseq);
conn->unacked = 0; conn->tx_unacked = 0;
} }
} }
@ -530,8 +530,8 @@ found:
* be beyond ackseq. * be beyond ackseq.
*/ */
ninfo("sndseq: %08x->%08x unackseq: %08x new unacked: %d\n", ninfo("sndseq: %08x->%08x unackseq: %08x new tx_unacked: %d\n",
tcp_getsequence(conn->sndseq), ackseq, unackseq, conn->unacked); tcp_getsequence(conn->sndseq), ackseq, unackseq, conn->tx_unacked);
tcp_setsequence(conn->sndseq, ackseq); tcp_setsequence(conn->sndseq, ackseq);
/* Do RTT estimation, unless we have done retransmissions. */ /* Do RTT estimation, unless we have done retransmissions. */
@ -619,7 +619,7 @@ found:
conn->sent = 0; conn->sent = 0;
conn->sndseq_max = 0; conn->sndseq_max = 0;
#endif #endif
conn->unacked = 0; conn->tx_unacked = 0;
flags = TCP_CONNECTED; flags = TCP_CONNECTED;
ninfo("TCP state: TCP_ESTABLISHED\n"); ninfo("TCP state: TCP_ESTABLISHED\n");
@ -639,7 +639,7 @@ found:
if ((tcp->flags & TCP_CTL) == TCP_SYN) if ((tcp->flags & TCP_CTL) == TCP_SYN)
{ {
tcp_ack(dev, conn, TCP_ACK | TCP_SYN); tcp_synack(dev, conn, TCP_ACK | TCP_SYN);
return; return;
} }
@ -714,7 +714,7 @@ found:
memcpy(conn->rcvseq, tcp->seqno, 4); memcpy(conn->rcvseq, tcp->seqno, 4);
net_incr32(conn->rcvseq, 1); net_incr32(conn->rcvseq, 1);
conn->unacked = 0; conn->tx_unacked = 0;
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
conn->isn = tcp_getsequence(tcp->ackno); conn->isn = tcp_getsequence(tcp->ackno);
@ -770,7 +770,7 @@ found:
* if the connection is going to be closed. * if the connection is going to be closed.
*/ */
#if 0 #if 0
if (conn->unacked > 0) if (conn->tx_unacked > 0)
{ {
goto drop; goto drop;
} }
@ -791,7 +791,7 @@ found:
(void)tcp_callback(dev, conn, flags); (void)tcp_callback(dev, conn, flags);
conn->tcpstateflags = TCP_LAST_ACK; conn->tcpstateflags = TCP_LAST_ACK;
conn->unacked = 1; conn->tx_unacked = 1;
conn->nrtx = 0; conn->nrtx = 0;
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
conn->sndseq_max = tcp_getsequence(conn->sndseq) + 1; conn->sndseq_max = tcp_getsequence(conn->sndseq) + 1;
@ -943,7 +943,7 @@ found:
if ((tcp->flags & TCP_FIN) != 0) if ((tcp->flags & TCP_FIN) != 0)
{ {
if ((flags & TCP_ACKDATA) != 0 && conn->unacked == 0) if ((flags & TCP_ACKDATA) != 0 && conn->tx_unacked == 0)
{ {
conn->tcpstateflags = TCP_TIME_WAIT; conn->tcpstateflags = TCP_TIME_WAIT;
conn->timer = 0; conn->timer = 0;
@ -960,7 +960,7 @@ found:
tcp_send(dev, conn, TCP_ACK, tcpiplen); tcp_send(dev, conn, TCP_ACK, tcpiplen);
return; return;
} }
else if ((flags & TCP_ACKDATA) != 0 && conn->unacked == 0) else if ((flags & TCP_ACKDATA) != 0 && conn->tx_unacked == 0)
{ {
conn->tcpstateflags = TCP_FIN_WAIT_2; conn->tcpstateflags = TCP_FIN_WAIT_2;
ninfo("TCP state: TCP_FIN_WAIT_2\n"); ninfo("TCP state: TCP_FIN_WAIT_2\n");

View File

@ -547,10 +547,10 @@ void tcp_reset(FAR struct net_driver_s *dev)
} }
/**************************************************************************** /****************************************************************************
* Name: tcp_ack * Name: tcp_synack
* *
* Description: * Description:
* Send the SYN or SYNACK response. * Send the SYN, ACK, or SYNACK response.
* *
* Input Parameters: * Input Parameters:
* dev - The device driver structure to use in the send operation * dev - The device driver structure to use in the send operation
@ -565,7 +565,7 @@ void tcp_reset(FAR struct net_driver_s *dev)
* *
****************************************************************************/ ****************************************************************************/
void tcp_ack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, void tcp_synack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
uint8_t ack) uint8_t ack)
{ {
struct tcp_hdr_s *tcp; struct tcp_hdr_s *tcp;
@ -609,7 +609,7 @@ void tcp_ack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
tcp->flags = ack; tcp->flags = ack;
/* We send out the TCP Maximum Segment Size option with our ack. */ /* We send out the TCP Maximum Segment Size option with our ACK. */
tcp->optdata[0] = TCP_OPT_MSS; tcp->optdata[0] = TCP_OPT_MSS;
tcp->optdata[1] = TCP_OPT_MSS_LEN; tcp->optdata[1] = TCP_OPT_MSS_LEN;

View File

@ -531,13 +531,13 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
/* Yes.. Reset the number of bytes sent sent from the write buffer */ /* Yes.. Reset the number of bytes sent sent from the write buffer */
sent = TCP_WBSENT(wrb); sent = TCP_WBSENT(wrb);
if (conn->unacked > sent) if (conn->tx_unacked > sent)
{ {
conn->unacked -= sent; conn->tx_unacked -= sent;
} }
else else
{ {
conn->unacked = 0; conn->tx_unacked = 0;
} }
if (conn->sent > sent) if (conn->sent > sent)
@ -550,8 +550,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
} }
TCP_WBSENT(wrb) = 0; TCP_WBSENT(wrb) = 0;
ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", ninfo("REXMIT: wrb=%p sent=%u, conn tx_unacked=%d sent=%d\n",
wrb, TCP_WBSENT(wrb), conn->unacked, conn->sent); wrb, TCP_WBSENT(wrb), conn->tx_unacked, conn->sent);
/* Increment the retransmit count on this write buffer. */ /* Increment the retransmit count on this write buffer. */
@ -603,13 +603,13 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
/* Reset the number of bytes sent sent from the write buffer */ /* Reset the number of bytes sent sent from the write buffer */
sent = TCP_WBSENT(wrb); sent = TCP_WBSENT(wrb);
if (conn->unacked > sent) if (conn->tx_unacked > sent)
{ {
conn->unacked -= sent; conn->tx_unacked -= sent;
} }
else else
{ {
conn->unacked = 0; conn->tx_unacked = 0;
} }
if (conn->sent > sent) if (conn->sent > sent)
@ -622,8 +622,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
} }
TCP_WBSENT(wrb) = 0; TCP_WBSENT(wrb) = 0;
ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", ninfo("REXMIT: wrb=%p sent=%u, conn tx_unacked=%d sent=%d\n",
wrb, TCP_WBSENT(wrb), conn->unacked, conn->sent); wrb, TCP_WBSENT(wrb), conn->tx_unacked, conn->sent);
/* Free any write buffers that have exceed the retry count */ /* Free any write buffers that have exceed the retry count */
@ -767,7 +767,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* number calculations. * number calculations.
*/ */
conn->unacked += sndlen; conn->tx_unacked += sndlen;
conn->sent += sndlen; conn->sent += sndlen;
/* Below prediction will become true, unless retransmission occurrence */ /* Below prediction will become true, unless retransmission occurrence */
@ -780,8 +780,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
conn->sndseq_max = predicted_seqno; conn->sndseq_max = predicted_seqno;
} }
ninfo("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n", ninfo("SEND: wrb=%p nrtx=%u tx_unacked=%u sent=%u\n",
wrb, TCP_WBNRTX(wrb), conn->unacked, conn->sent); wrb, TCP_WBNRTX(wrb), conn->tx_unacked, conn->sent);
/* Increment the count of bytes sent from this write buffer */ /* Increment the count of bytes sent from this write buffer */

View File

@ -530,7 +530,7 @@ end_wait:
/* There are no outstanding, unacknowledged bytes */ /* There are no outstanding, unacknowledged bytes */
conn->unacked = 0; conn->tx_unacked = 0;
/* Wake up the waiting thread */ /* Wake up the waiting thread */
@ -747,7 +747,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock,
* initial sequence number. * initial sequence number.
*/ */
conn->unacked = 0; conn->tx_unacked = 0;
/* Set the initial time for calculating timeouts */ /* Set the initial time for calculating timeouts */

View File

@ -614,7 +614,7 @@ ssize_t tcp_sendfile(FAR struct socket *psock, FAR struct file *infile,
* initial sequence number. * initial sequence number.
*/ */
conn->unacked = 0; conn->tx_unacked = 0;
#ifdef CONFIG_NET_SOCKOPTS #ifdef CONFIG_NET_SOCKOPTS
/* Set the initial time for calculating timeouts */ /* Set the initial time for calculating timeouts */

View File

@ -60,6 +60,20 @@
#include "socket/socket.h" #include "socket/socket.h"
#include "tcp/tcp.h" #include "tcp/tcp.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Per RFC 1122: "... an ACK should not be excessively delayed; in
* particular, the delay MUST be less than 0.5 seconds ..."
*
* NOTE: We only have 0.5 timing resolution here so the delay will be
* between 0.5 and 1.0 seconds, and may be delayed further, depending on the
* polling rate of the the driver (often 1 second).
*/
#define ACK_DELAY (1)
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
@ -187,7 +201,7 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
* retransmit. * retransmit.
*/ */
if (conn->unacked > 0) if (conn->tx_unacked > 0)
{ {
/* The connection has outstanding data */ /* The connection has outstanding data */
@ -315,14 +329,14 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
* SYNACK. * SYNACK.
*/ */
tcp_ack(dev, conn, TCP_ACK | TCP_SYN); tcp_synack(dev, conn, TCP_ACK | TCP_SYN);
goto done; goto done;
case TCP_SYN_SENT: case TCP_SYN_SENT:
/* In the SYN_SENT state, we retransmit out SYN. */ /* In the SYN_SENT state, we retransmit out SYN. */
tcp_ack(dev, conn, TCP_SYN); tcp_synack(dev, conn, TCP_SYN);
goto done; goto done;
case TCP_ESTABLISHED: case TCP_ESTABLISHED:
@ -454,7 +468,7 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
* dummy byte that we just sent. * dummy byte that we just sent.
*/ */
conn->unacked++; conn->tx_unacked++;
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* Increment the un-ACKed sequence number */ /* Increment the un-ACKed sequence number */
@ -472,9 +486,40 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
} }
#endif #endif
#ifdef CONFIG_NET_TCP_DELAYED_ACK
/* Handle delayed acknowledgments. Is there a segment with a
* delayed acknowledgment?
*/
if (conn->rx_unackseg > 0)
{
/* Increment the ACK delay. */
conn->rx_acktimer += hsec;
/* Per RFC 1122: "...an ACK should not be excessively
* delayed; in particular, the delay must be less than
* 0.5 seconds..."
*/
if (conn->rx_acktimer >= ACK_DELAY)
{
/* Reset the delayed ACK state and send the ACK
* packet.
*/
conn->rx_unackseg = 0;
conn->rx_acktimer = 0;
tcp_synack(dev, conn, TCP_ACK);
goto done;
}
}
#endif
/* There was no need for a retransmission and there was no /* There was no need for a retransmission and there was no
* need to probe the remote peer. We poll the application for * need to probe the remote peer and there was no need to
* new outgoing data. * send a delayed ACK. We poll the application for new
* outgoing data.
*/ */
result = tcp_callback(dev, conn, TCP_POLL); result = tcp_callback(dev, conn, TCP_POLL);