+ switch (tc->state)
+ {
+ case TCP_STATE_CLOSE_WAIT:
+ tcp_connection_timers_reset (tc);
+ /* App never returned with a close */
+ if (!(tc->flags & TCP_CONN_FINPNDG))
+ {
+ tcp_connection_set_state (tc, TCP_STATE_CLOSED);
+ session_transport_closed_notify (&tc->connection);
+ tcp_program_cleanup (wrk, tc);
+ tcp_workerp_stats_inc (wrk, to_closewait, 1);
+ break;
+ }
+
+ /* Send FIN either way and switch to LAST_ACK. */
+ tcp_cong_recovery_off (tc);
+ /* Make sure we don't try to send unsent data */
+ tc->snd_nxt = tc->snd_una;
+ tcp_send_fin (tc);
+ tcp_connection_set_state (tc, TCP_STATE_LAST_ACK);
+ session_transport_closed_notify (&tc->connection);
+
+ /* Make sure we don't wait in LAST ACK forever */
+ tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.lastack_time);
+ tcp_workerp_stats_inc (wrk, to_closewait2, 1);
+
+ /* Don't delete the connection yet */
+ break;
+ case TCP_STATE_FIN_WAIT_1:
+ tcp_connection_timers_reset (tc);
+ if (tc->flags & TCP_CONN_FINPNDG)
+ {
+ /* If FIN pending, we haven't sent everything, but we did try.
+ * Notify session layer that transport is closed. */
+ tcp_connection_set_state (tc, TCP_STATE_CLOSED);
+ tcp_send_reset (tc);
+ tcp_program_cleanup (wrk, tc);
+ }
+ else
+ {
+ /* We've sent the fin but no progress. Close the connection and
+ * to make sure everything is flushed, setup a cleanup timer */
+ tcp_connection_set_state (tc, TCP_STATE_CLOSED);
+ tcp_program_cleanup (wrk, tc);
+ }
+ session_transport_closed_notify (&tc->connection);
+ tcp_workerp_stats_inc (wrk, to_finwait1, 1);
+ break;
+ case TCP_STATE_LAST_ACK:
+ tcp_connection_timers_reset (tc);
+ tcp_connection_set_state (tc, TCP_STATE_CLOSED);
+ session_transport_closed_notify (&tc->connection);
+ tcp_program_cleanup (wrk, tc);
+ tcp_workerp_stats_inc (wrk, to_lastack, 1);
+ break;
+ case TCP_STATE_CLOSING:
+ tcp_connection_timers_reset (tc);
+ tcp_connection_set_state (tc, TCP_STATE_CLOSED);
+ session_transport_closed_notify (&tc->connection);
+ tcp_program_cleanup (wrk, tc);
+ tcp_workerp_stats_inc (wrk, to_closing, 1);
+ break;
+ case TCP_STATE_FIN_WAIT_2:
+ tcp_send_reset (tc);
+ tcp_connection_timers_reset (tc);
+ tcp_connection_set_state (tc, TCP_STATE_CLOSED);
+ session_transport_closed_notify (&tc->connection);
+ tcp_program_cleanup (wrk, tc);
+ tcp_workerp_stats_inc (wrk, to_finwait2, 1);
+ break;
+ case TCP_STATE_TIME_WAIT:
+ tcp_connection_set_state (tc, TCP_STATE_CLOSED);
+ tcp_program_cleanup (wrk, tc);
+ break;
+ default:
+ clib_warning ("waitclose in state: %U", format_tcp_state, tc->state);
+ break;
+ }