Index: uspace/srv/net/tl/tcp/sock.c
===================================================================
--- uspace/srv/net/tl/tcp/sock.c	(revision 23fe06c6026eaa4e768598be5751426f4a2a8ceb)
+++ uspace/srv/net/tl/tcp/sock.c	(revision 26ec91c2700ad1e6c97200450d94524ff4e27463)
@@ -553,5 +553,9 @@
 	socket_core_t *sock_core;
 	tcp_sockdata_t *socket;
+	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()");
@@ -565,6 +569,15 @@
 
 	socket = (tcp_sockdata_t *)sock_core->specific_data;
-	(void) socket;
-	/* XXX Close */
+	rc = tcp_uc_close(socket->conn);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		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);
 
 	rc = socket_destroy(net_sess, socket_id, &client->sockets, &gsock,
Index: uspace/srv/net/tl/tcp/ucall.c
===================================================================
--- uspace/srv/net/tl/tcp/ucall.c	(revision 23fe06c6026eaa4e768598be5751426f4a2a8ceb)
+++ uspace/srv/net/tl/tcp/ucall.c	(revision 26ec91c2700ad1e6c97200450d94524ff4e27463)
@@ -91,4 +91,6 @@
 
 	if (nconn->cstate != st_established) {
+		fibril_mutex_unlock(&nconn->cstate_lock);
+
 		log_msg(LVL_DEBUG, "tcp_uc_open: Connection was reset.");
 		assert(nconn->cstate == st_closed);
@@ -163,4 +165,6 @@
 
 	if (conn->rcv_buf_used == 0) {
+		fibril_mutex_unlock(&conn->rcv_buf_lock);
+
 		/* End of data, peer closed connection. */
 		assert(conn->rcv_buf_fin);
