Index: uspace/srv/net/tl/tcp/conn.c
===================================================================
--- uspace/srv/net/tl/tcp/conn.c	(revision 0d29e0cd6488c4ef4fadc92b7d448621df6d7f9f)
+++ uspace/srv/net/tl/tcp/conn.c	(revision bbf159a20a99023b10c2a8bcff9b59156f1a59eb)
@@ -93,4 +93,6 @@
 
 	/** Allocate send buffer */
+	fibril_mutex_initialize(&conn->snd_buf_lock);
+	fibril_condvar_initialize(&conn->snd_buf_cv);
 	conn->snd_buf_size = SND_BUF_SIZE;
 	conn->snd_buf_used = 0;
@@ -287,4 +289,5 @@
 
 	fibril_condvar_broadcast(&conn->rcv_buf_cv);
+	fibril_condvar_broadcast(&conn->snd_buf_cv);
 }
 
Index: uspace/srv/net/tl/tcp/tcp_type.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp_type.h	(revision 0d29e0cd6488c4ef4fadc92b7d448621df6d7f9f)
+++ uspace/srv/net/tl/tcp/tcp_type.h	(revision bbf159a20a99023b10c2a8bcff9b59156f1a59eb)
@@ -204,4 +204,8 @@
 	/** Send buffer contains FIN */
 	bool snd_buf_fin;
+	/** Send buffer lock */
+	fibril_mutex_t snd_buf_lock;
+	/** Send buffer CV. Broadcast when space is made available in buffer */
+	fibril_condvar_t snd_buf_cv;
 
 	/** Send unacknowledged */
Index: uspace/srv/net/tl/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.c	(revision 0d29e0cd6488c4ef4fadc92b7d448621df6d7f9f)
+++ uspace/srv/net/tl/tcp/tqueue.c	(revision bbf159a20a99023b10c2a8bcff9b59156f1a59eb)
@@ -167,4 +167,6 @@
 	log_msg(LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
 
+	fibril_mutex_lock(&conn->snd_buf_lock);
+
 	/* Number of free sequence numbers in send window */
 	avail_wnd = (conn->snd_una + conn->snd_wnd) - conn->snd_nxt;
@@ -176,6 +178,8 @@
 	    xfer_seqlen);
 
-	if (xfer_seqlen == 0)
-		return;
+	if (xfer_seqlen == 0) {
+		fibril_mutex_unlock(&conn->snd_buf_lock);
+		return;
+	}
 
 	/* XXX Do not always send immediately */
@@ -188,5 +192,4 @@
 		/* We are sending out FIN */
 		ctrl = CTL_FIN;
-		tcp_conn_fin_sent(conn);
 	} else {
 		ctrl = 0;
@@ -195,4 +198,5 @@
 	seg = tcp_segment_make_data(ctrl, conn->snd_buf, data_size);
 	if (seg == NULL) {
+		fibril_mutex_unlock(&conn->snd_buf_lock);
 		log_msg(LVL_ERROR, "Memory allocation failure.");
 		return;
@@ -206,4 +210,10 @@
 	if (send_fin)
 		conn->snd_buf_fin = false;
+
+	fibril_condvar_broadcast(&conn->snd_buf_cv);
+	fibril_mutex_unlock(&conn->snd_buf_lock);
+
+	if (send_fin)
+		tcp_conn_fin_sent(conn);
 
 	tcp_tqueue_seg(conn, seg);
Index: uspace/srv/net/tl/tcp/ucall.c
===================================================================
--- uspace/srv/net/tl/tcp/ucall.c	(revision 0d29e0cd6488c4ef4fadc92b7d448621df6d7f9f)
+++ uspace/srv/net/tl/tcp/ucall.c	(revision bbf159a20a99023b10c2a8bcff9b59156f1a59eb)
@@ -121,16 +121,25 @@
 	}
 
-	if (conn->snd_buf_fin)
+	fibril_mutex_lock(&conn->snd_buf_lock);
+
+	if (conn->snd_buf_fin) {
+		fibril_mutex_unlock(&conn->snd_buf_lock);
 		return TCP_ECLOSING;
+	}
 
 	while (size > 0) {
 		buf_free = conn->snd_buf_size - conn->snd_buf_used;
 		while (buf_free == 0 && !conn->reset) {
-			tcp_tqueue_new_data(conn);
+			log_msg(LVL_DEBUG, "%s: buf_free == 0, waiting.",
+			    conn->name);
+			fibril_condvar_wait(&conn->snd_buf_cv,
+			    &conn->snd_buf_lock);
 			buf_free = conn->snd_buf_size - conn->snd_buf_used;
 		}
 
-		if (conn->reset)
+		if (conn->reset) {
+			fibril_mutex_unlock(&conn->snd_buf_lock);
 			return TCP_ERESET;
+		}
 
 		xfer_size = min(size, buf_free);
@@ -141,6 +150,11 @@
 		conn->snd_buf_used += xfer_size;
 		size -= xfer_size;
-	}
-
+
+		fibril_mutex_unlock(&conn->snd_buf_lock);
+		tcp_tqueue_new_data(conn);
+		fibril_mutex_lock(&conn->snd_buf_lock);
+	}
+
+	fibril_mutex_unlock(&conn->snd_buf_lock);
 	tcp_tqueue_new_data(conn);
 
