diff --git a/mesh/mesh.c b/mesh/mesh.c
index 4abae4d92..f43d00b7c 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -612,14 +612,18 @@ static void attach_ready_cb(void *user_data, int status, struct mesh_node *node)
 {
 	struct l_dbus_message *reply;
 	struct l_dbus_message *pending_msg;
+	const char *method;
 
 	pending_msg = l_queue_remove_if(pending_queue, simple_match, user_data);
 	if (!pending_msg)
 		return;
 
+	method = l_dbus_message_get_member(pending_msg);
+
 	if (status == MESH_ERROR_NONE) {
 		reply = l_dbus_message_new_method_return(pending_msg);
-		node_build_attach_reply(node, reply);
+		node_build_attach_reply(node, reply,
+						!strcmp(method, "AttachFD"));
 	} else
 		reply = dbus_error(pending_msg, status, "Attach failed");
 
@@ -635,7 +639,7 @@ static struct l_dbus_message *attach_call(struct l_dbus *dbus,
 	const char *app_path, *sender;
 	struct l_dbus_message *pending_msg;
 
-	l_debug("Attach");
+	l_debug("%s", l_dbus_message_get_member(msg));
 
 	if (!l_dbus_message_get_arguments(msg, "ot", &app_path, &token))
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
@@ -846,6 +850,10 @@ static void setup_network_interface(struct l_dbus_interface *iface)
 					"oa(ya(qa{sv}))", "ot", "node",
 					"configuration", "app", "token");
 
+	l_dbus_interface_method(iface, "AttachFD", 0, attach_call,
+					"oa(ya(qa{sv}))h", "ot", "node",
+					"configuration", "fd", "app", "token");
+
 	l_dbus_interface_method(iface, "Leave", 0, leave_call, "", "t",
 								"token");
 
diff --git a/mesh/model.c b/mesh/model.c
index 5ed95afac..0bef11e36 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -21,6 +21,8 @@
 #include <config.h>
 #endif
 
+#include <sys/types.h>
+#include <sys/socket.h>
 #include <sys/time.h>
 #include <ell/ell.h>
 
@@ -44,6 +46,33 @@
 
 #define VIRTUAL_BASE			0x10000
 
+enum fd_msg_type {
+	DEV_KEY_MSG = 0,
+	APP_KEY_MSG = 1,
+};
+
+struct fd_msg {
+
+	uint8_t element;
+	uint16_t src;
+
+	enum fd_msg_type type :8;
+	union {
+		struct {
+			uint16_t net_idx;
+			uint8_t remote;
+		} dev;
+
+		struct {
+			uint16_t app_idx;
+			uint16_t dst;
+			uint8_t label[16];
+		} app;
+	};
+
+	uint8_t data[];
+} __attribute__((packed));
+
 struct mesh_model {
 	const struct mesh_model_ops *cbs;
 	void *user_data;
@@ -782,7 +811,50 @@ static int add_sub(struct mesh_net *net, struct mesh_model *mod,
 	return MESH_STATUS_SUCCESS;
 }
 
-static void send_dev_key_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
+static struct fd_msg *fd_msg_new(uint8_t ele_idx, uint16_t src, uint16_t size, const uint8_t *data, enum fd_msg_type type)
+{
+	size_t msg_len = sizeof(struct fd_msg) + size;
+	struct fd_msg *msg = l_malloc(msg_len);
+
+	msg->element = ele_idx;
+	msg->src = src;
+	msg->type = type;
+
+	memcpy(msg->data, data, size);
+
+	return msg;
+}
+
+static void fd_msg_send(struct l_io *io, struct fd_msg *msg, size_t size)
+{
+	struct iovec iov = {
+		.iov_base = msg,
+		.iov_len = sizeof(struct fd_msg) + size,
+	};
+	struct msghdr hdr = {
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+	};
+
+	(void)sendmsg(l_io_get_fd(io), &hdr, MSG_NOSIGNAL);
+
+	l_free(msg);
+}
+
+static void send_fd_dev_key_msg_rcvd(struct l_io *io, uint8_t ele_idx,
+				     uint16_t src, uint16_t app_idx,
+				     uint16_t net_idx, uint16_t size,
+				     const uint8_t *data)
+{
+	struct fd_msg *msg = fd_msg_new(ele_idx, src, size, data, DEV_KEY_MSG);
+
+	msg->dev.net_idx = net_idx;
+	msg->dev.remote = (app_idx != APP_IDX_DEV_LOCAL);
+
+	fd_msg_send(io, msg, size);
+}
+
+static void send_dbus_dev_key_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
 					uint16_t src, uint16_t app_idx,
 					uint16_t net_idx, uint16_t size,
 					const uint8_t *data)
@@ -818,7 +890,40 @@ static void send_dev_key_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
 	l_dbus_send(dbus, msg);
 }
 
-static void send_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
+static void send_dev_key_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
+				       uint16_t src, uint16_t app_idx,
+				       uint16_t net_idx, uint16_t size,
+				       const uint8_t *data)
+{
+	struct l_io *io = node_get_fd_io(node);
+
+	if (io)
+		send_fd_dev_key_msg_rcvd(io, ele_idx, src, app_idx, net_idx,
+					 size, data);
+	else
+		send_dbus_dev_key_msg_rcvd(node, ele_idx, src, app_idx, net_idx,
+					   size, data);
+}
+
+static void send_fd_msg_rcvd(struct l_io *io, uint8_t ele_idx,
+			     uint16_t src, uint16_t dst,
+			     const struct mesh_virtual *virt,
+			     uint16_t app_idx,
+			     uint16_t size, const uint8_t *data)
+{
+	struct fd_msg *msg = fd_msg_new(ele_idx, src, size, data, APP_KEY_MSG);
+
+	msg->app.app_idx = app_idx;
+	msg->app.dst = dst;
+
+	if (virt)
+		memcpy(msg->app.label, virt, sizeof(msg->app.label));
+
+	fd_msg_send(io, msg, size);
+}
+
+
+static void send_dbus_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
 					uint16_t src, uint16_t dst,
 					const struct mesh_virtual *virt,
 					uint16_t app_idx,
@@ -863,6 +968,22 @@ static void send_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
 	l_dbus_send(dbus, msg);
 }
 
+static void send_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
+			  uint16_t src, uint16_t dst,
+			  const struct mesh_virtual *virt,
+			  uint16_t app_idx,
+			  uint16_t size, const uint8_t *data)
+{
+	struct l_io *io = node_get_fd_io(node);
+
+	if (io)
+		send_fd_msg_rcvd(io, ele_idx, src, dst, virt, app_idx,
+				 size, data);
+	else
+		send_dbus_msg_rcvd(node, ele_idx, src, dst, virt, app_idx,
+				   size, data);
+}
+
 bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 			uint32_t seq, uint32_t iv_index,
 			uint16_t net_idx, uint16_t src, uint16_t dst,
@@ -986,6 +1107,7 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 				send_msg_rcvd(node, i, src, dst, decrypt_virt,
 						forward.app_idx, forward.size,
 						forward.data);
+
 			else if (decrypt_idx == APP_IDX_DEV_REMOTE ||
 				 decrypt_idx == APP_IDX_DEV_LOCAL)
 				send_dev_key_msg_rcvd(node, i, src, decrypt_idx,
diff --git a/mesh/node.c b/mesh/node.c
index 6140fdf9f..e00bed785 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -26,6 +26,8 @@
 #include <limits.h>
 #include <stdio.h>
 #include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
 
 #include <ell/ell.h>
 
@@ -105,6 +107,7 @@ struct mesh_node {
 	uint8_t proxy;
 	uint8_t friend;
 	uint8_t beacon;
+	struct l_io *fd_io;
 };
 
 struct node_import {
@@ -260,6 +263,7 @@ static void set_defaults(struct mesh_node *node)
 							MESH_MODE_UNSUPPORTED;
 	node->ttl = TTL_MASK;
 	node->seq_number = DEFAULT_SEQUENCE_NUMBER;
+	node->fd_io = NULL;
 }
 
 static struct mesh_node *node_new(const uint8_t uuid[16])
@@ -341,6 +345,13 @@ static void free_node_resources(void *data)
 	mesh_agent_remove(node->agent);
 	mesh_config_release(node->cfg);
 	mesh_net_free(node->net);
+
+	if (node->fd_io)
+	{
+		l_io_destroy(node->fd_io);
+		node->fd_io = NULL;
+	}
+
 	l_free(node->storage_dir);
 	l_free(node);
 }
@@ -745,6 +756,11 @@ uint16_t node_get_crpl(struct mesh_node *node)
 	return node->comp.crpl;
 }
 
+struct l_io *node_get_fd_io(struct mesh_node *node)
+{
+	return node->fd_io;
+}
+
 uint8_t node_relay_mode_get(struct mesh_node *node, uint8_t *count,
 							uint16_t *interval)
 {
@@ -1650,6 +1666,53 @@ static void send_managed_objects_request(const char *destination,
 					req, l_free, DEFAULT_DBUS_TIMEOUT);
 }
 
+static void fd_io_hup(struct l_io *io, void *user_data)
+{
+	struct mesh_node *node = user_data;
+
+	node->fd_io = NULL;
+
+	l_io_destroy(io);
+}
+
+static struct l_io *fd_io_new(struct mesh_node *node, int *fd)
+{
+	struct l_io *io;
+	int fds[2];
+
+	if (socketpair(AF_LOCAL, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
+		       0, fds) < 0)
+	{
+		return NULL;
+	}
+
+	io = l_io_new(fds[0]);
+	if (!io)
+	{
+		goto fail;
+	}
+
+	l_io_set_close_on_destroy(io, true);
+
+	if (!l_io_set_disconnect_handler(io, fd_io_hup, node, NULL))
+	{
+		goto fail;
+	}
+
+	*fd = fds[1];
+
+	return io;
+
+fail:
+	if (io)
+		l_io_destroy(io);
+
+	close(fds[0]);
+	close(fds[1]);
+
+	return NULL;
+}
+
 /* Establish relationship between application and mesh node */
 void node_attach(const char *app_root, const char *sender, uint64_t token,
 					node_ready_func_t cb, void *user_data)
@@ -1770,8 +1833,16 @@ static void build_element_config(void *a, void *b)
 	l_dbus_message_builder_leave_struct(builder);
 }
 
+static void append_fd(struct l_dbus_message_builder *builder, ...)
+{
+	va_list args;
+	va_start(args, builder);
+	l_dbus_message_builder_append_from_valist(builder, "h", args);
+	va_end(args);
+}
+
 void node_build_attach_reply(struct mesh_node *node,
-						struct l_dbus_message *reply)
+				struct l_dbus_message *reply, bool use_fd)
 {
 	struct l_dbus_message_builder *builder;
 
@@ -1784,6 +1855,16 @@ void node_build_attach_reply(struct mesh_node *node,
 	l_dbus_message_builder_enter_array(builder, "(ya(qa{sv}))");
 	l_queue_foreach(node->elements, build_element_config, builder);
 	l_dbus_message_builder_leave_array(builder);
+
+	if (use_fd)
+	{
+		int fd = -1;
+		node->fd_io = fd_io_new(node, &fd);
+		append_fd(builder, fd);
+
+		close(fd);
+	}
+
 	l_dbus_message_builder_finalize(builder);
 	l_dbus_message_builder_destroy(builder);
 }
diff --git a/mesh/node.h b/mesh/node.h
index e26d410c8..6d0696824 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -23,6 +23,7 @@ struct mesh_io;
 struct mesh_agent;
 struct mesh_config;
 struct mesh_config_node;
+struct l_io;
 
 typedef void (*node_ready_func_t) (void *user_data, int status,
 							struct mesh_node *node);
@@ -77,13 +78,14 @@ uint8_t node_friend_mode_get(struct mesh_node *node);
 const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx);
 const char *node_get_owner(struct mesh_node *node);
 const char *node_get_app_path(struct mesh_node *node);
+struct l_io *node_get_fd_io(struct mesh_node *node);
 bool node_add_pending_local(struct mesh_node *node, void *info);
 void node_attach_io_all(struct mesh_io *io);
 void node_attach_io(struct mesh_node *node, struct mesh_io *io);
 void node_attach(const char *app_root, const char *sender, uint64_t token,
 					node_ready_func_t cb, void *user_data);
 void node_build_attach_reply(struct mesh_node *node,
-						struct l_dbus_message *reply);
+				struct l_dbus_message *reply, bool use_fd);
 void node_create(const char *app_root, const char *sender, const uint8_t *uuid,
 					node_ready_func_t cb, void *user_data);
 void node_import(const char *app_root, const char *sender, const uint8_t *uuid,
