Index: uspace/srv/net/tl/tcp/state.c
===================================================================
--- uspace/srv/net/tl/tcp/state.c	(revision 4f3f62855fb8ab97bb5a2ce3c7cf2d7175e81f34)
+++ uspace/srv/net/tl/tcp/state.c	(revision 854e79a6ed3807edf8743a2e61951ca2086df2c8)
@@ -54,4 +54,7 @@
  * @param acpass	Active/passive
  * @param conn		Connection
+ *
+ * XXX We should be able to call active open on an existing listening
+ * connection.
  */
 void tcp_uc_open(uint16_t lport, tcp_sock_t *fsock, acpass_t acpass,
@@ -80,5 +83,6 @@
 
 /** SEND user call */
-void tcp_uc_send(tcp_conn_t *conn, void *data, size_t size, xflags_t flags)
+tcp_error_t tcp_uc_send(tcp_conn_t *conn, void *data, size_t size,
+    xflags_t flags)
 {
 	size_t buf_free;
@@ -86,4 +90,15 @@
 
 	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) {
@@ -102,9 +117,11 @@
 
 	tcp_tqueue_new_data(conn);
+
+	return TCP_EOK;
 }
 
 /** RECEIVE user call */
-void tcp_uc_receive(tcp_conn_t *conn, void *buf, size_t size, size_t *rcvd,
-    xflags_t *xflags)
+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;
@@ -112,11 +129,6 @@
 	log_msg(LVL_DEBUG, "tcp_uc_receive()");
 
-	/*
-	 * XXX Handle all states for all user calls properly, return
-	 * errors as appropriate.
-	 */
 	if (conn->cstate == st_closed)
-		return;
-
+		return TCP_ENOTEXIST;
 
 	fibril_mutex_lock(&conn->rcv_buf_lock);
@@ -130,9 +142,8 @@
 	if (conn->rcv_buf_used == 0) {
 		/* End of data, peer closed connection. */
-		/* XXX How should RECEIVE signal end of data? */
 		assert(conn->rcv_buf_fin);
 		*rcvd = 0;
 		*xflags = 0;
-		return;
+		return TCP_ECLOSING;
 	}
 
@@ -158,13 +169,23 @@
 	log_msg(LVL_DEBUG, "tcp_uc_receive() - returning %zu bytes",
 	    xfer_size);
+
+	return TCP_EOK;
 }
 
 /** CLOSE user call */
-void tcp_uc_close(tcp_conn_t *conn)
+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;
 }
 
@@ -211,10 +232,4 @@
 }
 
-/** Retransmission timeout */
-void tcp_to_retransmit(void)
-{
-	log_msg(LVL_DEBUG, "tcp_to_retransmit()");
-}
-
 /**
  * @}
Index: uspace/srv/net/tl/tcp/state.h
===================================================================
--- uspace/srv/net/tl/tcp/state.h	(revision 4f3f62855fb8ab97bb5a2ce3c7cf2d7175e81f34)
+++ uspace/srv/net/tl/tcp/state.h	(revision 854e79a6ed3807edf8743a2e61951ca2086df2c8)
@@ -43,7 +43,7 @@
  */
 extern void tcp_uc_open(uint16_t, tcp_sock_t *, acpass_t, tcp_conn_t **);
-extern void tcp_uc_send(tcp_conn_t *, void *, size_t, xflags_t);
-extern void tcp_uc_receive(tcp_conn_t *, void *, size_t, size_t *, xflags_t *);
-extern void tcp_uc_close(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 *);
@@ -58,5 +58,4 @@
  */
 extern void tcp_to_user(void);
-extern void tcp_to_retransmit(void);
 
 #endif
Index: uspace/srv/net/tl/tcp/tcp_type.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp_type.h	(revision 4f3f62855fb8ab97bb5a2ce3c7cf2d7175e81f34)
+++ uspace/srv/net/tl/tcp/tcp_type.h	(revision 854e79a6ed3807edf8743a2e61951ca2086df2c8)
@@ -68,4 +68,32 @@
 } tcp_cstate_t;
 
+/** Error codes returned by TCP user calls (per the spec). */
+typedef enum {
+	/* OK */
+	TCP_EOK,
+	/* Connection aborted due to user timeout */
+	TCP_EABORTED,
+	/* Connection already exists */
+	TCP_EEXISTS,
+	/* Connection closing */
+	TCP_ECLOSING,
+	/* Connection does not exist */
+	TCP_ENOTEXIST,
+	/* Connection illegal for this process */
+	TCP_EILLEGAL,
+	/* Connection not open */
+	TCP_ENOTOPEN,
+	/* Connection reset */
+	TCP_ERESET,
+	/* Foreign socket unspecified */
+	TCP_EUNSPEC,
+	/* Insufficient resources */
+	TCP_ENORES,
+	/* Precedence not allowed */
+	TCP_EINVPREC,
+	/* Security/compartment not allowed */
+	TCP_EINVCOMP
+} tcp_error_t;
+
 typedef enum {
 	XF_PUSH		= 0x1,
