Index: uspace/srv/net/tl/tcp/conn.c
===================================================================
--- uspace/srv/net/tl/tcp/conn.c	(revision f343a1676dea97f58427b5c5890f157ff1271413)
+++ uspace/srv/net/tl/tcp/conn.c	(revision 6df418c4ef80dc56e75e408fbe68f7d9b495baa9)
@@ -99,5 +99,9 @@
 	tcp_iqueue_init(&conn->incoming, conn);
 
+	/* Initialize retransmission queue */
+	tcp_tqueue_init(&conn->retransmit, conn);
+
 	conn->cstate = st_listen;
+	conn->fin_is_acked = false;
 	conn->ident.local = *lsock;
 	if (fsock != NULL)
@@ -152,4 +156,6 @@
 		assert(false);
 	}
+
+	conn->fin_is_acked = false;
 }
 
@@ -525,5 +531,9 @@
 		return cp_done;
 
-	/* TODO */
+	if (conn->fin_is_acked) {
+		log_msg(LVL_DEBUG, " FIN acked -> Fin-Wait-2");
+		conn->cstate = st_fin_wait_2;
+	}
+
 	return cp_continue;
 }
Index: uspace/srv/net/tl/tcp/conn.h
===================================================================
--- uspace/srv/net/tl/tcp/conn.h	(revision f343a1676dea97f58427b5c5890f157ff1271413)
+++ uspace/srv/net/tl/tcp/conn.h	(revision 6df418c4ef80dc56e75e408fbe68f7d9b495baa9)
@@ -43,4 +43,5 @@
 extern void tcp_conn_sync(tcp_conn_t *);
 extern void tcp_conn_fin_sent(tcp_conn_t *);
+extern void tcp_conn_ack_of_fin_rcvd(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/segment.c
===================================================================
--- uspace/srv/net/tl/tcp/segment.c	(revision f343a1676dea97f58427b5c5890f157ff1271413)
+++ uspace/srv/net/tl/tcp/segment.c	(revision 6df418c4ef80dc56e75e408fbe68f7d9b495baa9)
@@ -53,4 +53,38 @@
 }
 
+/** Create duplicate of segment.
+ *
+ * @param seg	Segment
+ * @return 	Duplicate segment
+ */
+tcp_segment_t *tcp_segment_dup(tcp_segment_t *seg)
+{
+	tcp_segment_t *scopy;
+	size_t tsize;
+
+	scopy = tcp_segment_new();
+	if (scopy == NULL)
+		return NULL;
+
+	scopy->ctrl = seg->ctrl;
+	scopy->seq = seg->seq;
+	scopy->ack = seg->ack;
+	scopy->len = seg->len;
+	scopy->wnd = seg->wnd;
+	scopy->up = seg->up;
+
+	tsize = tcp_segment_text_size(seg);
+	scopy->data = calloc(tsize, 1);
+	if (scopy->data == NULL) {
+		free(scopy);
+		return NULL;
+	}
+
+	memcpy(scopy->data, seg->data, tsize);
+	scopy->dfptr = scopy->data;
+
+	return scopy;
+}
+
 /** Create a control-only segment.
  *
Index: uspace/srv/net/tl/tcp/segment.h
===================================================================
--- uspace/srv/net/tl/tcp/segment.h	(revision f343a1676dea97f58427b5c5890f157ff1271413)
+++ uspace/srv/net/tl/tcp/segment.h	(revision 6df418c4ef80dc56e75e408fbe68f7d9b495baa9)
@@ -41,4 +41,5 @@
 extern tcp_segment_t *tcp_segment_new(void);
 extern void tcp_segment_delete(tcp_segment_t *);
+extern tcp_segment_t *tcp_segment_dup(tcp_segment_t *);
 extern tcp_segment_t *tcp_segment_make_ctrl(tcp_control_t);
 extern tcp_segment_t *tcp_segment_make_rst(tcp_segment_t *);
Index: uspace/srv/net/tl/tcp/tcp_type.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp_type.h	(revision f343a1676dea97f58427b5c5890f157ff1271413)
+++ uspace/srv/net/tl/tcp/tcp_type.h	(revision 6df418c4ef80dc56e75e408fbe68f7d9b495baa9)
@@ -99,4 +99,9 @@
 } tcp_iqueue_t;
 
+typedef struct {
+	struct tcp_conn *conn;
+	list_t list;
+} tcp_tqueue_t;
+
 typedef struct tcp_conn {
 	link_t link;
@@ -108,6 +113,12 @@
 	tcp_cstate_t cstate;
 
+	/** Set when FIN is removed from the retransmission queue */
+	bool fin_is_acked;
+
 	/** Queue of incoming segments */
 	tcp_iqueue_t incoming;
+
+	/** Retransmission queue */
+	tcp_tqueue_t retransmit;
 
 	/** Receive buffer */
@@ -199,4 +210,9 @@
 } tcp_iqueue_entry_t;
 
+typedef struct {
+	link_t link;
+	tcp_segment_t *seg;
+} tcp_tqueue_entry_t;
+
 typedef enum {
 	cp_continue,
Index: uspace/srv/net/tl/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.c	(revision f343a1676dea97f58427b5c5890f157ff1271413)
+++ uspace/srv/net/tl/tcp/tqueue.c	(revision 6df418c4ef80dc56e75e408fbe68f7d9b495baa9)
@@ -35,15 +35,24 @@
  */
 
+#include <adt/list.h>
 #include <byteorder.h>
 #include <io/log.h>
 #include <macros.h>
 #include <mem.h>
+#include <stdlib.h>
 #include "conn.h"
 #include "header.h"
 #include "rqueue.h"
 #include "segment.h"
+#include "seq_no.h"
 #include "tqueue.h"
 #include "tcp_type.h"
 
+void tcp_tqueue_init(tcp_tqueue_t *tqueue, tcp_conn_t *conn)
+{
+	tqueue->conn = conn;
+	list_initialize(&tqueue->list);
+}
+
 void tcp_tqueue_ctrl_seg(tcp_conn_t *conn, tcp_control_t ctrl)
 {
@@ -58,6 +67,31 @@
 void tcp_tqueue_seg(tcp_conn_t *conn, tcp_segment_t *seg)
 {
+	tcp_segment_t *rt_seg;
+	tcp_tqueue_entry_t *tqe;
+
 	log_msg(LVL_DEBUG, "tcp_tqueue_seg(%p, %p)", conn, seg);
-	/* XXX queue */
+
+	/*
+	 * Add segment to retransmission queue
+	 */
+
+	if (seg->len > 0) {
+		rt_seg = tcp_segment_dup(seg);
+		if (rt_seg == NULL) {
+			log_msg(LVL_ERROR, "Memory allocation failed.");
+			/* XXX Handle properly */
+			return;
+		}
+
+		tqe = calloc(1, sizeof(tcp_tqueue_entry_t));
+		if (tqe == NULL) {
+			log_msg(LVL_ERROR, "Memory allocation failed.");
+			/* XXX Handle properly */
+			return;
+		}
+
+		tqe->seg = rt_seg;
+		list_append(&tqe->link, &conn->retransmit.list);
+	}
 
 	/*
@@ -146,6 +180,33 @@
 void tcp_tqueue_ack_received(tcp_conn_t *conn)
 {
-	(void) conn;
-
+	link_t *cur, *next;
+
+	log_msg(LVL_DEBUG, "tcp_tqueue_ack_received(%p)", conn);
+
+	cur = conn->retransmit.list.head.next;
+
+	while (cur != &conn->retransmit.list.head) {
+		next = cur->next;
+
+		tcp_tqueue_entry_t *tqe = list_get_instance(cur,
+		    tcp_tqueue_entry_t, link);
+
+		if (seq_no_segment_acked(conn, tqe->seg, conn->snd_una)) {
+			/* Remove acknowledged segment */
+			list_remove(cur);
+
+			if ((tqe->seg->ctrl & CTL_FIN) != 0) {
+				/* Our FIN has been acked */
+				conn->fin_is_acked = true;
+			}
+
+			tcp_segment_delete(tqe->seg);
+			free(tqe);
+		}
+
+		cur = next;
+	}
+
+	/* Possibly transmit more data */
 	tcp_tqueue_new_data(conn);
 }
Index: uspace/srv/net/tl/tcp/tqueue.h
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.h	(revision f343a1676dea97f58427b5c5890f157ff1271413)
+++ uspace/srv/net/tl/tcp/tqueue.h	(revision 6df418c4ef80dc56e75e408fbe68f7d9b495baa9)
@@ -39,4 +39,5 @@
 #include "tcp_type.h"
 
+extern void tcp_tqueue_init(tcp_tqueue_t *, tcp_conn_t *);
 extern void tcp_tqueue_ctrl_seg(tcp_conn_t *, tcp_control_t);
 extern void tcp_tqueue_seg(tcp_conn_t *, tcp_segment_t *);
