From 08e9dff0e9dcfb43ca76208bf569adc735842c8c Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 29 Jun 2021 20:00:57 +0900 Subject: [PATCH] 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 --- net/tcp/tcp_close.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/tcp/tcp_close.c b/net/tcp/tcp_close.c index 2998d0d8624..36e71b81cd1 100644 --- a/net/tcp/tcp_close.c +++ b/net/tcp/tcp_close.c @@ -139,6 +139,22 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev, * 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; flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE; }