tcp_close: disable send callback before sending FIN

This fixes connection closing issues with CONFIG_NET_TCP_WRITE_BUFFERS.

Because TCP_CLOSE is used for both of input and output for tcp_callback,
the close callback and the send callback confuses each other as
the following. As it effectively disposes the connection immediately,
we end up with responding to the consequent ACK and FIN/ACK from the peer
with RSTs.

tcp_timer
    -> tcp_close_eventhandler
        returns TCP_CLOSE (meaning an active close)
    -> psock_send_eventhandler
        called with TCP_CLOSE from tcp_close_eventhandler, misinterpet as
        a passive close.
        -> tcp_lost_connection
            -> tcp_shutdown_monitor
                -> tcp_callback
                    -> tcp_close_eventhandler
                        misinterpret TCP_CLOSE from itself as
                        a passive close
This commit is contained in:
YAMAMOTO Takashi 2021-06-29 20:00:57 +09:00 committed by Xiang Xiao
parent 326a8ef0a2
commit 08e9dff0e9

View File

@ -139,6 +139,22 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
* is set in the response * is set in the response
*/ */
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
FAR struct socket *psock = pstate->cl_psock;
/* We don't need the send callback anymore. */
if (psock->s_sndcb != NULL)
{
psock->s_sndcb->flags = 0;
psock->s_sndcb->event = NULL;
/* The callback will be freed by tcp_free. */
psock->s_sndcb = NULL;
}
#endif
dev->d_len = 0; dev->d_len = 0;
flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE; flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE;
} }