Index: uspace/srv/udp/Makefile
===================================================================
--- uspace/srv/udp/Makefile	(revision 4794417377cbb1cbec100c66f846ee6561928eb2)
+++ uspace/srv/udp/Makefile	(revision ee603c4748782944b7cead483ab765c2c120b05b)
@@ -33,4 +33,5 @@
 
 SOURCES = \
+	assoc.c \
 	msg.c \
 	sock.c \
Index: uspace/srv/udp/assoc.c
===================================================================
--- uspace/srv/udp/assoc.c	(revision ee603c4748782944b7cead483ab765c2c120b05b)
+++ uspace/srv/udp/assoc.c	(revision ee603c4748782944b7cead483ab765c2c120b05b)
@@ -0,0 +1,244 @@
+/*
+ * 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 UDP associations
+ */
+
+#include <adt/list.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <io/log.h>
+#include <stdlib.h>
+
+#include "assoc.h"
+#include "msg.h"
+#include "pdu.h"
+#include "ucall.h"
+#include "udp_inet.h"
+#include "udp_type.h"
+
+LIST_INITIALIZE(assoc_list);
+FIBRIL_MUTEX_INITIALIZE(assoc_list_lock);
+
+/** Create new association structure.
+ *
+ * @param lsock		Local socket (will be deeply copied)
+ * @param fsock		Foreign socket (will be deeply copied)
+ * @return		New association or NULL
+ */
+udp_assoc_t *udp_assoc_new(udp_sock_t *lsock, udp_sock_t *fsock)
+{
+	udp_assoc_t *assoc = NULL;
+
+	/* Allocate connection structure */
+	assoc = calloc(1, sizeof(udp_assoc_t));
+	if (assoc == NULL)
+		goto error;
+
+	fibril_mutex_initialize(&assoc->lock);
+
+	/* One for the user */
+	atomic_set(&assoc->refcnt, 1);
+
+	/* Initialize receive queue */
+	list_initialize(&assoc->rcv_queue);
+	fibril_condvar_initialize(&assoc->rcv_queue_cv);
+
+	if (lsock != NULL)
+		assoc->ident.local = *lsock;
+	if (fsock != NULL)
+		assoc->ident.foreign = *fsock;
+
+	return assoc;
+error:
+	return NULL;
+}
+
+/** Destroy association structure.
+ *
+ * Association structure should be destroyed when the folowing conditions
+ * are met:
+ * (1) user has deleted the association
+ * (2) nobody is holding references to the association
+ *
+ * This happens when @a assoc->refcnt is zero as we count (1)
+ * as an extra reference.
+ *
+ * @param conn		Connection
+ */
+static void udp_assoc_free(udp_assoc_t *assoc)
+{
+	log_msg(LVL_DEBUG, "%s: udp_assoc_free(%p)", assoc->name, assoc);
+
+	while (!list_empty(&assoc->rcv_queue)) {
+		link_t *link = list_first(&assoc->rcv_queue);
+//		....;
+		list_remove(link);
+	}
+
+	free(assoc);
+}
+
+/** Add reference to association.
+ *
+ * Increase association reference count by one.
+ *
+ * @param assoc		Association
+ */
+void udp_assoc_addref(udp_assoc_t *assoc)
+{
+	log_msg(LVL_DEBUG, "%s: upd_assoc_addref(%p)", assoc->name, assoc);
+	atomic_inc(&assoc->refcnt);
+}
+
+/** Remove reference from association.
+ *
+ * Decrease association reference count by one.
+ *
+ * @param assoc		Association
+ */
+void udp_assoc_delref(udp_assoc_t *assoc)
+{
+	log_msg(LVL_DEBUG, "%s: udp_assoc_delref(%p)", assoc->name, assoc);
+
+	if (atomic_predec(&assoc->refcnt) == 0)
+		udp_assoc_free(assoc);
+}
+
+/** Delete association.
+ *
+ * The caller promises not make no further references to @a assoc.
+ * UDP will free @a assoc eventually.
+ *
+ * @param assoc		Association
+ */
+void udp_assoc_delete(udp_assoc_t *assoc)
+{
+	log_msg(LVL_DEBUG, "%s: udp_assoc_delete(%p)", assoc->name, assoc);
+
+	assert(assoc->deleted == false);
+	udp_assoc_delref(assoc);
+	assoc->deleted = true;
+}
+
+/** Enlist association.
+ *
+ * Add association to the association map.
+ */
+void udp_assoc_add(udp_assoc_t *assoc)
+{
+	udp_assoc_addref(assoc);
+	fibril_mutex_lock(&assoc_list_lock);
+	list_append(&assoc->link, &assoc_list);
+	fibril_mutex_unlock(&assoc_list_lock);
+}
+
+/** Delist association.
+ *
+ * Remove association from the association map.
+ */
+void udp_assoc_remove(udp_assoc_t *assoc)
+{
+	fibril_mutex_lock(&assoc_list_lock);
+	list_remove(&assoc->link);
+	fibril_mutex_unlock(&assoc_list_lock);
+	udp_assoc_delref(assoc);
+}
+
+/** Set foreign socket in association.
+ *
+ * @param assoc		Association
+ * @param fsock		Foreign socket (deeply copied)
+ */
+void udp_assoc_set_foreign(udp_assoc_t *assoc, udp_sock_t *fsock)
+{
+	log_msg(LVL_DEBUG, "udp_assoc_set_foreign(%p, %p)", assoc, fsock);
+	fibril_mutex_lock(&assoc->lock);
+	assoc->ident.foreign = *fsock;
+	fibril_mutex_unlock(&assoc->lock);
+}
+
+/** Set local socket in association.
+ *
+ * @param assoc		Association
+ * @param fsock		Foreign socket (deeply copied)
+ */
+void udp_assoc_set_local(udp_assoc_t *assoc, udp_sock_t *lsock)
+{
+	log_msg(LVL_DEBUG, "udp_assoc_set_local(%p, %p)", assoc, lsock);
+	fibril_mutex_lock(&assoc->lock);
+	assoc->ident.local = *lsock;
+	fibril_mutex_unlock(&assoc->lock);
+}
+
+/** Send message to association.
+ *
+ * @param assoc		Association
+ * @param fsock		Foreign socket or NULL not to override @a assoc
+ * @param msg		Message
+ *
+ * @return		EOK on success
+ *			EINVAL if foreign socket is not set
+ *			ENOMEM if out of resources
+ *			EIO if no route to destination exists
+ */
+int udp_assoc_send(udp_assoc_t *assoc, udp_sock_t *fsock, udp_msg_t *msg)
+{
+	udp_pdu_t *pdu;
+	udp_sockpair_t sp;
+	int rc;
+
+	/* @a fsock can be used to override the foreign socket */
+	sp = assoc->ident;
+	if (fsock != NULL)
+		sp.foreign = *fsock;
+
+	if (sp.foreign.addr.ipv4 == 0 || sp.foreign.port == 0)
+		return EINVAL;
+
+	rc = udp_pdu_encode(&sp, msg, &pdu);
+	if (rc != EOK)
+		return ENOMEM;
+
+	rc = udp_transmit_pdu(pdu);
+	if (rc != EOK)
+		return EIO;
+
+	udp_pdu_delete(pdu);
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/udp/assoc.h
===================================================================
--- uspace/srv/udp/assoc.h	(revision ee603c4748782944b7cead483ab765c2c120b05b)
+++ uspace/srv/udp/assoc.h	(revision ee603c4748782944b7cead483ab765c2c120b05b)
@@ -0,0 +1,54 @@
+/*
+ * 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 UDP associations
+ */
+
+#ifndef ASSOC_H
+#define ASSOC_H
+
+#include <sys/types.h>
+#include "udp_type.h"
+
+extern udp_assoc_t *udp_assoc_new(udp_sock_t *, udp_sock_t *);
+extern void udp_assoc_delete(udp_assoc_t *);
+extern void udp_assoc_add(udp_assoc_t *);
+extern void udp_assoc_remove(udp_assoc_t *);
+extern void udp_assoc_addref(udp_assoc_t *);
+extern void udp_assoc_delref(udp_assoc_t *);
+extern void udp_assoc_set_foreign(udp_assoc_t *, udp_sock_t *);
+extern void udp_assoc_set_local(udp_assoc_t *, udp_sock_t *);
+extern int udp_assoc_send(udp_assoc_t *, udp_sock_t *, udp_msg_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/udp/ucall.c
===================================================================
--- uspace/srv/udp/ucall.c	(revision 4794417377cbb1cbec100c66f846ee6561928eb2)
+++ uspace/srv/udp/ucall.c	(revision ee603c4748782944b7cead483ab765c2c120b05b)
@@ -37,5 +37,5 @@
 #include <io/log.h>
 
-//#include "conn.h"
+#include "assoc.h"
 #include "udp_type.h"
 #include "ucall.h"
@@ -43,8 +43,13 @@
 udp_error_t udp_uc_create(udp_assoc_t **assoc)
 {
-//	udo_assoc_t *nassoc;
+	udp_assoc_t *nassoc;
 
 	log_msg(LVL_DEBUG, "udp_uc_create()");
+	nassoc = udp_assoc_new(NULL, NULL);
+	if (nassoc == NULL)
+		return UDP_ENORES;
 
+	udp_assoc_add(nassoc);
+	*assoc = nassoc;
 	return UDP_EOK;
 }
@@ -52,8 +57,7 @@
 udp_error_t udp_uc_set_foreign(udp_assoc_t *assoc, udp_sock_t *fsock)
 {
-//	udo_assoc_t *nconn;
-
 	log_msg(LVL_DEBUG, "udp_uc_set_foreign(%p, %p)", assoc, fsock);
 
+	udp_assoc_set_foreign(assoc, fsock);
 	return UDP_EOK;
 }
@@ -61,8 +65,7 @@
 udp_error_t udp_uc_set_local(udp_assoc_t *assoc, udp_sock_t *lsock)
 {
-//	udo_assoc_t *nconn;
-
 	log_msg(LVL_DEBUG, "udp_uc_set_local(%p, %p)", assoc, lsock);
 
+	udp_assoc_set_local(assoc, lsock);
 	return UDP_EOK;
 }
@@ -71,5 +74,21 @@
     size_t size, xflags_t flags)
 {
+	int rc;
+	udp_msg_t msg;
+
 	log_msg(LVL_DEBUG, "%s: udp_uc_send()", assoc->name);
+
+	msg.data = data;
+	msg.data_size = size;
+
+	rc = udp_assoc_send(assoc, fsock, &msg);
+	switch (rc) {
+	case ENOMEM:
+		return UDP_ENORES;
+	case EINVAL:
+		return UDP_EUNSPEC;
+	case EIO:
+		return UDP_ENOROUTE;
+	}
 	return UDP_EOK;
 }
@@ -92,6 +111,7 @@
 void udp_uc_destroy(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "udp_uc_delete()");
-//	udp_assoc_destroy(assoc);
+	log_msg(LVL_DEBUG, "udp_uc_destroy()");
+	udp_assoc_remove(assoc);
+	udp_assoc_delete(assoc);
 }
 
Index: uspace/srv/udp/udp_inet.c
===================================================================
--- uspace/srv/udp/udp_inet.c	(revision 4794417377cbb1cbec100c66f846ee6561928eb2)
+++ uspace/srv/udp/udp_inet.c	(revision ee603c4748782944b7cead483ab765c2c120b05b)
@@ -43,10 +43,7 @@
 #include <task.h>
 
-/*
-#include "pdu.h"
-#include "rqueue.h"
-*/
 #include "std.h"
 #include "udp_inet.h"
+#include "udp_type.h"
 
 static int udp_inet_ev_recv(inet_dgram_t *dgram);
@@ -123,33 +120,22 @@
 
 /** Transmit PDU over network layer. */
-/*void tcp_transmit_pdu(tcp_pdu_t *pdu)
+int udp_transmit_pdu(udp_pdu_t *pdu)
 {
 	int rc;
-	uint8_t *pdu_raw;
-	size_t pdu_raw_size;
 	inet_dgram_t dgram;
 
-	pdu_raw_size = pdu->header_size + pdu->text_size;
-	pdu_raw = malloc(pdu_raw_size);
-	if (pdu_raw == NULL) {
-		log_msg(LVL_ERROR, "Failed to transmit PDU. Out of memory.");
-		return;
-	}
-
-	memcpy(pdu_raw, pdu->header, pdu->header_size);
-	memcpy(pdu_raw + pdu->header_size, pdu->text,
-	    pdu->text_size);
-
-	dgram.src.ipv4 = pdu->src_addr.ipv4;
-	dgram.dest.ipv4 = pdu->dest_addr.ipv4;
+	dgram.src.ipv4 = pdu->src.ipv4;
+	dgram.dest.ipv4 = pdu->dest.ipv4;
 	dgram.tos = 0;
-	dgram.data = pdu_raw;
-	dgram.size = pdu_raw_size;
+	dgram.data = pdu->data;
+	dgram.size = pdu->data_size;
 
 	rc = inet_send(&dgram, INET_TTL_MAX, 0);
 	if (rc != EOK)
 		log_msg(LVL_ERROR, "Failed to transmit PDU.");
+
+	return rc;
 }
-*/
+
 /** Process received PDU. */
 /*
Index: uspace/srv/udp/udp_inet.h
===================================================================
--- uspace/srv/udp/udp_inet.h	(revision 4794417377cbb1cbec100c66f846ee6561928eb2)
+++ uspace/srv/udp/udp_inet.h	(revision ee603c4748782944b7cead483ab765c2c120b05b)
@@ -36,5 +36,8 @@
 #define UDP_INET_H
 
+#include "udp_type.h"
+
 extern int udp_inet_init(void);
+extern int udp_transmit_pdu(udp_pdu_t *);
 
 #endif
Index: uspace/srv/udp/udp_type.h
===================================================================
--- uspace/srv/udp/udp_type.h	(revision 4794417377cbb1cbec100c66f846ee6561928eb2)
+++ uspace/srv/udp/udp_type.h	(revision ee603c4748782944b7cead483ab765c2c120b05b)
@@ -41,5 +41,11 @@
 
 typedef enum {
-	UDP_EOK
+	UDP_EOK,
+	/* Insufficient resources */
+	UDP_ENORES,
+	/* Foreign socket unspecified */
+	UDP_EUNSPEC,
+	/* No route to destination */
+	UDP_ENOROUTE
 } udp_error_t;
 
@@ -92,7 +98,29 @@
 } udp_client_t;
 
+/** UDP association
+ *
+ * This is a rough equivalent of a TCP connection endpoint. It allows
+ * sending and receiving UDP datagrams and it is uniquely identified
+ * by a socket pair.
+ */
 typedef struct {
 	char *name;
+	link_t link;
+
+	/** Association identification (local and foreign socket) */
 	udp_sockpair_t ident;
+
+	/** True if association was deleted by user */
+	bool deleted;
+
+	/** Protects access to association structure */
+	fibril_mutex_t lock;
+	/** Reference count */
+	atomic_t refcnt;
+
+	/** Receive queue */
+	list_t rcv_queue;
+	/** Receive queue CV. Broadcast when new datagram is inserted */
+	fibril_condvar_t rcv_queue_cv;
 } udp_assoc_t;
 
