net/tcp: In tcp_input(), add the logic to detect, decode, and respond to TCP Keep-Alive packets. In tcp_timer(), fix some problems with the way that TCP Keep-Alive probes were being formatted.
This commit is contained in:
parent
1f52c13814
commit
ae399b9b62
@ -385,11 +385,58 @@ found:
|
|||||||
|
|
||||||
dev->d_len -= (len + iplen);
|
dev->d_len -= (len + iplen);
|
||||||
|
|
||||||
/* First, check if the sequence number of the incoming packet is
|
#ifdef CONFIG_NET_TCP_KEEPALIVE
|
||||||
* what we're expecting next. If not, we send out an ACK with the
|
/* Check for a to KeepAlive probes. These packets have these properties:
|
||||||
* correct numbers in, unless we are in the SYN_RCVD state and
|
*
|
||||||
* receive a SYN, in which case we should retransmit our SYNACK
|
* - TCP_ACK flag is set. SYN/FIN/RST never appear in a Keepalive probe.
|
||||||
* (which is done further down).
|
* - Sequence number is the sequence number of previously ACKed data, i.e.,
|
||||||
|
* the expected sequence number minus one.
|
||||||
|
* - The data payload is one or two bytes.
|
||||||
|
*
|
||||||
|
* We would expect a KeepAlive only in the ESTABLISHED state and only after
|
||||||
|
* some time has elapsed with no network activity. If there is un-ACKed data,
|
||||||
|
* then we will let the normal TCP re-transmission logic handle that case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((tcp->flags & TCP_ACK) != 0 &&
|
||||||
|
(tcp->flags & (TCP_SYN | TCP_FIN | TCP_RST)) == 0 &&
|
||||||
|
(conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED &&
|
||||||
|
(dev->d_len == 0 || dev->d_len == 1) &&
|
||||||
|
conn->unacked <= 0)
|
||||||
|
{
|
||||||
|
uint32_t ackseq;
|
||||||
|
uint32_t rcvseq;
|
||||||
|
|
||||||
|
/* Get the sequence number of that has just been acknowledged by this
|
||||||
|
* incoming packet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ackseq = tcp_getsequence(tcp->seqno);
|
||||||
|
rcvseq = tcp_getsequence(conn->rcvseq);
|
||||||
|
|
||||||
|
if (ackseq < rcvseq)
|
||||||
|
{
|
||||||
|
if (dev->d_len > 0)
|
||||||
|
{
|
||||||
|
/* Increment the received sequence number (perhaps including the
|
||||||
|
* discarded dummy byte in the probe).
|
||||||
|
*/
|
||||||
|
|
||||||
|
net_incr32(conn->rcvseq, dev->d_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And send a "normal" acknowledgment of the KeepAlive probe */
|
||||||
|
|
||||||
|
tcp_send(dev, conn, TCP_ACK, tcpiplen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check if the sequence number of the incoming packet is what we are
|
||||||
|
* expecting next. If not, we send out an ACK with the correct numbers
|
||||||
|
* in, unless we are in the SYN_RCVD state and receive a SYN, in which
|
||||||
|
* case we should retransmit our SYNACK (which is done further down).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!((((conn->tcpstateflags & TCP_STATE_MASK) == TCP_SYN_SENT) &&
|
if (!((((conn->tcpstateflags & TCP_STATE_MASK) == TCP_SYN_SENT) &&
|
||||||
@ -405,10 +452,9 @@ found:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next, check if the incoming segment acknowledges any outstanding
|
/* Check if the incoming segment acknowledges any outstanding data. If so,
|
||||||
* data. If so, we update the sequence number, reset the length of
|
* we update the sequence number, reset the length of the outstanding
|
||||||
* the outstanding data, calculate RTT estimations, and reset the
|
* data, calculate RTT estimations, and reset the retransmission timer.
|
||||||
* retransmission timer.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((tcp->flags & TCP_ACK) != 0 && conn->unacked > 0)
|
if ((tcp->flags & TCP_ACK) != 0 && conn->unacked > 0)
|
||||||
@ -764,7 +810,7 @@ found:
|
|||||||
#endif /* CONFIG_NET_TCPURGDATA */
|
#endif /* CONFIG_NET_TCPURGDATA */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NET_TCP_KEEPALIVE
|
#ifdef CONFIG_NET_TCP_KEEPALIVE
|
||||||
/* If the established socket receives an ACK or any kind of data
|
/* If the established socket receives an ACK or any kind of data
|
||||||
* from the remote peer (whether we accept it or not), then reset
|
* from the remote peer (whether we accept it or not), then reset
|
||||||
* the keep alive timer.
|
* the keep alive timer.
|
||||||
|
@ -364,6 +364,7 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
|||||||
if (conn->keepalive)
|
if (conn->keepalive)
|
||||||
{
|
{
|
||||||
socktimeo_t timeo;
|
socktimeo_t timeo;
|
||||||
|
uint32_t saveseq;
|
||||||
|
|
||||||
/* If this is the first probe, then the keepstart time is
|
/* If this is the first probe, then the keepstart time is
|
||||||
* the time that the last ACK or data was received from the
|
* the time that the last ACK or data was received from the
|
||||||
@ -381,6 +382,7 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
|||||||
{
|
{
|
||||||
timeo = (socktimeo_t)conn->keepidle;
|
timeo = (socktimeo_t)conn->keepidle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Yes... has the idle period elapsed with no data or ACK
|
/* Yes... has the idle period elapsed with no data or ACK
|
||||||
* received from the remote peer?
|
* received from the remote peer?
|
||||||
*/
|
*/
|
||||||
@ -422,10 +424,38 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* And send the probe */
|
/* And send the probe (along with a garbage byte).
|
||||||
|
* The packet we sned 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.
|
||||||
|
* - The data payload is one or two bytes.
|
||||||
|
*
|
||||||
|
* tcp_send() will send the TCP sequence number as
|
||||||
|
* conn->sndseq. Rather than creating a new
|
||||||
|
* interface, we spoof tcp_end() here:
|
||||||
|
*/
|
||||||
|
|
||||||
tcp_send(dev, conn, TCP_ACK, tcpiplen);
|
saveseq = tcp_getsequence(conn->sndseq);
|
||||||
|
tcp_setsequence(conn->sndseq, saveseq - 1);
|
||||||
|
|
||||||
|
tcp_send(dev, conn, TCP_ACK, tcpiplen + 1);
|
||||||
|
|
||||||
|
tcp_setsequence(conn->sndseq, saveseq);
|
||||||
|
|
||||||
|
/* Increment the number of un-ACKed bytes due to the dummy
|
||||||
|
* byte that we just sent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
conn->unacked++;
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||||
|
/* Increment the un-ACKed sequence number */
|
||||||
|
|
||||||
|
conn->sndseq_max++;
|
||||||
|
#endif
|
||||||
/* Update for the next probe */
|
/* Update for the next probe */
|
||||||
|
|
||||||
conn->keeptime = clock_systimer();
|
conn->keeptime = clock_systimer();
|
||||||
|
Loading…
Reference in New Issue
Block a user