net/tcp:Added tcp zero window probe timer support
https://www.rfc-editor.org/rfc/rfc1122#page-92 Signed-off-by: wangyingdong <wangyingdong@xiaomi.com>
This commit is contained in:
parent
1a832eb554
commit
2ce31c442f
@ -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 */
|
||||
|
@ -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 &&
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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?
|
||||
|
Loading…
Reference in New Issue
Block a user