Index: uspace/srv/net/tl/tcp/conn.c
===================================================================
--- uspace/srv/net/tl/tcp/conn.c	(revision 32aea9f480bd0b1171c0ef3bdc0230277d2d79a0)
+++ uspace/srv/net/tl/tcp/conn.c	(revision f343a1676dea97f58427b5c5890f157ff1271413)
@@ -130,4 +130,26 @@
 	tcp_tqueue_ctrl_seg(conn, CTL_SYN);
 	conn->cstate = st_syn_sent;
+}
+
+/** FIN has been sent.
+ *
+ * This function should be called when FIN is sent over the connection,
+ * as a result the connection state is changed appropriately.
+ */
+void tcp_conn_fin_sent(tcp_conn_t *conn)
+{
+	switch (conn->cstate) {
+	case st_syn_received:
+	case st_established:
+		log_msg(LVL_DEBUG, "FIN sent -> Fin-Wait-1");
+		conn->cstate = st_fin_wait_1;
+		break;
+	case st_close_wait:
+		log_msg(LVL_DEBUG, "FIN sent -> Close-Wait");
+		conn->cstate = st_last_ack;
+		break;
+	default:
+		assert(false);
+	}
 }
 
@@ -734,5 +756,34 @@
 		conn->rcv_wnd--;
 
-		/* TODO Change connection state */
+		/* Change connection state */
+		switch (conn->cstate) {
+		case st_listen:
+		case st_syn_sent:
+		case st_closed:
+			/* Connection not synchronized */
+			assert(false);
+		case st_syn_received:
+		case st_established:
+			log_msg(LVL_DEBUG, "FIN received -> Close-Wait");
+			conn->cstate = st_close_wait;
+			break;
+		case st_fin_wait_1:
+			log_msg(LVL_DEBUG, "FIN received -> Closing");
+			conn->cstate = st_closing;
+			break;
+		case st_fin_wait_2:
+			log_msg(LVL_DEBUG, "FIN received -> Time-Wait");
+			conn->cstate = st_time_wait;
+			/* XXX start time-wait timer */
+			break;
+		case st_close_wait:
+		case st_closing:
+		case st_last_ack:
+			/* Do nothing */
+			break;
+		case st_time_wait:
+			/* XXX Restart the 2 MSL time-wait timeout */
+			break;
+		}
 
 		/* Add FIN to the receive buffer */
Index: uspace/srv/net/tl/tcp/conn.h
===================================================================
--- uspace/srv/net/tl/tcp/conn.h	(revision 32aea9f480bd0b1171c0ef3bdc0230277d2d79a0)
+++ uspace/srv/net/tl/tcp/conn.h	(revision f343a1676dea97f58427b5c5890f157ff1271413)
@@ -42,4 +42,5 @@
 void tcp_conn_add(tcp_conn_t *);
 extern void tcp_conn_sync(tcp_conn_t *);
+extern void tcp_conn_fin_sent(tcp_conn_t *);
 extern tcp_conn_t *tcp_conn_find(tcp_sockpair_t *);
 extern bool tcp_conn_got_syn(tcp_conn_t *);
Index: uspace/srv/net/tl/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.c	(revision 32aea9f480bd0b1171c0ef3bdc0230277d2d79a0)
+++ uspace/srv/net/tl/tcp/tqueue.c	(revision f343a1676dea97f58427b5c5890f157ff1271413)
@@ -119,4 +119,5 @@
 		/* We are sending out FIN */
 		ctrl = CTL_FIN;
+		tcp_conn_fin_sent(conn);
 	} else {
 		ctrl = 0;
