forward.c
6fbf66fa
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
564a2109
  *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
6fbf66fa
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program (see the file COPYING included with this
  *  distribution); if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include "syshead.h"
 
 #include "forward.h"
 #include "init.h"
 #include "push.h"
 #include "gremlin.h"
 #include "mss.h"
 #include "event.h"
6add6b2f
 #include "ps.h"
03731db3
 #include "dhcp.h"
16322c78
 #include "common.h"
6fbf66fa
 
 #include "memdbg.h"
 
 #include "forward-inline.h"
 #include "occ-inline.h"
 #include "ping-inline.h"
 
16322c78
 counter_type link_read_bytes_global;  /* GLOBAL */
 counter_type link_write_bytes_global; /* GLOBAL */
 
6fbf66fa
 /* show event wait debugging info */
 
 #ifdef ENABLE_DEBUG
 
 const char *
 wait_status_string (struct context *c, struct gc_arena *gc)
 {
   struct buffer out = alloc_buf_gc (64, gc);
   buf_printf (&out, "I/O WAIT %s|%s|%s|%s %s",
 	      tun_stat (c->c1.tuntap, EVENT_READ, gc),
 	      tun_stat (c->c1.tuntap, EVENT_WRITE, gc),
 	      socket_stat (c->c2.link_socket, EVENT_READ, gc),
 	      socket_stat (c->c2.link_socket, EVENT_WRITE, gc),
 	      tv_string (&c->c2.timeval, gc));
   return BSTR (&out);
 }
 
 void
 show_wait_status (struct context *c)
 {
   struct gc_arena gc = gc_new ();
   dmsg (D_EVENT_WAIT, "%s", wait_status_string (c, &gc));
   gc_free (&gc);
 }
 
 #endif
 
 /*
  * In TLS mode, let TLS level respond to any control-channel
  * packets which were received, or prepare any packets for
  * transmission.
  *
  * tmp_int is purely an optimization that allows us to call
  * tls_multi_process less frequently when there's not much
  * traffic on the control-channel.
  *
  */
 #if defined(USE_CRYPTO) && defined(USE_SSL)
 void
 check_tls_dowork (struct context *c)
 {
   interval_t wakeup = BIG_TIMEOUT;
 
   if (interval_test (&c->c2.tmp_int))
     {
344ee918
       const int tmp_status = tls_multi_process
 	(c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr,
 	 get_link_socket_info (c), &wakeup);
       if (tmp_status == TLSMP_ACTIVE)
6fbf66fa
 	{
 	  update_time ();
 	  interval_action (&c->c2.tmp_int);
 	}
344ee918
       else if (tmp_status == TLSMP_KILL)
 	{
 	  c->sig->signal_received = SIGTERM;
 	  c->sig->signal_text = "auth-control-exit";
 	}
6fbf66fa
 
       interval_future_trigger (&c->c2.tmp_int, wakeup);
     }
 
   interval_schedule_wakeup (&c->c2.tmp_int, &wakeup);
 
   if (wakeup)
     context_reschedule_sec (c, wakeup);
 }
 #endif
 
 #if defined(USE_CRYPTO) && defined(USE_SSL)
 
 void
 check_tls_errors_co (struct context *c)
 {
   msg (D_STREAM_ERRORS, "Fatal TLS error (check_tls_errors_co), restarting");
   c->sig->signal_received = c->c2.tls_exit_signal; /* SOFT-SIGUSR1 -- TLS error */
   c->sig->signal_text = "tls-error";
 }
 
 void
 check_tls_errors_nco (struct context *c)
 {
   c->sig->signal_received = c->c2.tls_exit_signal; /* SOFT-SIGUSR1 -- TLS error */
   c->sig->signal_text = "tls-error";
 }
 
 #endif
 
 #if P2MP
 
 /*
  * Handle incoming configuration
  * messages on the control channel.
  */
 void
 check_incoming_control_channel_dowork (struct context *c)
 {
   const int len = tls_test_payload_len (c->c2.tls_multi);
   if (len)
     {
       struct gc_arena gc = gc_new ();
       struct buffer buf = alloc_buf_gc (len, &gc);
       if (tls_rec_payload (c->c2.tls_multi, &buf))
 	{
 	  /* force null termination of message */
 	  buf_null_terminate (&buf);
 
 	  /* enforce character class restrictions */
 	  string_mod (BSTR (&buf), CC_PRINT, CC_CRLF, 0);
 
 	  if (buf_string_match_head_str (&buf, "AUTH_FAILED"))
 	    receive_auth_failed (c, &buf);
 	  else if (buf_string_match_head_str (&buf, "PUSH_"))
 	    incoming_push_message (c, &buf);
f25071b6
 	  else if (buf_string_match_head_str (&buf, "RESTART"))
 	    server_pushed_restart (c, &buf);
6fbf66fa
 	  else
 	    msg (D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR (&buf));
 	}
       else
 	{
 	  msg (D_PUSH_ERRORS, "WARNING: Receive control message failed");
 	}
 
       gc_free (&gc);
     }
 }
 
 /*
  * Periodically resend PUSH_REQUEST until PUSH message received
  */
 void
 check_push_request_dowork (struct context *c)
 {
   send_push_request (c);
72bf37c7
 
   /* if no response to first push_request, retry at 5 second intervals */
   event_timeout_modify_wakeup (&c->c2.push_request_interval, 5);
6fbf66fa
 }
 
f25071b6
 #endif /* P2MP */
6fbf66fa
 
 /*
  * Things that need to happen immediately after connection initiation should go here.
  */
 void
 check_connection_established_dowork (struct context *c)
 {
   if (event_timeout_trigger (&c->c2.wait_for_connect, &c->c2.timeval, ETT_DEFAULT))
     {
       if (CONNECTION_ESTABLISHED (c))
 	{
 #if P2MP
 	  /* if --pull was specified, send a push request to server */
 	  if (c->c2.tls_multi && c->options.pull)
 	    {
 #ifdef ENABLE_MANAGEMENT
 	      if (management)
 		{
 		  management_set_state (management,
 					OPENVPN_STATE_GET_CONFIG,
 					NULL,
5ad84585
 					0,
6fbf66fa
 					0);
 		}
 #endif
72bf37c7
 	      /* send push request in 1 sec */
 	      event_timeout_init (&c->c2.push_request_interval, 1, now);
6fbf66fa
 	      reset_coarse_timers (c);
 	    }
 	  else
 #endif
 	    {
 	      do_up (c, false, 0);
 	    }
 
 	  event_timeout_clear (&c->c2.wait_for_connect);
 	}
     }
 }
 
 /*
  * Send a string to remote over the TLS control channel.
  * Used for push/pull messages, passing username/password,
  * etc.
  */
 bool
 send_control_channel_string (struct context *c, const char *str, int msglevel)
 {
 #if defined(USE_CRYPTO) && defined(USE_SSL)
 
   if (c->c2.tls_multi) {
     bool stat;
 
     /* buffered cleartext write onto TLS control channel */
     stat = tls_send_payload (c->c2.tls_multi, (uint8_t*) str, strlen (str) + 1);
 
     /* reschedule tls_multi_process */
     interval_action (&c->c2.tmp_int);
     context_immediate_reschedule (c); /* ZERO-TIMEOUT */
 
     msg (msglevel, "SENT CONTROL [%s]: '%s' (status=%d)",
 	 tls_common_name (c->c2.tls_multi, false),
 	 str,
 	 (int) stat);
 
     return stat;
   }
 #endif
   return true;
 }
 
 /*
  * Add routes.
  */
 
 static void
 check_add_routes_action (struct context *c, const bool errors)
 {
3c7f2f55
   do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
6fbf66fa
   update_time ();
   event_timeout_clear (&c->c2.route_wakeup);
   event_timeout_clear (&c->c2.route_wakeup_expire);
   initialization_sequence_completed (c, errors ? ISC_ERRORS : 0); /* client/p2p --route-delay was defined */
 }
 
 void
 check_add_routes_dowork (struct context *c)
 {
   if (test_routes (c->c1.route_list, c->c1.tuntap))
     {
       check_add_routes_action (c, false);
     }
   else if (event_timeout_trigger (&c->c2.route_wakeup_expire, &c->c2.timeval, ETT_DEFAULT))
     {
       check_add_routes_action (c, true);
     }
   else
     {
       msg (D_ROUTE, "Route: Waiting for TUN/TAP interface to come up...");
c67d59cd
       if (c->c1.tuntap)
a9c802b2
 	{
 	  if (!tun_standby (c->c1.tuntap))
 	    {
 	      c->sig->signal_received = SIGHUP;
 	      c->sig->signal_text = "ip-fail";
 	      c->persist.restart_sleep_seconds = 10;
 #ifdef WIN32
 	      show_routes (M_INFO|M_NOPREFIX);
 	      show_adapters (M_INFO|M_NOPREFIX);
 #endif
 	    }
 	}
c67d59cd
       update_time ();
6fbf66fa
       if (c->c2.route_wakeup.n != 1)
 	event_timeout_init (&c->c2.route_wakeup, 1, now);
c67d59cd
       event_timeout_reset (&c->c2.ping_rec_interval);
6fbf66fa
     }
 }
 
 /*
  * Should we exit due to inactivity timeout?
  */
 void
 check_inactivity_timeout_dowork (struct context *c)
 {
   msg (M_INFO, "Inactivity timeout (--inactive), exiting");
   c->sig->signal_received = SIGTERM;
   c->sig->signal_text = "inactive";
 }
 
 #if P2MP
 
e1e977f3
 void
 check_server_poll_timeout_dowork (struct context *c)
 {
   event_timeout_reset (&c->c2.server_poll_interval);
   if (!tls_initial_packet_received (c->c2.tls_multi))
     {
       msg (M_INFO, "Server poll timeout, restarting");
       c->sig->signal_received = SIGUSR1;
       c->sig->signal_text = "server_poll";
       c->persist.restart_sleep_seconds = -1;
     }
 }
 
6fbf66fa
 /*
f25071b6
  * Schedule a signal n_seconds from now.
6fbf66fa
  */
 void
f25071b6
 schedule_exit (struct context *c, const int n_seconds, const int signal)
6fbf66fa
 {
92bbb061
   tls_set_single_session (c->c2.tls_multi);
6fbf66fa
   update_time ();
   reset_coarse_timers (c);
   event_timeout_init (&c->c2.scheduled_exit, n_seconds, now);
f25071b6
   c->c2.scheduled_exit_signal = signal;
6fbf66fa
   msg (D_SCHED_EXIT, "Delayed exit in %d seconds", n_seconds);
 }
 
 /*
  * Scheduled exit?
  */
 void
 check_scheduled_exit_dowork (struct context *c)
 {
f25071b6
   c->sig->signal_received = c->c2.scheduled_exit_signal;
6fbf66fa
   c->sig->signal_text = "delayed-exit";
 }
 
 #endif
 
 /*
  * Should we write timer-triggered status file.
  */
 void
 check_status_file_dowork (struct context *c)
 {
   if (c->c1.status_output)
     print_status (c, c->c1.status_output);
 }
 
 #ifdef ENABLE_FRAGMENT
 /*
  * Should we deliver a datagram fragment to remote?
  */
 void
 check_fragment_dowork (struct context *c)
 {
   struct link_socket_info *lsi = get_link_socket_info (c);
 
   /* OS MTU Hint? */
   if (lsi->mtu_changed && c->c2.ipv4_tun)
     {
       frame_adjust_path_mtu (&c->c2.frame_fragment, c->c2.link_socket->mtu,
4e9a51d7
 			     c->options.ce.proto);
6fbf66fa
       lsi->mtu_changed = false;
     }
 
   if (fragment_outgoing_defined (c->c2.fragment))
     {
       if (!c->c2.to_link.len)
 	{
 	  /* encrypt a fragment for output to TCP/UDP port */
 	  ASSERT (fragment_ready_to_send (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment));
 	  encrypt_sign (c, false);
 	}
     }
 
   fragment_housekeeping (c->c2.fragment, &c->c2.frame_fragment, &c->c2.timeval);
 }
 #endif
 
 /*
  * Buffer reallocation, for use with null encryption.
  */
 static inline void
 buffer_turnover (const uint8_t *orig_buf, struct buffer *dest_stub, struct buffer *src_stub, struct buffer *storage)
 {
   if (orig_buf == src_stub->data && src_stub->data != storage->data)
     {
       buf_assign (storage, src_stub);
       *dest_stub = *storage;
     }
   else
     {
       *dest_stub = *src_stub;
     }
 }
 
 /*
  * Compress, fragment, encrypt and HMAC-sign an outgoing packet.
  * Input: c->c2.buf
  * Output: c->c2.to_link
  */
 void
 encrypt_sign (struct context *c, bool comp_frag)
 {
   struct context_buffers *b = c->c2.buffers;
   const uint8_t *orig_buf = c->c2.buf.data;
 
 #if P2MP_SERVER
   /*
    * Drop non-TLS outgoing packet if client-connect script/plugin
    * has not yet succeeded.
    */
   if (c->c2.context_auth != CAS_SUCCEEDED)
     c->c2.buf.len = 0;
 #endif
 
   if (comp_frag)
     {
 #ifdef USE_LZO
       /* Compress the packet. */
537073fd
       if (lzo_defined (&c->c2.lzo_compwork))
6fbf66fa
 	lzo_compress (&c->c2.buf, b->lzo_compress_buf, &c->c2.lzo_compwork, &c->c2.frame);
 #endif
 #ifdef ENABLE_FRAGMENT
       if (c->c2.fragment)
 	fragment_outgoing (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment);
 #endif
     }
 
 #ifdef USE_CRYPTO
 #ifdef USE_SSL
   /*
    * If TLS mode, get the key we will use to encrypt
    * the packet.
    */
   if (c->c2.tls_multi)
     {
       /*tls_mutex_lock (c->c2.tls_multi);*/
       tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &c->c2.crypto_options);
     }
 #endif
 
   /*
    * Encrypt the packet and write an optional
    * HMAC signature.
    */
   openvpn_encrypt (&c->c2.buf, b->encrypt_buf, &c->c2.crypto_options, &c->c2.frame);
 #endif
   /*
    * Get the address we will be sending the packet to.
    */
   link_socket_get_outgoing_addr (&c->c2.buf, get_link_socket_info (c),
 				 &c->c2.to_link_addr);
 #ifdef USE_CRYPTO
 #ifdef USE_SSL
   /*
    * In TLS mode, prepend the appropriate one-byte opcode
    * to the packet which identifies it as a data channel
    * packet and gives the low-permutation version of
    * the key-id to the recipient so it knows which
    * decrypt key to use.
    */
   if (c->c2.tls_multi)
     {
       tls_post_encrypt (c->c2.tls_multi, &c->c2.buf);
       /*tls_mutex_unlock (c->c2.tls_multi);*/
     }
 #endif
 #endif
 
   /* if null encryption, copy result to read_tun_buf */
   buffer_turnover (orig_buf, &c->c2.to_link, &c->c2.buf, &b->read_tun_buf);
 }
 
 /*
  * Coarse timers work to 1 second resolution.
  */
 static void
 process_coarse_timers (struct context *c)
 {
 #ifdef USE_CRYPTO
   /* flush current packet-id to file once per 60
      seconds if --replay-persist was specified */
   check_packet_id_persist_flush (c);
 #endif
 
   /* should we update status file? */
   check_status_file (c);
 
   /* process connection establishment items */
   check_connection_established (c);
 
 #if P2MP
   /* see if we should send a push_request in response to --pull */
   check_push_request (c);
 #endif
 
90efcacb
 #ifdef PLUGIN_PF
47ae8457
   pf_check_reload (c);
 #endif
 
6fbf66fa
   /* process --route options */
   check_add_routes (c);
 
   /* possibly exit due to --inactive */
   check_inactivity_timeout (c);
   if (c->sig->signal_received)
     return;
 
   /* restart if ping not received */
   check_ping_restart (c);
   if (c->sig->signal_received)
     return;
 
 #if P2MP
e1e977f3
   check_server_poll_timeout (c);
   if (c->sig->signal_received)
     return;
 
6fbf66fa
   check_scheduled_exit (c);
   if (c->sig->signal_received)
     return;
 #endif
 
 #ifdef ENABLE_OCC
   /* Should we send an OCC_REQUEST message? */
   check_send_occ_req (c);
 
   /* Should we send an MTU load test? */
   check_send_occ_load_test (c);
 
   /* Should we send an OCC_EXIT message to remote? */
   if (c->c2.explicit_exit_notification_time_wait)
     process_explicit_exit_notification_timer_wakeup (c);
 #endif
 
   /* Should we ping the remote? */
   check_ping_send (c);
 }
 
 static void
 check_coarse_timers_dowork (struct context *c)
 {
   const struct timeval save = c->c2.timeval;
   c->c2.timeval.tv_sec = BIG_TIMEOUT;
   c->c2.timeval.tv_usec = 0;
   process_coarse_timers (c);
   c->c2.coarse_timer_wakeup = now + c->c2.timeval.tv_sec; 
 
   dmsg (D_INTERVAL, "TIMER: coarse timer wakeup %d seconds", (int) c->c2.timeval.tv_sec);
 
   /* Is the coarse timeout NOT the earliest one? */
   if (c->c2.timeval.tv_sec > save.tv_sec)
     c->c2.timeval = save;
 }
 
 static inline void
 check_coarse_timers (struct context *c)
 {
   const time_t local_now = now;
   if (local_now >= c->c2.coarse_timer_wakeup)
     check_coarse_timers_dowork (c);
   else
     context_reschedule_sec (c, c->c2.coarse_timer_wakeup - local_now);
 }
 
 static void
 check_timeout_random_component_dowork (struct context *c)
 {
   const int update_interval = 10; /* seconds */
   c->c2.update_timeout_random_component = now + update_interval;
   c->c2.timeout_random_component.tv_usec = (time_t) get_random () & 0x0003FFFF;
   c->c2.timeout_random_component.tv_sec = 0;
 
   dmsg (D_INTERVAL, "RANDOM USEC=%d", (int) c->c2.timeout_random_component.tv_usec);
 }
 
 static inline void
 check_timeout_random_component (struct context *c)
 {
   if (now >= c->c2.update_timeout_random_component)
     check_timeout_random_component_dowork (c);
   if (c->c2.timeval.tv_sec >= 1)
     tv_add (&c->c2.timeval, &c->c2.timeout_random_component);
 }
 
 #ifdef ENABLE_SOCKS
 
 /*
  * Handle addition and removal of the 10-byte Socks5 header
  * in UDP packets.
  */
 
 static inline void
 socks_postprocess_incoming_link (struct context *c)
 {
   if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4)
     socks_process_incoming_udp (&c->c2.buf, &c->c2.from);
 }
 
 static inline void
 socks_preprocess_outgoing_link (struct context *c,
8bc93d7f
 				struct link_socket_actual **to_addr,
6fbf66fa
 				int *size_delta)
 {
   if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4)
     {
8bc93d7f
       *size_delta += socks_process_outgoing_udp (&c->c2.to_link, c->c2.to_link_addr);
6fbf66fa
       *to_addr = &c->c2.link_socket->socks_relay;
     }
 }
 
 /* undo effect of socks_preprocess_outgoing_link */
 static inline void
 link_socket_write_post_size_adjust (int *size,
 				    int size_delta,
 				    struct buffer *buf)
 {
   if (size_delta > 0 && *size > size_delta)
     {
       *size -= size_delta;
       if (!buf_advance (buf, size_delta))
 	*size = 0;
     }
 }
 #endif
 
 /*
  * Output: c->c2.buf
  */
 
 void
 read_incoming_link (struct context *c)
 {
   /*
    * Set up for recvfrom call to read datagram
    * sent to our TCP/UDP port.
    */
   int status;
 
ba3ff466
   /*ASSERT (!c->c2.to_tun.len);*/
6fbf66fa
 
ba3ff466
   perf_push (PERF_READ_IN_LINK);
6fbf66fa
 
   c->c2.buf = c->c2.buffers->read_link_buf;
   ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM_ADJ (&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK)));
3c7f2f55
 
8bc93d7f
   status = link_socket_read (c->c2.link_socket,
 			     &c->c2.buf,
 			     MAX_RW_SIZE_LINK (&c->c2.frame),
 			     &c->c2.from);
6fbf66fa
 
   if (socket_connection_reset (c->c2.link_socket, status))
     {
6add6b2f
 #if PORT_SHARE
       if (port_share && socket_foreign_protocol_detected (c->c2.link_socket))
6fbf66fa
 	{
6add6b2f
 	  const struct buffer *fbuf = socket_foreign_protocol_head (c->c2.link_socket);
 	  const int sd = socket_foreign_protocol_sd (c->c2.link_socket);
 	  port_share_redirect (port_share, fbuf, sd);
6fbf66fa
 	  c->sig->signal_received = SIGTERM;
6add6b2f
 	  c->sig->signal_text = "port-share-redirect";
6fbf66fa
 	}
       else
6add6b2f
 #endif
       {
 	/* received a disconnect from a connection-oriented protocol */
 	if (c->options.inetd)
 	  {
 	    c->sig->signal_received = SIGTERM;
3cf6c932
 	    c->sig->signal_text = "connection-reset-inetd";
6add6b2f
 	    msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status);
 	  }
 	else
 	  {
3cf6c932
 #ifdef ENABLE_OCC
 	    if (event_timeout_defined(&c->c2.explicit_exit_notification_interval))
 	      {
 		msg (D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status);
 		openvpn_sleep(1);
 	      }
 	    else
 #endif
 	      {
 		c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- TCP connection reset */
 		c->sig->signal_text = "connection-reset";
 		msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status);
 	      }
6add6b2f
 	  }
       }
6fbf66fa
       perf_pop ();
       return;
     }
 
   /* check recvfrom status */
   check_status (status, "read", c->c2.link_socket, NULL);
 
 #ifdef ENABLE_SOCKS
   /* Remove socks header if applicable */
   socks_postprocess_incoming_link (c);
 #endif
 
   perf_pop ();
 }
 
 /*
  * Input:  c->c2.buf
  * Output: c->c2.to_tun
  */
 
 void
 process_incoming_link (struct context *c)
 {
   struct gc_arena gc = gc_new ();
   bool decrypt_status;
   struct link_socket_info *lsi = get_link_socket_info (c);
   const uint8_t *orig_buf = c->c2.buf.data;
 
   perf_push (PERF_PROC_IN_LINK);
 
   if (c->c2.buf.len > 0)
     {
       c->c2.link_read_bytes += c->c2.buf.len;
16322c78
       link_read_bytes_global += c->c2.buf.len;
6fbf66fa
       c->c2.original_recv_size = c->c2.buf.len;
34a507c9
 #ifdef ENABLE_MANAGEMENT
       if (management)
5f435d64
 	{
 	  management_bytes_in (management, c->c2.buf.len);
 #ifdef MANAGEMENT_DEF_AUTH
 	  management_bytes_server (management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context);
 #endif
 	}
34a507c9
 #endif
6fbf66fa
     }
   else
     c->c2.original_recv_size = 0;
5f435d64
   
6fbf66fa
 #ifdef ENABLE_DEBUG
   /* take action to corrupt packet if we are in gremlin test mode */
   if (c->options.gremlin) {
     if (!ask_gremlin (c->options.gremlin))
       c->c2.buf.len = 0;
     corrupt_gremlin (&c->c2.buf, c->options.gremlin);
   }
 #endif
 
   /* log incoming packet */
 #ifdef LOG_RW
4b19afc3
   if (c->c2.log_rw && c->c2.buf.len > 0)
6fbf66fa
     fprintf (stderr, "R");
 #endif
   msg (D_LINK_RW, "%s READ [%d] from %s: %s",
        proto2ascii (lsi->proto, true),
        BLEN (&c->c2.buf),
8bc93d7f
        print_link_socket_actual (&c->c2.from, &gc),
6fbf66fa
        PROTO_DUMP (&c->c2.buf, &gc));
 
   /*
    * Good, non-zero length packet received.
    * Commence multi-stage processing of packet,
    * such as authenticate, decrypt, decompress.
    * If any stage fails, it sets buf.len to 0 or -1,
    * telling downstream stages to ignore the packet.
    */
   if (c->c2.buf.len > 0)
     {
       if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from))
 	link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from);
 
 #ifdef USE_CRYPTO
 #ifdef USE_SSL
       if (c->c2.tls_multi)
 	{
 	  /*
 	   * If tls_pre_decrypt returns true, it means the incoming
 	   * packet was a good TLS control channel packet.  If so, TLS code
 	   * will deal with the packet and set buf.len to 0 so downstream
 	   * stages ignore it.
 	   *
 	   * If the packet is a data channel packet, tls_pre_decrypt
 	   * will load crypto_options with the correct encryption key
 	   * and return false.
 	   */
 	  /*tls_mutex_lock (c->c2.tls_multi);*/
 	  if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &c->c2.crypto_options))
 	    {
 	      interval_action (&c->c2.tmp_int);
 
 	      /* reset packet received timer if TLS packet */
 	      if (c->options.ping_rec_timeout)
 		event_timeout_reset (&c->c2.ping_rec_interval);
 	    }
 	}
 #if P2MP_SERVER
       /*
        * Drop non-TLS packet if client-connect script/plugin has not
        * yet succeeded.
        */
       if (c->c2.context_auth != CAS_SUCCEEDED)
 	c->c2.buf.len = 0;
 #endif
 #endif /* USE_SSL */
 
       /* authenticate and decrypt the incoming packet */
       decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf, &c->c2.crypto_options, &c->c2.frame);
 
 #ifdef USE_SSL
       if (c->c2.tls_multi)
 	{
 	  /*tls_mutex_unlock (c->c2.tls_multi);*/
 	}
 #endif
       
       if (!decrypt_status && link_socket_connection_oriented (c->c2.link_socket))
 	{
 	  /* decryption errors are fatal in TCP mode */
 	  c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- decryption error in TCP mode */
 	  c->sig->signal_text = "decryption-error";
 	  msg (D_STREAM_ERRORS, "Fatal decryption error (process_incoming_link), restarting");
 	  goto done;
 	}
 
 #endif /* USE_CRYPTO */
 
 #ifdef ENABLE_FRAGMENT
       if (c->c2.fragment)
 	fragment_incoming (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment);
 #endif
 
 #ifdef USE_LZO
       /* decompress the incoming packet */
537073fd
       if (lzo_defined (&c->c2.lzo_compwork))
6fbf66fa
 	lzo_decompress (&c->c2.buf, c->c2.buffers->lzo_decompress_buf, &c->c2.lzo_compwork, &c->c2.frame);
 #endif
3c7f2f55
 
 #ifdef PACKET_TRUNCATION_CHECK
c67d59cd
       /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
3c7f2f55
       ipv4_packet_size_verify (BPTR (&c->c2.buf),
 			       BLEN (&c->c2.buf),
 			       TUNNEL_TYPE (c->c1.tuntap),
 			       "POST_DECRYPT",
 			       &c->c2.n_trunc_post_decrypt);
 #endif
 
6fbf66fa
       /*
        * Set our "official" outgoing address, since
        * if buf.len is non-zero, we know the packet
        * authenticated.  In TLS mode we do nothing
        * because TLS mode takes care of source address
        * authentication.
        *
        * Also, update the persisted version of our packet-id.
        */
       if (!TLS_MODE (c))
 	link_socket_set_outgoing_addr (&c->c2.buf, lsi, &c->c2.from, NULL, c->c2.es);
 
       /* reset packet received timer */
       if (c->options.ping_rec_timeout && c->c2.buf.len > 0)
 	event_timeout_reset (&c->c2.ping_rec_interval);
 
       /* increment authenticated receive byte count */
       if (c->c2.buf.len > 0)
 	{
 	  c->c2.link_read_bytes_auth += c->c2.buf.len;
 	  c->c2.max_recv_size_local = max_int (c->c2.original_recv_size, c->c2.max_recv_size_local);
 	}
 
       /* Did we just receive an openvpn ping packet? */
       if (is_ping_msg (&c->c2.buf))
 	{
c67d59cd
 	  dmsg (D_PING, "RECEIVED PING PACKET");
6fbf66fa
 	  c->c2.buf.len = 0; /* drop packet */
 	}
 
 #ifdef ENABLE_OCC
       /* Did we just receive an OCC packet? */
       if (is_occ_msg (&c->c2.buf))
 	process_received_occ_msg (c);
 #endif
 
       buffer_turnover (orig_buf, &c->c2.to_tun, &c->c2.buf, &c->c2.buffers->read_link_buf);
 
       /* to_tun defined + unopened tuntap can cause deadlock */
       if (!tuntap_defined (c->c1.tuntap))
 	c->c2.to_tun.len = 0;
     }
   else
     {
       buf_reset (&c->c2.to_tun);
     }
  done:
   perf_pop ();
   gc_free (&gc);
 }
 
 /*
  * Output: c->c2.buf
  */
 
 void
 read_incoming_tun (struct context *c)
 {
   /*
    * Setup for read() call on TUN/TAP device.
    */
ba3ff466
   /*ASSERT (!c->c2.to_link.len);*/
 
   perf_push (PERF_READ_IN_TUN);
6fbf66fa
 
   c->c2.buf = c->c2.buffers->read_tun_buf;
 #ifdef TUN_PASS_BUFFER
   read_tun_buffered (c->c1.tuntap, &c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame));
 #else
   ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));
   ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)));
   c->c2.buf.len = read_tun (c->c1.tuntap, BPTR (&c->c2.buf), MAX_RW_SIZE_TUN (&c->c2.frame));
 #endif
 
3c7f2f55
 #ifdef PACKET_TRUNCATION_CHECK
   ipv4_packet_size_verify (BPTR (&c->c2.buf),
 			   BLEN (&c->c2.buf),
 			   TUNNEL_TYPE (c->c1.tuntap),
 			   "READ_TUN",
 			   &c->c2.n_trunc_tun_read);
 #endif
 
6fbf66fa
   /* Was TUN/TAP interface stopped? */
   if (tuntap_stop (c->c2.buf.len))
     {
       c->sig->signal_received = SIGTERM;
       c->sig->signal_text = "tun-stop";
       msg (M_INFO, "TUN/TAP interface has been stopped, exiting");
       perf_pop ();
       return;		  
     }
 
   /* Check the status return from read() */
   check_status (c->c2.buf.len, "read from TUN/TAP", NULL, c->c1.tuntap);
 
   perf_pop ();
 }
 
 /*
  * Input:  c->c2.buf
  * Output: c->c2.to_link
  */
 
 void
 process_incoming_tun (struct context *c)
 {
   struct gc_arena gc = gc_new ();
 
   perf_push (PERF_PROC_IN_TUN);
 
   if (c->c2.buf.len > 0)
     c->c2.tun_read_bytes += c->c2.buf.len;
 
 #ifdef LOG_RW
4b19afc3
   if (c->c2.log_rw && c->c2.buf.len > 0)
6fbf66fa
     fprintf (stderr, "r");
 #endif
 
   /* Show packet content */
7b0a8146
   dmsg (D_TUN_RW, "TUN READ [%d]", BLEN (&c->c2.buf));
6fbf66fa
 
   if (c->c2.buf.len > 0)
     {
       /*
        * The --passtos and --mssfix options require
        * us to examine the IPv4 header.
        */
       process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX, &c->c2.buf);
3c7f2f55
 
 #ifdef PACKET_TRUNCATION_CHECK
c67d59cd
       /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
3c7f2f55
       ipv4_packet_size_verify (BPTR (&c->c2.buf),
 			       BLEN (&c->c2.buf),
 			       TUNNEL_TYPE (c->c1.tuntap),
 			       "PRE_ENCRYPT",
 			       &c->c2.n_trunc_pre_encrypt);
 #endif
 
6fbf66fa
       encrypt_sign (c, true);
     }
   else
     {
       buf_reset (&c->c2.to_link);
     }
   perf_pop ();
   gc_free (&gc);
 }
 
 void
 process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
 {
   if (!c->options.mssfix)
     flags &= ~PIPV4_MSSFIX;
 #if PASSTOS_CAPABILITY
   if (!c->options.passtos)
     flags &= ~PIPV4_PASSTOS;
 #endif
03731db3
   if (!c->options.route_gateway_via_dhcp || !route_list_default_gateway_needed (c->c1.route_list))
     flags &= ~PIPV4_EXTRACT_DHCP_ROUTER;
6fbf66fa
 
   if (buf->len > 0)
     {
       /*
        * The --passtos and --mssfix options require
        * us to examine the IPv4 header.
        */
 #if PASSTOS_CAPABILITY
       if (flags & (PIPV4_PASSTOS|PIPV4_MSSFIX))
 #else
       if (flags & PIPV4_MSSFIX)
 #endif
 	{
 	  struct buffer ipbuf = *buf;
 	  if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf))
 	    {
 #if PASSTOS_CAPABILITY
 	      /* extract TOS from IP header */
 	      if (flags & PIPV4_PASSTOS)
 		link_socket_extract_tos (c->c2.link_socket, &ipbuf);
 #endif
 			  
 	      /* possibly alter the TCP MSS */
 	      if (flags & PIPV4_MSSFIX)
 		mss_fixup (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
03731db3
 
 	      /* possibly extract a DHCP router message */
 	      if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
 		{
 		  const in_addr_t dhcp_router = dhcp_extract_router_msg (&ipbuf);
5c30df12
 		  if (dhcp_router)
 		    route_list_add_default_gateway (c->c1.route_list, c->c2.es, dhcp_router);
03731db3
 		}
6fbf66fa
 	    }
 	}
     }
 }
 
 /*
  * Input: c->c2.to_link
  */
 
 void
 process_outgoing_link (struct context *c)
 {
   struct gc_arena gc = gc_new ();
 
   perf_push (PERF_PROC_OUT_LINK);
 
   if (c->c2.to_link.len > 0 && c->c2.to_link.len <= EXPANDED_SIZE (&c->c2.frame))
     {
       /*
        * Setup for call to send/sendto which will send
        * packet to remote over the TCP/UDP port.
        */
       int size = 0;
8bc93d7f
       ASSERT (link_socket_actual_defined (c->c2.to_link_addr));
6fbf66fa
 
 #ifdef ENABLE_DEBUG
       /* In gremlin-test mode, we may choose to drop this packet */
       if (!c->options.gremlin || ask_gremlin (c->options.gremlin))
 #endif
 	{
 	  /*
 	   * Let the traffic shaper know how many bytes
 	   * we wrote.
 	   */
 #ifdef HAVE_GETTIMEOFDAY
 	  if (c->options.shaper)
 	    shaper_wrote_bytes (&c->c2.shaper, BLEN (&c->c2.to_link)
4e9a51d7
 				+ datagram_overhead (c->options.ce.proto));
6fbf66fa
 #endif
 	  /*
 	   * Let the pinger know that we sent a packet.
 	   */
 	  if (c->options.ping_send_timeout)
 	    event_timeout_reset (&c->c2.ping_send_interval);
 
 #if PASSTOS_CAPABILITY
 	  /* Set TOS */
 	  link_socket_set_tos (c->c2.link_socket);
 #endif
 
 	  /* Log packet send */
 #ifdef LOG_RW
 	  if (c->c2.log_rw)
 	    fprintf (stderr, "W");
 #endif
 	  msg (D_LINK_RW, "%s WRITE [%d] to %s: %s",
 	       proto2ascii (c->c2.link_socket->info.proto, true),
 	       BLEN (&c->c2.to_link),
8bc93d7f
 	       print_link_socket_actual (c->c2.to_link_addr, &gc),
6fbf66fa
 	       PROTO_DUMP (&c->c2.to_link, &gc));
 
 	  /* Packet send complexified by possible Socks5 usage */
 	  {
8bc93d7f
 	    struct link_socket_actual *to_addr = c->c2.to_link_addr;
6fbf66fa
 #ifdef ENABLE_SOCKS
 	    int size_delta = 0;
 #endif
 
 #ifdef ENABLE_SOCKS
 	    /* If Socks5 over UDP, prepend header */
 	    socks_preprocess_outgoing_link (c, &to_addr, &size_delta);
 #endif
 	    /* Send packet */
8bc93d7f
 	    size = link_socket_write (c->c2.link_socket,
 				      &c->c2.to_link,
 				      to_addr);
6fbf66fa
 
 #ifdef ENABLE_SOCKS
 	    /* Undo effect of prepend */
 	    link_socket_write_post_size_adjust (&size, size_delta, &c->c2.to_link);
 #endif
 	  }
 
 	  if (size > 0)
 	    {
 	      c->c2.max_send_size_local = max_int (size, c->c2.max_send_size_local);
 	      c->c2.link_write_bytes += size;
16322c78
 	      link_write_bytes_global += size;
34a507c9
 #ifdef ENABLE_MANAGEMENT
 	      if (management)
5f435d64
 		{
 		  management_bytes_out (management, size);
 #ifdef MANAGEMENT_DEF_AUTH
 		  management_bytes_server (management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context);
 #endif
 		}
34a507c9
 #endif
6fbf66fa
 	    }
 	}
 
       /* Check return status */
       check_status (size, "write", c->c2.link_socket, NULL);
 
       if (size > 0)
 	{
 	  /* Did we write a different size packet than we intended? */
 	  if (size != BLEN (&c->c2.to_link))
 	    msg (D_LINK_ERRORS,
 		 "TCP/UDP packet was truncated/expanded on write to %s (tried=%d,actual=%d)",
8bc93d7f
 		 print_link_socket_actual (c->c2.to_link_addr, &gc),
6fbf66fa
 		 BLEN (&c->c2.to_link),
 		 size);
 	}
838911cc
 
2cde039a
       /* if not a ping/control message, indicate activity regarding --inactive parameter */
       if (c->c2.buf.len > 0 )
         register_activity (c, size);
6fbf66fa
     }
   else
     {
       if (c->c2.to_link.len > 0)
 	msg (D_LINK_ERRORS, "TCP/UDP packet too large on write to %s (tried=%d,max=%d)",
8bc93d7f
 	     print_link_socket_actual (c->c2.to_link_addr, &gc),
6fbf66fa
 	     c->c2.to_link.len,
 	     EXPANDED_SIZE (&c->c2.frame));
     }
 
   buf_reset (&c->c2.to_link);
 
   perf_pop ();
   gc_free (&gc);
 }
 
 /*
  * Input: c->c2.to_tun
  */
 
 void
 process_outgoing_tun (struct context *c)
 {
   struct gc_arena gc = gc_new ();
 
   /*
    * Set up for write() call to TUN/TAP
    * device.
    */
ba3ff466
   if (c->c2.to_tun.len <= 0)
     return;
 
   perf_push (PERF_PROC_OUT_TUN);
6fbf66fa
 
   /*
    * The --mssfix option requires
    * us to examine the IPv4 header.
    */
03731db3
   process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_OUTGOING, &c->c2.to_tun);
6fbf66fa
 
   if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame))
     {
       /*
        * Write to TUN/TAP device.
        */
       int size;
 
 #ifdef LOG_RW
       if (c->c2.log_rw)
 	fprintf (stderr, "w");
 #endif
7b0a8146
       dmsg (D_TUN_RW, "TUN WRITE [%d]", BLEN (&c->c2.to_tun));
6fbf66fa
 
3c7f2f55
 #ifdef PACKET_TRUNCATION_CHECK
       ipv4_packet_size_verify (BPTR (&c->c2.to_tun),
 			       BLEN (&c->c2.to_tun),
 			       TUNNEL_TYPE (c->c1.tuntap),
 			       "WRITE_TUN",
 			       &c->c2.n_trunc_tun_write);
 #endif
 
6fbf66fa
 #ifdef TUN_PASS_BUFFER
       size = write_tun_buffered (c->c1.tuntap, &c->c2.to_tun);
 #else
       size = write_tun (c->c1.tuntap, BPTR (&c->c2.to_tun), BLEN (&c->c2.to_tun));
 #endif
 
       if (size > 0)
 	c->c2.tun_write_bytes += size;
       check_status (size, "write to TUN/TAP", NULL, c->c1.tuntap);
 
       /* check written packet size */
       if (size > 0)
 	{
 	  /* Did we write a different size packet than we intended? */
 	  if (size != BLEN (&c->c2.to_tun))
 	    msg (D_LINK_ERRORS,
 		 "TUN/TAP packet was destructively fragmented on write to %s (tried=%d,actual=%d)",
 		 c->c1.tuntap->actual_name,
 		 BLEN (&c->c2.to_tun),
 		 size);
838911cc
 
 	  /* indicate activity regarding --inactive parameter */
 	  register_activity (c, size);
6fbf66fa
 	}
     }
   else
     {
       /*
        * This should never happen, probably indicates some kind
        * of MTU mismatch.
        */
       msg (D_LINK_ERRORS, "tun packet too large on write (tried=%d,max=%d)",
 	   c->c2.to_tun.len,
 	   MAX_RW_SIZE_TUN (&c->c2.frame));
     }
 
   buf_reset (&c->c2.to_tun);
 
   perf_pop ();
   gc_free (&gc);
 }
 
 void
 pre_select (struct context *c)
 {
   /* make sure current time (now) is updated on function entry */
 
   /*
    * Start with an effectively infinite timeout, then let it
    * reduce to a timeout that reflects the component which
    * needs the earliest service.
    */
   c->c2.timeval.tv_sec = BIG_TIMEOUT;
   c->c2.timeval.tv_usec = 0;
 
 #if defined(WIN32)
   if (check_debug_level (D_TAP_WIN32_DEBUG))
     {
       c->c2.timeval.tv_sec = 1;
       if (tuntap_defined (c->c1.tuntap))
 	tun_show_debug (c->c1.tuntap);
     }
 #endif
 
   /* check coarse timers? */
   check_coarse_timers (c);
   if (c->sig->signal_received)
     return;
 
   /* Does TLS need service? */
   check_tls (c);
 
   /* In certain cases, TLS errors will require a restart */
   check_tls_errors (c);
   if (c->sig->signal_received)
     return;
 
   /* check for incoming configuration info on the control channel */
   check_incoming_control_channel (c);
 
 #ifdef ENABLE_OCC
   /* Should we send an OCC message? */
   check_send_occ_msg (c);
 #endif
 
 #ifdef ENABLE_FRAGMENT
   /* Should we deliver a datagram fragment to remote? */
   check_fragment (c);
 #endif
 
   /* Update random component of timeout */
   check_timeout_random_component (c);
 }
 
 /*
  * Wait for I/O events.  Used for both TCP & UDP sockets
  * in point-to-point mode and for UDP sockets in
  * point-to-multipoint mode.
  */
 
 void
 io_wait_dowork (struct context *c, const unsigned int flags)
 {
   unsigned int socket = 0;
   unsigned int tuntap = 0;
   struct event_set_return esr[4];
 
   /* These shifts all depend on EVENT_READ and EVENT_WRITE */
bb564a59
   static int socket_shift = 0;     /* depends on SOCKET_READ and SOCKET_WRITE */
   static int tun_shift = 2;        /* depends on TUN_READ and TUN_WRITE */
   static int err_shift = 4;        /* depends on ES_ERROR */
6fbf66fa
 #ifdef ENABLE_MANAGEMENT
bb564a59
   static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */
6fbf66fa
 #endif
 
   /*
    * Decide what kind of events we want to wait for.
    */
   event_reset (c->c2.event_set);
 
   /*
    * On win32 we use the keyboard or an event object as a source
    * of asynchronous signals.
    */
   if (flags & IOW_WAIT_SIGNAL)
     wait_signal (c->c2.event_set, (void*)&err_shift);
 
   /*
    * If outgoing data (for TCP/UDP port) pending, wait for ready-to-send
    * status from TCP/UDP port. Otherwise, wait for incoming data on
    * TUN/TAP device.
    */
   if (flags & IOW_TO_LINK)
     {
       if (flags & IOW_SHAPER)
 	{
 	  /*
 	   * If sending this packet would put us over our traffic shaping
 	   * quota, don't send -- instead compute the delay we must wait
 	   * until it will be OK to send the packet.
 	   */
 #ifdef HAVE_GETTIMEOFDAY
 	  int delay = 0;
 
 	  /* set traffic shaping delay in microseconds */
 	  if (c->options.shaper)
 	    delay = max_int (delay, shaper_delay (&c->c2.shaper));
 	  
 	  if (delay < 1000)
 	    {
 	      socket |= EVENT_WRITE;
 	    }
 	  else
 	    {
 	      shaper_soonest_event (&c->c2.timeval, delay);
 	    }
 #else /* HAVE_GETTIMEOFDAY */
 	  socket |= EVENT_WRITE;
 #endif /* HAVE_GETTIMEOFDAY */
 	}
       else
 	{
 	  socket |= EVENT_WRITE;
 	}
     }
   else if (!((flags & IOW_FRAG) && TO_LINK_FRAG (c)))
     {
       if (flags & IOW_READ_TUN)
 	tuntap |= EVENT_READ;
     }
 
   /*
    * If outgoing data (for TUN/TAP device) pending, wait for ready-to-send status
    * from device.  Otherwise, wait for incoming data on TCP/UDP port.
    */
   if (flags & IOW_TO_TUN)
     {
       tuntap |= EVENT_WRITE;
     }
   else
     {
       if (flags & IOW_READ_LINK)
 	socket |= EVENT_READ;
     }
 
   /*
    * outgoing bcast buffer waiting to be sent?
    */
   if (flags & IOW_MBUF)
     socket |= EVENT_WRITE;
 
   /*
    * Force wait on TUN input, even if also waiting on TCP/UDP output
    */
   if (flags & IOW_READ_TUN_FORCE)
     tuntap |= EVENT_READ;
 
   /*
    * Configure event wait based on socket, tuntap flags.
    */
   socket_set (c->c2.link_socket, c->c2.event_set, socket, (void*)&socket_shift, NULL);
   tun_set (c->c1.tuntap, c->c2.event_set, tuntap, (void*)&tun_shift, NULL);
 
 #ifdef ENABLE_MANAGEMENT
   if (management)
     management_socket_set (management, c->c2.event_set, (void*)&management_shift, NULL);
 #endif
 
   /*
    * Possible scenarios:
    *  (1) tcp/udp port has data available to read
    *  (2) tcp/udp port is ready to accept more data to write
    *  (3) tun dev has data available to read
    *  (4) tun dev is ready to accept more data to write
    *  (5) we received a signal (handler sets signal_received)
    *  (6) timeout (tv) expired
    */
 
   c->c2.event_set_status = ES_ERROR;
 
   if (!c->sig->signal_received)
     {
       if (!(flags & IOW_CHECK_RESIDUAL) || !socket_read_residual (c->c2.link_socket))
 	{
 	  int status;
 
 #ifdef ENABLE_DEBUG
 	  if (check_debug_level (D_EVENT_WAIT))
 	    show_wait_status (c);
 #endif
 
 	  /*
 	   * Wait for something to happen.
 	   */
 	  status = event_wait (c->c2.event_set, &c->c2.timeval, esr, SIZE(esr));
 
 	  check_status (status, "event_wait", NULL, NULL);
 
 	  if (status > 0)
 	    {
 	      int i;
 	      c->c2.event_set_status = 0;
 	      for (i = 0; i < status; ++i)
 		{
 		  const struct event_set_return *e = &esr[i];
 		  c->c2.event_set_status |= ((e->rwflags & 3) << *((int*)e->arg));
 		}
 	    }
 	  else if (status == 0)
 	    {
 	      c->c2.event_set_status = ES_TIMEOUT;
 	    }
 	}
       else
 	{
 	  c->c2.event_set_status = SOCKET_READ;
 	}
     }
 
   /* 'now' should always be a reasonably up-to-date timestamp */
   update_time ();
 
   /* set signal_received if a signal was received */
   if (c->c2.event_set_status & ES_ERROR)
     get_signal (&c->sig->signal_received);
 
   dmsg (D_EVENT_WAIT, "I/O WAIT status=0x%04x", c->c2.event_set_status);
 }
 
 void
 process_io (struct context *c)
 {
   const unsigned int status = c->c2.event_set_status;
 
 #ifdef ENABLE_MANAGEMENT
   if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE))
     {
       ASSERT (management);
       management_io (management);
     }
 #endif
 
   /* TCP/UDP port ready to accept write */
   if (status & SOCKET_WRITE)
     {
       process_outgoing_link (c);
     }
   /* TUN device ready to accept write */
   else if (status & TUN_WRITE)
     {
       process_outgoing_tun (c);
     }
   /* Incoming data on TCP/UDP port */
   else if (status & SOCKET_READ)
     {
       read_incoming_link (c);
       if (!IS_SIG (c))
 	process_incoming_link (c);
     }
   /* Incoming data on TUN device */
   else if (status & TUN_READ)
     {
       read_incoming_tun (c);
       if (!IS_SIG (c))
 	process_incoming_tun (c);
     }
 }