Merge branch 'synack'

This commit is contained in:
Gregory Nutt 2017-05-14 11:00:47 -06:00
commit 93d73b14ab
4 changed files with 97 additions and 18 deletions

View File

@ -697,6 +697,19 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
void tcp_listen_initialize(void);
/****************************************************************************
* Name: tcp_findlistener
*
* Description:
* Return the connection listener for connections on this port (if any)
*
* Assumptions:
* Called at interrupt level
*
****************************************************************************/
FAR struct tcp_conn_s *tcp_findlistener(uint16_t portno);
/****************************************************************************
* Name: tcp_unlisten
*

View File

@ -179,20 +179,25 @@ static void tcp_input(FAR struct net_driver_s *dev, unsigned int iplen)
conn = tcp_alloc_accept(dev, tcp);
if (conn)
{
/* The connection structure was successfully allocated. Now see if
* there is an application waiting to accept the connection (or at
* least queue it it for acceptance).
/* The connection structure was successfully allocated and has
* been initialized in the TCP_SYN_RECVD state. The expected
* sequence of events is then the rest of the 3-way handshake:
*
* 1. We just received a TCP SYN packet from a remote host.
* 2. We will send the SYN-ACK response below (perhaps
* repeatedly in the event of a timeout)
* 3. Then we expect to receive an ACK from the remote host
* indicated the TCP socket connection is ESTABLISHED.
*
* Possible failure:
*
* 1. The ACK is never received. This will be handled by
* a timeout managed by tcp_timer().
* 2. The listener "unlistens()". This will be handled by
* the failure of tcp_accept_connection() when the ACK is received.
*/
conn->crefs = 1;
if (tcp_accept_connection(dev, conn, tmp16) != OK)
{
/* No, then we have to give the connection back and drop the packet */
conn->crefs = 0;
tcp_free(conn);
conn = NULL;
}
}
if (!conn)
@ -462,8 +467,29 @@ found:
if ((flags & TCP_ACKDATA) != 0)
{
/* The three way handshake is complete and the TCP connection
* is now in the ESTABLISHED state.
*/
conn->tcpstateflags = TCP_ESTABLISHED;
/* Wake up any listener waiting for a connection on this port */
if (tcp_accept_connection(dev, conn, tcp->destport) != OK)
{
/* No more listener for current port. We can free conn here
* because it has not been shared with upper layers yet as
* handshake is not complete
*/
nerr("Listen canceled while waiting for ACK on port %d\n",
tcp->destport);
conn->crefs = 0;
tcp_free(conn);
conn = NULL;
goto drop;
}
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
conn->isn = tcp_getsequence(tcp->ackno);
tcp_setsequence(conn->sndseq, conn->isn);

View File

@ -257,7 +257,7 @@ int tcp_accept_connection(FAR struct net_driver_s *dev,
*/
listener = tcp_findlistener(portno);
if (listener)
if (listener != NULL)
{
/* Yes, there is a listener. Is it accepting connections now? */

View File

@ -218,17 +218,57 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
goto done;
}
#endif
/* Should we close the connection? */
/* Check for a timeout on connection in the TCP_SYN_RCVD state.
* On such timeouts, we would normally resend the SYNACK until
* the ACK is received, completing the 3-way handshek. But if
* the retry count elapsed, then we must assume that no ACK is
* forthcoming and terminate the attempted connection.
*/
if (
if (conn->tcpstateflags == TCP_SYN_RCVD &&
conn->nrtx >= TCP_MAXSYNRTX)
{
FAR struct tcp_conn_s *listener;
conn->tcpstateflags = TCP_CLOSED;
ninfo("TCP state: TCP_CLOSED\n");
/* Find the listener for this connectins */
listener = tcp_findlistener(conn->lport);
if (listener != NULL)
{
/* We call tcp_callback() for the connection with
* TCP_TIMEDOUT to inform the listener that the
* connection has timed out.
*/
result = tcp_callback(dev, listener, TCP_TIMEDOUT);
}
/* We also send a reset packet to the remote host. */
tcp_send(dev, conn, TCP_RST | TCP_ACK, hdrlen);
/* Finally, we must free this TCP connection structure */
tcp_free(conn);
goto done;
}
/* Otherwise, check for a timeout on an established connection.
* If the retry count is exceeded in this case, we should
* close the connection.
*/
else if (
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
conn->expired > 0 ||
#else
conn->nrtx == TCP_MAXRTX ||
conn->nrtx >= TCP_MAXRTX ||
#endif
((conn->tcpstateflags == TCP_SYN_SENT ||
conn->tcpstateflags == TCP_SYN_RCVD) &&
conn->nrtx == TCP_MAXSYNRTX)
(conn->tcpstateflags == TCP_SYN_SENT &&
conn->nrtx >= TCP_MAXSYNRTX)
)
{
conn->tcpstateflags = TCP_CLOSED;