Index: uspace/srv/net/tl/tcp/Makefile
===================================================================
--- uspace/srv/net/tl/tcp/Makefile	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ uspace/srv/net/tl/tcp/Makefile	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -34,14 +34,14 @@
 SOURCES = \
 	conn.c \
-	header.c \
 	iqueue.c \
 	ncsim.c \
+	pdu.c \
 	rqueue.c \
 	segment.c \
 	seq_no.c \
-	state.c \
 	tcp.c \
 	test.c \
-	tqueue.c 
+	tqueue.c \
+	ucall.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/tl/tcp/conn.c
===================================================================
--- uspace/srv/net/tl/tcp/conn.c	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ uspace/srv/net/tl/tcp/conn.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -45,7 +45,7 @@
 #include "segment.h"
 #include "seq_no.h"
-#include "state.h"
 #include "tcp_type.h"
 #include "tqueue.h"
+#include "ucall.h"
 
 #define RCV_BUF_SIZE 2/*4096*/
Index: uspace/srv/net/tl/tcp/header.c
===================================================================
--- uspace/srv/net/tl/tcp/header.c	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ 	(revision )
@@ -1,295 +1,0 @@
-/*
- * Copyright (c) 2011 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 tcp
- * @{
- */
-
-/**
- * @file TCP header encoding and decoding
- */
-
-#include <bitops.h>
-#include <byteorder.h>
-#include <errno.h>
-#include <mem.h>
-#include <stdlib.h>
-#include "header.h"
-#include "segment.h"
-#include "seq_no.h"
-#include "std.h"
-#include "tcp_type.h"
-
-#define TCP_CHECKSUM_INIT 0xffff
-
-static uint16_t tcp_checksum_calc(uint16_t ivalue, void *data, size_t size)
-{
-	uint16_t sum;
-	size_t words, i;
-	uint8_t *bdata;
-
-	sum = ~ivalue;
-	words = size / 2;
-	bdata = (uint8_t *)data;
-
-	for (i = 0; i < words; i++) {
-		sum += ~(((uint16_t)bdata[2*i] << 8) + bdata[2*i + 1]);
-	}
-
-	if (size % 2 != 0) {
-		sum += ~((uint16_t)bdata[2*words] << 8);
-	}
-
-	return ~sum;
-}
-
-static void tcp_header_decode_flags(uint16_t doff_flags, tcp_control_t *rctl)
-{
-	tcp_control_t ctl;
-
-	ctl = 0;
-
-	if ((doff_flags & BIT_V(uint16_t, DF_URG)) != 0)
-		ctl |= 0 /* XXX */;
-	if ((doff_flags & BIT_V(uint16_t, DF_ACK)) != 0)
-		ctl |= CTL_ACK;
-	if ((doff_flags & BIT_V(uint16_t, DF_PSH)) != 0)
-		ctl |= 0 /* XXX */;
-	if ((doff_flags & BIT_V(uint16_t, DF_RST)) != 0)
-		ctl |= CTL_RST;
-	if ((doff_flags & BIT_V(uint16_t, DF_SYN)) != 0)
-		ctl |= CTL_SYN;
-	if ((doff_flags & BIT_V(uint16_t, DF_FIN)) != 0)
-		ctl |= CTL_FIN;
-
-	*rctl = ctl;
-}
-
-static void tcp_header_encode_flags(tcp_control_t ctl, uint16_t doff_flags0,
-    uint16_t *rdoff_flags)
-{
-	uint16_t doff_flags;
-
-	doff_flags = doff_flags0;
-
-	if ((ctl & CTL_ACK) != 0)
-		doff_flags |= BIT_V(uint16_t, DF_ACK);
-	if ((ctl & CTL_RST) != 0)
-		doff_flags |= BIT_V(uint16_t, DF_RST);
-	if ((ctl & CTL_SYN) != 0)
-		doff_flags |= BIT_V(uint16_t, DF_SYN);
-	if ((ctl & CTL_FIN) != 0)
-		doff_flags |= BIT_V(uint16_t, DF_FIN);
-
-	*rdoff_flags = doff_flags;
-}
-
-static void tcp_header_setup(tcp_sockpair_t *sp, tcp_segment_t *seg, tcp_header_t *hdr)
-{
-	uint16_t doff_flags;
-
-	hdr->src_port = host2uint16_t_be(sp->local.port);
-	hdr->dest_port = host2uint16_t_be(sp->foreign.port);
-	hdr->seq = host2uint32_t_be(seg->seq);
-	hdr->ack = host2uint32_t_be(seg->ack);
-	tcp_header_encode_flags(seg->ctrl, 0, &doff_flags);
-	hdr->doff_flags = host2uint16_t_be(doff_flags);
-	hdr->window = host2uint16_t_be(seg->wnd);
-	hdr->checksum = 0;
-	hdr->urg_ptr = host2uint16_t_be(seg->up);
-}
-
-static void tcp_phdr_setup(tcp_pdu_t *pdu, tcp_phdr_t *phdr)
-{
-	phdr->src_addr = host2uint32_t_be(pdu->src_addr.ipv4);
-	phdr->dest_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
-	phdr->zero = 0;
-	phdr->protocol = 6; /* XXX Magic number */
-	phdr->tcp_length = host2uint16_t_be(pdu->header_size + pdu->text_size);
-}
-
-static void tcp_header_decode(tcp_header_t *hdr, tcp_segment_t *seg)
-{
-	tcp_header_decode_flags(uint16_t_be2host(hdr->doff_flags), &seg->ctrl);
-	seg->seq = uint32_t_be2host(hdr->seq);
-	seg->ack = uint32_t_be2host(hdr->ack);
-	seg->wnd = uint16_t_be2host(hdr->window);
-	seg->up = uint16_t_be2host(hdr->urg_ptr);
-}
-
-static int tcp_header_encode(tcp_sockpair_t *sp, tcp_segment_t *seg,
-    void **header, size_t *size)
-{
-	tcp_header_t *hdr;
-
-	hdr = calloc(1, sizeof(tcp_header_t));
-	if (hdr == NULL)
-		return ENOMEM;
-
-	tcp_header_setup(sp, seg, hdr);
-	*header = hdr;
-	*size = sizeof(tcp_header_t);
-
-	return EOK;
-}
-
-static tcp_pdu_t *tcp_pdu_new(void)
-{
-	return calloc(1, sizeof(tcp_pdu_t));
-}
-
-/** Create PDU with the specified header and text data.
- *
- * Note that you still need to set addresses in the returned PDU.
- *
- * @param hdr		Header data
- * @param hdr_size      Header size in bytes
- * @param text		Text data
- * @param text_size	Text size in bytes
- * @return		New PDU
- */
-tcp_pdu_t *tcp_pdu_create(void *hdr, size_t hdr_size, void *text,
-    size_t text_size)
-{
-	tcp_pdu_t *pdu;
-
-	pdu = tcp_pdu_new();
-	if (pdu == NULL)
-		return NULL;
-
-	pdu->header = malloc(hdr_size);
-	pdu->text = malloc(text_size);
-	if (pdu->header == NULL || pdu->text == NULL)
-		goto error;
-
-	memcpy(pdu->header, hdr, hdr_size);
-	memcpy(pdu->text, text, text_size);
-
-	pdu->header_size = hdr_size;
-	pdu->text_size = text_size;
-
-	return pdu;
-
-error:
-	if (pdu->header != NULL)
-		free(pdu->header);
-	if (pdu->text != NULL)
-		free(pdu->text);
-
-	return NULL;
-}
-
-void tcp_pdu_delete(tcp_pdu_t *pdu)
-{
-	free(pdu->header);
-	free(pdu->text);
-	free(pdu);
-}
-
-static uint16_t tcp_pdu_checksum_calc(tcp_pdu_t *pdu)
-{
-	uint16_t cs_phdr;
-	uint16_t cs_headers;
-	uint16_t cs_all;
-	tcp_phdr_t phdr;
-
-	tcp_phdr_setup(pdu, &phdr);
-	cs_phdr = tcp_checksum_calc(TCP_CHECKSUM_INIT, (void *)&phdr,
-	    sizeof(tcp_phdr_t));
-	cs_headers = tcp_checksum_calc(cs_phdr, pdu->header, pdu->header_size);
-	cs_all = tcp_checksum_calc(cs_headers, pdu->text, pdu->text_size);
-
-	return cs_all;
-}
-
-static void tcp_pdu_set_checksum(tcp_pdu_t *pdu, uint16_t checksum)
-{
-	tcp_header_t *hdr;
-
-	hdr = (tcp_header_t *)pdu->header;
-	hdr->checksum = host2uint16_t_le(checksum);
-}
-
-/** Encode outgoing PDU */
-int tcp_pdu_decode(tcp_pdu_t *pdu, tcp_sockpair_t *sp, tcp_segment_t **seg)
-{
-	tcp_segment_t *nseg;
-	tcp_header_t *hdr;
-
-	nseg = tcp_segment_make_data(0, pdu->text, pdu->text_size);
-	if (nseg == NULL)
-		return ENOMEM;
-
-	tcp_header_decode(pdu->header, nseg);
-	nseg->len += seq_no_control_len(nseg->ctrl);
-
-	hdr = (tcp_header_t *)pdu->header;
-
-	sp->local.port = uint16_t_be2host(hdr->dest_port);
-	sp->local.addr = pdu->dest_addr;
-	sp->foreign.port = uint16_t_be2host(hdr->src_port);
-	sp->foreign.addr = pdu->src_addr;
-
-	*seg = nseg;
-	return EOK;
-}
-
-/** Decode incoming PDU */
-int tcp_pdu_encode(tcp_sockpair_t *sp, tcp_segment_t *seg, tcp_pdu_t **pdu)
-{
-	tcp_pdu_t *npdu;
-	size_t text_size;
-	uint16_t checksum;
-
-	npdu = tcp_pdu_new();
-	if (npdu == NULL)
-		return ENOMEM;
-
-	npdu->src_addr = sp->local.addr;
-	npdu->dest_addr = sp->foreign.addr;
-	tcp_header_encode(sp, seg, &npdu->header, &npdu->header_size);
-
-	text_size = tcp_segment_text_size(seg);
-	npdu->text = calloc(1, text_size);
-	if (npdu->text == NULL)
-		return ENOMEM;
-
-	npdu->text_size = text_size;
-	memcpy(npdu->text, seg->data, text_size);
-
-	/* Checksum calculation */
-	checksum = tcp_pdu_checksum_calc(npdu);
-	tcp_pdu_set_checksum(npdu, checksum);
-
-	*pdu = npdu;
-	return EOK;
-}
-
-/**
- * @}
- */
Index: uspace/srv/net/tl/tcp/header.h
===================================================================
--- uspace/srv/net/tl/tcp/header.h	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ 	(revision )
@@ -1,50 +1,0 @@
-/*
- * Copyright (c) 2011 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 tcp
- * @{
- */
-/** @file TCP header encoding and decoding
- */
-
-#ifndef HEADER_H
-#define HEADER_H
-
-#include <sys/types.h>
-#include "std.h"
-#include "tcp_type.h"
-
-extern tcp_pdu_t *tcp_pdu_create(void *, size_t, void *, size_t);
-extern void tcp_pdu_delete(tcp_pdu_t *);
-extern int tcp_pdu_decode(tcp_pdu_t *, tcp_sockpair_t *, tcp_segment_t **);
-extern int tcp_pdu_encode(tcp_sockpair_t *, tcp_segment_t *, tcp_pdu_t **);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/tl/tcp/pdu.c
===================================================================
--- uspace/srv/net/tl/tcp/pdu.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
+++ uspace/srv/net/tl/tcp/pdu.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP header encoding and decoding
+ */
+
+#include <bitops.h>
+#include <byteorder.h>
+#include <errno.h>
+#include <mem.h>
+#include <stdlib.h>
+#include "pdu.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "std.h"
+#include "tcp_type.h"
+
+#define TCP_CHECKSUM_INIT 0xffff
+
+static uint16_t tcp_checksum_calc(uint16_t ivalue, void *data, size_t size)
+{
+	uint16_t sum;
+	size_t words, i;
+	uint8_t *bdata;
+
+	sum = ~ivalue;
+	words = size / 2;
+	bdata = (uint8_t *)data;
+
+	for (i = 0; i < words; i++) {
+		sum += ~(((uint16_t)bdata[2*i] << 8) + bdata[2*i + 1]);
+	}
+
+	if (size % 2 != 0) {
+		sum += ~((uint16_t)bdata[2*words] << 8);
+	}
+
+	return ~sum;
+}
+
+static void tcp_header_decode_flags(uint16_t doff_flags, tcp_control_t *rctl)
+{
+	tcp_control_t ctl;
+
+	ctl = 0;
+
+	if ((doff_flags & BIT_V(uint16_t, DF_URG)) != 0)
+		ctl |= 0 /* XXX */;
+	if ((doff_flags & BIT_V(uint16_t, DF_ACK)) != 0)
+		ctl |= CTL_ACK;
+	if ((doff_flags & BIT_V(uint16_t, DF_PSH)) != 0)
+		ctl |= 0 /* XXX */;
+	if ((doff_flags & BIT_V(uint16_t, DF_RST)) != 0)
+		ctl |= CTL_RST;
+	if ((doff_flags & BIT_V(uint16_t, DF_SYN)) != 0)
+		ctl |= CTL_SYN;
+	if ((doff_flags & BIT_V(uint16_t, DF_FIN)) != 0)
+		ctl |= CTL_FIN;
+
+	*rctl = ctl;
+}
+
+static void tcp_header_encode_flags(tcp_control_t ctl, uint16_t doff_flags0,
+    uint16_t *rdoff_flags)
+{
+	uint16_t doff_flags;
+
+	doff_flags = doff_flags0;
+
+	if ((ctl & CTL_ACK) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_ACK);
+	if ((ctl & CTL_RST) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_RST);
+	if ((ctl & CTL_SYN) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_SYN);
+	if ((ctl & CTL_FIN) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_FIN);
+
+	*rdoff_flags = doff_flags;
+}
+
+static void tcp_header_setup(tcp_sockpair_t *sp, tcp_segment_t *seg, tcp_header_t *hdr)
+{
+	uint16_t doff_flags;
+
+	hdr->src_port = host2uint16_t_be(sp->local.port);
+	hdr->dest_port = host2uint16_t_be(sp->foreign.port);
+	hdr->seq = host2uint32_t_be(seg->seq);
+	hdr->ack = host2uint32_t_be(seg->ack);
+	tcp_header_encode_flags(seg->ctrl, 0, &doff_flags);
+	hdr->doff_flags = host2uint16_t_be(doff_flags);
+	hdr->window = host2uint16_t_be(seg->wnd);
+	hdr->checksum = 0;
+	hdr->urg_ptr = host2uint16_t_be(seg->up);
+}
+
+static void tcp_phdr_setup(tcp_pdu_t *pdu, tcp_phdr_t *phdr)
+{
+	phdr->src_addr = host2uint32_t_be(pdu->src_addr.ipv4);
+	phdr->dest_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
+	phdr->zero = 0;
+	phdr->protocol = 6; /* XXX Magic number */
+	phdr->tcp_length = host2uint16_t_be(pdu->header_size + pdu->text_size);
+}
+
+static void tcp_header_decode(tcp_header_t *hdr, tcp_segment_t *seg)
+{
+	tcp_header_decode_flags(uint16_t_be2host(hdr->doff_flags), &seg->ctrl);
+	seg->seq = uint32_t_be2host(hdr->seq);
+	seg->ack = uint32_t_be2host(hdr->ack);
+	seg->wnd = uint16_t_be2host(hdr->window);
+	seg->up = uint16_t_be2host(hdr->urg_ptr);
+}
+
+static int tcp_header_encode(tcp_sockpair_t *sp, tcp_segment_t *seg,
+    void **header, size_t *size)
+{
+	tcp_header_t *hdr;
+
+	hdr = calloc(1, sizeof(tcp_header_t));
+	if (hdr == NULL)
+		return ENOMEM;
+
+	tcp_header_setup(sp, seg, hdr);
+	*header = hdr;
+	*size = sizeof(tcp_header_t);
+
+	return EOK;
+}
+
+static tcp_pdu_t *tcp_pdu_new(void)
+{
+	return calloc(1, sizeof(tcp_pdu_t));
+}
+
+/** Create PDU with the specified header and text data.
+ *
+ * Note that you still need to set addresses in the returned PDU.
+ *
+ * @param hdr		Header data
+ * @param hdr_size      Header size in bytes
+ * @param text		Text data
+ * @param text_size	Text size in bytes
+ * @return		New PDU
+ */
+tcp_pdu_t *tcp_pdu_create(void *hdr, size_t hdr_size, void *text,
+    size_t text_size)
+{
+	tcp_pdu_t *pdu;
+
+	pdu = tcp_pdu_new();
+	if (pdu == NULL)
+		return NULL;
+
+	pdu->header = malloc(hdr_size);
+	pdu->text = malloc(text_size);
+	if (pdu->header == NULL || pdu->text == NULL)
+		goto error;
+
+	memcpy(pdu->header, hdr, hdr_size);
+	memcpy(pdu->text, text, text_size);
+
+	pdu->header_size = hdr_size;
+	pdu->text_size = text_size;
+
+	return pdu;
+
+error:
+	if (pdu->header != NULL)
+		free(pdu->header);
+	if (pdu->text != NULL)
+		free(pdu->text);
+
+	return NULL;
+}
+
+void tcp_pdu_delete(tcp_pdu_t *pdu)
+{
+	free(pdu->header);
+	free(pdu->text);
+	free(pdu);
+}
+
+static uint16_t tcp_pdu_checksum_calc(tcp_pdu_t *pdu)
+{
+	uint16_t cs_phdr;
+	uint16_t cs_headers;
+	uint16_t cs_all;
+	tcp_phdr_t phdr;
+
+	tcp_phdr_setup(pdu, &phdr);
+	cs_phdr = tcp_checksum_calc(TCP_CHECKSUM_INIT, (void *)&phdr,
+	    sizeof(tcp_phdr_t));
+	cs_headers = tcp_checksum_calc(cs_phdr, pdu->header, pdu->header_size);
+	cs_all = tcp_checksum_calc(cs_headers, pdu->text, pdu->text_size);
+
+	return cs_all;
+}
+
+static void tcp_pdu_set_checksum(tcp_pdu_t *pdu, uint16_t checksum)
+{
+	tcp_header_t *hdr;
+
+	hdr = (tcp_header_t *)pdu->header;
+	hdr->checksum = host2uint16_t_le(checksum);
+}
+
+/** Encode outgoing PDU */
+int tcp_pdu_decode(tcp_pdu_t *pdu, tcp_sockpair_t *sp, tcp_segment_t **seg)
+{
+	tcp_segment_t *nseg;
+	tcp_header_t *hdr;
+
+	nseg = tcp_segment_make_data(0, pdu->text, pdu->text_size);
+	if (nseg == NULL)
+		return ENOMEM;
+
+	tcp_header_decode(pdu->header, nseg);
+	nseg->len += seq_no_control_len(nseg->ctrl);
+
+	hdr = (tcp_header_t *)pdu->header;
+
+	sp->local.port = uint16_t_be2host(hdr->dest_port);
+	sp->local.addr = pdu->dest_addr;
+	sp->foreign.port = uint16_t_be2host(hdr->src_port);
+	sp->foreign.addr = pdu->src_addr;
+
+	*seg = nseg;
+	return EOK;
+}
+
+/** Decode incoming PDU */
+int tcp_pdu_encode(tcp_sockpair_t *sp, tcp_segment_t *seg, tcp_pdu_t **pdu)
+{
+	tcp_pdu_t *npdu;
+	size_t text_size;
+	uint16_t checksum;
+
+	npdu = tcp_pdu_new();
+	if (npdu == NULL)
+		return ENOMEM;
+
+	npdu->src_addr = sp->local.addr;
+	npdu->dest_addr = sp->foreign.addr;
+	tcp_header_encode(sp, seg, &npdu->header, &npdu->header_size);
+
+	text_size = tcp_segment_text_size(seg);
+	npdu->text = calloc(1, text_size);
+	if (npdu->text == NULL)
+		return ENOMEM;
+
+	npdu->text_size = text_size;
+	memcpy(npdu->text, seg->data, text_size);
+
+	/* Checksum calculation */
+	checksum = tcp_pdu_checksum_calc(npdu);
+	tcp_pdu_set_checksum(npdu, checksum);
+
+	*pdu = npdu;
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/pdu.h
===================================================================
--- uspace/srv/net/tl/tcp/pdu.h	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
+++ uspace/srv/net/tl/tcp/pdu.h	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP PDU (encoded Protocol Data Unit) handling
+ */
+
+#ifndef PDU_H
+#define PDU_H
+
+#include <sys/types.h>
+#include "std.h"
+#include "tcp_type.h"
+
+extern tcp_pdu_t *tcp_pdu_create(void *, size_t, void *, size_t);
+extern void tcp_pdu_delete(tcp_pdu_t *);
+extern int tcp_pdu_decode(tcp_pdu_t *, tcp_sockpair_t *, tcp_segment_t **);
+extern int tcp_pdu_encode(tcp_sockpair_t *, tcp_segment_t *, tcp_pdu_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/rqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/rqueue.c	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ uspace/srv/net/tl/tcp/rqueue.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -41,9 +41,9 @@
 #include <thread.h>
 #include "conn.h"
-#include "header.h"
+#include "pdu.h"
 #include "rqueue.h"
 #include "segment.h"
-#include "state.h"
 #include "tcp_type.h"
+#include "ucall.h"
 
 /** Transcode bounced segments.
Index: uspace/srv/net/tl/tcp/state.c
===================================================================
--- uspace/srv/net/tl/tcp/state.c	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ 	(revision )
@@ -1,253 +1,0 @@
-/*
- * Copyright (c) 2011 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 tcp
- * @{
- */
-
-/**
- * @file TCP entry points (close to those defined in the RFC)
- */
-
-#include <fibril_synch.h>
-#include <io/log.h>
-#include <macros.h>
-#include <mem.h>
-#include "conn.h"
-#include "state.h"
-#include "tcp_type.h"
-#include "tqueue.h"
-
-/*
- * User calls
- */
-
-/** OPEN user call
- *
- * @param lport		Local port
- * @param fsock		Foreign socket
- * @param acpass	Active/passive
- * @param conn		Connection
- *
- * XXX We should be able to call active open on an existing listening
- * connection.
- */
-tcp_error_t tcp_uc_open(uint16_t lport, tcp_sock_t *fsock, acpass_t acpass,
-    tcp_conn_t **conn)
-{
-	tcp_conn_t *nconn;
-	tcp_sock_t lsock;
-
-	log_msg(LVL_DEBUG, "tcp_uc_open(%" PRIu16 ", %p, %s, %p)",
-	    lport, fsock, acpass == ap_active ? "active" : "passive",
-	    conn);
-
-	lsock.port = lport;
-	lsock.addr.ipv4 = 0x7f000001;
-
-	nconn = tcp_conn_new(&lsock, fsock);
-	tcp_conn_add(nconn);
-
-	if (acpass == ap_active) {
-		/* Synchronize (initiate) connection */
-		tcp_conn_sync(nconn);
-
-		/* Wait for connection to be established or reset */
-		log_msg(LVL_DEBUG, "tcp_uc_open: Wait for connection.");
-		fibril_mutex_lock(&nconn->cstate_lock);
-		while (nconn->cstate == st_syn_sent ||
-		    nconn->cstate == st_syn_received) {
-			fibril_condvar_wait(&nconn->cstate_cv, &nconn->cstate_lock);
-		}
-		if (nconn->cstate != st_established) {
-			log_msg(LVL_DEBUG, "tcp_uc_open: Connection was reset.");
-			assert(nconn->cstate == st_closed);
-			fibril_mutex_unlock(&nconn->cstate_lock);
-			return TCP_ERESET;
-		}
-		fibril_mutex_unlock(&nconn->cstate_lock);
-		log_msg(LVL_DEBUG, "tcp_uc_open: Connection was established.");
-	}
-
-	*conn = nconn;
-	return TCP_EOK;
-}
-
-/** SEND user call */
-tcp_error_t tcp_uc_send(tcp_conn_t *conn, void *data, size_t size,
-    xflags_t flags)
-{
-	size_t buf_free;
-	size_t xfer_size;
-
-	log_msg(LVL_DEBUG, "tcp_uc_send()");
-
-	if (conn->cstate == st_closed)
-		return TCP_ENOTEXIST;
-
-	if (conn->cstate == st_listen) {
-		/* Change connection to active */
-		tcp_conn_sync(conn);
-	}
-
-	if (conn->snd_buf_fin)
-		return TCP_ECLOSING;
-
-	while (size > 0) {
-		buf_free = conn->snd_buf_size - conn->snd_buf_used;
-		while (buf_free == 0)
-			tcp_tqueue_new_data(conn);
-
-		xfer_size = min(size, buf_free);
-
-		/* Copy data to buffer */
-		memcpy(conn->snd_buf + conn->snd_buf_used, data, xfer_size);
-		data += xfer_size;
-		conn->snd_buf_used += xfer_size;
-		size -= xfer_size;
-	}
-
-	tcp_tqueue_new_data(conn);
-
-	return TCP_EOK;
-}
-
-/** RECEIVE user call */
-tcp_error_t tcp_uc_receive(tcp_conn_t *conn, void *buf, size_t size,
-    size_t *rcvd, xflags_t *xflags)
-{
-	size_t xfer_size;
-
-	log_msg(LVL_DEBUG, "tcp_uc_receive()");
-
-	if (conn->cstate == st_closed)
-		return TCP_ENOTEXIST;
-
-	fibril_mutex_lock(&conn->rcv_buf_lock);
-
-	/* Wait for data to become available */
-	while (conn->rcv_buf_used == 0 && !conn->rcv_buf_fin) {
-		log_msg(LVL_DEBUG, "tcp_uc_receive() - wait for data");
-		fibril_condvar_wait(&conn->rcv_buf_cv, &conn->rcv_buf_lock);
-	}
-
-	if (conn->rcv_buf_used == 0) {
-		/* End of data, peer closed connection. */
-		assert(conn->rcv_buf_fin);
-		*rcvd = 0;
-		*xflags = 0;
-		return TCP_ECLOSING;
-	}
-
-	/* Copy data from receive buffer to user buffer */
-	xfer_size = min(size, conn->rcv_buf_used);
-	memcpy(buf, conn->rcv_buf, xfer_size);
-	*rcvd = xfer_size;
-
-	/* Remove data from receive buffer */
-	memmove(conn->rcv_buf, conn->rcv_buf + xfer_size, conn->rcv_buf_used -
-	    xfer_size);
-	conn->rcv_buf_used -= xfer_size;
-	conn->rcv_wnd += xfer_size;
-
-	fibril_mutex_unlock(&conn->rcv_buf_lock);
-
-	/* TODO */
-	*xflags = 0;
-
-	/* Send new size of receive window */
-	tcp_tqueue_ctrl_seg(conn, CTL_ACK);
-
-	log_msg(LVL_DEBUG, "tcp_uc_receive() - returning %zu bytes",
-	    xfer_size);
-
-	return TCP_EOK;
-}
-
-/** CLOSE user call */
-tcp_error_t tcp_uc_close(tcp_conn_t *conn)
-{
-	log_msg(LVL_DEBUG, "tcp_uc_close()");
-
-	if (conn->cstate == st_closed)
-		return TCP_ENOTEXIST;
-
-	if (conn->snd_buf_fin)
-		return TCP_ECLOSING;
-
-	conn->snd_buf_fin = true;
-	tcp_tqueue_new_data(conn);
-
-	return TCP_EOK;
-}
-
-/** ABORT user call */
-void tcp_uc_abort(tcp_conn_t *conn)
-{
-	log_msg(LVL_DEBUG, "tcp_uc_abort()");
-}
-
-/** STATUS user call */
-void tcp_uc_status(tcp_conn_t *conn, tcp_conn_status_t *cstatus)
-{
-	log_msg(LVL_DEBUG, "tcp_uc_status()");
-}
-
-
-/*
- * Arriving segments
- */
-
-/** Segment arrived */
-void tcp_as_segment_arrived(tcp_sockpair_t *sp, tcp_segment_t *seg)
-{
-	tcp_conn_t *conn;
-
-	log_msg(LVL_DEBUG, "tcp_as_segment_arrived()");
-
-	conn = tcp_conn_find(sp);
-	if (conn != NULL && conn->cstate != st_closed) {
-		tcp_conn_segment_arrived(conn, seg);
-	} else {
-		tcp_unexpected_segment(sp, seg);
-	}
-}
-
-/*
- * Timeouts
- */
-
-/** User timeout */
-void tcp_to_user(void)
-{
-	log_msg(LVL_DEBUG, "tcp_to_user()");
-}
-
-/**
- * @}
- */
Index: uspace/srv/net/tl/tcp/state.h
===================================================================
--- uspace/srv/net/tl/tcp/state.h	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ 	(revision )
@@ -1,64 +1,0 @@
-/*
- * Copyright (c) 2011 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 tcp
- * @{
- */
-/** @file TCP entry points (close to those defined in the RFC)
- */
-
-#ifndef STATE_H
-#define STATE_H
-
-#include <sys/types.h>
-#include "tcp_type.h"
-
-/*
- * User calls
- */
-extern tcp_error_t tcp_uc_open(uint16_t, tcp_sock_t *, acpass_t, tcp_conn_t **);
-extern tcp_error_t tcp_uc_send(tcp_conn_t *, void *, size_t, xflags_t);
-extern tcp_error_t tcp_uc_receive(tcp_conn_t *, void *, size_t, size_t *, xflags_t *);
-extern tcp_error_t tcp_uc_close(tcp_conn_t *);
-extern void tcp_uc_abort(tcp_conn_t *);
-extern void tcp_uc_status(tcp_conn_t *, tcp_conn_status_t *);
-
-/*
- * Arriving segments
- */
-extern void tcp_as_segment_arrived(tcp_sockpair_t *, tcp_segment_t *);
-
-/*
- * Timeouts
- */
-extern void tcp_to_user(void);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -52,6 +52,6 @@
 #include <packet_remote.h>
 
-#include "header.h"
 #include "ncsim.h"
+#include "pdu.h"
 #include "rqueue.h"
 #include "std.h"
Index: uspace/srv/net/tl/tcp/test.c
===================================================================
--- uspace/srv/net/tl/tcp/test.c	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ uspace/srv/net/tl/tcp/test.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -40,6 +40,6 @@
 #include <thread.h>
 #include <str.h>
-#include "state.h"
 #include "tcp_type.h"
+#include "ucall.h"
 
 #include "test.h"
Index: uspace/srv/net/tl/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.c	(revision 1812a0d8ca8948aa748d1e907a5241e37971f92c)
+++ uspace/srv/net/tl/tcp/tqueue.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -44,6 +44,6 @@
 #include <stdlib.h>
 #include "conn.h"
-#include "header.h"
 #include "ncsim.h"
+#include "pdu.h"
 #include "rqueue.h"
 #include "segment.h"
Index: uspace/srv/net/tl/tcp/ucall.c
===================================================================
--- uspace/srv/net/tl/tcp/ucall.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
+++ uspace/srv/net/tl/tcp/ucall.c	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP entry points (close to those defined in the RFC)
+ */
+
+#include <fibril_synch.h>
+#include <io/log.h>
+#include <macros.h>
+#include <mem.h>
+#include "conn.h"
+#include "tcp_type.h"
+#include "tqueue.h"
+#include "ucall.h"
+
+/*
+ * User calls
+ */
+
+/** OPEN user call
+ *
+ * @param lport		Local port
+ * @param fsock		Foreign socket
+ * @param acpass	Active/passive
+ * @param conn		Connection
+ *
+ * XXX We should be able to call active open on an existing listening
+ * connection.
+ */
+tcp_error_t tcp_uc_open(uint16_t lport, tcp_sock_t *fsock, acpass_t acpass,
+    tcp_conn_t **conn)
+{
+	tcp_conn_t *nconn;
+	tcp_sock_t lsock;
+
+	log_msg(LVL_DEBUG, "tcp_uc_open(%" PRIu16 ", %p, %s, %p)",
+	    lport, fsock, acpass == ap_active ? "active" : "passive",
+	    conn);
+
+	lsock.port = lport;
+	lsock.addr.ipv4 = 0x7f000001;
+
+	nconn = tcp_conn_new(&lsock, fsock);
+	tcp_conn_add(nconn);
+
+	if (acpass == ap_active) {
+		/* Synchronize (initiate) connection */
+		tcp_conn_sync(nconn);
+
+		/* Wait for connection to be established or reset */
+		log_msg(LVL_DEBUG, "tcp_uc_open: Wait for connection.");
+		fibril_mutex_lock(&nconn->cstate_lock);
+		while (nconn->cstate == st_syn_sent ||
+		    nconn->cstate == st_syn_received) {
+			fibril_condvar_wait(&nconn->cstate_cv, &nconn->cstate_lock);
+		}
+		if (nconn->cstate != st_established) {
+			log_msg(LVL_DEBUG, "tcp_uc_open: Connection was reset.");
+			assert(nconn->cstate == st_closed);
+			fibril_mutex_unlock(&nconn->cstate_lock);
+			return TCP_ERESET;
+		}
+		fibril_mutex_unlock(&nconn->cstate_lock);
+		log_msg(LVL_DEBUG, "tcp_uc_open: Connection was established.");
+	}
+
+	*conn = nconn;
+	return TCP_EOK;
+}
+
+/** SEND user call */
+tcp_error_t tcp_uc_send(tcp_conn_t *conn, void *data, size_t size,
+    xflags_t flags)
+{
+	size_t buf_free;
+	size_t xfer_size;
+
+	log_msg(LVL_DEBUG, "tcp_uc_send()");
+
+	if (conn->cstate == st_closed)
+		return TCP_ENOTEXIST;
+
+	if (conn->cstate == st_listen) {
+		/* Change connection to active */
+		tcp_conn_sync(conn);
+	}
+
+	if (conn->snd_buf_fin)
+		return TCP_ECLOSING;
+
+	while (size > 0) {
+		buf_free = conn->snd_buf_size - conn->snd_buf_used;
+		while (buf_free == 0)
+			tcp_tqueue_new_data(conn);
+
+		xfer_size = min(size, buf_free);
+
+		/* Copy data to buffer */
+		memcpy(conn->snd_buf + conn->snd_buf_used, data, xfer_size);
+		data += xfer_size;
+		conn->snd_buf_used += xfer_size;
+		size -= xfer_size;
+	}
+
+	tcp_tqueue_new_data(conn);
+
+	return TCP_EOK;
+}
+
+/** RECEIVE user call */
+tcp_error_t tcp_uc_receive(tcp_conn_t *conn, void *buf, size_t size,
+    size_t *rcvd, xflags_t *xflags)
+{
+	size_t xfer_size;
+
+	log_msg(LVL_DEBUG, "tcp_uc_receive()");
+
+	if (conn->cstate == st_closed)
+		return TCP_ENOTEXIST;
+
+	fibril_mutex_lock(&conn->rcv_buf_lock);
+
+	/* Wait for data to become available */
+	while (conn->rcv_buf_used == 0 && !conn->rcv_buf_fin) {
+		log_msg(LVL_DEBUG, "tcp_uc_receive() - wait for data");
+		fibril_condvar_wait(&conn->rcv_buf_cv, &conn->rcv_buf_lock);
+	}
+
+	if (conn->rcv_buf_used == 0) {
+		/* End of data, peer closed connection. */
+		assert(conn->rcv_buf_fin);
+		*rcvd = 0;
+		*xflags = 0;
+		return TCP_ECLOSING;
+	}
+
+	/* Copy data from receive buffer to user buffer */
+	xfer_size = min(size, conn->rcv_buf_used);
+	memcpy(buf, conn->rcv_buf, xfer_size);
+	*rcvd = xfer_size;
+
+	/* Remove data from receive buffer */
+	memmove(conn->rcv_buf, conn->rcv_buf + xfer_size, conn->rcv_buf_used -
+	    xfer_size);
+	conn->rcv_buf_used -= xfer_size;
+	conn->rcv_wnd += xfer_size;
+
+	fibril_mutex_unlock(&conn->rcv_buf_lock);
+
+	/* TODO */
+	*xflags = 0;
+
+	/* Send new size of receive window */
+	tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+
+	log_msg(LVL_DEBUG, "tcp_uc_receive() - returning %zu bytes",
+	    xfer_size);
+
+	return TCP_EOK;
+}
+
+/** CLOSE user call */
+tcp_error_t tcp_uc_close(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_close()");
+
+	if (conn->cstate == st_closed)
+		return TCP_ENOTEXIST;
+
+	if (conn->snd_buf_fin)
+		return TCP_ECLOSING;
+
+	conn->snd_buf_fin = true;
+	tcp_tqueue_new_data(conn);
+
+	return TCP_EOK;
+}
+
+/** ABORT user call */
+void tcp_uc_abort(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_abort()");
+}
+
+/** STATUS user call */
+void tcp_uc_status(tcp_conn_t *conn, tcp_conn_status_t *cstatus)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_status()");
+}
+
+
+/*
+ * Arriving segments
+ */
+
+/** Segment arrived */
+void tcp_as_segment_arrived(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_conn_t *conn;
+
+	log_msg(LVL_DEBUG, "tcp_as_segment_arrived()");
+
+	conn = tcp_conn_find(sp);
+	if (conn != NULL && conn->cstate != st_closed) {
+		tcp_conn_segment_arrived(conn, seg);
+	} else {
+		tcp_unexpected_segment(sp, seg);
+	}
+}
+
+/*
+ * Timeouts
+ */
+
+/** User timeout */
+void tcp_to_user(void)
+{
+	log_msg(LVL_DEBUG, "tcp_to_user()");
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/ucall.h
===================================================================
--- uspace/srv/net/tl/tcp/ucall.h	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
+++ uspace/srv/net/tl/tcp/ucall.h	(revision 762b48a762b5d5cea87fa88f4df171dc2f08c45e)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP user calls (close to those defined in the RFC)
+ */
+
+#ifndef UCALL_H
+#define UCALL_H
+
+#include <sys/types.h>
+#include "tcp_type.h"
+
+/*
+ * User calls
+ */
+extern tcp_error_t tcp_uc_open(uint16_t, tcp_sock_t *, acpass_t, tcp_conn_t **);
+extern tcp_error_t tcp_uc_send(tcp_conn_t *, void *, size_t, xflags_t);
+extern tcp_error_t tcp_uc_receive(tcp_conn_t *, void *, size_t, size_t *, xflags_t *);
+extern tcp_error_t tcp_uc_close(tcp_conn_t *);
+extern void tcp_uc_abort(tcp_conn_t *);
+extern void tcp_uc_status(tcp_conn_t *, tcp_conn_status_t *);
+
+/*
+ * Arriving segments
+ */
+extern void tcp_as_segment_arrived(tcp_sockpair_t *, tcp_segment_t *);
+
+/*
+ * Timeouts
+ */
+extern void tcp_to_user(void);
+
+#endif
+
+/** @}
+ */
