Index: uspace/srv/net/tcp/conn.c
===================================================================
--- uspace/srv/net/tcp/conn.c	(revision 0a1e7e4d2a546c77ee164eecd49445abce8f9415)
+++ uspace/srv/net/tcp/conn.c	(revision 6c4eedf11368c6c47c86ab45352946ba67b15bdc)
@@ -47,4 +47,5 @@
 #include "iqueue.h"
 #include "pdu.h"
+#include "rqueue.h"
 #include "segment.h"
 #include "seq_no.h"
@@ -65,5 +66,9 @@
 /** Connection association map */
 static amap_t *amap;
+/** Taken after tcp_conn_t lock */
 static FIBRIL_MUTEX_INITIALIZE(amap_lock);
+
+/** Internal loopback configuration */
+tcp_lb_t tcp_conn_lb = tcp_lb_none;
 
 static void tcp_conn_seg_process(tcp_conn_t *, tcp_segment_t *);
@@ -71,4 +76,6 @@
 static void tcp_conn_tw_timer_clear(tcp_conn_t *);
 static void tcp_transmit_segment(inet_ep2_t *, tcp_segment_t *);
+static void tcp_conn_trim_seg_to_wnd(tcp_conn_t *, tcp_segment_t *);
+static void tcp_reply_rst(inet_ep2_t *, tcp_segment_t *);
 
 static tcp_tqueue_cb_t tcp_conn_tqueue_cb = {
@@ -324,5 +331,5 @@
  * Remove connection from the connection map.
  */
-void tcp_conn_remove(tcp_conn_t *conn)
+static void tcp_conn_remove(tcp_conn_t *conn)
 {
 	if (!conn->mapped)
@@ -369,4 +376,6 @@
 void tcp_conn_sync(tcp_conn_t *conn)
 {
+	assert(fibril_mutex_is_locked(&conn->lock));
+
 	/* XXX select ISS */
 	conn->iss = 1;
@@ -1358,5 +1367,5 @@
  * @param seg		Segment
  */
-void tcp_conn_trim_seg_to_wnd(tcp_conn_t *conn, tcp_segment_t *seg)
+static void tcp_conn_trim_seg_to_wnd(tcp_conn_t *conn, tcp_segment_t *seg)
 {
 	uint32_t left, right;
@@ -1382,6 +1391,15 @@
 }
 
+/** Transmit segment over network.
+ *
+ * @param epp Endpoint pair with source and destination information
+ * @param seg Segment (ownership retained by caller)
+ */
 static void tcp_transmit_segment(inet_ep2_t *epp, tcp_segment_t *seg)
 {
+	tcp_pdu_t *pdu;
+	tcp_segment_t *dseg;
+	inet_ep2_t rident;
+
 	log_msg(LOG_DEFAULT, LVL_DEBUG,
 	    "tcp_transmit_segment(l:(%u),f:(%u), %p)",
@@ -1393,8 +1411,16 @@
 	tcp_segment_dump(seg);
 
-//	tcp_rqueue_bounce_seg(sp, seg);
-//	tcp_ncsim_bounce_seg(sp, seg);
-
-	tcp_pdu_t *pdu;
+	if (tcp_conn_lb == tcp_lb_segment) {
+		/* Loop back segment */
+//		tcp_ncsim_bounce_seg(sp, seg);
+
+		/* Reverse the identification */
+		tcp_ep2_flipped(epp, &rident);
+
+		/* Insert segment back into rqueue */
+		dseg = tcp_segment_dup(seg);
+		tcp_rqueue_insert_seg(&rident, dseg);
+		return;
+	}
 
 	if (tcp_pdu_encode(epp, seg, &pdu) != EOK) {
@@ -1403,4 +1429,19 @@
 	}
 
+	if (tcp_conn_lb == tcp_lb_pdu) {
+		/* Loop back PDU */
+		if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
+			log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
+			tcp_pdu_delete(pdu);
+			return;
+		}
+
+		tcp_pdu_delete(pdu);
+
+		/* Insert decoded segment into rqueue */
+		tcp_rqueue_insert_seg(&rident, dseg);
+		return;
+	}
+
 	tcp_transmit_pdu(pdu);
 	tcp_pdu_delete(pdu);
@@ -1425,5 +1466,5 @@
  * @param seg		Incoming segment
  */
-void tcp_reply_rst(inet_ep2_t *epp, tcp_segment_t *seg)
+static void tcp_reply_rst(inet_ep2_t *epp, tcp_segment_t *seg)
 {
 	tcp_segment_t *rseg;
Index: uspace/srv/net/tcp/conn.h
===================================================================
--- uspace/srv/net/tcp/conn.h	(revision 0a1e7e4d2a546c77ee164eecd49445abce8f9415)
+++ uspace/srv/net/tcp/conn.h	(revision 6c4eedf11368c6c47c86ab45352946ba67b15bdc)
@@ -45,9 +45,7 @@
 extern void tcp_conn_delete(tcp_conn_t *);
 extern int tcp_conn_add(tcp_conn_t *);
-extern void tcp_conn_remove(tcp_conn_t *);
 extern void tcp_conn_reset(tcp_conn_t *conn);
 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_ref(inet_ep2_t *);
 extern void tcp_conn_addref(tcp_conn_t *);
@@ -58,8 +56,8 @@
 extern void tcp_conn_segment_arrived(tcp_conn_t *, inet_ep2_t *,
     tcp_segment_t *);
-extern void tcp_conn_trim_seg_to_wnd(tcp_conn_t *, tcp_segment_t *);
 extern void tcp_unexpected_segment(inet_ep2_t *, tcp_segment_t *);
 extern void tcp_ep2_flipped(inet_ep2_t *, inet_ep2_t *);
-extern void tcp_reply_rst(inet_ep2_t *, tcp_segment_t *);
+
+extern tcp_lb_t tcp_conn_lb;
 
 #endif
Index: uspace/srv/net/tcp/ncsim.c
===================================================================
--- uspace/srv/net/tcp/ncsim.c	(revision 0a1e7e4d2a546c77ee164eecd49445abce8f9415)
+++ uspace/srv/net/tcp/ncsim.c	(revision 6c4eedf11368c6c47c86ab45352946ba67b15bdc)
@@ -73,8 +73,10 @@
 	tcp_squeue_entry_t *sqe;
 	tcp_squeue_entry_t *old_qe;
+	inet_ep2_t rident;
 	link_t *link;
 
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ncsim_bounce_seg()");
-	tcp_rqueue_bounce_seg(epp, seg);
+	tcp_ep2_flipped(epp, &rident);
+	tcp_rqueue_insert_seg(&rident, seg);
 	return;
 
@@ -125,4 +127,5 @@
 	link_t *link;
 	tcp_squeue_entry_t *sqe;
+	inet_ep2_t rident;
 	int rc;
 
@@ -148,5 +151,6 @@
 
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "NCSim - End Sleep");
-		tcp_rqueue_bounce_seg(&sqe->epp, sqe->seg);
+		tcp_ep2_flipped(&sqe->epp, &rident);
+		tcp_rqueue_insert_seg(&rident, sqe->seg);
 		free(sqe);
 	}
Index: uspace/srv/net/tcp/rqueue.c
===================================================================
--- uspace/srv/net/tcp/rqueue.c	(revision 0a1e7e4d2a546c77ee164eecd49445abce8f9415)
+++ uspace/srv/net/tcp/rqueue.c	(revision 6c4eedf11368c6c47c86ab45352946ba67b15bdc)
@@ -43,17 +43,8 @@
 #include <fibril_synch.h>
 #include "conn.h"
-#include "pdu.h"
 #include "rqueue.h"
 #include "segment.h"
 #include "tcp_type.h"
 #include "ucall.h"
-
-/** Transcode bounced segments.
- *
- * If defined, segments bounced via the internal debugging loopback will
- * be encoded to a PDU and the decoded. Otherwise they will be bounced back
- * directly without passing the encoder-decoder.
- */
-#define BOUNCE_TRANSCODE
 
 static prodcons_t rqueue;
@@ -87,49 +78,8 @@
 }
 
-/** Bounce segment directy into receive queue without constructing the PDU.
- *
- * This is for testing purposes only.
- *
- * @param sp	Endpoint pair, oriented for transmission
- * @param seg	Segment
- */
-void tcp_rqueue_bounce_seg(inet_ep2_t *epp, tcp_segment_t *seg)
-{
-	inet_ep2_t rident;
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_bounce_seg()");
-
-#ifdef BOUNCE_TRANSCODE
-	tcp_pdu_t *pdu;
-	tcp_segment_t *dseg;
-
-	if (tcp_pdu_encode(epp, seg, &pdu) != EOK) {
-		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
-		return;
-	}
-
-	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
-		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
-		return;
-	}
-
-	tcp_pdu_delete(pdu);
-
-	/** Insert decoded segment into rqueue */
-	tcp_rqueue_insert_seg(&rident, dseg);
-	tcp_segment_delete(seg);
-#else
-	/* Reverse the identification */
-	tcp_ep2_flipped(epp, &rident);
-
-	/* Insert segment back into rqueue */
-	tcp_rqueue_insert_seg(&rident, seg);
-#endif
-}
-
 /** Insert segment into receive queue.
  *
  * @param epp	Endpoint pair, oriented for reception
- * @param seg	Segment
+ * @param seg	Segment (ownership transferred to rqueue)
  */
 void tcp_rqueue_insert_seg(inet_ep2_t *epp, tcp_segment_t *seg)
Index: uspace/srv/net/tcp/rqueue.h
===================================================================
--- uspace/srv/net/tcp/rqueue.h	(revision 0a1e7e4d2a546c77ee164eecd49445abce8f9415)
+++ uspace/srv/net/tcp/rqueue.h	(revision 6c4eedf11368c6c47c86ab45352946ba67b15bdc)
@@ -42,5 +42,4 @@
 extern void tcp_rqueue_fibril_start(void);
 extern void tcp_rqueue_fini(void);
-extern void tcp_rqueue_bounce_seg(inet_ep2_t *, tcp_segment_t *);
 extern void tcp_rqueue_insert_seg(inet_ep2_t *, tcp_segment_t *);
 
Index: uspace/srv/net/tcp/tcp_type.h
===================================================================
--- uspace/srv/net/tcp/tcp_type.h	(revision 0a1e7e4d2a546c77ee164eecd49445abce8f9415)
+++ uspace/srv/net/tcp/tcp_type.h	(revision 6c4eedf11368c6c47c86ab45352946ba67b15bdc)
@@ -379,4 +379,14 @@
 } tcp_client_t;
 
+/** Internal loopback type */
+typedef enum {
+	/** No loopback */
+	tcp_lb_none,
+	/** Segment loopback */
+	tcp_lb_segment,
+	/** PDU loopback */
+	tcp_lb_pdu
+} tcp_lb_t;
+
 #endif
 
Index: uspace/srv/net/tcp/test/conn.c
===================================================================
--- uspace/srv/net/tcp/test/conn.c	(revision 0a1e7e4d2a546c77ee164eecd49445abce8f9415)
+++ uspace/srv/net/tcp/test/conn.c	(revision 6c4eedf11368c6c47c86ab45352946ba67b15bdc)
@@ -33,8 +33,14 @@
 
 #include "../conn.h"
+#include "../rqueue.h"
+#include "../ucall.h"
 
 PCUT_INIT
 
 PCUT_TEST_SUITE(conn);
+
+static tcp_rqueue_cb_t test_rqueue_cb = {
+	.seg_received = tcp_as_segment_arrived
+};
 
 PCUT_TEST_BEFORE
@@ -48,8 +54,12 @@
 	rc = tcp_conns_init();
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	tcp_rqueue_init(&test_rqueue_cb);
+	tcp_rqueue_fibril_start();
 }
 
 PCUT_TEST_AFTER
 {
+	tcp_rqueue_fini();
 	tcp_conns_fini();
 }
@@ -71,6 +81,6 @@
 }
 
-/** Test adding, finding and removing a connection */
-PCUT_TEST(add_find_remove)
+/** Test adding, finding and deleting a connection */
+PCUT_TEST(add_find_delete)
 {
 	tcp_conn_t *conn, *cfound;
@@ -101,3 +111,38 @@
 }
 
+/** Test trying to connect to endpoint that sends RST back */
+PCUT_TEST(connect_rst)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+	int rc;
+
+	tcp_conn_lb = tcp_lb_segment;
+
+	inet_ep2_init(&epp);
+	inet_addr(&epp.local.addr, 127, 0, 0, 1);
+	inet_addr(&epp.remote.addr, 127, 0, 0, 1);
+	epp.remote.port = inet_port_user_lo;
+
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	rc = tcp_conn_add(conn);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_INT_EQUALS(st_listen, conn->cstate);
+
+	tcp_conn_lock(conn);
+	tcp_conn_sync(conn);
+	PCUT_ASSERT_INT_EQUALS(st_syn_sent, conn->cstate);
+
+	while (conn->cstate == st_syn_sent)
+                fibril_condvar_wait(&conn->cstate_cv, &conn->lock);
+
+	PCUT_ASSERT_INT_EQUALS(st_closed, conn->cstate);
+
+	tcp_conn_unlock(conn);
+	tcp_conn_delete(conn);
+}
+
 PCUT_EXPORT(conn);
Index: uspace/srv/net/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tcp/tqueue.c	(revision 0a1e7e4d2a546c77ee164eecd49445abce8f9415)
+++ uspace/srv/net/tcp/tqueue.c	(revision 6c4eedf11368c6c47c86ab45352946ba67b15bdc)
@@ -106,4 +106,6 @@
 	tcp_segment_t *seg;
 
+	assert(fibril_mutex_is_locked(&conn->lock));
+
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
 
@@ -117,4 +119,6 @@
 	tcp_segment_t *rt_seg;
 	tcp_tqueue_entry_t *tqe;
+
+	assert(fibril_mutex_is_locked(&conn->lock));
 
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_tqueue_seg(%p, %p)", conn->name, conn,
@@ -366,4 +370,6 @@
 static void tcp_tqueue_timer_set(tcp_conn_t *conn)
 {
+	assert(fibril_mutex_is_locked(&conn->lock));
+
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_set() begin", conn->name);
 
@@ -381,4 +387,6 @@
 static void tcp_tqueue_timer_clear(tcp_conn_t *conn)
 {
+	assert(fibril_mutex_is_locked(&conn->lock));
+
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_clear() begin", conn->name);
 
