From 5c0f166aa077ee8f092c8003423571d1b67b049b Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Wed, 19 Dec 2018 01:38:57 -0800 Subject: [PATCH] tcp: fix fin in syn-rcvd Change-Id: Iba7c08c9edcf76ea24d00d5ea9e0586e9f94df4e Signed-off-by: Florin Coras --- src/vnet/tcp/tcp.c | 12 ++++++------ src/vnet/tcp/tcp_input.c | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index 9a3c90425b2..b1ed99a4dee 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -290,22 +290,21 @@ tcp_connection_reset (tcp_connection_t * tc) tcp_connection_timers_reset (tc); /* Set the cleanup timer, in case the session layer/app don't * cleanly close the connection */ - tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME); + tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME); stream_session_reset_notify (&tc->connection); break; case TCP_STATE_CLOSE_WAIT: case TCP_STATE_FIN_WAIT_1: case TCP_STATE_FIN_WAIT_2: case TCP_STATE_CLOSING: - tc->state = TCP_STATE_CLOSED; - TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc); tcp_connection_timers_reset (tc); - tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME); + tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME); break; case TCP_STATE_CLOSED: return; } tc->state = TCP_STATE_CLOSED; + TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc); } /** @@ -1252,7 +1251,7 @@ tcp_timer_waitclose_handler (u32 conn_index) /* Session didn't come back with a close(). Send FIN either way * and switch to LAST_ACK. */ - if (tc->state == TCP_STATE_CLOSE_WAIT) + if (tc->state == TCP_STATE_CLOSE_WAIT && (tc->flags & TCP_CONN_FINPNDG)) { /* Make sure we don't try to send unsent data */ tcp_connection_timers_reset (tc); @@ -1269,8 +1268,9 @@ tcp_timer_waitclose_handler (u32 conn_index) } else if (tc->state == TCP_STATE_FIN_WAIT_1) { - /* Wait for session layer to clean up tx events */ + tcp_connection_timers_reset (tc); tc->state = TCP_STATE_CLOSED; + /* Wait for session layer to clean up tx events */ tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME); return; } diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index 8481c76f489..f1d0f0186d5 100644 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -2725,7 +2725,8 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } /* Make sure the ack is exactly right */ - if (tc0->rcv_nxt != vnet_buffer (b0)->tcp.seq_number || is_fin0) + if (tc0->rcv_nxt != vnet_buffer (b0)->tcp.seq_number || is_fin0 + || vnet_buffer (b0)->tcp.data_len) { tcp_connection_reset (tc0); error0 = TCP_ERROR_SEGMENT_INVALID; @@ -2912,14 +2913,18 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, switch (tc0->state) { case TCP_STATE_ESTABLISHED: + tcp_rcv_fin (wrk, tc0, b0, &error0); + break; case TCP_STATE_SYN_RCVD: - /* Send FIN-ACK notify app and enter CLOSE-WAIT */ + /* Send FIN-ACK, enter LAST-ACK and because the app was not + * notified yet, set a cleanup timer instead of relying on + * disconnect notify and the implicit close call. */ tcp_connection_timers_reset (tc0); + tc0->rcv_nxt += 1; tcp_send_fin (tc0); - stream_session_disconnect_notify (&tc0->connection); - tc0->state = TCP_STATE_CLOSE_WAIT; - tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME); + tc0->state = TCP_STATE_LAST_ACK; TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); + tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); break; case TCP_STATE_CLOSE_WAIT: case TCP_STATE_CLOSING: @@ -3601,6 +3606,7 @@ do { \ } while (0) /* RFC 793: In LISTEN if RST drop and if ACK return RST */ + _(LISTEN, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID); _(LISTEN, TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET, TCP_ERROR_ACK_INVALID); _(LISTEN, TCP_FLAG_RST, TCP_INPUT_NEXT_DROP, TCP_ERROR_INVALID_CONNECTION); _(LISTEN, TCP_FLAG_SYN, TCP_INPUT_NEXT_LISTEN, TCP_ERROR_NONE); @@ -3697,6 +3703,7 @@ do { \ TCP_ERROR_NONE); /* FIN in reply to our FIN from the other side */ _(FIN_WAIT_1, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(FIN_WAIT_1, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(FIN_WAIT_1, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); -- 2.16.6