+ switch (tc0->state)
+ {
+ case TCP_STATE_ESTABLISHED:
+ /* Account for the FIN and send ack */
+ tc0->rcv_nxt += 1;
+ tcp_program_ack (wrk, tc0);
+ tcp_connection_set_state (tc0, TCP_STATE_CLOSE_WAIT);
+ tcp_program_disconnect (wrk, tc0);
+ tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
+ break;
+ case TCP_STATE_SYN_RCVD:
+ /* 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);
+ tcp_connection_set_state (tc0, TCP_STATE_LAST_ACK);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
+ break;
+ case TCP_STATE_CLOSE_WAIT:
+ case TCP_STATE_CLOSING:
+ case TCP_STATE_LAST_ACK:
+ /* move along .. */
+ break;
+ case TCP_STATE_FIN_WAIT_1:
+ tc0->rcv_nxt += 1;
+ tcp_connection_set_state (tc0, TCP_STATE_CLOSING);
+ tcp_program_ack (wrk, tc0);
+ /* Wait for ACK but not forever */
+ tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
+ break;
+ case TCP_STATE_FIN_WAIT_2:
+ /* Got FIN, send ACK! Be more aggressive with resource cleanup */
+ tc0->rcv_nxt += 1;
+ tcp_connection_set_state (tc0, TCP_STATE_TIME_WAIT);
+ tcp_connection_timers_reset (tc0);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
+ tcp_program_ack (wrk, tc0);
+ break;
+ case TCP_STATE_TIME_WAIT:
+ /* Remain in the TIME-WAIT state. Restart the time-wait
+ * timeout.
+ */
+ tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
+ break;