Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ HelenOS.config	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -578,6 +578,6 @@
 # USB settings
 
-% USB release build (less logging)
-! CONFIG_USB_RELEASE_BUILD (y/n)
+% USB verbose messages
+! CONFIG_USB_VERBOSE (n/y)
 
 % Start virtual USB host controller
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ boot/Makefile.common	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -177,4 +177,5 @@
 	$(USPACE_PATH)/app/nettest3/nettest3 \
 	$(USPACE_PATH)/app/netecho/netecho \
+	$(USPACE_PATH)/app/nterm/nterm \
 	$(USPACE_PATH)/app/ping/ping \
 	$(USPACE_PATH)/app/stats/stats \
Index: kernel/arch/amd64/include/mm/page.h
===================================================================
--- kernel/arch/amd64/include/mm/page.h	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/arch/amd64/include/mm/page.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -33,13 +33,4 @@
  */
 
-/** Paging on AMD64
- *
- * The space is divided in positive numbers (uspace) and
- * negative numbers (kernel). The 'negative' space starting
- * with 0xffff800000000000 and ending with 0xffffffffffffffff
- * is identically mapped physical memory.
- *
- */
-
 #ifndef KERN_amd64_PAGE_H_
 #define KERN_amd64_PAGE_H_
Index: kernel/genarch/src/mm/page_pt.c
===================================================================
--- kernel/genarch/src/mm/page_pt.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/genarch/src/mm/page_pt.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -48,4 +48,5 @@
 #include <align.h>
 #include <macros.h>
+#include <bitops.h>
 
 static void pt_mapping_insert(as_t *, uintptr_t, uintptr_t, unsigned int);
@@ -292,4 +293,18 @@
 }
 
+/** Return the size of the region mapped by a single PTL0 entry.
+ *
+ * @return Size of the region mapped by a single PTL0 entry.
+ */
+static uintptr_t ptl0_step_get(void)
+{
+	size_t va_bits;
+
+	va_bits = fnzb(PTL0_ENTRIES) + fnzb(PTL1_ENTRIES) + fnzb(PTL2_ENTRIES) +
+	    fnzb(PTL3_ENTRIES) + PAGE_WIDTH;
+
+	return 1UL << (va_bits - fnzb(PTL0_ENTRIES));
+}
+
 /** Make the mappings in the given range global accross all address spaces.
  *
@@ -309,5 +324,5 @@
 {
 	uintptr_t ptl0 = PA2KA((uintptr_t) AS_KERNEL->genarch.page_table);
-	uintptr_t ptl0step = (((uintptr_t) -1) / PTL0_ENTRIES) + 1;
+	uintptr_t ptl0_step = ptl0_step_get();
 	size_t order;
 	uintptr_t addr;
@@ -321,9 +336,8 @@
 #endif
 
-	ASSERT(ispwr2(ptl0step));
 	ASSERT(size > 0);
 
-	for (addr = ALIGN_DOWN(base, ptl0step); addr - 1 < base + size - 1;
-	    addr += ptl0step) {
+	for (addr = ALIGN_DOWN(base, ptl0_step); addr - 1 < base + size - 1;
+	    addr += ptl0_step) {
 		uintptr_t l1;
 
Index: kernel/generic/include/lib/ra.h
===================================================================
--- kernel/generic/include/lib/ra.h	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/generic/include/lib/ra.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -42,5 +42,5 @@
 
 typedef struct {
-	SPINLOCK_DECLARE(lock);
+	IRQ_SPINLOCK_DECLARE(lock);
 	list_t spans;		/**< List of arena's spans. */
 } ra_arena_t;
Index: kernel/generic/include/mm/slab.h
===================================================================
--- kernel/generic/include/mm/slab.h	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/generic/include/mm/slab.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -81,5 +81,5 @@
 	slab_magazine_t *current;
 	slab_magazine_t *last;
-	SPINLOCK_DECLARE(lock);
+	IRQ_SPINLOCK_DECLARE(lock);
 } slab_mag_cache_t;
 
@@ -113,8 +113,8 @@
 	list_t full_slabs;     /**< List of full slabs */
 	list_t partial_slabs;  /**< List of partial slabs */
-	SPINLOCK_DECLARE(slablock);
+	IRQ_SPINLOCK_DECLARE(slablock);
 	/* Magazines */
 	list_t magazines;  /**< List o full magazines */
-	SPINLOCK_DECLARE(maglock);
+	IRQ_SPINLOCK_DECLARE(maglock);
 	
 	/** CPU cache */
Index: kernel/generic/src/lib/ra.c
===================================================================
--- kernel/generic/src/lib/ra.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/generic/src/lib/ra.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -185,5 +185,5 @@
 		return NULL;
 
-	spinlock_initialize(&arena->lock, "arena_lock");
+	irq_spinlock_initialize(&arena->lock, "arena_lock");
 	list_initialize(&arena->spans);
 
@@ -209,7 +209,7 @@
 
 	/* TODO: check for overlaps */
-	spinlock_lock(&arena->lock);
+	irq_spinlock_lock(&arena->lock, true);
 	list_append(&span->span_link, &arena->spans);
-	spinlock_unlock(&arena->lock);
+	irq_spinlock_unlock(&arena->lock, true);
 	return true;
 }
@@ -390,5 +390,5 @@
 	ASSERT(ispwr2(alignment));
 
-	spinlock_lock(&arena->lock);
+	irq_spinlock_lock(&arena->lock, true);
 	list_foreach(arena->spans, cur) {
 		ra_span_t *span = list_get_instance(cur, ra_span_t, span_link);
@@ -398,5 +398,5 @@
 			break;
 	}
-	spinlock_unlock(&arena->lock);
+	irq_spinlock_unlock(&arena->lock, true);
 
 	return base;
@@ -406,5 +406,5 @@
 void ra_free(ra_arena_t *arena, uintptr_t base, size_t size)
 {
-	spinlock_lock(&arena->lock);
+	irq_spinlock_lock(&arena->lock, true);
 	list_foreach(arena->spans, cur) {
 		ra_span_t *span = list_get_instance(cur, ra_span_t, span_link);
@@ -412,9 +412,9 @@
 		if (iswithin(span->base, span->size, base, size)) {
 			ra_span_free(span, base, size);
-			spinlock_unlock(&arena->lock);
+			irq_spinlock_unlock(&arena->lock, true);
 			return;
 		}
 	}
-	spinlock_unlock(&arena->lock);
+	irq_spinlock_unlock(&arena->lock, true);
 
 	panic("Freeing to wrong arena (base=%" PRIxn ", size=%" PRIdn ").",
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/generic/src/mm/frame.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -1086,4 +1086,9 @@
 #endif
 		
+		/*
+		 * Since the mem_avail_mtx is an active mutex, we need to disable interrupts
+		 * to prevent deadlock with TLB shootdown.
+		 */
+		ipl_t ipl = interrupts_disable();
 		mutex_lock(&mem_avail_mtx);
 		
@@ -1098,4 +1103,5 @@
 		
 		mutex_unlock(&mem_avail_mtx);
+		interrupts_restore(ipl);
 		
 #ifdef CONFIG_DEBUG
@@ -1161,4 +1167,11 @@
 	 * Signal that some memory has been freed.
 	 */
+
+	
+	/*
+	 * Since the mem_avail_mtx is an active mutex, we need to disable interrupts
+	 * to prevent deadlock with TLB shootdown.
+	 */
+	ipl_t ipl = interrupts_disable();
 	mutex_lock(&mem_avail_mtx);
 	if (mem_avail_req > 0)
@@ -1170,4 +1183,5 @@
 	}
 	mutex_unlock(&mem_avail_mtx);
+	interrupts_restore(ipl);
 	
 	if (!(flags & FRAME_NO_RESERVE))
Index: kernel/generic/src/mm/slab.c
===================================================================
--- kernel/generic/src/mm/slab.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/generic/src/mm/slab.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -264,5 +264,5 @@
 		freed = cache->destructor(obj);
 	
-	spinlock_lock(&cache->slablock);
+	irq_spinlock_lock(&cache->slablock, true);
 	ASSERT(slab->available < cache->objects);
 	
@@ -275,5 +275,5 @@
 		/* Free associated memory */
 		list_remove(&slab->link);
-		spinlock_unlock(&cache->slablock);
+		irq_spinlock_unlock(&cache->slablock, true);
 		
 		return freed + slab_space_free(cache, slab);
@@ -284,5 +284,5 @@
 	}
 	
-	spinlock_unlock(&cache->slablock);
+	irq_spinlock_unlock(&cache->slablock, true);
 	return freed;
 }
@@ -295,5 +295,5 @@
 NO_TRACE static void *slab_obj_create(slab_cache_t *cache, unsigned int flags)
 {
-	spinlock_lock(&cache->slablock);
+	irq_spinlock_lock(&cache->slablock, true);
 	
 	slab_t *slab;
@@ -308,10 +308,10 @@
 		 *
 		 */
-		spinlock_unlock(&cache->slablock);
+		irq_spinlock_unlock(&cache->slablock, true);
 		slab = slab_space_alloc(cache, flags);
 		if (!slab)
 			return NULL;
 		
-		spinlock_lock(&cache->slablock);
+		irq_spinlock_lock(&cache->slablock, true);
 	} else {
 		slab = list_get_instance(list_first(&cache->partial_slabs),
@@ -329,5 +329,5 @@
 		list_prepend(&slab->link, &cache->partial_slabs);
 	
-	spinlock_unlock(&cache->slablock);
+	irq_spinlock_unlock(&cache->slablock, true);
 	
 	if ((cache->constructor) && (cache->constructor(obj, flags))) {
@@ -355,5 +355,5 @@
 	link_t *cur;
 	
-	spinlock_lock(&cache->maglock);
+	irq_spinlock_lock(&cache->maglock, true);
 	if (!list_empty(&cache->magazines)) {
 		if (first)
@@ -366,6 +366,6 @@
 		atomic_dec(&cache->magazine_counter);
 	}
-	
-	spinlock_unlock(&cache->maglock);
+	irq_spinlock_unlock(&cache->maglock, true);
+
 	return mag;
 }
@@ -377,10 +377,10 @@
     slab_magazine_t *mag)
 {
-	spinlock_lock(&cache->maglock);
+	irq_spinlock_lock(&cache->maglock, true);
 	
 	list_prepend(&mag->link, &cache->magazines);
 	atomic_inc(&cache->magazine_counter);
 	
-	spinlock_unlock(&cache->maglock);
+	irq_spinlock_unlock(&cache->maglock, true);
 }
 
@@ -414,5 +414,5 @@
 	slab_magazine_t *lastmag = cache->mag_cache[CPU->id].last;
 	
-	ASSERT(spinlock_locked(&cache->mag_cache[CPU->id].lock));
+	ASSERT(irq_spinlock_locked(&cache->mag_cache[CPU->id].lock));
 	
 	if (cmag) { /* First try local CPU magazines */
@@ -451,14 +451,14 @@
 		return NULL;
 	
-	spinlock_lock(&cache->mag_cache[CPU->id].lock);
+	irq_spinlock_lock(&cache->mag_cache[CPU->id].lock, true);
 	
 	slab_magazine_t *mag = get_full_current_mag(cache);
 	if (!mag) {
-		spinlock_unlock(&cache->mag_cache[CPU->id].lock);
+		irq_spinlock_unlock(&cache->mag_cache[CPU->id].lock, true);
 		return NULL;
 	}
 	
 	void *obj = mag->objs[--mag->busy];
-	spinlock_unlock(&cache->mag_cache[CPU->id].lock);
+	irq_spinlock_unlock(&cache->mag_cache[CPU->id].lock, true);
 	
 	atomic_dec(&cache->cached_objs);
@@ -481,5 +481,5 @@
 	slab_magazine_t *lastmag = cache->mag_cache[CPU->id].last;
 	
-	ASSERT(spinlock_locked(&cache->mag_cache[CPU->id].lock));
+	ASSERT(irq_spinlock_locked(&cache->mag_cache[CPU->id].lock));
 	
 	if (cmag) {
@@ -531,9 +531,9 @@
 		return -1;
 	
-	spinlock_lock(&cache->mag_cache[CPU->id].lock);
+	irq_spinlock_lock(&cache->mag_cache[CPU->id].lock, true);
 	
 	slab_magazine_t *mag = make_empty_current_mag(cache);
 	if (!mag) {
-		spinlock_unlock(&cache->mag_cache[CPU->id].lock);
+		irq_spinlock_unlock(&cache->mag_cache[CPU->id].lock, true);
 		return -1;
 	}
@@ -541,5 +541,5 @@
 	mag->objs[mag->busy++] = obj;
 	
-	spinlock_unlock(&cache->mag_cache[CPU->id].lock);
+	irq_spinlock_unlock(&cache->mag_cache[CPU->id].lock, true);
 	
 	atomic_inc(&cache->cached_objs);
@@ -593,5 +593,5 @@
 	for (i = 0; i < config.cpu_count; i++) {
 		memsetb(&cache->mag_cache[i], sizeof(cache->mag_cache[i]), 0);
-		spinlock_initialize(&cache->mag_cache[i].lock,
+		irq_spinlock_initialize(&cache->mag_cache[i].lock,
 		    "slab.cache.mag_cache[].lock");
 	}
@@ -624,6 +624,6 @@
 	list_initialize(&cache->magazines);
 	
-	spinlock_initialize(&cache->slablock, "slab.cache.slablock");
-	spinlock_initialize(&cache->maglock, "slab.cache.maglock");
+	irq_spinlock_initialize(&cache->slablock, "slab.cache.slablock");
+	irq_spinlock_initialize(&cache->maglock, "slab.cache.maglock");
 	
 	if (!(cache->flags & SLAB_CACHE_NOMAGAZINE))
@@ -704,5 +704,5 @@
 		size_t i;
 		for (i = 0; i < config.cpu_count; i++) {
-			spinlock_lock(&cache->mag_cache[i].lock);
+			irq_spinlock_lock(&cache->mag_cache[i].lock, true);
 			
 			mag = cache->mag_cache[i].current;
@@ -716,5 +716,5 @@
 			cache->mag_cache[i].last = NULL;
 			
-			spinlock_unlock(&cache->mag_cache[i].lock);
+			irq_spinlock_unlock(&cache->mag_cache[i].lock, true);
 		}
 	}
Index: kernel/generic/src/synch/mutex.c
===================================================================
--- kernel/generic/src/synch/mutex.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/generic/src/synch/mutex.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -40,4 +40,5 @@
 #include <debug.h>
 #include <arch.h>
+#include <stacktrace.h>
 
 /** Initialize mutex.
@@ -61,4 +62,6 @@
 	return semaphore_count_get(&mtx->sem) <= 0;
 }
+
+#define MUTEX_DEADLOCK_THRESHOLD	100000000
 
 /** Acquire mutex.
@@ -87,8 +90,19 @@
 		ASSERT(!(flags & SYNCH_FLAGS_INTERRUPTIBLE));
 		
+		unsigned int cnt = 0;
+		bool deadlock_reported = false;
 		do {
+			if (cnt++ > MUTEX_DEADLOCK_THRESHOLD) {
+				printf("cpu%u: looping on active mutex %p\n",
+				    CPU->id, mtx);
+				stack_trace();
+				cnt = 0;
+				deadlock_reported = true;
+			}
 			rc = semaphore_trydown(&mtx->sem);
 		} while (SYNCH_FAILED(rc) &&
 		    !(flags & SYNCH_FLAGS_NON_BLOCKING));
+		if (deadlock_reported)
+			printf("cpu%u: not deadlocked\n", CPU->id);
 	}
 
Index: kernel/generic/src/synch/spinlock.c
===================================================================
--- kernel/generic/src/synch/spinlock.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ kernel/generic/src/synch/spinlock.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -44,4 +44,5 @@
 #include <debug.h>
 #include <symtab.h>
+#include <stacktrace.h>
 
 #ifdef CONFIG_SMP
@@ -104,4 +105,5 @@
 			    "caller=%p (%s)\n", CPU->id, lock, lock->name,
 			    (void *) CALLER, symtab_fmt_name_lookup(CALLER));
+			stack_trace();
 			
 			i = 0;
@@ -260,5 +262,5 @@
 	int rc = spinlock_trylock(&(lock->lock));
 	
-	ASSERT_IRQ_SPINLOCK(!lock->guard, lock);
+	ASSERT_IRQ_SPINLOCK(!rc || !lock->guard, lock);
 	return rc;
 }
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/Makefile	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -51,4 +51,5 @@
 	app/mkexfat \
 	app/mkmfs \
+	app/nterm \
 	app/redir \
 	app/sbi \
Index: uspace/app/nterm/Makefile
===================================================================
--- uspace/app/nterm/Makefile	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
+++ uspace/app/nterm/Makefile	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2012 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+BINARY = nterm
+
+SOURCES = \
+	conn.c \
+	nterm.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/nterm/conn.c
===================================================================
--- uspace/app/nterm/conn.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
+++ uspace/app/nterm/conn.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nterm
+ * @{
+ */
+/** @file
+ */
+
+#include <bool.h>
+#include <errno.h>
+#include <fibril.h>
+#include <net/socket.h>
+#include <stdio.h>
+#include <str_error.h>
+#include <sys/types.h>
+
+#include "conn.h"
+#include "nterm.h"
+
+static int conn_fd;
+static fid_t rcv_fid;
+
+#define RECV_BUF_SIZE 1024
+static uint8_t recv_buf[RECV_BUF_SIZE];
+
+static int rcv_fibril(void *arg)
+{
+	ssize_t nr;
+
+	while (true) {
+		nr = recv(conn_fd, recv_buf, RECV_BUF_SIZE, 0);
+		if (nr < 0)
+			break;
+
+		nterm_received(recv_buf, nr);
+	}
+
+	if (nr == ENOTCONN)
+		printf("\n[Other side has closed the connection]\n");
+	else
+		printf("'\n[Receive errror (%s)]\n", str_error(nr));
+
+	exit(0);
+	return 0;
+}
+
+int conn_open(const char *addr_s, const char *port_s)
+{
+	struct sockaddr_in addr;
+	int rc;
+	char *endptr;
+
+	addr.sin_family = AF_INET;
+
+	rc = inet_pton(addr.sin_family, addr_s, (uint8_t *)&addr.sin_addr);
+	if (rc != EOK) {
+		printf("Invalid addres %s\n", addr_s);
+		return EINVAL;
+	}
+
+	addr.sin_port = htons(strtol(port_s, &endptr, 10));
+	if (*endptr != '\0') {
+		printf("Invalid port number %s\n", port_s);
+		return EINVAL;
+	}
+
+	conn_fd = socket(PF_INET, SOCK_STREAM, 0);
+	if (conn_fd < 0)
+		goto error;
+
+	printf("Connecting to address %s port %u\n", addr_s, ntohs(addr.sin_port));
+
+	rc = connect(conn_fd, (struct sockaddr *)&addr, sizeof(addr));
+	if (rc != EOK)
+		goto error;
+
+	rcv_fid = fibril_create(rcv_fibril, NULL);
+	if (rcv_fid == 0)
+		goto error;
+
+	fibril_add_ready(rcv_fid);
+
+	return EOK;
+
+error:
+	if (conn_fd >= 0) {
+		closesocket(conn_fd);
+		conn_fd = -1;
+	}
+
+	return EIO;
+}
+
+int conn_send(void *data, size_t size)
+{
+	int rc;
+
+	rc = send(conn_fd, data, size, 0);
+	if (rc != EOK)
+		return EIO;
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/app/nterm/conn.h
===================================================================
--- uspace/app/nterm/conn.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
+++ uspace/app/nterm/conn.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup edit
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef CONN_H
+#define CONN_H
+
+#include <sys/types.h>
+
+extern int conn_open(const char *, const char *);
+extern int conn_send(void *, size_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nterm/nterm.c
===================================================================
--- uspace/app/nterm/nterm.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
+++ uspace/app/nterm/nterm.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nterm
+ * @{
+ */
+/** @file Network serial terminal emulator.
+ */
+
+#include <bool.h>
+#include <errno.h>
+#include <io/console.h>
+#include <stdio.h>
+
+#include "conn.h"
+#include "nterm.h"
+
+#define NAME "nterm"
+
+static console_ctrl_t *con;
+static bool done;
+
+static void key_handle_ctrl(kbd_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_Q:
+		done = true;
+		break;
+	default:
+		break;
+	}
+}
+
+static void send_char(wchar_t c)
+{
+	char cbuf[STR_BOUNDS(1)];
+	size_t offs;
+	int rc;
+
+	offs = 0;
+	chr_encode(c, cbuf, &offs, STR_BOUNDS(1));
+
+	rc = conn_send(cbuf, offs);
+	if (rc != EOK) {
+		printf("[Failed sending data]\n");
+	}
+}
+
+static void key_handle_unmod(kbd_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_ENTER:
+		send_char('\n');
+		break;
+	default:
+		if (ev->c >= 32 || ev->c == '\t' || ev->c == '\b') {
+			send_char(ev->c);
+		}
+	}
+}
+
+static void key_handle(kbd_event_t *ev)
+{
+	if ((ev->mods & KM_ALT) == 0 &&
+	    (ev->mods & KM_SHIFT) == 0 &&
+	    (ev->mods & KM_CTRL) != 0) {
+		key_handle_ctrl(ev);
+	} else if ((ev->mods & (KM_CTRL | KM_ALT)) == 0) {
+		key_handle_unmod(ev);
+	}
+}
+
+void nterm_received(void *data, size_t size)
+{
+	fwrite(data, size, 1, stdout);
+	fflush(stdout);
+}
+
+static void print_syntax(void)
+{
+	printf("syntax: nterm <ip-address> <port>\n");
+}
+
+int main(int argc, char *argv[])
+{
+	kbd_event_t ev;
+	int rc;
+
+	if (argc != 3) {
+		print_syntax();
+		return 1;
+	}
+
+	rc = conn_open(argv[1], argv[2]);
+	if (rc != EOK) {
+		printf("Error connecting.\n");
+		return 1;
+	}
+
+	printf("Connection established.\n");
+
+	con = console_init(stdin, stdout);
+
+	done = false;
+	while (!done) {
+		console_get_kbd_event(con, &ev);
+		if (ev.type == KEY_PRESS)
+			key_handle(&ev);
+	}
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/nterm/nterm.h
===================================================================
--- uspace/app/nterm/nterm.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
+++ uspace/app/nterm/nterm.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup edit
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef NTERM_H
+#define NTERM_H
+
+#include <sys/types.h>
+
+extern void nterm_received(void *, size_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/usb/include/usb/debug.h
===================================================================
--- uspace/lib/usb/include/usb/debug.h	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/lib/usb/include/usb/debug.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -81,8 +81,8 @@
 
 /** Default log level. */
-#ifdef CONFIG_USB_RELEASE_BUILD
+#ifdef CONFIG_USB_VERBOSE
+#  define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_DEBUG
+#else
 #  define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_INFO
-#else
-#  define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_DEBUG
 #endif
 
Index: uspace/srv/net/tcp/conn.c
===================================================================
--- uspace/srv/net/tcp/conn.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/conn.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -184,5 +184,5 @@
 void tcp_conn_addref(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_addref(%p)", conn->name, conn);
+	log_msg(LVL_DEBUG2, "%s: tcp_conn_addref(%p)", conn->name, conn);
 	atomic_inc(&conn->refcnt);
 }
@@ -196,5 +196,5 @@
 void tcp_conn_delref(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_delref(%p)", conn->name, conn);
+	log_msg(LVL_DEBUG2, "%s: tcp_conn_delref(%p)", conn->name, conn);
 
 	if (atomic_predec(&conn->refcnt) == 0)
@@ -312,5 +312,5 @@
 static bool tcp_socket_match(tcp_sock_t *sock, tcp_sock_t *patt)
 {
-	log_msg(LVL_DEBUG, "tcp_socket_match(sock=(%x,%u), pat=(%x,%u))",
+	log_msg(LVL_DEBUG2, "tcp_socket_match(sock=(%x,%u), pat=(%x,%u))",
 	    sock->addr.ipv4, sock->port, patt->addr.ipv4, patt->port);
 
@@ -323,5 +323,5 @@
 		return false;
 
-	log_msg(LVL_DEBUG, " -> match");
+	log_msg(LVL_DEBUG2, " -> match");
 
 	return true;
@@ -331,5 +331,5 @@
 static bool tcp_sockpair_match(tcp_sockpair_t *sp, tcp_sockpair_t *pattern)
 {
-	log_msg(LVL_DEBUG, "tcp_sockpair_match(%p, %p)", sp, pattern);
+	log_msg(LVL_DEBUG2, "tcp_sockpair_match(%p, %p)", sp, pattern);
 
 	if (!tcp_socket_match(&sp->local, &pattern->local))
@@ -360,5 +360,5 @@
 		tcp_conn_t *conn = list_get_instance(link, tcp_conn_t, link);
 		tcp_sockpair_t *csp = &conn->ident;
-		log_msg(LVL_DEBUG, "compare with conn (f:(%x,%u), l:(%x,%u))",
+		log_msg(LVL_DEBUG2, "compare with conn (f:(%x,%u), l:(%x,%u))",
 		    csp->foreign.addr.ipv4, csp->foreign.port,
 		    csp->local.addr.ipv4, csp->local.port);
Index: uspace/srv/net/tcp/ncsim.c
===================================================================
--- uspace/srv/net/tcp/ncsim.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/ncsim.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -44,5 +44,5 @@
 #include <io/log.h>
 #include <stdlib.h>
-#include <thread.h>
+#include <fibril.h>
 #include "conn.h"
 #include "ncsim.h"
@@ -119,6 +119,6 @@
 }
 
-/** Network condition simulator handler thread. */
-static void tcp_ncsim_thread(void *arg)
+/** Network condition simulator handler fibril. */
+static int tcp_ncsim_fibril(void *arg)
 {
 	link_t *link;
@@ -126,5 +126,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_ncsim_thread()");
+	log_msg(LVL_DEBUG, "tcp_ncsim_fibril()");
 
 
@@ -151,19 +151,23 @@
 		free(sqe);
 	}
+
+	/* Not reached */
+	return 0;
 }
 
-/** Start simulator handler thread. */
-void tcp_ncsim_thread_start(void)
+/** Start simulator handler fibril. */
+void tcp_ncsim_fibril_start(void)
 {
-	thread_id_t tid;
-        int rc;
+	fid_t fid;
 
-	log_msg(LVL_DEBUG, "tcp_ncsim_thread_start()");
+	log_msg(LVL_DEBUG, "tcp_ncsim_fibril_start()");
 
-	rc = thread_create(tcp_ncsim_thread, NULL, "ncsim", &tid);
-	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed creating ncsim thread.");
+	fid = fibril_create(tcp_ncsim_fibril, NULL);
+	if (fid == 0) {
+		log_msg(LVL_ERROR, "Failed creating ncsim fibril.");
 		return;
 	}
+
+	fibril_add_ready(fid);
 }
 
Index: uspace/srv/net/tcp/ncsim.h
===================================================================
--- uspace/srv/net/tcp/ncsim.h	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/ncsim.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -40,6 +40,5 @@
 extern void tcp_ncsim_init(void);
 extern void tcp_ncsim_bounce_seg(tcp_sockpair_t *, tcp_segment_t *);
-extern void tcp_ncsim_thread_start(void);
-
+extern void tcp_ncsim_fibril_start(void);
 
 #endif
Index: uspace/srv/net/tcp/rqueue.c
===================================================================
--- uspace/srv/net/tcp/rqueue.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/rqueue.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -39,5 +39,5 @@
 #include <io/log.h>
 #include <stdlib.h>
-#include <thread.h>
+#include <fibril.h>
 #include "conn.h"
 #include "pdu.h"
@@ -128,11 +128,11 @@
 }
 
-/** Receive queue handler thread. */
-static void tcp_rqueue_thread(void *arg)
+/** Receive queue handler fibril. */
+static int tcp_rqueue_fibril(void *arg)
 {
 	link_t *link;
 	tcp_rqueue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "tcp_rqueue_thread()");
+	log_msg(LVL_DEBUG, "tcp_rqueue_fibril()");
 
 	while (true) {
@@ -142,19 +142,23 @@
 		tcp_as_segment_arrived(&rqe->sp, rqe->seg);
 	}
+
+	/* Not reached */
+	return 0;
 }
 
-/** Start receive queue handler thread. */
-void tcp_rqueue_thread_start(void)
+/** Start receive queue handler fibril. */
+void tcp_rqueue_fibril_start(void)
 {
-	thread_id_t tid;
-        int rc;
+	fid_t fid;
 
-	log_msg(LVL_DEBUG, "tcp_rqueue_thread_start()");
+	log_msg(LVL_DEBUG, "tcp_rqueue_fibril_start()");
 
-	rc = thread_create(tcp_rqueue_thread, NULL, "rqueue", &tid);
-	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed creating rqueue thread.");
+	fid = fibril_create(tcp_rqueue_fibril, NULL);
+	if (fid == 0) {
+		log_msg(LVL_ERROR, "Failed creating rqueue fibril.");
 		return;
 	}
+
+	fibril_add_ready(fid);
 }
 
Index: uspace/srv/net/tcp/rqueue.h
===================================================================
--- uspace/srv/net/tcp/rqueue.h	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/rqueue.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -42,5 +42,5 @@
 extern void tcp_rqueue_insert_seg(tcp_sockpair_t *, tcp_segment_t *);
 extern void tcp_rqueue_handler(void *);
-extern void tcp_rqueue_thread_start(void);
+extern void tcp_rqueue_fibril_start(void);
 
 
Index: uspace/srv/net/tcp/segment.c
===================================================================
--- uspace/srv/net/tcp/segment.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/segment.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -248,11 +248,11 @@
 void tcp_segment_dump(tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "Segment dump:");
-	log_msg(LVL_DEBUG, " - ctrl = %u", (unsigned)seg->ctrl);
-	log_msg(LVL_DEBUG, " - seq = % " PRIu32, seg->seq);
-	log_msg(LVL_DEBUG, " - ack = % " PRIu32, seg->ack);
-	log_msg(LVL_DEBUG, " - len = % " PRIu32, seg->len);
-	log_msg(LVL_DEBUG, " - wnd = % " PRIu32, seg->wnd);
-	log_msg(LVL_DEBUG, " - up = % " PRIu32, seg->up);
+	log_msg(LVL_DEBUG2, "Segment dump:");
+	log_msg(LVL_DEBUG2, " - ctrl = %u", (unsigned)seg->ctrl);
+	log_msg(LVL_DEBUG2, " - seq = % " PRIu32, seg->seq);
+	log_msg(LVL_DEBUG2, " - ack = % " PRIu32, seg->ack);
+	log_msg(LVL_DEBUG2, " - len = % " PRIu32, seg->len);
+	log_msg(LVL_DEBUG2, " - wnd = % " PRIu32, seg->wnd);
+	log_msg(LVL_DEBUG2, " - up = % " PRIu32, seg->up);
 }
 
Index: uspace/srv/net/tcp/sock.c
===================================================================
--- uspace/srv/net/tcp/sock.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/sock.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -51,6 +51,4 @@
 #include "ucall.h"
 
-#define FRAGMENT_SIZE 1024
-
 #define MAX_BACKLOG 128
 
@@ -66,4 +64,5 @@
 static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
 static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg);
+static int tcp_sock_recv_fibril(void *arg);
 
 int tcp_sock_init(void)
@@ -97,5 +96,5 @@
 	async_exch_t *exch = async_exchange_begin(sock_core->sess);
 	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
-	    FRAGMENT_SIZE, 0, 0, 1);
+	    TCP_SOCK_FRAGMENT_SIZE, 0, 0, 1);
 	async_exchange_end(exch);
 }
@@ -106,12 +105,65 @@
 	async_exch_t *exch = async_exchange_begin(lsock_core->sess);
 	async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
-	    FRAGMENT_SIZE, 0, 0, 0);
+	    TCP_SOCK_FRAGMENT_SIZE, 0, 0, 0);
 	async_exchange_end(exch);
 }
 
+static int tcp_sock_create(tcp_client_t *client, tcp_sockdata_t **rsock)
+{
+	tcp_sockdata_t *sock;
+
+	log_msg(LVL_DEBUG, "tcp_sock_create()");
+	*rsock = NULL;
+
+	sock = calloc(sizeof(tcp_sockdata_t), 1);
+	if (sock == NULL)
+		return ENOMEM;
+
+	fibril_mutex_initialize(&sock->lock);
+	sock->client = client;
+
+	sock->recv_buffer_used = 0;
+	sock->recv_error = TCP_EOK;
+	fibril_mutex_initialize(&sock->recv_buffer_lock);
+	fibril_condvar_initialize(&sock->recv_buffer_cv);
+	list_initialize(&sock->ready);
+
+	*rsock = sock;
+	return EOK;
+}
+
+static void tcp_sock_uncreate(tcp_sockdata_t *sock)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_uncreate()");
+	free(sock);
+}
+
+static int tcp_sock_finish_setup(tcp_sockdata_t *sock, int *sock_id)
+{
+	socket_core_t *sock_core;
+	int rc;
+
+	log_msg(LVL_DEBUG, "tcp_sock_finish_setup()");
+
+	sock->recv_fibril = fibril_create(tcp_sock_recv_fibril, sock);
+	if (sock->recv_fibril == 0)
+		return ENOMEM;
+
+	rc = socket_create(&sock->client->sockets, sock->client->sess,
+	    sock, sock_id);
+
+	if (rc != EOK)
+		return rc;
+
+	sock_core = socket_cores_find(&sock->client->sockets, *sock_id);
+	assert(sock_core != NULL);
+	sock->sock_core = sock_core;
+
+	return EOK;
+}
+
 static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
 	tcp_sockdata_t *sock;
-	socket_core_t *sock_core;
 	int sock_id;
 	int rc;
@@ -119,31 +171,26 @@
 
 	log_msg(LVL_DEBUG, "tcp_sock_socket()");
-	sock = calloc(sizeof(tcp_sockdata_t), 1);
-	if (sock == NULL) {
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-
-	fibril_mutex_initialize(&sock->lock);
-	sock->client = client;
+
+	rc = tcp_sock_create(client, &sock);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
 	sock->laddr.ipv4 = TCP_IPV4_ANY;
 	sock->lconn = NULL;
 	sock->backlog = 0;
-	list_initialize(&sock->ready);
 
 	sock_id = SOCKET_GET_SOCKET_ID(call);
-	rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
+	rc = tcp_sock_finish_setup(sock, &sock_id);
 	if (rc != EOK) {
+		tcp_sock_uncreate(sock);
 		async_answer_0(callid, rc);
 		return;
 	}
 
-	sock_core = socket_cores_find(&client->sockets, sock_id);
-	assert(sock_core != NULL);
-	sock->sock_core = sock_core;
-
 	SOCKET_SET_SOCKET_ID(answer, sock_id);
 
-	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
 	SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
 	
@@ -361,9 +408,8 @@
 	}
 
+	if (rc == EOK)
+		fibril_add_ready(socket->recv_fibril);
+
 	async_answer_0(callid, rc);
-
-	/* Push one fragment notification to client's queue */
-	tcp_sock_notify_data(sock_core);
-	log_msg(LVL_DEBUG, "tcp_sock_connect(): notify conn\n");
 }
 
@@ -374,5 +420,4 @@
 	int asock_id;
 	socket_core_t *sock_core;
-	socket_core_t *asock_core;
 	tcp_sockdata_t *socket;
 	tcp_sockdata_t *asocket;
@@ -444,33 +489,31 @@
 	/* Allocate socket for accepted connection */
 
-	log_msg(LVL_DEBUG, "tcp_sock_accept(): allocate asocket\n");
-	asocket = calloc(sizeof(tcp_sockdata_t), 1);
-	if (asocket == NULL) {
-		fibril_mutex_unlock(&socket->lock);
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-
-	fibril_mutex_initialize(&asocket->lock);
-	asocket->client = client;
+	rc = tcp_sock_create(client, &asocket);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&socket->lock);
+		async_answer_0(callid, rc);
+		return;
+	}
+
 	asocket->conn = conn;
 	log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
 
-	rc = socket_create(&client->sockets, client->sess, asocket, &asock_id);
+	rc = tcp_sock_finish_setup(asocket, &asock_id);
 	if (rc != EOK) {
+		tcp_sock_uncreate(asocket);
 		fibril_mutex_unlock(&socket->lock);
 		async_answer_0(callid, rc);
 		return;
 	}
+
+	fibril_add_ready(asocket->recv_fibril);
+
 	log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
 
-	asock_core = socket_cores_find(&client->sockets, asock_id);
-	assert(asock_core != NULL);
-
-	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
 	SOCKET_SET_SOCKET_ID(answer, asock_id);
 	SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
 	
-	async_answer_3(callid, asock_core->socket_id,
+	async_answer_3(callid, asocket->sock_core->socket_id,
 	    IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
 	    IPC_GET_ARG3(answer));
@@ -478,5 +521,4 @@
 	/* Push one fragment notification to client's queue */
 	log_msg(LVL_DEBUG, "tcp_sock_accept(): notify data\n");
-	tcp_sock_notify_data(asock_core);
 	fibril_mutex_unlock(&socket->lock);
 }
@@ -492,5 +534,5 @@
 	ipc_callid_t wcallid;
 	size_t length;
-	uint8_t buffer[FRAGMENT_SIZE];
+	uint8_t buffer[TCP_SOCK_FRAGMENT_SIZE];
 	tcp_error_t trc;
 	int rc;
@@ -523,6 +565,6 @@
 		}
 
-		if (length > FRAGMENT_SIZE)
-			length = FRAGMENT_SIZE;
+		if (length > TCP_SOCK_FRAGMENT_SIZE)
+			length = TCP_SOCK_FRAGMENT_SIZE;
 
 		rc = async_data_write_finalize(wcallid, buffer, length);
@@ -560,5 +602,5 @@
 
 	IPC_SET_ARG1(answer, 0);
-	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
 	async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
 	    IPC_GET_ARG2(answer));
@@ -581,8 +623,5 @@
 	ipc_call_t answer;
 	ipc_callid_t rcallid;
-	uint8_t buffer[FRAGMENT_SIZE];
 	size_t data_len;
-	xflags_t xflags;
-	tcp_error_t trc;
 	struct sockaddr_in addr;
 	tcp_sock_t *rsock;
@@ -611,9 +650,18 @@
 	(void)flags;
 
-	trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE, &data_len,
-	    &xflags);
-	log_msg(LVL_DEBUG, "**** tcp_uc_receive done");
-
-	switch (trc) {
+	log_msg(LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
+	fibril_mutex_lock(&socket->recv_buffer_lock);
+	while (socket->recv_buffer_used == 0 && socket->recv_error == TCP_EOK) {
+		log_msg(LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
+		fibril_condvar_wait(&socket->recv_buffer_cv,
+		    &socket->recv_buffer_lock);
+	}
+
+	log_msg(LVL_DEBUG, "Got data in sock recv_buffer");
+
+	data_len = socket->recv_buffer_used;
+	rc = socket->recv_error;
+
+	switch (socket->recv_error) {
 	case TCP_EOK:
 		rc = EOK;
@@ -630,6 +678,7 @@
 	}
 
-	log_msg(LVL_DEBUG, "**** tcp_uc_receive -> %d", rc);
+	log_msg(LVL_DEBUG, "**** recv result -> %d", rc);
 	if (rc != EOK) {
+		fibril_mutex_unlock(&socket->recv_buffer_lock);
 		fibril_mutex_unlock(&socket->lock);
 		async_answer_0(callid, rc);
@@ -646,4 +695,5 @@
 		log_msg(LVL_DEBUG, "addr read receive");
 		if (!async_data_read_receive(&rcallid, &addr_length)) {
+			fibril_mutex_unlock(&socket->recv_buffer_lock);
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, EINVAL);
@@ -657,4 +707,5 @@
 		rc = async_data_read_finalize(rcallid, &addr, addr_length);
 		if (rc != EOK) {
+			fibril_mutex_unlock(&socket->recv_buffer_lock);
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, EINVAL);
@@ -665,4 +716,5 @@
 	log_msg(LVL_DEBUG, "data read receive");
 	if (!async_data_read_receive(&rcallid, &length)) {
+		fibril_mutex_unlock(&socket->recv_buffer_lock);
 		fibril_mutex_unlock(&socket->lock);
 		async_answer_0(callid, EINVAL);
@@ -674,5 +726,16 @@
 
 	log_msg(LVL_DEBUG, "data read finalize");
-	rc = async_data_read_finalize(rcallid, buffer, length);
+	rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
+
+	socket->recv_buffer_used -= length;
+	log_msg(LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
+	    socket->recv_buffer_used);
+	if (socket->recv_buffer_used > 0) {
+		memmove(socket->recv_buffer, socket->recv_buffer + length,
+		    socket->recv_buffer_used);
+		tcp_sock_notify_data(socket->sock_core);
+	}
+
+	fibril_condvar_broadcast(&socket->recv_buffer_cv);
 
 	if (length < data_len && rc == EOK)
@@ -681,7 +744,6 @@
 	SOCKET_SET_READ_DATA_LENGTH(answer, length);
 	async_answer_1(callid, EOK, IPC_GET_ARG1(answer));
-	
-	/* Push one fragment notification to client's queue */
-	tcp_sock_notify_data(sock_core);
+
+	fibril_mutex_unlock(&socket->recv_buffer_lock);
 	fibril_mutex_unlock(&socket->lock);
 }
@@ -694,7 +756,4 @@
 	tcp_error_t trc;
 	int rc;
-	uint8_t buffer[FRAGMENT_SIZE];
-	size_t data_len;
-	xflags_t xflags;
 
 	log_msg(LVL_DEBUG, "tcp_sock_close()");
@@ -717,12 +776,4 @@
 			return;
 		}
-
-		/* Drain incoming data. This should really be done in the background. */
-		do {
-			trc = tcp_uc_receive(socket->conn, buffer,
-			    FRAGMENT_SIZE, &data_len, &xflags);
-		} while (trc == TCP_EOK);
-
-		tcp_uc_delete(socket->conn);
 	}
 
@@ -776,4 +827,44 @@
 	tcp_sock_notify_aconn(socket->sock_core);
 	fibril_mutex_unlock(&socket->lock);
+}
+
+static int tcp_sock_recv_fibril(void *arg)
+{
+	tcp_sockdata_t *sock = (tcp_sockdata_t *)arg;
+	size_t data_len;
+	xflags_t xflags;
+	tcp_error_t trc;
+
+	log_msg(LVL_DEBUG, "tcp_sock_recv_fibril()");
+
+	while (true) {
+		log_msg(LVL_DEBUG, "call tcp_uc_receive()");
+		fibril_mutex_lock(&sock->recv_buffer_lock);
+		while (sock->recv_buffer_used != 0)
+			fibril_condvar_wait(&sock->recv_buffer_cv,
+			    &sock->recv_buffer_lock);
+
+		trc = tcp_uc_receive(sock->conn, sock->recv_buffer,
+		    TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags);
+
+		if (trc != TCP_EOK) {
+			sock->recv_error = trc;
+			fibril_condvar_broadcast(&sock->recv_buffer_cv);
+			fibril_mutex_unlock(&sock->recv_buffer_lock);
+			tcp_sock_notify_data(sock->sock_core);
+			break;
+		}
+
+		log_msg(LVL_DEBUG, "got data - broadcast recv_buffer_cv");
+
+		sock->recv_buffer_used = data_len;
+		fibril_condvar_broadcast(&sock->recv_buffer_cv);
+		fibril_mutex_unlock(&sock->recv_buffer_lock);
+		tcp_sock_notify_data(sock->sock_core);
+	}
+
+	tcp_uc_delete(sock->conn);
+
+	return 0;
 }
 
Index: uspace/srv/net/tcp/tcp.c
===================================================================
--- uspace/srv/net/tcp/tcp.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/tcp.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -180,8 +180,8 @@
 
 	tcp_rqueue_init();
-	tcp_rqueue_thread_start();
+	tcp_rqueue_fibril_start();
 
 	tcp_ncsim_init();
-	tcp_ncsim_thread_start();
+	tcp_ncsim_fibril_start();
 
 	if (0) tcp_test();
Index: uspace/srv/net/tcp/tcp_type.h
===================================================================
--- uspace/srv/net/tcp/tcp_type.h	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/tcp_type.h	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -39,4 +39,5 @@
 #include <async.h>
 #include <bool.h>
+#include <fibril.h>
 #include <fibril_synch.h>
 #include <socket_core.h>
@@ -331,4 +332,6 @@
 } tcp_client_t;
 
+#define TCP_SOCK_FRAGMENT_SIZE 1024
+
 typedef struct tcp_sockdata {
 	/** Lock */
@@ -348,4 +351,11 @@
 	/** List of connections (from lconn) that are ready to be accepted */
 	list_t ready;
+	/** Receiving fibril */
+	fid_t recv_fibril;
+	uint8_t recv_buffer[TCP_SOCK_FRAGMENT_SIZE];
+	size_t recv_buffer_used;
+	fibril_mutex_t recv_buffer_lock;
+	fibril_condvar_t recv_buffer_cv;
+	tcp_error_t recv_error;
 } tcp_sockdata_t;
 
Index: uspace/srv/net/tcp/test.c
===================================================================
--- uspace/srv/net/tcp/test.c	(revision 738b549ba5c1b98bef3c6232df7b8771066de0cf)
+++ uspace/srv/net/tcp/test.c	(revision 4b824457e99e96b4e0176beb18eabdc25b8895da)
@@ -38,5 +38,5 @@
 #include <errno.h>
 #include <stdio.h>
-#include <thread.h>
+#include <fibril.h>
 #include <str.h>
 #include "tcp_type.h"
@@ -47,5 +47,5 @@
 #define RCV_BUF_SIZE 64
 
-static void test_srv(void *arg)
+static int test_srv(void *arg)
 {
 	tcp_conn_t *conn;
@@ -84,7 +84,8 @@
 
 	printf("test_srv() terminating\n");
+	return 0;
 }
 
-static void test_cli(void *arg)
+static int test_cli(void *arg)
 {
 	tcp_conn_t *conn;
@@ -112,11 +113,12 @@
 	printf("C: User close...\n");
 	tcp_uc_close(conn);
+
+	return 0;
 }
 
 void tcp_test(void)
 {
-	thread_id_t srv_tid;
-	thread_id_t cli_tid;
-	int rc;
+	fid_t srv_fid;
+	fid_t cli_fid;
 
 	printf("tcp_test()\n");
@@ -125,17 +127,21 @@
 
 	if (0) {
-		rc = thread_create(test_srv, NULL, "test_srv", &srv_tid);
-		if (rc != EOK) {
-			printf("Failed to create server thread.\n");
+		srv_fid = fibril_create(test_srv, NULL);
+		if (srv_fid == 0) {
+			printf("Failed to create server fibril.\n");
 			return;
 		}
+
+		fibril_add_ready(srv_fid);
 	}
 
 	if (0) {
-		rc = thread_create(test_cli, NULL, "test_cli", &cli_tid);
-		if (rc != EOK) {
-			printf("Failed to create client thread.\n");
+		cli_fid = fibril_create(test_cli, NULL);
+		if (cli_fid == 0) {
+			printf("Failed to create client fibril.\n");
 			return;
 		}
+
+		fibril_add_ready(cli_fid);
 	}
 }
