diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c
index 2b5c5b1..2d0af06 100644
--- a/src/openvpn/mtcp.c
+++ b/src/openvpn/mtcp.c
@@ -126,69 +126,3 @@
                    &mi->tcp_rwflags);
     }
 }
-
-bool
-multi_tcp_process_outgoing_link_ready(struct multi_context *m, struct multi_instance *mi,
-                                      const unsigned int mpp_flags)
-{
-    struct mbuf_item item;
-    bool ret = true;
-    ASSERT(mi);
-
-    /* extract from queue */
-    if (mbuf_extract_item(mi->tcp_link_out_deferred, &item)) /* ciphertext IP packet */
-    {
-        dmsg(D_MULTI_TCP, "MULTI TCP: transmitting previously deferred packet");
-
-        ASSERT(mi == item.instance);
-        mi->context.c2.to_link = item.buffer->buf;
-        ret = multi_process_outgoing_link_dowork(m, mi, mpp_flags);
-        mbuf_free_buf(item.buffer);
-    }
-    return ret;
-}
-
-bool
-multi_tcp_process_outgoing_link(struct multi_context *m, bool defer, const unsigned int mpp_flags)
-{
-    struct multi_instance *mi = multi_process_outgoing_link_pre(m);
-    bool ret = true;
-
-    if (mi)
-    {
-        if ((defer && !proto_is_dgram(mi->context.c2.link_sockets[0]->info.proto))
-            || mbuf_defined(mi->tcp_link_out_deferred))
-        {
-            /* save to queue */
-            struct buffer *buf = &mi->context.c2.to_link;
-            if (BLEN(buf) > 0)
-            {
-                struct mbuf_buffer *mb = mbuf_alloc_buf(buf);
-                struct mbuf_item item;
-
-                set_prefix(mi);
-                dmsg(D_MULTI_TCP, "MULTI TCP: queuing deferred packet");
-                item.buffer = mb;
-                item.instance = mi;
-                mbuf_add_item(mi->tcp_link_out_deferred, &item);
-                mbuf_free_buf(mb);
-                buf_reset(buf);
-                ret = multi_process_post(m, mi, mpp_flags);
-                if (!ret)
-                {
-                    mi = NULL;
-                }
-                clear_prefix();
-            }
-        }
-        else
-        {
-            ret = multi_process_outgoing_link_dowork(m, mi, mpp_flags);
-            if (!ret)
-            {
-                mi = NULL;
-            }
-        }
-    }
-    return ret;
-}
diff --git a/src/openvpn/mtcp.h b/src/openvpn/mtcp.h
index de9d7ba..47c6308 100644
--- a/src/openvpn/mtcp.h
+++ b/src/openvpn/mtcp.h
@@ -41,16 +41,8 @@
 
 void multi_tcp_set_global_rw_flags(struct multi_context *m, struct multi_instance *mi);
 
-bool multi_tcp_process_outgoing_link(struct multi_context *m, bool defer,
-                                     const unsigned int mpp_flags);
-
-bool multi_tcp_process_outgoing_link_ready(struct multi_context *m, struct multi_instance *mi,
-                                           const unsigned int mpp_flags);
-
 struct multi_instance *multi_create_instance_tcp(struct multi_context *m, struct link_socket *sock);
 
-void multi_tcp_link_out_deferred(struct multi_context *m, struct multi_instance *mi);
-
 void multi_tcp_delete_event(struct multi_io *multi_io, event_t event);
 
 #endif /* ifndef MTCP_H */
diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 201d756..217b299 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -29,6 +29,7 @@
 #include "multi.h"
 #include <inttypes.h>
 #include "forward.h"
+#include "multi_io.h"
 
 #include "memdbg.h"
 #include "ssl_pkt.h"
@@ -470,7 +471,7 @@
 {
     if (m->pending)
     {
-        multi_process_outgoing_link_dowork(m, m->pending, mpp_flags);
+        multi_io_send_link(m, m->pending, mpp_flags);
     }
 }
 
diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h
index 2d4983c..5aed191 100644
--- a/src/openvpn/multi.h
+++ b/src/openvpn/multi.h
@@ -294,7 +294,7 @@
  * may need updating and some follow-up action may be required.  This
  * function controls the necessary postprocessing.  It is called by many
  * other functions that handle VPN tunnel related activity, such as \c
- * multi_process_incoming_link(), \c multi_process_outgoing_link(), \c
+ * multi_process_incoming_link(), \c multi_io_write_link(), \c
  * multi_process_incoming_tun(), \c multi_io_write_tun(), and \c
  * multi_process_timeout(), among others.
  *
@@ -412,27 +412,6 @@
 #endif
 
 /*
- * Determine which instance has pending output
- * and prepare the output for sending in
- * the to_link buffer.
- */
-static inline struct multi_instance *
-multi_process_outgoing_link_pre(struct multi_context *m)
-{
-    struct multi_instance *mi = NULL;
-
-    if (m->pending)
-    {
-        mi = m->pending;
-    }
-    else if (mbuf_defined(m->mbuf))
-    {
-        mi = multi_get_queue(m->mbuf);
-    }
-    return mi;
-}
-
-/*
  * Per-client route quota management
  */
 
@@ -629,18 +608,6 @@
     (OPT_P_INSTANCE | OPT_P_INHERIT | OPT_P_PUSH | OPT_P_TIMER | OPT_P_CONFIG | OPT_P_ECHO \
      | OPT_P_COMP | OPT_P_SOCKFLAGS)
 
-static inline bool
-multi_process_outgoing_link_dowork(struct multi_context *m, struct multi_instance *mi,
-                                   const unsigned int mpp_flags)
-{
-    bool ret = true;
-    set_prefix(mi);
-    process_outgoing_link(&mi->context, mi->context.c2.link_sockets[0]);
-    ret = multi_process_post(m, mi, mpp_flags);
-    clear_prefix();
-    return ret;
-}
-
 /**
  * Determines if the ifconfig_push_local address falls into the range of the local
  * IP addresses of the VPN interface (ifconfig_local with ifconfig_remote_netmask)
diff --git a/src/openvpn/multi_io.c b/src/openvpn/multi_io.c
index 164b214..ac730b4 100644
--- a/src/openvpn/multi_io.c
+++ b/src/openvpn/multi_io.c
@@ -346,6 +346,104 @@
     clear_prefix();
 }
 
+/*
+ * Determine which instance has pending output
+ * and prepare the output for sending in
+ * the to_link buffer.
+ */
+static struct multi_instance *
+multi_io_write_link_pre(struct multi_context *m)
+{
+    struct multi_instance *mi = NULL;
+
+    if (m->pending)
+    {
+        mi = m->pending;
+    }
+    else if (mbuf_defined(m->mbuf))
+    {
+        mi = multi_get_queue(m->mbuf);
+    }
+    return mi;
+}
+
+bool
+multi_io_send_link(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags)
+{
+    bool ret = true;
+    set_prefix(mi);
+    process_outgoing_link(&mi->context, mi->context.c2.link_sockets[0]);
+    ret = multi_process_post(m, mi, mpp_flags);
+    clear_prefix();
+    return ret;
+}
+
+static bool
+multi_io_write_link_deferred(struct multi_context *m, struct multi_instance *mi,
+                             const unsigned int mpp_flags)
+{
+    struct mbuf_item item;
+    bool ret = true;
+    ASSERT(mi);
+
+    /* extract from queue */
+    if (mbuf_extract_item(mi->tcp_link_out_deferred, &item)) /* ciphertext IP packet */
+    {
+        dmsg(D_MULTI_TCP, "MULTI TCP: transmitting previously deferred packet");
+
+        ASSERT(mi == item.instance);
+        mi->context.c2.to_link = item.buffer->buf;
+        ret = multi_io_send_link(m, mi, mpp_flags);
+        mbuf_free_buf(item.buffer);
+    }
+    return ret;
+}
+
+static bool
+multi_io_write_link(struct multi_context *m, bool defer, const unsigned int mpp_flags)
+{
+    struct multi_instance *mi = multi_io_write_link_pre(m);
+    bool ret = true;
+
+    if (mi)
+    {
+        if ((defer && !proto_is_dgram(mi->context.c2.link_sockets[0]->info.proto))
+            || mbuf_defined(mi->tcp_link_out_deferred))
+        {
+            /* save to queue */
+            struct buffer *buf = &mi->context.c2.to_link;
+            if (BLEN(buf) > 0)
+            {
+                struct mbuf_buffer *mb = mbuf_alloc_buf(buf);
+                struct mbuf_item item;
+
+                set_prefix(mi);
+                dmsg(D_MULTI_TCP, "MULTI TCP: queuing deferred packet");
+                item.buffer = mb;
+                item.instance = mi;
+                mbuf_add_item(mi->tcp_link_out_deferred, &item);
+                mbuf_free_buf(mb);
+                buf_reset(buf);
+                ret = multi_process_post(m, mi, mpp_flags);
+                if (!ret)
+                {
+                    mi = NULL;
+                }
+                clear_prefix();
+            }
+        }
+        else
+        {
+            ret = multi_io_send_link(m, mi, mpp_flags);
+            if (!ret)
+            {
+                mi = NULL;
+            }
+        }
+    }
+    return ret;
+}
+
 static struct multi_instance *
 multi_io_dispatch(struct multi_context *m, struct multi_instance *mi, const int action)
 {
@@ -399,15 +497,15 @@
 
         case TA_SOCKET_WRITE_READY:
             ASSERT(mi);
-            multi_tcp_process_outgoing_link_ready(m, mi, mpp_flags);
+            multi_io_write_link_deferred(m, mi, mpp_flags);
             break;
 
         case TA_SOCKET_WRITE:
-            multi_tcp_process_outgoing_link(m, false, mpp_flags);
+            multi_io_write_link(m, false, mpp_flags);
             break;
 
         case TA_SOCKET_WRITE_DEFERRED:
-            multi_tcp_process_outgoing_link(m, true, mpp_flags);
+            multi_io_write_link(m, true, mpp_flags);
             break;
 
         case TA_INITIAL:
diff --git a/src/openvpn/multi_io.h b/src/openvpn/multi_io.h
index 4299cba..c7f8f89 100644
--- a/src/openvpn/multi_io.h
+++ b/src/openvpn/multi_io.h
@@ -72,4 +72,7 @@
 
 void multi_io_delete_event(struct multi_io *multi_io, event_t event);
 
+bool multi_io_send_link(struct multi_context *m, struct multi_instance *mi,
+                        const unsigned int mpp_flags);
+
 #endif /* ifndef MULTI_IO_H */
