Index: uspace/srv/net/udp/Makefile
===================================================================
--- uspace/srv/net/udp/Makefile	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ uspace/srv/net/udp/Makefile	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -28,6 +28,4 @@
 
 USPACE_PREFIX = ../../..
-LIBS = $(LIBNET_PREFIX)/libnet.a
-EXTRA_CFLAGS = -I$(LIBNET_PREFIX)/include
 BINARY = udp
 
@@ -35,6 +33,6 @@
 	assoc.c \
 	msg.c \
-	sock.c \
 	pdu.c \
+	service.c \
 	ucall.c \
 	udp.c \
Index: uspace/srv/net/udp/assoc.c
===================================================================
--- uspace/srv/net/udp/assoc.c	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ uspace/srv/net/udp/assoc.c	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -36,4 +36,5 @@
 
 #include <adt/list.h>
+#include <errno.h>
 #include <stdbool.h>
 #include <fibril_synch.h>
@@ -62,5 +63,6 @@
  * @return		New association or NULL
  */
-udp_assoc_t *udp_assoc_new(udp_sock_t *lsock, udp_sock_t *fsock)
+udp_assoc_t *udp_assoc_new(udp_sock_t *lsock, udp_sock_t *fsock,
+    udp_assoc_cb_t *cb, void *cb_arg)
 {
 	udp_assoc_t *assoc = NULL;
@@ -82,8 +84,10 @@
 	if (lsock != NULL)
 		assoc->ident.local = *lsock;
-	
+
 	if (fsock != NULL)
 		assoc->ident.foreign = *fsock;
 
+	assoc->cb = cb;
+	assoc->cb_arg = cb_arg;
 	return assoc;
 error:
@@ -258,5 +262,5 @@
 	int rc;
 
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send(%p, %p, %p)",
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_send(%p, %p, %p)",
 	    assoc, fsock, msg);
 
@@ -266,12 +270,23 @@
 		sp.foreign = *fsock;
 
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_send - check addr any");
+
 	if ((inet_addr_is_any(&sp.foreign.addr)) ||
 	    (sp.foreign.port == UDP_PORT_ANY))
 		return EINVAL;
 
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_send - check version");
+
+	if (sp.foreign.addr.version != sp.local.addr.version)
+		return EINVAL;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_send - encode pdu");
+
 	rc = udp_pdu_encode(&sp, msg, &pdu);
 	if (rc != EOK)
 		return ENOMEM;
 
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_send - transmit");
+
 	rc = udp_transmit_pdu(pdu);
 	udp_pdu_delete(pdu);
@@ -280,4 +295,5 @@
 		return EIO;
 
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_send - success");
 	return EOK;
 }
@@ -292,5 +308,5 @@
 	udp_rcv_queue_entry_t *rqe;
 
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv()");
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_recv()");
 
 	fibril_mutex_lock(&assoc->lock);
@@ -303,8 +319,8 @@
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - association was reset");
 		fibril_mutex_unlock(&assoc->lock);
-		return ECONNABORTED;
+		return ENXIO;
 	}
 
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - got a message");
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_recv() - got a message");
 	link = list_first(&assoc->rcv_queue);
 	rqe = list_get_instance(link, udp_rcv_queue_entry_t, link);
@@ -328,9 +344,9 @@
 	int rc;
 
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", rsp, msg);
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_received(%p, %p)", rsp, msg);
 
 	assoc = udp_assoc_find_ref(rsp);
 	if (assoc == NULL) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "No association found. Message dropped.");
+		log_msg(LOG_DEFAULT, LVL_NOTE, "No association found. Message dropped.");
 		/* XXX Generate ICMP error. */
 		/* XXX Might propagate error directly by error return. */
@@ -339,9 +355,14 @@
 	}
 
-	rc = udp_assoc_queue_msg(assoc, rsp, msg);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "Out of memory. Message dropped.");
+	if (0) {
+		rc = udp_assoc_queue_msg(assoc, rsp, msg);
+		if (rc != EOK) {
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Out of memory. Message dropped.");
 		/* XXX Generate ICMP error? */
+		}
 	}
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "call assoc->cb->recv_msg");
+	assoc->cb->recv_msg(assoc->cb_arg, rsp, msg);
 }
 
@@ -387,6 +408,13 @@
 static bool udp_socket_match(udp_sock_t *sock, udp_sock_t *patt)
 {
-	log_msg(LOG_DEFAULT, LVL_DEBUG,
-	    "udp_socket_match(sock=(%u), pat=(%u))", sock->port, patt->port);
+	char *sa, *pa;
+
+	sa = pa = (char *)"?";
+	(void) inet_addr_format(&sock->addr, &sa);
+	(void) inet_addr_format(&patt->addr, &pa);
+
+	log_msg(LOG_DEFAULT, LVL_NOTE,
+	    "udp_socket_match(sock=(%s,%u), pat=(%s,%u))",
+	    sa, sock->port, pa, patt->port);
 	
 	if ((!inet_addr_is_any(&patt->addr)) &&
@@ -394,9 +422,11 @@
 		return false;
 	
+	log_msg(LOG_DEFAULT, LVL_NOTE, "addr OK");
+	
 	if ((patt->port != UDP_PORT_ANY) &&
 	    (patt->port != sock->port))
 		return false;
 	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, " -> match");
+	log_msg(LOG_DEFAULT, LVL_NOTE, " -> match");
 	
 	return true;
@@ -430,14 +460,26 @@
 static udp_assoc_t *udp_assoc_find_ref(udp_sockpair_t *sp)
 {
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_find_ref(%p)", sp);
+	char *la, *ra;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_find_ref(%p)", sp);
 	
 	fibril_mutex_lock(&assoc_list_lock);
 	
+	log_msg(LOG_DEFAULT, LVL_NOTE, "associations:");
 	list_foreach(assoc_list, link, udp_assoc_t, assoc) {
 		udp_sockpair_t *asp = &assoc->ident;
 		
+		la = ra = NULL;
+
+		(void) inet_addr_format(&asp->local.addr, &la);
+		(void) inet_addr_format(&asp->foreign.addr, &ra);
+
+		log_msg(LOG_DEFAULT, LVL_NOTE, "find_ref:asp=%p la=%s ra=%s",
+		    asp, la, ra);
 		/* Skip unbound associations */
-		if (asp->local.port == UDP_PORT_ANY)
+		if (asp->local.port == UDP_PORT_ANY) {
+			log_msg(LOG_DEFAULT, LVL_NOTE, "skip unbound");
 			continue;
+		}
 		
 		if (udp_sockpair_match(sp, asp)) {
@@ -446,7 +488,10 @@
 			fibril_mutex_unlock(&assoc_list_lock);
 			return assoc;
+		} else {
+			log_msg(LOG_DEFAULT, LVL_NOTE, "not matched");
 		}
 	}
 	
+	log_msg(LOG_DEFAULT, LVL_NOTE, "associations END");
 	fibril_mutex_unlock(&assoc_list_lock);
 	return NULL;
Index: uspace/srv/net/udp/assoc.h
===================================================================
--- uspace/srv/net/udp/assoc.h	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ uspace/srv/net/udp/assoc.h	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -40,5 +40,6 @@
 #include "udp_type.h"
 
-extern udp_assoc_t *udp_assoc_new(udp_sock_t *, udp_sock_t *);
+extern udp_assoc_t *udp_assoc_new(udp_sock_t *, udp_sock_t *, udp_assoc_cb_t *,
+    void *);
 extern void udp_assoc_delete(udp_assoc_t *);
 extern void udp_assoc_add(udp_assoc_t *);
Index: uspace/srv/net/udp/pdu.c
===================================================================
--- uspace/srv/net/udp/pdu.c	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ uspace/srv/net/udp/pdu.c	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -41,5 +41,4 @@
 #include <stdlib.h>
 #include <inet/addr.h>
-#include <net/socket_codes.h>
 #include "msg.h"
 #include "pdu.h"
Index: uspace/srv/net/udp/service.c
===================================================================
--- uspace/srv/net/udp/service.c	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
+++ uspace/srv/net/udp/service.c	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2015 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 udp
+ * @{
+ */
+
+/**
+ * @file HelenOS service implementation
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <inet/endpoint.h>
+#include <io/log.h>
+#include <ipc/services.h>
+#include <ipc/udp.h>
+#include <loc.h>
+#include <macros.h>
+#include <stdlib.h>
+
+#include "assoc.h"
+#include "msg.h"
+#include "service.h"
+#include "udp_type.h"
+
+#define NAME "udp"
+
+#define MAX_MSG_SIZE DATA_XFER_LIMIT
+
+static void udp_cassoc_recv_msg(void *, udp_sockpair_t *, udp_msg_t *);
+
+static udp_assoc_cb_t udp_cassoc_cb = {
+	.recv_msg = udp_cassoc_recv_msg
+};
+
+static int udp_cassoc_queue_msg(udp_cassoc_t *cassoc, udp_sockpair_t *sp,
+    udp_msg_t *msg)
+{
+	udp_crcv_queue_entry_t *rqe;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_cassoc_queue_msg(%p, %p, %p)",
+	    cassoc, sp, msg);
+
+	rqe = calloc(1, sizeof(udp_crcv_queue_entry_t));
+	if (rqe == NULL)
+		return ENOMEM;
+
+	link_initialize(&rqe->link);
+	rqe->sp = *sp;
+	rqe->msg = msg;
+	rqe->cassoc = cassoc;
+
+//	fibril_mutex_lock(&assoc->lock);
+	list_append(&rqe->link, &cassoc->client->crcv_queue);
+//	fibril_mutex_unlock(&assoc->lock);
+
+//	fibril_condvar_broadcast(&assoc->rcv_queue_cv);
+
+	return EOK;
+}
+
+
+static int udp_ev_data(udp_client_t *client)
+{
+	async_exch_t *exch;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_ev_data()");
+
+	exch = async_exchange_begin(client->sess);
+	sysarg_t rc = async_req_0_0(exch, UDP_EV_DATA);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
+static int udp_cassoc_create(udp_client_t *client, udp_assoc_t *assoc,
+    udp_cassoc_t **rcassoc)
+{
+	udp_cassoc_t *cassoc;
+	sysarg_t id;
+
+	cassoc = calloc(1, sizeof(udp_cassoc_t));
+	if (cassoc == NULL)
+		return ENOMEM;
+
+	/* Allocate new ID */
+	id = 0;
+	list_foreach (client->cassoc, lclient, udp_cassoc_t, cassoc) {
+		if (cassoc->id >= id)
+			id = cassoc->id + 1;
+	}
+
+	cassoc->id = id;
+	cassoc->client = client;
+	cassoc->assoc = assoc;
+
+	list_append(&cassoc->lclient, &client->cassoc);
+	*rcassoc = cassoc;
+	return EOK;
+}
+
+static void udp_cassoc_destroy(udp_cassoc_t *cassoc)
+{
+	list_remove(&cassoc->lclient);
+	free(cassoc);
+}
+
+static int udp_cassoc_get(udp_client_t *client, sysarg_t id,
+    udp_cassoc_t **rcassoc)
+{
+	list_foreach (client->cassoc, lclient, udp_cassoc_t, cassoc) {
+		if (cassoc->id == id) {
+			*rcassoc = cassoc;
+			return EOK;
+		}
+	}
+
+	return ENOENT;
+}
+
+static void udp_cassoc_recv_msg(void *arg, udp_sockpair_t *sp, udp_msg_t *msg)
+{
+	udp_cassoc_t *cassoc = (udp_cassoc_t *) arg;
+
+	udp_cassoc_queue_msg(cassoc, sp, msg);
+	udp_ev_data(cassoc->client);
+}
+
+static int udp_assoc_create_impl(udp_client_t *client, inet_ep2_t *epp,
+    sysarg_t *rassoc_id)
+{
+	udp_assoc_t *assoc;
+	udp_cassoc_t *cassoc;
+	udp_sock_t local;
+	udp_sock_t remote;
+	int rc;
+	char *la, *ra;
+
+	local.addr = epp->local.addr;
+	local.port = epp->local.port;
+	remote.addr = epp->remote.addr;
+	remote.port = epp->remote.port;
+
+	la = (char *)"xxx";
+	ra = (char *)"yyy";
+
+	(void) inet_addr_format(&epp->local.addr, &la);
+	(void) inet_addr_format(&epp->remote.addr, &ra);
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_create_impl la=%s ra=%s",
+	    la, ra);
+
+	assoc = udp_assoc_new(&local, &remote, NULL, NULL);
+	if (assoc == NULL)
+		return EIO;
+
+	if (epp->local_link != 0)
+		udp_assoc_set_iplink(assoc, epp->local_link);
+
+	rc = udp_cassoc_create(client, assoc, &cassoc);
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
+		udp_assoc_delete(assoc);
+		return ENOMEM;
+	}
+
+	assoc->cb = &udp_cassoc_cb;
+	assoc->cb_arg = cassoc;
+
+	udp_assoc_add(assoc);
+
+	*rassoc_id = cassoc->id;
+	return EOK;
+}
+
+static int udp_assoc_destroy_impl(udp_client_t *client, sysarg_t assoc_id)
+{
+	udp_cassoc_t *cassoc;
+	int rc;
+
+	rc = udp_cassoc_get(client, assoc_id, &cassoc);
+	if (rc != EOK) {
+		assert(rc == ENOENT);
+		return ENOENT;
+	}
+
+	udp_assoc_remove(cassoc->assoc);
+	udp_assoc_reset(cassoc->assoc);
+	udp_assoc_delete(cassoc->assoc);
+	udp_cassoc_destroy(cassoc);
+	return EOK;
+}
+
+static int udp_assoc_send_msg_impl(udp_client_t *client, sysarg_t assoc_id,
+    inet_ep_t *dest, void *data, size_t size)
+{
+	udp_msg_t msg;
+	udp_sock_t remote;
+	udp_cassoc_t *cassoc;
+	int rc;
+
+	rc = udp_cassoc_get(client, assoc_id, &cassoc);
+	if (rc != EOK)
+		return rc;
+
+	remote.addr = dest->addr;
+	remote.port = dest->port;
+
+	msg.data = data;
+	msg.data_size = size;
+	rc = udp_assoc_send(cassoc->assoc, &remote, &msg);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+static void udp_callback_create_srv(udp_client_t *client, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_callback_create_srv()");
+
+	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (sess == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	client->sess = sess;
+	async_answer_0(iid, EOK);
+}
+
+static void udp_assoc_create_srv(udp_client_t *client, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	inet_ep2_t epp;
+	sysarg_t assoc_id;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_create_srv()");
+
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(inet_ep2_t)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	rc = async_data_write_finalize(callid, &epp, size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	rc = udp_assoc_create_impl(client, &epp, &assoc_id);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	async_answer_1(iid, EOK, assoc_id);
+}
+
+static void udp_assoc_destroy_srv(udp_client_t *client, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	sysarg_t assoc_id;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_destroy_srv()");
+
+	assoc_id = IPC_GET_ARG1(*icall);
+	rc = udp_assoc_destroy_impl(client, assoc_id);
+	async_answer_0(iid, rc);
+}
+
+static void udp_assoc_send_msg_srv(udp_client_t *client, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	inet_ep_t dest;
+	sysarg_t assoc_id;
+	void *data;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send_msg_srv()");
+
+	/* Receive dest */
+
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(inet_ep_t)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	rc = async_data_write_finalize(callid, &dest, size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	/* Receive message data */
+
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size > MAX_MSG_SIZE) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	data = malloc(size);
+	if (data == NULL) {
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(iid, ENOMEM);
+	}
+
+	rc = async_data_write_finalize(callid, data, size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		free(data);
+		return;
+	}
+
+	assoc_id = IPC_GET_ARG1(*icall);
+
+	rc = udp_assoc_send_msg_impl(client, assoc_id, &dest, data, size);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		free(data);
+		return;
+	}
+
+	async_answer_0(iid, EOK);
+	free(data);
+}
+
+static udp_crcv_queue_entry_t *udp_rmsg_get_next(udp_client_t *client)
+{
+	link_t *link;
+
+	link = list_first(&client->crcv_queue);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, udp_crcv_queue_entry_t, link);
+}
+
+static void udp_rmsg_info_srv(udp_client_t *client, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	inet_ep_t ep;
+	udp_crcv_queue_entry_t *enext;
+	sysarg_t assoc_id;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_info_srv()");
+	enext = udp_rmsg_get_next(client);
+
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (enext == NULL) {
+		async_answer_0(callid, ENOENT);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+
+	inet_ep_init(&ep);
+	ep.addr = enext->sp.foreign.addr;
+	ep.port = enext->sp.foreign.port;
+
+	rc = async_data_read_finalize(callid, &ep, max(size, (ssize_t)sizeof(ep)));
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	assoc_id = enext->cassoc->id;
+	size = enext->msg->data_size;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_info_srv(): assoc_id=%zu, "
+	    "size=%zu", assoc_id, size);
+	async_answer_2(iid, EOK, assoc_id, size);
+}
+
+static void udp_rmsg_read_srv(udp_client_t *client, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	ssize_t msg_size;
+	udp_crcv_queue_entry_t *enext;
+	void *data;
+	size_t size;
+	ssize_t off;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_read_srv()");
+	off = IPC_GET_ARG1(*icall);
+
+	enext = udp_rmsg_get_next(client);
+
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (enext == NULL) {
+		async_answer_0(callid, ENOENT);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+
+	data = enext->msg->data + off;
+	msg_size = enext->msg->data_size;
+
+	rc = async_data_read_finalize(callid, data, max(msg_size - off,
+	    (ssize_t)size));
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	async_answer_0(iid, EOK);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_read_srv(): OK");
+}
+
+static void udp_rmsg_discard_srv(udp_client_t *client, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	udp_crcv_queue_entry_t *enext;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_discard_srv()");
+
+	enext = udp_rmsg_get_next(client);
+	if (enext == NULL) {
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+
+	list_remove(&enext->link);
+	udp_msg_delete(enext->msg);
+	async_answer_0(iid, EOK);
+}
+
+static void udp_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	udp_client_t client;
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn()");
+
+	list_initialize(&client.cassoc);
+	list_initialize(&client.crcv_queue);
+
+	while (true) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "udp_client_conn: wait req");
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		sysarg_t method = IPC_GET_IMETHOD(call);
+
+		log_msg(LOG_DEFAULT, LVL_NOTE, "udp_client_conn: method=%d",
+		    (int)method);
+		if (!method) {
+			/* The other side has hung up */
+			async_answer_0(callid, EOK);
+			return;
+		}
+
+		switch (method) {
+		case UDP_CALLBACK_CREATE:
+			udp_callback_create_srv(&client, callid, &call);
+			break;
+		case UDP_ASSOC_CREATE:
+			udp_assoc_create_srv(&client, callid, &call);
+			break;
+		case UDP_ASSOC_DESTROY:
+			udp_assoc_destroy_srv(&client, callid, &call);
+			break;
+		case UDP_ASSOC_SEND_MSG:
+			udp_assoc_send_msg_srv(&client, callid, &call);
+			break;
+		case UDP_RMSG_INFO:
+			udp_rmsg_info_srv(&client, callid, &call);
+			break;
+		case UDP_RMSG_READ:
+			udp_rmsg_read_srv(&client, callid, &call);
+			break;
+		case UDP_RMSG_DISCARD:
+			udp_rmsg_discard_srv(&client, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
+int udp_service_init(void)
+{
+	int rc;
+	service_id_t sid;
+
+	async_set_client_connection(udp_client_conn);
+
+	rc = loc_server_register(NAME);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
+		return EIO;
+	}
+
+	rc = loc_service_register(SERVICE_NAME_UDP, &sid);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service.");
+		return EIO;
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/udp/service.h
===================================================================
--- uspace/srv/net/udp/service.h	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
+++ uspace/srv/net/udp/service.h	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 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 udp
+ * @{
+ */
+/** @file HelenOS service implementation
+ */
+
+#ifndef SERVICE_H
+#define SERVICE_H
+
+extern int udp_service_init(void);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/udp/sock.c
===================================================================
--- uspace/srv/net/udp/sock.c	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ 	(revision )
@@ -1,836 +1,0 @@
-/*
- * Copyright (c) 2008 Lukas Mejdrech
- * Copyright (c) 2013 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 udp
- * @{
- */
-
-/**
- * @file Socket provider
- */
-
-#include <async.h>
-#include <byteorder.h>
-#include <errno.h>
-#include <inet/inet.h>
-#include <io/log.h>
-#include <ipc/services.h>
-#include <ipc/socket.h>
-#include <net/socket.h>
-#include <ns.h>
-
-#include "sock.h"
-#include "std.h"
-#include "udp_type.h"
-#include "ucall.h"
-
-/** Free ports pool start. */
-#define UDP_FREE_PORTS_START		1025
-
-/** Free ports pool end. */
-#define UDP_FREE_PORTS_END		65535
-
-static int last_used_port = UDP_FREE_PORTS_START - 1;
-static socket_ports_t gsock;
-
-static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
-static int udp_sock_recv_fibril(void *arg);
-
-int udp_sock_init(void)
-{
-	socket_ports_initialize(&gsock);
-	
-	async_set_client_connection(udp_sock_connection);
-	
-	int rc = service_register(SERVICE_UDP);
-	if (rc != EOK)
-		return EEXIST;
-	
-	return EOK;
-}
-
-static void udp_free_sock_data(socket_core_t *sock_core)
-{
-	udp_sockdata_t *socket;
-
-	socket = (udp_sockdata_t *)sock_core->specific_data;
-	(void)socket;
-
-	/* XXX We need to force the receive fibril to quit */
-}
-
-static void udp_sock_notify_data(socket_core_t *sock_core)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
-	async_exch_t *exch = async_exchange_begin(sock_core->sess);
-	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t) sock_core->socket_id,
-	    UDP_FRAGMENT_SIZE, 0, 0, 1);
-	async_exchange_end(exch);
-}
-
-static void udp_sock_socket(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	udp_sockdata_t *sock;
-	socket_core_t *sock_core;
-	int sock_id;
-	int rc;
-	ipc_call_t answer;
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_socket()");
-	sock = calloc(1, sizeof(udp_sockdata_t));
-	if (sock == NULL) {
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-
-	fibril_mutex_initialize(&sock->lock);
-	sock->client = client;
-
-	sock->recv_buffer_used = 0;
-	sock->recv_error = UDP_EOK;
-	fibril_mutex_initialize(&sock->recv_buffer_lock);
-	fibril_condvar_initialize(&sock->recv_buffer_cv);
-
-	rc = udp_uc_create(&sock->assoc);
-	if (rc != EOK) {
-		free(sock);
-		async_answer_0(callid, rc);
-		return;
-	}
-
-	sock->recv_fibril = fibril_create(udp_sock_recv_fibril, sock);
-	if (sock->recv_fibril == 0) {
-		udp_uc_destroy(sock->assoc);
-		free(sock);
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-
-	sock_id = SOCKET_GET_SOCKET_ID(call);
-	rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
-	if (rc != EOK) {
-		fibril_destroy(sock->recv_fibril);
-		udp_uc_destroy(sock->assoc);
-		free(sock);
-		async_answer_0(callid, rc);
-		return;
-	}
-
-	fibril_add_ready(sock->recv_fibril);
-
-	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, UDP_FRAGMENT_SIZE);
-	SOCKET_SET_HEADER_SIZE(answer, sizeof(udp_header_t));
-	async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
-	    IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
-}
-
-static void udp_sock_bind(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_bind()");
-	log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
-	
-	struct sockaddr_in6 *addr6 = NULL;
-	size_t addr_len;
-	int rc = async_data_write_accept((void **) &addr6, false, 0, 0, 0, &addr_len);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		return;
-	}
-	
-	if ((addr_len != sizeof(struct sockaddr_in)) &&
-	    (addr_len != sizeof(struct sockaddr_in6))) {
-		async_answer_0(callid, EINVAL);
-		goto out;
-	}
-	
-	struct sockaddr_in *addr = (struct sockaddr_in *) addr6;
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_bind");
-	
-	rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
-	    addr6, addr_len, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
-	    last_used_port);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		goto out;
-	}
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
-	
-	socket_core_t *sock_core = socket_cores_find(&client->sockets,
-	    SOCKET_GET_SOCKET_ID(call));
-	if (sock_core == NULL) {
-		async_answer_0(callid, ENOENT);
-		goto out;
-	}
-	
-	udp_sockdata_t *socket =
-	    (udp_sockdata_t *) sock_core->specific_data;
-	
-	udp_sock_t fsocket;
-	
-	fsocket.port = sock_core->port;
-	
-	switch (addr->sin_family) {
-	case AF_INET:
-		inet_sockaddr_in_addr(addr, &fsocket.addr);
-		break;
-	case AF_INET6:
-		inet_sockaddr_in6_addr(addr6, &fsocket.addr);
-		break;
-	default:
-		async_answer_0(callid, EINVAL);
-		goto out;
-	}
-	
-	udp_error_t urc = udp_uc_set_local(socket->assoc, &fsocket);
-	
-	switch (urc) {
-	case UDP_EOK:
-		rc = EOK;
-		break;
-/*	case TCP_ENOTEXIST:
-		rc = ENOTCONN;
-		break;
-	case TCP_ECLOSING:
-		rc = ENOTCONN;
-		break;
-	case TCP_ERESET:
-		rc = ECONNABORTED;
-		break;*/
-	default:
-		assert(false);
-	}
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
-	async_answer_0(callid, rc);
-	
-out:
-	if (addr6 != NULL)
-		free(addr6);
-}
-
-static void udp_sock_listen(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_listen()");
-	async_answer_0(callid, ENOTSUP);
-}
-
-static void udp_sock_connect(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connect()");
-	async_answer_0(callid, ENOTSUP);
-}
-
-static void udp_sock_accept(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_accept()");
-	async_answer_0(callid, ENOTSUP);
-}
-
-static void udp_sock_sendto(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_send()");
-	
-	uint8_t *buffer = calloc(UDP_FRAGMENT_SIZE, 1);
-	if (buffer == NULL) {
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-	
-	struct sockaddr_in6 *addr6 = NULL;
-	struct sockaddr_in *addr;
-	udp_sock_t fsocket;
-	udp_sock_t *fsocket_ptr;
-	
-	if (IPC_GET_IMETHOD(call) == NET_SOCKET_SENDTO) {
-		size_t addr_len;
-		int rc = async_data_write_accept((void **) &addr6, false,
-		    0, 0, 0, &addr_len);
-		if (rc != EOK) {
-			async_answer_0(callid, rc);
-			goto out;
-		}
-		
-		if ((addr_len != sizeof(struct sockaddr_in)) &&
-		    (addr_len != sizeof(struct sockaddr_in6))) {
-			async_answer_0(callid, EINVAL);
-			goto out;
-		}
-		
-		addr = (struct sockaddr_in *) addr6;
-		
-		switch (addr->sin_family) {
-		case AF_INET:
-			inet_sockaddr_in_addr(addr, &fsocket.addr);
-			break;
-		case AF_INET6:
-			inet_sockaddr_in6_addr(addr6, &fsocket.addr);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-			goto out;
-		}
-		
-		fsocket.port = uint16_t_be2host(addr->sin_port);
-		fsocket_ptr = &fsocket;
-	} else
-		fsocket_ptr = NULL;
-	
-	int socket_id = SOCKET_GET_SOCKET_ID(call);
-	
-	SOCKET_GET_FLAGS(call);
-	
-	socket_core_t *sock_core =
-	    socket_cores_find(&client->sockets, socket_id);
-	if (sock_core == NULL) {
-		async_answer_0(callid, ENOTSOCK);
-		goto out;
-	}
-	
-	udp_sockdata_t *socket =
-	    (udp_sockdata_t *) sock_core->specific_data;
-	
-	if (sock_core->port <= 0) {
-		/* Implicitly bind socket to port */
-		int rc = socket_bind_free_port(&gsock, sock_core,
-		    UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, last_used_port);
-		if (rc != EOK) {
-			async_answer_0(callid, rc);
-			goto out;
-		}
-		
-		assert(sock_core->port > 0);
-		
-		udp_error_t urc = udp_uc_set_local_port(socket->assoc,
-		    sock_core->port);
-		
-		if (urc != UDP_EOK) {
-			// TODO: better error handling
-			async_answer_0(callid, EINTR);
-			goto out;
-		}
-		
-		last_used_port = sock_core->port;
-	}
-	
-	fibril_mutex_lock(&socket->lock);
-	
-	if (inet_addr_is_any(&socket->assoc->ident.local.addr) &&
-		socket->assoc->ident.iplink == 0) {
-		/* Determine local IP address */
-		inet_addr_t loc_addr;
-		inet_addr_t rem_addr;
-		
-		rem_addr = fsocket_ptr ? fsocket.addr :
-		    socket->assoc->ident.foreign.addr;
-		
-		int rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
-		if (rc != EOK) {
-			fibril_mutex_unlock(&socket->lock);
-			async_answer_0(callid, rc);
-			log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_sendto: Failed to "
-			    "determine local address.");
-			goto out;
-		}
-		
-		socket->assoc->ident.local.addr = loc_addr;
-	}
-	
-	assert(socket->assoc != NULL);
-	
-	int fragments = SOCKET_GET_DATA_FRAGMENTS(call);
-	for (int index = 0; index < fragments; index++) {
-		ipc_callid_t wcallid;
-		size_t length;
-		
-		if (!async_data_write_receive(&wcallid, &length)) {
-			fibril_mutex_unlock(&socket->lock);
-			async_answer_0(callid, EINVAL);
-			goto out;
-		}
-		
-		if (length > UDP_FRAGMENT_SIZE)
-			length = UDP_FRAGMENT_SIZE;
-		
-		int rc = async_data_write_finalize(wcallid, buffer, length);
-		if (rc != EOK) {
-			fibril_mutex_unlock(&socket->lock);
-			async_answer_0(callid, rc);
-			goto out;
-		}
-		
-		udp_error_t urc =
-		    udp_uc_send(socket->assoc, fsocket_ptr, buffer, length, 0);
-		
-		switch (urc) {
-		case UDP_EOK:
-			rc = EOK;
-			break;
-		case UDP_ENORES:
-			rc = ENOMEM;
-			break;
-		case UDP_EUNSPEC:
-			rc = EINVAL;
-			break;
-		case UDP_ENOROUTE:
-			rc = EIO;
-			break;
-		default:
-			assert(false);
-		}
-		
-		if (rc != EOK) {
-			fibril_mutex_unlock(&socket->lock);
-			async_answer_0(callid, rc);
-			goto out;
-		}
-	}
-	
-	ipc_call_t answer;
-	
-	IPC_SET_ARG1(answer, 0);
-	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
-	async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
-	    IPC_GET_ARG2(answer));
-	fibril_mutex_unlock(&socket->lock);
-	
-out:
-	if (addr6 != NULL)
-		free(addr6);
-	
-	free(buffer);
-}
-
-static void udp_sock_recvfrom(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
-	
-	int socket_id = SOCKET_GET_SOCKET_ID(call);
-	
-	socket_core_t *sock_core =
-	    socket_cores_find(&client->sockets, socket_id);
-	if (sock_core == NULL) {
-		async_answer_0(callid, ENOTSOCK);
-		return;
-	}
-	
-	udp_sockdata_t *socket =
-	    (udp_sockdata_t *) sock_core->specific_data;
-	
-	fibril_mutex_lock(&socket->lock);
-	
-	if (socket->assoc == NULL) {
-		fibril_mutex_unlock(&socket->lock);
-		async_answer_0(callid, ENOTCONN);
-		return;
-	}
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
-	
-	fibril_mutex_lock(&socket->recv_buffer_lock);
-	
-	while ((socket->recv_buffer_used == 0) &&
-	    (socket->recv_error == UDP_EOK)) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
-		fibril_condvar_wait(&socket->recv_buffer_cv,
-		    &socket->recv_buffer_lock);
-	}
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
-	
-	size_t data_len = socket->recv_buffer_used;
-	udp_error_t urc = socket->recv_error;
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv data_len=%zu", data_len);
-	
-	int rc;
-	
-	switch (urc) {
-	case UDP_EOK:
-		rc = EOK;
-		break;
-/*	case TCP_ENOTEXIST:
-	case TCP_ECLOSING:
-		rc = ENOTCONN;
-		break;
-	case TCP_ERESET:
-		rc = ECONNABORTED;
-		break;*/
-	default:
-		assert(false);
-	}
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
-	
-	if (rc != EOK) {
-		fibril_mutex_unlock(&socket->recv_buffer_lock);
-		fibril_mutex_unlock(&socket->lock);
-		async_answer_0(callid, rc);
-		return;
-	}
-	
-	ipc_callid_t rcallid;
-	size_t addr_size = 0;
-	
-	if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
-		/* Fill address */
-		udp_sock_t *rsock = &socket->recv_fsock;
-		struct sockaddr_in addr;
-		struct sockaddr_in6 addr6;
-		size_t addr_length;
-		
-		uint16_t addr_af = inet_addr_sockaddr_in(&rsock->addr, &addr,
-		    &addr6);
-		
-		switch (addr_af) {
-		case AF_INET:
-			addr.sin_port = host2uint16_t_be(rsock->port);
-			
-			log_msg(LOG_DEFAULT, 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);
-				return;
-			}
-			
-			if (addr_length > sizeof(addr))
-				addr_length = sizeof(addr);
-			
-			addr_size = sizeof(addr);
-			
-			log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
-			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);
-				return;
-			}
-			
-			break;
-		case AF_INET6:
-			addr6.sin6_port = host2uint16_t_be(rsock->port);
-			
-			log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 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);
-				return;
-			}
-			
-			if (addr_length > sizeof(addr6))
-				addr_length = sizeof(addr6);
-			
-			addr_size = sizeof(addr6);
-			
-			log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read finalize");
-			rc = async_data_read_finalize(rcallid, &addr6, addr_length);
-			if (rc != EOK) {
-				fibril_mutex_unlock(&socket->recv_buffer_lock);
-				fibril_mutex_unlock(&socket->lock);
-				async_answer_0(callid, EINVAL);
-				return;
-			}
-			
-			break;
-		default:
-			fibril_mutex_unlock(&socket->recv_buffer_lock);
-			fibril_mutex_unlock(&socket->lock);
-			async_answer_0(callid, EINVAL);
-			return;
-		}
-	}
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
-	
-	size_t length;
-	if (!async_data_read_receive(&rcallid, &length)) {
-		fibril_mutex_unlock(&socket->recv_buffer_lock);
-		fibril_mutex_unlock(&socket->lock);
-		async_answer_0(callid, EINVAL);
-		return;
-	}
-	
-	if (length > data_len)
-		length = data_len;
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
-	
-	rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
-	
-	if ((length < data_len) && (rc == EOK))
-		rc = EOVERFLOW;
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "read_data_length <- %zu", length);
-	
-	ipc_call_t answer;
-	
-	IPC_SET_ARG2(answer, 0);
-	SOCKET_SET_READ_DATA_LENGTH(answer, length);
-	SOCKET_SET_ADDRESS_LENGTH(answer, addr_size);
-	async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
-	    IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
-	
-	socket->recv_buffer_used = 0;
-	
-	fibril_condvar_broadcast(&socket->recv_buffer_cv);
-	fibril_mutex_unlock(&socket->recv_buffer_lock);
-	fibril_mutex_unlock(&socket->lock);
-}
-
-static void udp_sock_close(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
-	int socket_id = SOCKET_GET_SOCKET_ID(call);
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - find core");
-	socket_core_t *sock_core =
-	    socket_cores_find(&client->sockets, socket_id);
-	if (sock_core == NULL) {
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - core not found");
-		async_answer_0(callid, ENOTSOCK);
-		return;
-	}
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - spec data");
-	udp_sockdata_t *socket =
-	    (udp_sockdata_t *) sock_core->specific_data;
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - lock socket");
-	fibril_mutex_lock(&socket->lock);
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - lock socket buffer");
-	fibril_mutex_lock(&socket->recv_buffer_lock);
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_close - set socket->sock_core = NULL");
-	socket->sock_core = NULL;
-	fibril_mutex_unlock(&socket->recv_buffer_lock);
-
-	udp_uc_reset(socket->assoc);
-
-	int rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
-	    udp_free_sock_data);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_close - socket_destroy failed");
-		fibril_mutex_unlock(&socket->lock);
-		async_answer_0(callid, rc);
-		return;
-	}
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_close - broadcast recv_buffer_cv");
-	fibril_condvar_broadcast(&socket->recv_buffer_cv);
-
-	fibril_mutex_unlock(&socket->lock);
-	async_answer_0(callid, EOK);
-}
-
-static void udp_sock_getsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_getsockopt()");
-	async_answer_0(callid, ENOTSUP);
-}
-
-static void udp_sock_setsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_setsockopt)");
-	log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
-	
-	void *data = NULL;
-	size_t data_len;
-	int rc = async_data_write_accept(&data, false, 0, 0, 0, &data_len);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, " - failed accepting data");
-		async_answer_0(callid, rc);
-		return;
-	}
-	
-	sysarg_t opt_level = SOL_SOCKET;
-	sysarg_t opt_name = SOCKET_GET_OPT_NAME(call);
-	
-	if (opt_level != SOL_SOCKET || opt_name != SO_IPLINK ||
-	    data_len != sizeof(service_id_t)) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, " - failed opt_level/name/len");
-		log_msg(LOG_DEFAULT, LVL_DEBUG, " - failed opt_level=%d, "
-		    "opt_name=%d, data_len=%zu", (int)opt_level, (int)opt_name,
-		    data_len);
-		async_answer_0(callid, EINVAL);
-		return;
-	}
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
-	
-	socket_core_t *sock_core = socket_cores_find(&client->sockets,
-	    SOCKET_GET_SOCKET_ID(call));
-	if (sock_core == NULL) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, " - failed getting sock_core");
-		async_answer_0(callid, ENOENT);
-		return;
-	}
-	
-	udp_sockdata_t *socket =
-	    (udp_sockdata_t *) sock_core->specific_data;
-	
-	service_id_t iplink = *(service_id_t *)data;
-	udp_uc_set_iplink(socket->assoc, iplink);
-	
-	log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
-	async_answer_0(callid, EOK);
-}
-
-
-static int udp_sock_recv_fibril(void *arg)
-{
-	udp_sockdata_t *sock = (udp_sockdata_t *)arg;
-	udp_error_t urc;
-	xflags_t xflags;
-	size_t rcvd;
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recv_fibril()");
-
-	fibril_mutex_lock(&sock->recv_buffer_lock);
-
-	while (true) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] wait for rcv buffer empty()");
-		while ((sock->recv_buffer_used != 0) && (sock->sock_core != NULL)) {
-			fibril_condvar_wait(&sock->recv_buffer_cv,
-			    &sock->recv_buffer_lock);
-		}
-
-		fibril_mutex_unlock(&sock->recv_buffer_lock);
-
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] call udp_uc_receive()");
-		urc = udp_uc_receive(sock->assoc, sock->recv_buffer,
-		    UDP_FRAGMENT_SIZE, &rcvd, &xflags, &sock->recv_fsock);
-		fibril_mutex_lock(&sock->recv_buffer_lock);
-		sock->recv_error = urc;
-
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] udp_uc_receive -> %d", urc);
-
-		if (sock->sock_core != NULL)
-			udp_sock_notify_data(sock->sock_core);
-
-		if (urc != UDP_EOK) {
-			log_msg(LOG_DEFAULT, LVL_DEBUG, "[] urc != UDP_EOK, break");
-			fibril_condvar_broadcast(&sock->recv_buffer_cv);
-			fibril_mutex_unlock(&sock->recv_buffer_lock);
-			break;
-		}
-
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] got data - broadcast recv_buffer_cv");
-
-		sock->recv_buffer_used = rcvd;
-		fibril_condvar_broadcast(&sock->recv_buffer_cv);
-	}
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recv_fibril() exited loop");
-	udp_uc_destroy(sock->assoc);
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recv_fibril() terminated");
-
-	return 0;
-}
-
-static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	ipc_callid_t callid;
-	ipc_call_t call;
-	udp_client_t client;
-
-	/* Accept the connection */
-	async_answer_0(iid, EOK);
-
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: begin");
-
-	client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
-	socket_cores_initialize(&client.sockets);
-
-	while (true) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: wait");
-		callid = async_get_call(&call);
-		if (!IPC_GET_IMETHOD(call))
-			break;
-
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: METHOD=%d",
-		    (int)IPC_GET_IMETHOD(call));
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case NET_SOCKET:
-			udp_sock_socket(&client, callid, call);
-			break;
-		case NET_SOCKET_BIND:
-			udp_sock_bind(&client, callid, call);
-			break;
-		case NET_SOCKET_LISTEN:
-			udp_sock_listen(&client, callid, call);
-			break;
-		case NET_SOCKET_CONNECT:
-			udp_sock_connect(&client, callid, call);
-			break;
-		case NET_SOCKET_ACCEPT:
-			udp_sock_accept(&client, callid, call);
-			break;
-		case NET_SOCKET_SEND:
-		case NET_SOCKET_SENDTO:
-			udp_sock_sendto(&client, callid, call);
-			break;
-		case NET_SOCKET_RECV:
-		case NET_SOCKET_RECVFROM:
-			udp_sock_recvfrom(&client, callid, call);
-			break;
-		case NET_SOCKET_CLOSE:
-			udp_sock_close(&client, callid, call);
-			break;
-		case NET_SOCKET_GETSOCKOPT:
-			udp_sock_getsockopt(&client, callid, call);
-			break;
-		case NET_SOCKET_SETSOCKOPT:
-			udp_sock_setsockopt(&client, callid, call);
-			break;
-		default:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-	}
-
-	/* Clean up */
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: Clean up");
-	async_hangup(client.sess);
-	socket_cores_release(NULL, &client.sockets, &gsock, udp_free_sock_data);
-}
-
-/**
- * @}
- */
Index: uspace/srv/net/udp/sock.h
===================================================================
--- uspace/srv/net/udp/sock.h	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * 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 udp
- * @{
- */
-/** @file Socket provider
- */
-
-#ifndef SOCK_H
-#define SOCK_H
-
-#include <async.h>
-
-extern int udp_sock_init(void);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/udp/ucall.c
===================================================================
--- uspace/srv/net/udp/ucall.c	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ uspace/srv/net/udp/ucall.c	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -35,6 +35,8 @@
  */
 
+#include <errno.h>
 #include <io/log.h>
 #include <macros.h>
+#include <mem.h>
 
 #include "assoc.h"
@@ -48,5 +50,5 @@
 
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_create()");
-	nassoc = udp_assoc_new(NULL, NULL);
+	nassoc = udp_assoc_new(NULL, NULL, NULL, NULL);
 	if (nassoc == NULL)
 		return UDP_ENORES;
@@ -125,5 +127,5 @@
 	case EOK:
 		break;
-	case ECONNABORTED:
+	case ENXIO:
 		return UDP_ERESET;
 	default:
Index: uspace/srv/net/udp/udp.c
===================================================================
--- uspace/srv/net/udp/udp.c	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ uspace/srv/net/udp/udp.c	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -41,6 +41,6 @@
 #include <task.h>
 
+#include "service.h"
 #include "udp_inet.h"
-#include "sock.h"
 
 #define NAME       "udp"
@@ -58,7 +58,7 @@
 	}
 
-	rc = udp_sock_init();
+	rc = udp_service_init();
 	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing socket service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing UDP service.");
 		return ENOENT;
 	}
Index: uspace/srv/net/udp/udp_type.h
===================================================================
--- uspace/srv/net/udp/udp_type.h	(revision 071a2c601fac2101a98c133b9823c0326c0f876b)
+++ uspace/srv/net/udp/udp_type.h	(revision fab2746a5541d35bc79cbed917f66153231e4a4b)
@@ -36,8 +36,8 @@
 #define UDP_TYPE_H
 
+#include <async.h>
 #include <fibril.h>
 #include <fibril_synch.h>
 #include <ipc/loc.h>
-#include <socket_core.h>
 #include <sys/types.h>
 #include <inet/addr.h>
@@ -99,7 +99,6 @@
 
 typedef struct {
-	async_sess_t *sess;
-	socket_cores_t sockets;
-} udp_client_t;
+	void (*recv_msg)(void *, udp_sockpair_t *, udp_msg_t *);
+} udp_assoc_cb_t;
 
 /** UDP association
@@ -131,29 +130,11 @@
 	/** Receive queue CV. Broadcast when new datagram is inserted */
 	fibril_condvar_t rcv_queue_cv;
+
+	udp_assoc_cb_t *cb;
+	void *cb_arg;
 } udp_assoc_t;
 
 typedef struct {
 } udp_assoc_status_t;
-
-typedef struct udp_sockdata {
-	/** Lock */
-	fibril_mutex_t lock;
-	/** Socket core */
-	socket_core_t *sock_core;
-	/** Client */
-	udp_client_t *client;
-	/** Connection */
-	udp_assoc_t *assoc;
-	/** User-configured IP link */
-	service_id_t iplink;
-	/** Receiving fibril */
-	fid_t recv_fibril;
-	uint8_t recv_buffer[UDP_FRAGMENT_SIZE];
-	size_t recv_buffer_used;
-	udp_sock_t recv_fsock;
-	fibril_mutex_t recv_buffer_lock;
-	fibril_condvar_t recv_buffer_cv;
-	udp_error_t recv_error;
-} udp_sockdata_t;
 
 typedef struct {
@@ -166,4 +147,34 @@
 } udp_rcv_queue_entry_t;
 
+typedef struct udp_cassoc {
+	/** Association */
+	udp_assoc_t *assoc;
+	/** Association ID for the client */
+	sysarg_t id;
+	/** Client */
+	struct udp_client *client;
+	link_t lclient;
+} udp_cassoc_t;
+
+typedef struct {
+	/** Link to receive queue */
+	link_t link;
+	/** Socket pair */
+	udp_sockpair_t sp;
+	/** Message */
+	udp_msg_t *msg;
+	/** Client association */
+	udp_cassoc_t *cassoc;
+} udp_crcv_queue_entry_t;
+
+typedef struct udp_client {
+	/** Client callback session */
+	async_sess_t *sess;
+	/** Client assocations */
+	list_t cassoc; /* of udp_cassoc_t */
+	/** Client receive queue */
+	list_t crcv_queue;
+} udp_client_t;
+
 #endif
 
