diff --git a/TODO b/TODO
index 6d454df..fdb42f9 100644
--- a/TODO
+++ b/TODO
@@ -4,6 +4,8 @@ distro/packaging:
            https://bugzilla.redhat.com/show_bug.cgi?id=893015
 
 link/host level:
+ - (issue) review all transport code to deal with errors and memory leaks
+           and make it consistent across
  - (issue) change knet_bench to allow protocol specification per link
  - (issue) review memory locking across
  - (issue) simplify handling of DATA and HOSTINFO code paths in send/recv code
diff --git a/libknet/Makefile.am b/libknet/Makefile.am
index b76a220..de0ce75 100644
--- a/libknet/Makefile.am
+++ b/libknet/Makefile.am
@@ -28,7 +28,6 @@ sources			= \
 			  crypto.c \
 			  handle.c \
 			  host.c \
-			  listener.c \
 			  link.c \
 			  logging.c \
 			  nsscrypto.c \
@@ -58,7 +57,6 @@ noinst_HEADERS		= \
 			  host.h \
 			  internals.h \
 			  link.h \
-			  listener.h \
 			  logging.h \
 			  nsscrypto.h \
 			  onwire.h \
diff --git a/libknet/handle.c b/libknet/handle.c
index fef199c..b3f59c8 100644
--- a/libknet/handle.c
+++ b/libknet/handle.c
@@ -46,9 +46,9 @@ static int _init_locks(knet_handle_t knet_h)
 
 	knet_h->lock_init_done = 1;
 
-	savederrno = pthread_rwlock_init(&knet_h->listener_rwlock, NULL);
+	savederrno = pthread_rwlock_init(&knet_h->fd_tracker_rwlock, NULL);
 	if (savederrno) {
-		log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize listener rwlock: %s",
+		log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize fd_tracker_rwlock rwlock: %s",
 			strerror(savederrno));
 		goto exit_fail;
 	}
@@ -106,7 +106,7 @@ static void _destroy_locks(knet_handle_t knet_h)
 {
 	knet_h->lock_init_done = 0;
 	pthread_rwlock_destroy(&knet_h->global_rwlock);
-	pthread_rwlock_destroy(&knet_h->listener_rwlock);
+	pthread_rwlock_destroy(&knet_h->fd_tracker_rwlock);
 	pthread_rwlock_destroy(&knet_h->host_rwlock);
 	pthread_mutex_destroy(&knet_h->host_mutex);
 	pthread_cond_destroy(&knet_h->host_cond);
@@ -314,6 +314,8 @@ static int _init_buffers(knet_handle_t knet_h)
 	}
 	memset(knet_h->pmtudbuf_crypt, 0, KNET_DATABUFSIZE_CRYPT);
 
+	memset(knet_h->knet_transport_fd_tracker, KNET_MAX_TRANSPORTS, sizeof(knet_h->knet_transport_fd_tracker));
+
 	return 0;
 
 exit_fail:
@@ -460,10 +462,9 @@ static int _start_transports(knet_handle_t knet_h)
 				knet_h->transport_ops[i] = get_sctp_transport();
 				break;
 		}
-		if ((knet_h->transport_ops[i]) &&
-		    (knet_h->transport_ops[i]->handle_allocate)) {
-			knet_h->transport_ops[i]->handle_allocate(knet_h, &knet_h->transports[i]);
-			if (!knet_h->transports[i]) {
+
+		if (knet_h->transport_ops[i]) {
+			if (knet_h->transport_ops[i]->transport_init(knet_h) < 0) {
 				savederrno = errno;
 				log_err(knet_h, KNET_SUB_HANDLE, "Failed to allocate transport handle for %s: %s",
 					knet_h->transport_ops[i]->transport_name,
@@ -479,14 +480,19 @@ out:
 	return err;
 }
 
+#include <stdio.h>
+
 static void _stop_transports(knet_handle_t knet_h)
 {
 	int i;
 
+	for (i=0; i<25; i++) {
+		fprintf(stderr, "OPEN[%d]: %d\n", i, knet_h->knet_transport_fd_tracker[i]);
+	}
+
 	for (i=0; i<KNET_MAX_TRANSPORTS; i++) {
-		if ((knet_h->transport_ops[i]) &&
-		    (knet_h->transport_ops[i]->handle_free)) {
-			knet_h->transport_ops[i]->handle_free(knet_h, knet_h->transports[i]);
+		if (knet_h->transport_ops[i]) {
+			knet_h->transport_ops[i]->transport_free(knet_h);
 		}
 	}
 }
diff --git a/libknet/internals.h b/libknet/internals.h
index 4784c21..8b556ba 100644
--- a/libknet/internals.h
+++ b/libknet/internals.h
@@ -31,12 +31,6 @@ typedef void *knet_transport_link_t; /* per link transport handle */
 typedef void *knet_transport_t;      /* per knet_h transport handle */
 struct  knet_transport_ops;          /* Forward because of circular dependancy */
 
-struct knet_listener {
-	int sock;
-	struct sockaddr_storage address;
-	struct knet_listener *next;
-};
-
 struct knet_link {
 	/* required */
 	struct sockaddr_storage src_addr;
@@ -53,9 +47,8 @@ struct knet_link {
 	/* internals */
 	uint8_t link_id;
 	uint8_t transport_type;                 /* #defined constant from API */
-	knet_transport_link_t transport;
+	knet_transport_link_t transport_link;   /* link_info_t from transport */
 	int outsock;
-	int listener_sock;
 	unsigned int configured:1;		/* set to 1 if src/dst have been configured */
 	unsigned int remoteconnected:1;		/* link is enabled for data (peer view) */
 	unsigned int donnotremoteupdate:1;	/* define source of the update */
@@ -140,11 +133,11 @@ struct knet_handle {
 	struct knet_host *host_head;
 	struct knet_host *host_tail;
 	struct knet_host *host_index[KNET_MAX_HOST];
-	knet_transport_t transports[KNET_MAX_TRANSPORTS];
-	struct knet_transport_ops *transport_ops[KNET_MAX_TRANSPORTS];
+	knet_transport_t transports[KNET_MAX_TRANSPORTS+1];
+	struct knet_transport_ops *transport_ops[KNET_MAX_TRANSPORTS+1];
+	uint8_t knet_transport_fd_tracker[KNET_MAX_HOST * KNET_MAX_LINK * 4]; /* blabla */
 	uint16_t host_ids[KNET_MAX_HOST];
 	size_t   host_ids_entries;
-	struct knet_listener *listener_head;
 	struct knet_header *recv_from_sock_buf[PCKT_FRAG_MAX];
 	struct knet_header *send_to_links_buf[PCKT_FRAG_MAX];
 	struct knet_header *recv_from_links_buf[PCKT_FRAG_MAX];
@@ -157,7 +150,7 @@ struct knet_handle {
 	pthread_t pmtud_link_handler_thread;
 	int lock_init_done;
 	pthread_rwlock_t global_rwlock;		/* global config lock */
-	pthread_rwlock_t listener_rwlock;	/* listener add/rm lock, can switch to mutex? */
+	pthread_rwlock_t fd_tracker_rwlock;	/* transport add/rm lock */
 	pthread_rwlock_t host_rwlock;		/* send_host_info lock, can switch to mutex? */
 	pthread_mutex_t host_mutex;		/* host mutex for cond wait on pckt send, switch to mutex/sync_send ? */
 	pthread_cond_t host_cond;		/* conditional for above */
@@ -209,24 +202,46 @@ struct knet_handle {
 };
 
 typedef struct knet_transport_ops {
+/*
+ * MUST HAVE section when implementing a protocol.
+ * Calls in this section are expected to be
+ * available and internal knet does not check
+ * if they exists or not. it will just call them.
+ */
 
-	int (*handle_allocate)(knet_handle_t knet_h, knet_transport_t *transport);
-	int (*handle_free)(knet_handle_t knet_h, knet_transport_t transport);
+/*
+ * transport generic information
+ */
+	const char *transport_name;
+	uint32_t transport_mtu_overhead;
+/*
+ * transport init must allocate the new transport
+ * and perform all internal initializations
+ * (threads, lists, etc).
+ */
+	int (*transport_init)(knet_handle_t knet_h);
+/*
+ * transport free must releases _all_ resources
+ * allocated by tranport_init
+ */
+	int (*transport_free)(knet_handle_t knet_h);
+
+/*
+ * link operations should take care of all the
+ * sockets and epoll management for a given link/transport set
+ * transport_link_disable should return err = -1 and errno = EBUSY
+ * if listener is still in use, and any other errno in case
+ * the link cannot be disabled.
+ */
+	int (*transport_link_enable)(knet_handle_t knet_h, struct knet_link *link);
+	int (*transport_link_disable)(knet_handle_t knet_h, struct knet_link *link);
+/*
+ * OPTIONAL section (for now)
+ * this section still needs cleaning
+ * remember to add a "is_data_pckt" ops
+ */
 	int (*handle_fd_eof)(knet_handle_t knet_h, int sockfd);
 	int (*handle_fd_notification)(knet_handle_t knet_h, int sockfd, struct iovec *iov, size_t iovlen);
-
-	int (*link_allocate)(knet_handle_t knet_h, knet_transport_t transport,
-			     struct knet_link *link,
-			     knet_transport_link_t *transport_link,
-			     uint8_t link_id, struct sockaddr_storage *src_address,
-			     struct sockaddr_storage *dst_address, int *listen_sock);
-	int (*link_listener_start)(knet_handle_t knet_h, knet_transport_link_t transport_link,
-				   uint8_t link_id,
-				   struct sockaddr_storage *address, struct sockaddr_storage *dst_address);
-	int (*link_free)(knet_transport_link_t transport_link);
-	int (*link_get_mtu_overhead)(knet_transport_link_t transport_link);
-
-	const char *transport_name;
 } knet_transport_ops_t;
 
 /**
diff --git a/libknet/link.c b/libknet/link.c
index 4087fa9..4e7dd6a 100644
--- a/libknet/link.c
+++ b/libknet/link.c
@@ -18,7 +18,6 @@
 #include "internals.h"
 #include "logging.h"
 #include "link.h"
-#include "listener.h"
 #include "transports.h"
 #include "host.h"
 
@@ -157,10 +156,7 @@ int knet_link_set_config(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id
 exit_unlock:
 	if (!err) {
 		link->transport_type = transport;
-		if ((knet_h->transport_ops[link->transport_type]) &&
-		    (knet_h->transport_ops[link->transport_type]->link_get_mtu_overhead)) {
-			link->proto_overhead = knet_h->transport_ops[link->transport_type]->link_get_mtu_overhead(link->transport);
-		}
+		link->proto_overhead = knet_h->transport_ops[link->transport_type]->transport_mtu_overhead;
 		link->configured = 1;
 		link->pong_count = KNET_LINK_DEFAULT_PONG_COUNT;
 		link->has_valid_mtu = 0;
@@ -323,23 +319,11 @@ int knet_link_set_enable(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id
 	}
 
 	if (enabled) {
-		if (knet_h->transport_ops[link->transport_type]->link_allocate(
-			    knet_h, knet_h->transports[link->transport_type],
-			    link,
-			    &link->transport, link_id,
-			    &link->src_addr, &link->dst_addr,
-			    &link->outsock) < 0) {
+		if (knet_h->transport_ops[link->transport_type]->transport_link_enable(knet_h, link) < 0) {
 			savederrno = errno;
 			err = -1;
 			goto exit_unlock;
 		}
-
-		if (_listener_add(knet_h, host_id, link_id) < 0) {
-			savederrno = errno;
-			err = -1;
-			log_err(knet_h, KNET_SUB_LINK, "Unable to setup listener for this link");
-			goto exit_unlock;
-		}
 		log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is enabled",
 			  host_id, link_id);
 	}
@@ -368,9 +352,8 @@ int knet_link_set_enable(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id
 		goto exit_unlock;
 	}
 
-	err = _listener_remove(knet_h, host_id, link_id);
+	err = knet_h->transport_ops[link->transport_type]->transport_link_disable(knet_h, link);
 	savederrno = errno;
-
 	if ((err) && (savederrno != EBUSY)) {
 		log_err(knet_h, KNET_SUB_LINK, "Unable to remove listener for this link");
 		if (_link_updown(knet_h, host_id, link_id, 1, link->status.connected)) {
diff --git a/libknet/transport_common.c b/libknet/transport_common.c
index afacd04..545f8fc 100644
--- a/libknet/transport_common.c
+++ b/libknet/transport_common.c
@@ -118,7 +118,7 @@ exit_error:
 void _close_socket(knet_handle_t knet_h, int sockfd)
 {
 	struct epoll_event ev;
-	int i;
+	int err;
 
 	log_err(knet_h, KNET_SUB_RX, "EOF received on socket fd %d", sockfd);
 
@@ -131,26 +131,51 @@ void _close_socket(knet_handle_t knet_h, int sockfd)
 			strerror(errno));
 	}
 
-	/* Tell transport that the FD has been closed */
-	for (i=0; i<KNET_MAX_TRANSPORTS; i++) {
-		if ((knet_h->transport_ops[i]) &&
-		    (knet_h->transport_ops[i]->handle_fd_eof) &&
-		    (!knet_h->transport_ops[i]->handle_fd_eof(knet_h, sockfd)))
-			break;
+	err = pthread_rwlock_rdlock(&knet_h->fd_tracker_rwlock);
+	if (err) {
+		log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to get read lock: %s", strerror(err));
+		return;
 	}
+	if ((knet_h->transport_ops[knet_h->knet_transport_fd_tracker[sockfd]]) &&
+	    (knet_h->transport_ops[knet_h->knet_transport_fd_tracker[sockfd]]->handle_fd_eof)) {
+		knet_h->transport_ops[knet_h->knet_transport_fd_tracker[sockfd]]->handle_fd_eof(knet_h, sockfd);
+	}
+	pthread_rwlock_unlock(&knet_h->fd_tracker_rwlock);
 }
 
 void _handle_socket_notification(knet_handle_t knet_h, int sockfd, struct iovec *iov, size_t iovlen)
 {
-	int i;
-
-	/* Find the transport and post the message */
-	for (i=0; i<KNET_MAX_TRANSPORTS; i++) {
-		if ((knet_h->transport_ops[i]) &&
-		    (knet_h->transport_ops[i]->handle_fd_notification) &&
-		    (knet_h->transport_ops[i]->handle_fd_notification(knet_h, sockfd, iov, iovlen)))
-			break;
+	int err;
+
+	err = pthread_rwlock_rdlock(&knet_h->fd_tracker_rwlock);
+	if (err) {
+		log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to get read lock: %s", strerror(err));
+		return;
 	}
+	if ((knet_h->transport_ops[knet_h->knet_transport_fd_tracker[sockfd]]) &&
+	    (knet_h->transport_ops[knet_h->knet_transport_fd_tracker[sockfd]]->handle_fd_notification)) {
+		knet_h->transport_ops[knet_h->knet_transport_fd_tracker[sockfd]]->handle_fd_notification(knet_h, sockfd, iov, iovlen);
+	}
+	pthread_rwlock_unlock(&knet_h->fd_tracker_rwlock);
+}
+
+int _set_fd_tracker(knet_handle_t knet_h, int sockfd, uint8_t transport)
+{
+	int savederrno;
+
+	savederrno = pthread_rwlock_wrlock(&knet_h->fd_tracker_rwlock);
+	if (savederrno) {
+		log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to get write lock: %s",
+			strerror(savederrno));
+		errno = savederrno;
+		return -1;
+	}
+
+	knet_h->knet_transport_fd_tracker[sockfd] = transport;
+
+	pthread_rwlock_unlock(&knet_h->fd_tracker_rwlock);
+
+	return 0;
 }
 
 /*
diff --git a/libknet/transport_sctp.c b/libknet/transport_sctp.c
index 79ae75f..1d2e72a 100644
--- a/libknet/transport_sctp.c
+++ b/libknet/transport_sctp.c
@@ -380,7 +380,7 @@ static int sctp_handle_fd_eof(knet_handle_t knet_h, int sock_fd)
 	return -1;
 }
 
-static int sctp_handle_allocate(knet_handle_t knet_h, knet_transport_t *transport)
+static int sctp_transport_init(knet_handle_t knet_h)
 {
 	sctp_handle_info_t *handle_info;
 	int savederrno;
@@ -424,8 +424,7 @@ static int sctp_handle_allocate(knet_handle_t knet_h, knet_transport_t *transpor
                 goto exit_fail;
         }
 
-	*transport = handle_info;
-
+	knet_h->transports[KNET_TRANSPORT_SCTP] = handle_info;
 	return 0;
 
 exit_fail:
@@ -433,17 +432,17 @@ exit_fail:
 	return -1;
 }
 
-static int sctp_handle_free(knet_handle_t knet_h, knet_transport_t transport)
+static int sctp_transport_free(knet_handle_t knet_h)
 {
 	sctp_handle_info_t *handle_info;
 	void *thread_status;
 
-	if (!transport) {
+	if (!knet_h->transports[KNET_TRANSPORT_SCTP]) {
 		errno = EINVAL;
 		return -1;
 	}
 
-	handle_info = transport;
+	handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];;
 
 	if (handle_info->listen_thread) {
 		pthread_cancel(handle_info->listen_thread);
@@ -455,12 +454,13 @@ static int sctp_handle_free(knet_handle_t knet_h, knet_transport_t transport)
 		pthread_join(handle_info->connect_thread, &thread_status);
 	}
 
-	free(handle_info);
+	free(knet_h->transports[KNET_TRANSPORT_SCTP]);
+	knet_h->transports[KNET_TRANSPORT_SCTP] = NULL;
 
 	return 0;
 }
 
-
+#if 0
 static int sctp_link_listener_start(knet_handle_t knet_h, knet_transport_link_t transport_link,
 				    uint8_t link_id,
 				    struct sockaddr_storage *address, struct sockaddr_storage *dst_address)
@@ -528,14 +528,8 @@ exit_error:
 	errno = savederrno;
 	return err;
 }
-
-
-static int sctp_link_allocate(knet_handle_t knet_h, knet_transport_t transport,
-			      struct knet_link *link,
-			      knet_transport_link_t *transport_link,
-			      uint8_t link_id,
-			      struct sockaddr_storage *address, struct sockaddr_storage *dst_address,
-			      int *send_sock)
+#endif
+static int sctp_transport_link_enable(knet_handle_t knet_h, struct knet_link *link)
 {
 	int savederrno = EINVAL;
 	int err;
@@ -548,8 +542,8 @@ static int sctp_link_allocate(knet_handle_t knet_h, knet_transport_t transport,
 		return -1;
 	}
 	info->knet_handle = knet_h;
-	memcpy(&info->dst_address, dst_address, sizeof(struct sockaddr_storage));
-	handle_info = transport;
+	memcpy(&info->dst_address, &link->dst_addr, sizeof(struct sockaddr_storage));
+	handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
 	info->link = link;
 	info->on_epoll = 0;
 	info->sendrecv_sock = -1;
@@ -565,13 +559,13 @@ static int sctp_link_allocate(knet_handle_t knet_h, knet_transport_t transport,
 		goto exit_error;
 	}
 
-	info->transport = transport;
+	info->transport = knet_h->transports[KNET_TRANSPORT_SCTP];
 	pthread_rwlock_wrlock(&handle_info->links_list_lock);
 	knet_list_add(&info->list, &handle_info->links_list);
 	pthread_rwlock_unlock(&handle_info->links_list_lock);
 
-	*transport_link = (knet_transport_link_t *)info;
-	*send_sock = info->sendrecv_sock;
+	link->transport_link = info;
+	link->outsock = info->sendrecv_sock;
 	return 0;
 
 exit_error:
@@ -579,10 +573,9 @@ exit_error:
 	return err;
 }
 
-static int sctp_link_free(knet_transport_link_t transport)
+static int sctp_transport_link_disable(knet_handle_t knet_h, struct knet_link *link)
 {
-
-	sctp_link_info_t *info = (sctp_link_info_t *)transport;
+	sctp_link_info_t *info = link->transport_link;
 	sctp_handle_info_t *handle_info = info->transport;
 	int i;
 	struct epoll_event ev;
@@ -616,7 +609,7 @@ static int sctp_link_free(knet_transport_link_t transport)
 	pthread_rwlock_unlock(&handle_info->links_list_lock);
 
 	/* Remove from epoll */
-	free(transport);
+	free(info);
 
 	return 0;
 }
@@ -674,23 +667,16 @@ static int sctp_handle_fd_notification(knet_handle_t knet_h, int sockfd, struct
 	return -1;
 }
 
-static int sctp_link_get_mtu_overhead(knet_transport_t transport)
-{
-	return KNET_PMTUD_SCTP_OVERHEAD;
-}
-
 static knet_transport_ops_t sctp_transport_ops = {
-
-	.handle_allocate = sctp_handle_allocate,
-	.handle_free = sctp_handle_free,
 	.handle_fd_eof = sctp_handle_fd_eof,
 	.handle_fd_notification = sctp_handle_fd_notification,
 
-	.link_allocate = sctp_link_allocate,
-	.link_listener_start = sctp_link_listener_start,
-	.link_free = sctp_link_free,
-	.link_get_mtu_overhead = sctp_link_get_mtu_overhead,
 	.transport_name = "SCTP",
+	.transport_mtu_overhead = KNET_PMTUD_SCTP_OVERHEAD,
+	.transport_init = sctp_transport_init,
+	.transport_free = sctp_transport_free,
+	.transport_link_enable = sctp_transport_link_enable,
+	.transport_link_disable = sctp_transport_link_disable,
 };
 
 knet_transport_ops_t *get_sctp_transport()
diff --git a/libknet/transport_udp.c b/libknet/transport_udp.c
index 339d89f..e8bc3bb 100644
--- a/libknet/transport_udp.c
+++ b/libknet/transport_udp.c
@@ -23,6 +23,7 @@
 
 typedef struct udp_handle_info {
 	knet_handle_t knet_h;
+	pthread_rwlock_t links_list_lock;
 	struct knet_list_head links_list;
 } udp_handle_info_t;
 
@@ -35,68 +36,70 @@ typedef struct udp_link_info {
 	struct sockaddr_storage local_address;
 } udp_link_info_t;
 
-static int udp_handle_allocate(knet_handle_t knet_h, knet_transport_t *transport)
+static int udp_transport_init(knet_handle_t knet_h)
 {
-	udp_handle_info_t * handle_info;
+	udp_handle_info_t *handle_info;
 
 	handle_info = malloc(sizeof(udp_handle_info_t));
 	if (!handle_info) {
 		return -1;
 	}
+
 	handle_info->knet_h = knet_h;
 	knet_list_init(&handle_info->links_list);
+	pthread_rwlock_init(&handle_info->links_list_lock, NULL);
 
-	*transport = handle_info;
+	knet_h->transports[KNET_TRANSPORT_UDP] = handle_info;
 	return 0;
 }
 
-static int udp_handle_free(knet_handle_t knet_h, knet_transport_t transport)
+static int udp_transport_free(knet_handle_t knet_h)
 {
-	free(transport);
-	return 0;
-}
+	udp_handle_info_t *handle_info;
+
+	if (!knet_h->transports[KNET_TRANSPORT_UDP]) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	handle_info = knet_h->transports[KNET_TRANSPORT_UDP];
+
+	pthread_rwlock_destroy(&handle_info->links_list_lock);
+	free(handle_info);
+	knet_h->transports[KNET_TRANSPORT_UDP] = NULL;
 
-static int udp_link_listener_start(knet_handle_t knet_h, knet_transport_link_t transport_link,
-				   uint8_t link_id,
-				   struct sockaddr_storage *address, struct sockaddr_storage *dst_address)
-{
 	return 0;
 }
 
-
-static int udp_link_allocate(knet_handle_t knet_h, knet_transport_t transport,
-			     struct knet_link *link,
-			     knet_transport_link_t *transport_link,
-			     uint8_t link_id,
-			     struct sockaddr_storage *address, struct sockaddr_storage *dst_address,
-			     int *send_sock)
+static int udp_transport_link_enable(knet_handle_t knet_h, struct knet_link *link)
 {
 	int sock;
 	int savederrno;
 	struct epoll_event ev;
 	int err;
 	udp_link_info_t *info;
-	udp_handle_info_t *handle_info = transport;
+	udp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_UDP];
+
+	pthread_rwlock_wrlock(&handle_info->links_list_lock);
 
 	/* Only allocate a new link if the local address is different */
 	knet_list_for_each_entry(info, &handle_info->links_list, list) {
-		if (memcmp(&info->local_address, address, sizeof(struct sockaddr_storage)) == 0) {
-
+		if (memcmp(&info->local_address, &link->src_addr, sizeof(struct sockaddr_storage)) == 0) {
 			log_debug(knet_h, KNET_SUB_TRANSP_UDP, "Re-using existing UDP socket for new link");
-			*send_sock = info->socket_fd;
-			*transport_link = info;
+			link->outsock = info->socket_fd;
+			link->transport_link = info;
 			return 0;
 		}
 	}
 
 	info = malloc(sizeof(udp_link_info_t));
 	if (!info) {
-		return -1;
+		goto exit_error;
 	}
 	info->knet_handle = knet_h;
 	info->handle_info = handle_info;
 
-	sock = socket(address->ss_family, SOCK_DGRAM, 0);
+	sock = socket(link->src_addr.ss_family, SOCK_DGRAM, 0);
 	if (sock < 0) {
 		savederrno = errno;
 		err = -1;
@@ -105,12 +108,12 @@ static int udp_link_allocate(knet_handle_t knet_h, knet_transport_t transport,
 		goto exit_error;
 	}
 
-	if (_configure_transport_socket(knet_h, sock, dst_address, "UDP") < 0) {
+	if (_configure_transport_socket(knet_h, sock, &link->src_addr, "UDP") < 0) {
 		err = -1;
 		goto exit_error;
 	}
 
-	if (bind(sock, (struct sockaddr *)address, sizeof(struct sockaddr_storage)) < 0) {
+	if (bind(sock, (struct sockaddr *)&link->src_addr, sizeof(struct sockaddr_storage)) < 0) {
 		savederrno = errno;
 		err = -1;
 		log_err(knet_h, KNET_SUB_TRANSP_UDP, "Unable to bind listener socket: %s",
@@ -130,44 +133,97 @@ static int udp_link_allocate(knet_handle_t knet_h, knet_transport_t transport,
 		goto exit_error;
 	}
 
-	memcpy(&info->local_address, address, sizeof(struct sockaddr_storage));
+	if (_set_fd_tracker(knet_h, sock, KNET_TRANSPORT_UDP) < 0) {
+		savederrno = errno;
+		err = -1;
+		log_err(knet_h, KNET_SUB_TRANSP_UDP, "Unable to set fd tracker: %s",
+			strerror(savederrno));
+		goto exit_error;
+	}
+
+	memcpy(&info->local_address, &link->src_addr, sizeof(struct sockaddr_storage));
 	knet_list_add(&info->list, &handle_info->links_list);
 	info->socket_fd = sock;
-	*transport_link = &info->transport;
-	*send_sock = sock;
-	return 0;
+	link->transport_link = info;
+	link->outsock = sock;
+	err = 0;
 
 exit_error:
+	pthread_rwlock_unlock(&handle_info->links_list_lock);
+	errno = savederrno;
 	return err;
 }
 
-static int udp_link_free(knet_transport_link_t transport)
+static int udp_transport_link_disable(knet_handle_t knet_h, struct knet_link *link)
 {
-	udp_link_info_t *info = transport;
+	int err = 0, savederrno = 0;
+	int found = 0;
+	struct knet_host *host;
+	int link_idx;
+	udp_link_info_t *info = link->transport_link;
 	udp_handle_info_t *handle_info = info->handle_info;
+	struct epoll_event ev;
 
-	knet_list_del(&info->list);
+	pthread_rwlock_wrlock(&handle_info->links_list_lock);
+
+	for (host = knet_h->host_head; host != NULL; host = host->next) {
+		for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
+			if (host->link[link_idx].status.enabled != 1)
+				continue;
 
-	if (knet_list_empty(&handle_info->links_list)) {
-		free(transport);
+			if (host->link[link_idx].transport_link == info) {
+				found = 1;
+				break;
+			}
+		}
 	}
-	return 0;
-}
 
-static int udp_link_get_mtu_overhead(knet_transport_link_t transport)
-{
-	return KNET_PMTUD_UDP_OVERHEAD;
+	if (found) {
+		link->outsock = 0;
+		link->transport_link = NULL;
+		log_debug(knet_h, KNET_SUB_TRANSP_UDP, "UDP socket %d still in use", info->socket_fd);
+		savederrno = EBUSY;
+		err = -1;
+		goto exit_error;
+	}
+
+	memset(&ev, 0, sizeof(struct epoll_event));
+	ev.events = EPOLLIN;
+	ev.data.fd = info->socket_fd;
+
+	if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_DEL, info->socket_fd, &ev) < 0) {
+		savederrno = errno;
+		err = -1;
+		log_err(knet_h, KNET_SUB_TRANSP_UDP, "Unable to remove UDP socket from epoll poll: %s",
+			strerror(errno));
+		goto exit_error;
+	}
+
+	if (_set_fd_tracker(knet_h, info->socket_fd, KNET_MAX_TRANSPORTS) < 0) {
+		savederrno = errno;
+		err = -1;
+		log_err(knet_h, KNET_SUB_TRANSP_UDP, "Unable to set fd tracker: %s",
+			strerror(savederrno));
+		goto exit_error;
+	}
+
+	knet_list_del(&info->list);
+	free(link->transport_link);
+	link->outsock = 0;
+	link->transport_link = NULL;
+
+exit_error:
+	pthread_rwlock_unlock(&handle_info->links_list_lock);
+	return err;
 }
 
 static knet_transport_ops_t udp_transport_ops = {
-	.handle_allocate = udp_handle_allocate,
-	.handle_free = udp_handle_free,
-
-	.link_allocate = udp_link_allocate,
-	.link_listener_start = udp_link_listener_start,
-	.link_free = udp_link_free,
-	.link_get_mtu_overhead = udp_link_get_mtu_overhead,
 	.transport_name = "UDP",
+	.transport_mtu_overhead = KNET_PMTUD_UDP_OVERHEAD,
+	.transport_init = udp_transport_init,
+	.transport_free = udp_transport_free,
+	.transport_link_enable = udp_transport_link_enable,
+	.transport_link_disable = udp_transport_link_disable,
 };
 
 knet_transport_ops_t *get_udp_transport()
diff --git a/libknet/transports.h b/libknet/transports.h
index b790bef..0391b9f 100644
--- a/libknet/transports.h
+++ b/libknet/transports.h
@@ -14,6 +14,7 @@ knet_transport_ops_t *get_sctp_transport(void);
 
 int _configure_transport_socket(knet_handle_t knet_h, int sock, struct sockaddr_storage *address, const char *type);
 void _close_socket(knet_handle_t knet_h, int sockfd);
+int _set_fd_tracker(knet_handle_t knet_h, int sockfd, uint8_t transport);
 void _handle_socket_notification(knet_handle_t knet_h, int sockfd, struct iovec *iov, size_t iovlen);
 
 int _transport_addrtostr(const struct sockaddr *sa, socklen_t salen, char *str[2]);
