must delay iteration over paths until later, as we may be right now creating a connection
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_tunnels.c
index 7d281022c3edb5ef833dbf6da817c2d098225398..d63da29d4c6c65c2acabf4f363dd738651f35acc 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
      This file is part of GNUnet.
      Copyright (C) 2013, 2017 GNUnet e.V.
@@ -18,7 +17,6 @@
      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */
-
 /**
  * @file cadet/gnunet-service-cadet-new_tunnels.c
  * @brief Information we track per tunnel.
  * @author Christian Grothoff
  *
  * FIXME:
+ * - check KX estate machine -- make sure it is never stuck!
+ * - clean up KX logic, including adding sender authentication
+ * - implement connection management (evaluate, kill old ones,
+ *   search for new ones)
  * - when managing connections, distinguish those that
  *   have (recently) had traffic from those that were
  *   never ready (or not recently)
- * - clean up KX logic!
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_signatures.h"
-#include "cadet_protocol.h"
-#include "cadet_path.h"
 #include "gnunet-service-cadet-new.h"
+#include "cadet_protocol.h"
 #include "gnunet-service-cadet-new_channel.h"
 #include "gnunet-service-cadet-new_connection.h"
 #include "gnunet-service-cadet-new_tunnels.h"
@@ -224,43 +224,6 @@ struct CadetTunnelAxolotl
 };
 
 
-/**
- * Entry in list of connections used by tunnel, with metadata.
- */
-struct CadetTConnection
-{
-  /**
-   * Next in DLL.
-   */
-  struct CadetTConnection *next;
-
-  /**
-   * Prev in DLL.
-   */
-  struct CadetTConnection *prev;
-
-  /**
-   * Connection handle.
-   */
-  struct CadetConnection *cc;
-
-  /**
-   * Tunnel this connection belongs to.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Creation time, to keep oldest connection alive.
-   */
-  struct GNUNET_TIME_Absolute created;
-
-  /**
-   * Connection throughput, to keep fastest connection alive.
-   */
-  uint32_t throughput;
-};
-
-
 /**
  * Struct used to save messages in a non-ready tunnel to send once connected.
  */
@@ -336,19 +299,29 @@ struct CadetTunnel
   struct CadetTunnelAxolotl ax;
 
   /**
-   * State of the tunnel connectivity.
+   * Task scheduled if there are no more channels using the tunnel.
    */
-  enum CadetTunnelCState cstate;
+  struct GNUNET_SCHEDULER_Task *destroy_task;
 
   /**
-   * State of the tunnel encryption.
+   * Task to trim connections if too many are present.
    */
-  enum CadetTunnelEState estate;
+  struct GNUNET_SCHEDULER_Task *maintain_connections_task;
+
+  /**
+   * Task to trigger KX.
+   */
+  struct GNUNET_SCHEDULER_Task *kx_task;
+
+  /**
+   * Tokenizer for decrypted messages.
+   */
+  struct GNUNET_MessageStreamTokenizer *mst;
 
   /**
-   * Task to start the rekey process.
+   * Dispatcher for decrypted messages only (do NOT use for sending!).
    */
-  struct GNUNET_SCHEDULER_Task *rekey_task;
+  struct GNUNET_MQ_Handle *mq;
 
   /**
    * DLL of connections that are actively used to reach the destination peer.
@@ -362,14 +335,14 @@ struct CadetTunnel
 
   /**
    * Channels inside this tunnel. Maps
-   * `struct GCT_ChannelTunnelNumber` to a `struct CadetChannel`.
+   * `struct GNUNET_CADET_ChannelTunnelNumber` to a `struct CadetChannel`.
    */
   struct GNUNET_CONTAINER_MultiHashMap32 *channels;
 
   /**
    * Channel ID for the next created channel in this tunnel.
    */
-  struct GCT_ChannelTunnelNumber next_chid;
+  struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
 
   /**
    * Queued messages, to transmit once tunnel gets connected.
@@ -381,25 +354,26 @@ struct CadetTunnel
    */
   struct CadetTunnelQueueEntry *tq_tail;
 
+
   /**
-   * Task scheduled if there are no more channels using the tunnel.
+   * Ephemeral message in the queue (to avoid queueing more than one).
    */
-  struct GNUNET_SCHEDULER_Task *destroy_task;
+  struct CadetConnectionQueue *ephm_hKILL;
 
   /**
-   * Task to trim connections if too many are present.
+   * Pong message in the queue.
    */
-  struct GNUNET_SCHEDULER_Task *maintain_connections_task;
+  struct CadetConnectionQueue *pong_hKILL;
 
   /**
-   * Ephemeral message in the queue (to avoid queueing more than one).
+   * How long do we wait until we retry the KX?
    */
-  struct CadetConnectionQueue *ephm_hKILL;
+  struct GNUNET_TIME_Relative kx_retry_delay;
 
   /**
-   * Pong message in the queue.
+   * When do we try the next KX?
    */
-  struct CadetConnectionQueue *pong_hKILL;
+  struct GNUNET_TIME_Absolute next_kx_attempt;
 
   /**
    * Number of connections in the @e connection_head DLL.
@@ -410,6 +384,12 @@ struct CadetTunnel
    * Number of entries in the @e tq_head DLL.
    */
   unsigned int tq_len;
+
+  /**
+   * State of the tunnel encryption.
+   */
+  enum CadetTunnelEState estate;
+
 };
 
 
@@ -427,15 +407,45 @@ GCT_2s (const struct CadetTunnel *t)
 
   if (NULL == t)
     return "T(NULL)";
-
   GNUNET_snprintf (buf,
                    sizeof (buf),
                    "T(%s)",
-                   GCP_2s (t->destination));
+                   GNUNET_i2s (GCP_get_id (t->destination)));
   return buf;
 }
 
 
+/**
+ * Get string description for tunnel encryption state.
+ *
+ * @param es Tunnel state.
+ *
+ * @return String representation.
+ */
+static const char *
+estate2s (enum CadetTunnelEState es)
+{
+  static char buf[32];
+
+  switch (es)
+  {
+    case CADET_TUNNEL_KEY_UNINITIALIZED:
+      return "CADET_TUNNEL_KEY_UNINITIALIZED";
+    case CADET_TUNNEL_KEY_SENT:
+      return "CADET_TUNNEL_KEY_SENT";
+    case CADET_TUNNEL_KEY_PING:
+      return "CADET_TUNNEL_KEY_PING";
+    case CADET_TUNNEL_KEY_OK:
+      return "CADET_TUNNEL_KEY_OK";
+    case CADET_TUNNEL_KEY_REKEY:
+      return "CADET_TUNNEL_KEY_REKEY";
+    default:
+      SPRINTF (buf, "%u (UNKNOWN STATE)", es);
+      return buf;
+  }
+}
+
+
 /**
  * Return the peer to which this tunnel goes.
  *
@@ -463,6 +473,22 @@ GCT_count_channels (struct CadetTunnel *t)
 }
 
 
+/**
+ * Lookup a channel by its @a ctn.
+ *
+ * @param t tunnel to look in
+ * @param ctn number of channel to find
+ * @return NULL if channel does not exist
+ */
+struct CadetChannel *
+lookup_channel (struct CadetTunnel *t,
+                struct GNUNET_CADET_ChannelTunnelNumber ctn)
+{
+  return GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                              ntohl (ctn.cn));
+}
+
+
 /**
  * Count all created connections of a tunnel. Not necessarily ready connections!
  *
@@ -478,16 +504,34 @@ GCT_count_any_connections (struct CadetTunnel *t)
 
 
 /**
- * Get the connectivity state of a tunnel.
- *
- * @param t Tunnel.
+ * Find first connection that is ready in the list of
+ * our connections.  Picks ready connections round-robin.
  *
- * @return Tunnel's connectivity state.
+ * @param t tunnel to search
+ * @return NULL if we have no connection that is ready
  */
-enum CadetTunnelCState
-GCT_get_cstate (struct CadetTunnel *t)
+static struct CadetTConnection *
+get_ready_connection (struct CadetTunnel *t)
 {
-  return t->cstate;
+  for (struct CadetTConnection *pos = t->connection_head;
+       NULL != pos;
+       pos = pos->next)
+    if (GNUNET_YES == pos->is_ready)
+    {
+      if (pos != t->connection_tail)
+      {
+        /* move 'pos' to the end, so we try other ready connections
+           first next time (round-robin, modulo availability) */
+        GNUNET_CONTAINER_DLL_remove (t->connection_head,
+                                     t->connection_tail,
+                                     pos);
+        GNUNET_CONTAINER_DLL_insert_tail (t->connection_head,
+                                          t->connection_tail,
+                                          pos);
+      }
+      return pos;
+    }
+  return NULL;
 }
 
 
@@ -518,6 +562,19 @@ new_ephemeral (struct CadetTunnel *t)
 }
 
 
+
+/**
+ * Called when either we have a new connection, or a new message in the
+ * queue, or some existing connection has transmission capacity.  Looks
+ * at our message queue and if there is a message, picks a connection
+ * to send it on.
+ *
+ * @param t tunnel to process messages on
+ */
+static void
+trigger_transmissions (struct CadetTunnel *t);
+
+
 /* ************************************** start core crypto ***************************** */
 
 
@@ -750,7 +807,7 @@ t_ax_decrypt (struct CadetTunnel *t,
  */
 static void
 t_h_encrypt (struct CadetTunnel *t,
-             struct GNUNET_CADET_Encrypted *msg)
+             struct GNUNET_CADET_TunnelEncryptedMessage *msg)
 {
   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
   struct CadetTunnelAxolotl *ax;
@@ -779,8 +836,8 @@ t_h_encrypt (struct CadetTunnel *t,
  */
 static void
 t_h_decrypt (struct CadetTunnel *t,
-             const struct GNUNET_CADET_Encrypted *src,
-             struct GNUNET_CADET_Encrypted *dst)
+             const struct GNUNET_CADET_TunnelEncryptedMessage *src,
+             struct GNUNET_CADET_TunnelEncryptedMessage *dst)
 {
   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
   struct CadetTunnelAxolotl *ax;
@@ -831,13 +888,13 @@ delete_skipped_key (struct CadetTunnel *t,
 static ssize_t
 try_old_ax_keys (struct CadetTunnel *t,
                  void *dst,
-                 const struct GNUNET_CADET_Encrypted *src,
+                 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
                  size_t size)
 {
   struct CadetTunnelSkippedKey *key;
   struct GNUNET_ShortHashCode *hmac;
   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct GNUNET_CADET_Encrypted plaintext_header;
+  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
   struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK;
   size_t esize;
   size_t res;
@@ -847,7 +904,7 @@ try_old_ax_keys (struct CadetTunnel *t,
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Trying skipped keys\n");
   hmac = &plaintext_header.hmac;
-  esize = size - sizeof (struct GNUNET_CADET_Encrypted);
+  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
 
   /* Find a correct Header Key */
   valid_HK = NULL;
@@ -870,8 +927,8 @@ try_old_ax_keys (struct CadetTunnel *t,
     return -1;
 
   /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */
-  GNUNET_assert (size > sizeof (struct GNUNET_CADET_Encrypted));
-  len = size - sizeof (struct GNUNET_CADET_Encrypted);
+  GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage));
+  len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
   GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader));
 
   /* Decrypt header */
@@ -1009,18 +1066,18 @@ store_ax_keys (struct CadetTunnel *t,
 static ssize_t
 t_ax_decrypt_and_validate (struct CadetTunnel *t,
                            void *dst,
-                           const struct GNUNET_CADET_Encrypted *src,
+                           const struct GNUNET_CADET_TunnelEncryptedMessage *src,
                            size_t size)
 {
   struct CadetTunnelAxolotl *ax;
   struct GNUNET_ShortHashCode msg_hmac;
   struct GNUNET_HashCode hmac;
-  struct GNUNET_CADET_Encrypted plaintext_header;
+  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
   uint32_t Np;
   uint32_t PNp;
   size_t esize; /* Size of encryped payload */
 
-  esize = size - sizeof (struct GNUNET_CADET_Encrypted);
+  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
   ax = &t->ax;
 
   /* Try current HK */
@@ -1115,161 +1172,587 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t,
 }
 
 
-/* ************************************** end core crypto ***************************** */
-
-
 /**
- * Add a channel to a tunnel.
+ * Our tunnel became ready for the first time, notify channels
+ * that have been waiting.
  *
- * @param t Tunnel.
- * @param ch Channel
- * @return unique number identifying @a ch within @a t
+ * @param cls our tunnel, not used
+ * @param key unique ID of the channel, not used
+ * @param value the `struct CadetChannel` to notify
+ * @return #GNUNET_OK (continue to iterate)
  */
-struct GCT_ChannelTunnelNumber
-GCT_add_channel (struct CadetTunnel *t,
-                 struct CadetChannel *ch)
+static int
+notify_tunnel_up_cb (void *cls,
+                     uint32_t key,
+                     void *value)
 {
-  struct GCT_ChannelTunnelNumber ret;
-  uint32_t chid;
+  struct CadetChannel *ch = value;
 
-  chid = ntohl (t->next_chid.channel_in_tunnel);
-  while (NULL !=
-         GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                              chid))
-    chid++;
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
-                                                      chid,
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  t->next_chid.channel_in_tunnel = htonl (chid + 1);
-  ret.channel_in_tunnel = htonl (chid);
-  return ret;
+  GCCH_tunnel_up (ch);
+  return GNUNET_OK;
 }
 
 
 /**
- * This tunnel is no longer used, destroy it.
+ * Change the tunnel encryption state.
+ * If the encryption state changes to OK, stop the rekey task.
  *
- * @param cls the idle tunnel
+ * @param t Tunnel whose encryption state to change, or NULL.
+ * @param state New encryption state.
  */
-static void
-destroy_tunnel (void *cls)
+void
+GCT_change_estate (struct CadetTunnel *t,
+                   enum CadetTunnelEState state)
 {
-  struct CadetTunnel *t = cls;
-  struct CadetTConnection *ct;
-  struct CadetTunnelQueueEntry *tqe;
+  enum CadetTunnelEState old = t->estate;
 
-  t->destroy_task = NULL;
-  GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (t->channels));
-  while (NULL != (ct = t->connection_head))
-  {
-    GNUNET_assert (ct->t == t);
-    GNUNET_CONTAINER_DLL_remove (t->connection_head,
-                                 t->connection_tail,
-                                 ct);
-    GCC_destroy (ct->cc);
-    GNUNET_free (ct);
-  }
-  while (NULL != (tqe = t->tq_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (t->tq_head,
-                                 t->tq_tail,
-                                 tqe);
-    GNUNET_MQ_discard (tqe->env);
-    GNUNET_free (tqe);
-  }
-  GCP_drop_tunnel (t->destination,
-                   t);
-  GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
-  if (NULL != t->maintain_connections_task)
+  t->estate = state;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Tunnel %s estate changed from %d to %d\n",
+       GCT_2s (t),
+       old,
+       state);
+
+  if ( (CADET_TUNNEL_KEY_OK != old) &&
+       (CADET_TUNNEL_KEY_OK == t->estate) )
   {
-    GNUNET_SCHEDULER_cancel (t->maintain_connections_task);
-    t->maintain_connections_task = NULL;
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    if (CADET_TUNNEL_KEY_REKEY != old)
+    {
+      /* notify all channels that have been waiting */
+      GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                               &notify_tunnel_up_cb,
+                                               t);
+    }
+
+    /* FIXME: schedule rekey task! */
   }
-  GNUNET_free (t);
 }
 
 
 /**
- * A connection is ready for transmission.  Looks at our message queue
- * and if there is a message, sends it out via the connection.
+ * Send a KX message.
  *
- * @param cls the `struct CadetTConnection` that is ready
- */
-static void
-connection_ready_cb (void *cls)
-{
-  struct CadetTConnection *ct = cls;
-  struct CadetTunnel *t = ct->t;
-  struct CadetTunnelQueueEntry *tq = t->tq_head;
-
-  if (NULL == tq)
-    return; /* no messages pending right now */
-
-  /* ready to send message 'tq' on tunnel 'ct' */
-  GNUNET_assert (t == tq->t);
-  GNUNET_CONTAINER_DLL_remove (t->tq_head,
-                               t->tq_tail,
-                               tq);
-  if (NULL != tq->cid)
-    *tq->cid = *GCC_get_id (ct->cc);
-  GCC_transmit (ct->cc,
-                tq->env);
-  tq->cont (tq->cont_cls);
-  GNUNET_free (tq);
-}
-
-
-/**
- * Called when either we have a new connection, or a new message in the
- * queue, or some existing connection has transmission capacity.  Looks
- * at our message queue and if there is a message, picks a connection
- * to send it on.
+ * FIXME: does not take care of sender-authentication yet!
  *
- * @param t tunnel to process messages on
+ * @param t Tunnel on which to send it.
+ * @param force_reply Force the other peer to reply with a KX message.
  */
 static void
-trigger_transmissions (struct CadetTunnel *t)
+send_kx (struct CadetTunnel *t,
+         int force_reply)
 {
+  struct CadetTunnelAxolotl *ax = &t->ax;
   struct CadetTConnection *ct;
+  struct CadetConnection *cc;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
+  enum GNUNET_CADET_KX_Flags flags;
 
-  if (NULL == t->tq_head)
-    return; /* no messages pending right now */
-  for (ct = t->connection_head;
-       NULL != ct;
-       ct = ct->next)
-    if (GNUNET_YES == GCC_is_ready (ct->cc))
-      break;
+  ct = get_ready_connection (t);
   if (NULL == ct)
-    return; /* no connections ready */
-  connection_ready_cb (ct);
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Wanted to send KX on tunnel %s, but no connection is ready, deferring\n",
+                GCT_2s (t));
+    return;
+  }
+  cc = ct->cc;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending KX on tunnel %s using connection %s\n",
+              GCT_2s (t),
+              GCC_2s (ct->cc));
+
+  // GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
+  flags = GNUNET_CADET_KX_FLAG_NONE;
+  if (GNUNET_YES == force_reply)
+    flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
+  msg->flags = htonl (flags);
+  msg->cid = *GCC_get_id (cc);
+  GNUNET_CRYPTO_ecdhe_key_get_public (ax->kx_0,
+                                      &msg->ephemeral_key);
+  GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs,
+                                      &msg->ratchet_key);
+  GCC_transmit (cc,
+                env);
+  t->kx_retry_delay = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
+  t->next_kx_attempt = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
+  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_SENT);
 }
 
 
 /**
- * Function called to maintain the connections underlying our tunnel.
- * Tries to maintain (incl. tear down) connections for the tunnel, and
- * if there is a significant change, may trigger transmissions.
+ * Handle KX message.
  *
- * Basically, needs to check if there are connections that perform
- * badly, and if so eventually kill them and trigger a replacement.
- * The strategy is to open one more connection than
- * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
- * least-performing one, and then inquire for new ones.
+ * FIXME: sender-authentication in KX is missing!
  *
- * @param cls the `struct CadetTunnel`
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
  */
-static void
-maintain_connections_cb (void *cls)
+void
+GCT_handle_kx (struct CadetTConnection *ct,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
 {
-  struct CadetTunnel *t = cls;
-
-  GNUNET_break (0); // FIXME: implement!
-}
+  struct CadetTunnel *t = ct->t;
+  struct CadetTunnelAxolotl *ax = &t->ax;
+  struct GNUNET_HashCode key_material[3];
+  struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
+  const char salt[] = "CADET Axolotl salt";
+  const struct GNUNET_PeerIdentity *pid;
+  int am_I_alice;
+
+  pid = GCP_get_id (t->destination);
+  if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+                                           pid))
+    am_I_alice = GNUNET_YES;
+  else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+                                                pid))
+    am_I_alice = GNUNET_NO;
+  else
+  {
+    GNUNET_break_op (0);
+    return;
+  }
 
+  if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags)))
+  {
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             GNUNET_NO);
+  }
 
-/**
+  if (0 == memcmp (&ax->DHRr,
+                   &msg->ratchet_key,
+                   sizeof (msg->ratchet_key)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         " known ratchet key, exit\n");
+    return;
+  }
+
+  ax->DHRr = msg->ratchet_key;
+
+  /* ECDH A B0 */
+  if (GNUNET_YES == am_I_alice)
+  {
+    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
+                              &msg->ephemeral_key, /* B0 */
+                              &key_material[0]);
+  }
+  else
+  {
+    GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0,            /* B0 */
+                              &pid->public_key,    /* A */
+                              &key_material[0]);
+  }
+
+  /* ECDH A0 B */
+  if (GNUNET_YES == am_I_alice)
+  {
+    GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0,            /* A0 */
+                              &pid->public_key,    /* B */
+                              &key_material[1]);
+  }
+  else
+  {
+    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
+                              &msg->ephemeral_key, /* B0 */
+                              &key_material[1]);
+
+
+  }
+
+  /* ECDH A0 B0 */
+  /* (This is the triple-DH, we could probably safely skip this,
+     as A0/B0 are already in the key material.) */
+  GNUNET_CRYPTO_ecc_ecdh (ax->kx_0,             /* A0 or B0 */
+                          &msg->ephemeral_key,  /* B0 or A0 */
+                          &key_material[2]);
+
+  /* KDF */
+  GNUNET_CRYPTO_kdf (keys, sizeof (keys),
+                     salt, sizeof (salt),
+                     &key_material, sizeof (key_material),
+                     NULL);
+
+  if (0 == memcmp (&ax->RK,
+                   &keys[0],
+                   sizeof (ax->RK)))
+  {
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         " known handshake key, exit\n");
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Handling KX message for tunnel %s\n",
+              GCT_2s (t));
+
+  ax->RK = keys[0];
+  if (GNUNET_YES == am_I_alice)
+  {
+    ax->HKr = keys[1];
+    ax->NHKs = keys[2];
+    ax->NHKr = keys[3];
+    ax->CKr = keys[4];
+    ax->ratchet_flag = GNUNET_YES;
+  }
+  else
+  {
+    ax->HKs = keys[1];
+    ax->NHKr = keys[2];
+    ax->NHKs = keys[3];
+    ax->CKs = keys[4];
+    ax->ratchet_flag = GNUNET_NO;
+    ax->ratchet_allowed = GNUNET_NO;
+    ax->ratchet_counter = 0;
+    ax->ratchet_expiration
+      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
+                                  ratchet_time);
+  }
+  ax->PNs = 0;
+  ax->Nr = 0;
+  ax->Ns = 0;
+
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_PING);
+    break;
+  case CADET_TUNNEL_KEY_SENT:
+    /* Got a response to us sending our key; now
+       we can start transmitting! */
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_OK);
+    trigger_transmissions (t);
+    break;
+  case CADET_TUNNEL_KEY_PING:
+    /* Got a key yet again; need encrypted payload to advance */
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    /* Did not expect a key, but so what. */
+    break;
+  case CADET_TUNNEL_KEY_REKEY:
+    /* Got a key yet again; need encrypted payload to advance */
+    break;
+  }
+}
+
+
+/* ************************************** end core crypto ***************************** */
+
+
+/**
+ * Compute the next free channel tunnel number for this tunnel.
+ *
+ * @param t the tunnel
+ * @return unused number that can uniquely identify a channel in the tunnel
+ */
+static struct GNUNET_CADET_ChannelTunnelNumber
+get_next_free_ctn (struct CadetTunnel *t)
+{
+  struct GNUNET_CADET_ChannelTunnelNumber ret;
+  uint32_t ctn;
+
+  /* FIXME: this logic does NOT prevent both ends of the
+     channel from picking the same CTN!
+     Need to reserve one bit of the CTN for the
+     direction, i.e. which side established the connection! */
+  ctn = ntohl (t->next_ctn.cn);
+  while (NULL !=
+         GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                              ctn))
+    ctn++;
+  t->next_ctn.cn = htonl (ctn + 1);
+  ret.cn = ntohl (ctn);
+  return ret;
+}
+
+
+/**
+ * Add a channel to a tunnel, and notify channel that we are ready
+ * for transmission if we are already up.  Otherwise that notification
+ * will be done later in #notify_tunnel_up_cb().
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @return unique number identifying @a ch within @a t
+ */
+struct GNUNET_CADET_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+                 struct CadetChannel *ch)
+{
+  struct GNUNET_CADET_ChannelTunnelNumber ctn;
+
+  ctn = get_next_free_ctn (t);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
+                                                      ntohl (ctn.cn),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Adding channel %s to tunnel %s\n",
+              GCCH_2s (ch),
+              GCT_2s (t));
+  if ( (CADET_TUNNEL_KEY_OK == t->estate) ||
+       (CADET_TUNNEL_KEY_REKEY == t->estate) )
+    GCCH_tunnel_up (ch);
+  return ctn;
+}
+
+
+/**
+ * This tunnel is no longer used, destroy it.
+ *
+ * @param cls the idle tunnel
+ */
+static void
+destroy_tunnel (void *cls)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetTConnection *ct;
+  struct CadetTunnelQueueEntry *tq;
+
+  t->destroy_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Destroying idle tunnel %s\n",
+              GCT_2s (t));
+  GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (t->channels));
+  while (NULL != (ct = t->connection_head))
+  {
+    GNUNET_assert (ct->t == t);
+    GNUNET_CONTAINER_DLL_remove (t->connection_head,
+                                 t->connection_tail,
+                                 ct);
+    GCC_destroy (ct->cc);
+    GNUNET_free (ct);
+  }
+  while (NULL != (tq = t->tq_head))
+    GCT_send_cancel (tq);
+  GCP_drop_tunnel (t->destination,
+                   t);
+  GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
+  if (NULL != t->maintain_connections_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->maintain_connections_task);
+    t->maintain_connections_task = NULL;
+  }
+  GNUNET_MST_destroy (t->mst);
+  GNUNET_MQ_destroy (t->mq);
+  while (NULL != t->ax.skipped_head)
+    delete_skipped_key (t,
+                        t->ax.skipped_head);
+  GNUNET_assert (0 == t->ax.skipped);
+  GNUNET_free_non_null (t->ax.kx_0);
+  GNUNET_free_non_null (t->ax.DHRs);
+  GNUNET_free (t);
+}
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @param ctn unique number identifying @a ch within @a t
+ */
+void
+GCT_remove_channel (struct CadetTunnel *t,
+                    struct CadetChannel *ch,
+                    struct GNUNET_CADET_ChannelTunnelNumber ctn)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Removing channel %s from tunnel %s\n",
+              GCCH_2s (ch),
+              GCT_2s (t));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
+                                                         ntohl (ctn.cn),
+                                                         ch));
+  if (0 ==
+      GNUNET_CONTAINER_multihashmap32_size (t->channels))
+  {
+    t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+                                                    &destroy_tunnel,
+                                                    t);
+  }
+}
+
+
+/**
+ * Destroys the tunnel @a t now, without delay. Used during shutdown.
+ *
+ * @param t tunnel to destroy
+ */
+void
+GCT_destroy_tunnel_now (struct CadetTunnel *t)
+{
+  GNUNET_assert (0 ==
+                 GNUNET_CONTAINER_multihashmap32_size (t->channels));
+  GNUNET_SCHEDULER_cancel (t->destroy_task);
+  destroy_tunnel (t);
+}
+
+
+/**
+ * It's been a while, we should try to redo the KX, if we can.
+ *
+ * @param cls the `struct CadetTunnel` to do KX for.
+ */
+static void
+retry_kx (void *cls)
+{
+  struct CadetTunnel *t = cls;
+
+  t->kx_task = NULL;
+  send_kx (t,
+           ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
+             (CADET_TUNNEL_KEY_SENT == t->estate) )
+           ? GNUNET_YES
+           : GNUNET_NO);
+}
+
+
+/**
+ * Send normal payload from queue in @a t via connection @a ct.
+ * Does nothing if our payload queue is empty.
+ *
+ * @param t tunnel to send data from
+ * @param ct connection to use for transmission (is ready)
+ */
+static void
+try_send_normal_payload (struct CadetTunnel *t,
+                         struct CadetTConnection *ct)
+{
+  struct CadetTunnelQueueEntry *tq;
+
+  GNUNET_assert (GNUNET_YES == ct->is_ready);
+  tq = t->tq_head;
+  if (NULL == tq)
+  {
+    /* no messages pending right now */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Not sending payload of tunnel %s on ready connection %s (nothing pending)\n",
+                GCT_2s (t),
+                GCC_2s (ct->cc));
+    return;
+  }
+  /* ready to send message 'tq' on tunnel 'ct' */
+  GNUNET_assert (t == tq->t);
+  GNUNET_CONTAINER_DLL_remove (t->tq_head,
+                               t->tq_tail,
+                               tq);
+  if (NULL != tq->cid)
+    *tq->cid = *GCC_get_id (ct->cc);
+  ct->is_ready = GNUNET_NO;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending payload of tunnel %s on connection %s\n",
+              GCT_2s (t),
+              GCC_2s (ct->cc));
+  GCC_transmit (ct->cc,
+                tq->env);
+  if (NULL != tq->cont)
+    tq->cont (tq->cont_cls);
+  GNUNET_free (tq);
+}
+
+
+/**
+ * A connection is @a is_ready for transmission.  Looks at our message
+ * queue and if there is a message, sends it out via the connection.
+ *
+ * @param cls the `struct CadetTConnection` that is @a is_ready
+ * @param is_ready #GNUNET_YES if connection are now ready,
+ *                 #GNUNET_NO if connection are no longer ready
+ */
+static void
+connection_ready_cb (void *cls,
+                     int is_ready)
+{
+  struct CadetTConnection *ct = cls;
+  struct CadetTunnel *t = ct->t;
+
+  if (GNUNET_NO == is_ready)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Connection %s no longer ready for tunnel %s\n",
+                GCC_2s (ct->cc),
+                GCT_2s (t));
+    ct->is_ready = GNUNET_NO;
+    return;
+  }
+  ct->is_ready = GNUNET_YES;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Connection %s now ready for tunnel %s in state %s\n",
+              GCC_2s (ct->cc),
+              GCT_2s (t),
+              estate2s (t->estate));
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+    send_kx (t,
+             GNUNET_YES);
+    break;
+  case CADET_TUNNEL_KEY_SENT:
+  case CADET_TUNNEL_KEY_PING:
+    /* opportunity to #retry_kx() starts now, schedule job */
+    if (NULL == t->kx_task)
+    {
+      t->kx_task
+        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+                                   &retry_kx,
+                                   t);
+    }
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    try_send_normal_payload (t,
+                             ct);
+    break;
+  case CADET_TUNNEL_KEY_REKEY:
+    send_kx (t,
+             GNUNET_NO);
+    t->estate = CADET_TUNNEL_KEY_OK;
+    break;
+  }
+}
+
+
+/**
+ * Called when either we have a new connection, or a new message in the
+ * queue, or some existing connection has transmission capacity.  Looks
+ * at our message queue and if there is a message, picks a connection
+ * to send it on.
+ *
+ * @param t tunnel to process messages on
+ */
+static void
+trigger_transmissions (struct CadetTunnel *t)
+{
+  struct CadetTConnection *ct;
+
+  if (NULL == t->tq_head)
+    return; /* no messages pending right now */
+  ct = get_ready_connection (t);
+  if (NULL == ct)
+    return; /* no connections ready */
+  try_send_normal_payload (t,
+                           ct);
+}
+
+
+/**
  * Consider using the path @a p for the tunnel @a t.
  * The tunnel destination is at offset @a off in path @a p.
  *
@@ -1297,7 +1780,13 @@ consider_path_cb (void *cls,
 
     ps = GCC_get_path (ct->cc);
     if (ps == path)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Ignoring duplicate path %s for tunnel %s.\n",
+                  GCPP_2s (path),
+                  GCT_2s (t));
       return GNUNET_YES; /* duplicate */
+    }
     min_length = GNUNET_MIN (min_length,
                              GCPP_get_length (ps));
     max_desire = GNUNET_MAX (max_desire,
@@ -1341,7 +1830,7 @@ consider_path_cb (void *cls,
                        path,
                        ct,
                        &connection_ready_cb,
-                       t);
+                       ct);
   /* FIXME: schedule job to kill connection (and path?)  if it takes
      too long to get ready! (And track performance data on how long
      other connections took with the tunnel!)
@@ -1350,10 +1839,46 @@ consider_path_cb (void *cls,
                                t->connection_tail,
                                ct);
   t->num_connections++;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Found interesting path %s for tunnel %s, created connection %s\n",
+              GCPP_2s (path),
+              GCT_2s (t),
+              GCC_2s (ct->cc));
   return GNUNET_YES;
 }
 
 
+/**
+ * Function called to maintain the connections underlying our tunnel.
+ * Tries to maintain (incl. tear down) connections for the tunnel, and
+ * if there is a significant change, may trigger transmissions.
+ *
+ * Basically, needs to check if there are connections that perform
+ * badly, and if so eventually kill them and trigger a replacement.
+ * The strategy is to open one more connection than
+ * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
+ * least-performing one, and then inquire for new ones.
+ *
+ * @param cls the `struct CadetTunnel`
+ */
+static void
+maintain_connections_cb (void *cls)
+{
+  struct CadetTunnel *t = cls;
+
+  t->maintain_connections_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Performing connection maintenance for tunnel %s.\n",
+              GCT_2s (t));
+
+  (void) GCP_iterate_paths (t->destination,
+                            &consider_path_cb,
+                            t);
+
+  GNUNET_break (0); // FIXME: implement!
+}
+
+
 /**
  * Consider using the path @a p for the tunnel @a t.
  * The tunnel destination is at offset @a off in path @a p.
@@ -1374,104 +1899,351 @@ GCT_consider_path (struct CadetTunnel *t,
 
 
 /**
- * Create a tunnel to @a destionation.  Must only be called
- * from within #GCP_get_tunnel().
+ * NOT IMPLEMENTED.
  *
- * @param destination where to create the tunnel to
- * @return new tunnel to @a destination
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg  the message we received on the tunnel
  */
-struct CadetTunnel *
-GCT_create_tunnel (struct CadetPeer *destination)
+static void
+handle_plaintext_keepalive (void *cls,
+                            const struct GNUNET_MessageHeader *msg)
 {
-  struct CadetTunnel *t;
+  struct CadetTunnel *t = cls;
 
-  t = GNUNET_new (struct CadetTunnel);
-  t->destination = destination;
-  t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
-  (void) GCP_iterate_paths (destination,
-                            &consider_path_cb,
-                            t);
-  t->maintain_connections_task
-    = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
-                                t);
-  return t;
+  GNUNET_break (0); // FIXME
 }
 
 
 /**
- * Remove a channel from a tunnel.
+ * Check that @a msg is well-formed.
  *
- * @param t Tunnel.
- * @param ch Channel
- * @param gid unique number identifying @a ch within @a t
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg  the message we received on the tunnel
+ * @return #GNUNET_OK (any variable-size payload goes)
  */
-void
-GCT_remove_channel (struct CadetTunnel *t,
-                    struct CadetChannel *ch,
-                    struct GCT_ChannelTunnelNumber gid)
+static int
+check_plaintext_data (void *cls,
+                      const struct GNUNET_CADET_ChannelAppDataMessage *msg)
 {
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
-                                                         ntohl (gid.channel_in_tunnel),
-                                                         ch));
-  if (0 ==
-      GNUNET_CONTAINER_multihashmap32_size (t->channels))
+  return GNUNET_OK;
+}
+
+
+/**
+ * We received payload data for a channel.  Locate the channel
+ * and process the data, or return an error if the channel is unknown.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg the message we received on the tunnel
+ */
+static void
+handle_plaintext_data (void *cls,
+                       const struct GNUNET_CADET_ChannelAppDataMessage *msg)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       msg->ctn);
+  if (NULL == ch)
   {
-    t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
-                                                    &destroy_tunnel,
-                                                    t);
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Receicved %u bytes of application data for unknown channel %u, sending DESTROY\n",
+         (unsigned int) (ntohs (msg->header.size) - sizeof (*msg)),
+         ntohl (msg->ctn.cn));
+    GCT_send_channel_destroy (t,
+                              msg->ctn);
+    return;
   }
+  GCCH_handle_channel_plaintext_data (ch,
+                                      msg);
 }
 
 
 /**
- * Change the tunnel encryption state.
- * If the encryption state changes to OK, stop the rekey task.
+ * We received an acknowledgement for data we sent on a channel.
+ * Locate the channel and process it, or return an error if the
+ * channel is unknown.
  *
- * @param t Tunnel whose encryption state to change, or NULL.
- * @param state New encryption state.
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param ack the message we received on the tunnel
+ */
+static void
+handle_plaintext_data_ack (void *cls,
+                           const struct GNUNET_CADET_ChannelDataAckMessage *ack)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       ack->ctn);
+  if (NULL == ch)
+  {
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Receicved DATA_ACK for unknown channel %u, sending DESTROY\n",
+         ntohl (ack->ctn.cn));
+    GCT_send_channel_destroy (t,
+                              ack->ctn);
+    return;
+  }
+  GCCH_handle_channel_plaintext_data_ack (ch,
+                                          ack);
+}
+
+
+/**
+ * We have received a request to open a channel to a port from
+ * another peer.  Creates the incoming channel.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param cc the message we received on the tunnel
+ */
+static void
+handle_plaintext_channel_open (void *cls,
+                               const struct GNUNET_CADET_ChannelOpenMessage *cc)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+  struct GNUNET_CADET_ChannelTunnelNumber ctn;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Receicved channel OPEN on port %s from peer %s\n",
+       GNUNET_h2s (&cc->port),
+       GCP_2s (GCT_get_destination (t)));
+  ctn = get_next_free_ctn (t);
+  ch = GCCH_channel_incoming_new (t,
+                                  ctn,
+                                  &cc->port,
+                                  ntohl (cc->opt));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
+                                                      ntohl (ctn.cn),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+}
+
+
+/**
+ * Send a DESTROY message via the tunnel.
+ *
+ * @param t the tunnel to transmit over
+ * @param ctn ID of the channel to destroy
  */
 void
-GCT_change_estate (struct CadetTunnel *t,
-                   enum CadetTunnelEState state)
+GCT_send_channel_destroy (struct CadetTunnel *t,
+                          struct GNUNET_CADET_ChannelTunnelNumber ctn)
 {
-  enum CadetTunnelEState old = t->estate;
+  struct GNUNET_CADET_ChannelManageMessage msg;
 
-  t->estate = state;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Tunnel %s estate changed from %d to %d\n",
-       GCT_2s (t),
-       old,
-       state);
+       "Sending DESTORY message for channel ID %u\n",
+       ntohl (ctn.cn));
+  msg.header.size = htons (sizeof (msg));
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
+  msg.reserved = htonl (0);
+  msg.ctn = ctn;
+  GCT_send (t,
+            &msg.header,
+            NULL,
+            NULL);
+}
 
-  if ( (CADET_TUNNEL_KEY_OK != old) &&
-       (CADET_TUNNEL_KEY_OK == t->estate) )
+
+/**
+ * We have received confirmation from the target peer that the
+ * given channel could be established (the port is open).
+ * Tell the client.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param cm the message we received on the tunnel
+ */
+static void
+handle_plaintext_channel_open_ack (void *cls,
+                                   const struct GNUNET_CADET_ChannelManageMessage *cm)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       cm->ctn);
+  if (NULL == ch)
   {
-    if (NULL != t->rekey_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->rekey_task);
-      t->rekey_task = NULL;
-    }
-#if FIXME
-    /* Send queued data if tunnel is not loopback */
-    if (myid != GCP_get_short_id (t->peer))
-      send_queued_data (t);
-#endif
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received channel OPEN_ACK for unknown channel, sending DESTROY\n",
+         GCCH_2s (ch));
+    GCT_send_channel_destroy (t,
+                              cm->ctn);
+    return;
   }
+  GCCH_handle_channel_open_ack (ch);
 }
 
 
 /**
- * Handle KX message.
+ * We received a message saying that a channel should be destroyed.
+ * Pass it on to the correct channel.
  *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param cm the message we received on the tunnel
+ */
+static void
+handle_plaintext_channel_destroy (void *cls,
+                                  const struct GNUNET_CADET_ChannelManageMessage *cm)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       cm->ctn);
+  if (NULL == ch)
+  {
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received channel DESTORY for unknown channel. Ignoring.\n",
+         GCCH_2s (ch));
+    return;
+  }
+  GCCH_handle_remote_destroy (ch);
+}
+
+
+/**
+ * Handles a message we decrypted, by injecting it into
+ * our message queue (which will do the dispatching).
+ *
+ * @param cls the `struct CadetTunnel` that got the message
+ * @param msg the message
+ * @return #GNUNET_OK (continue to process)
+ */
+static int
+handle_decrypted (void *cls,
+                  const struct GNUNET_MessageHeader *msg)
+{
+  struct CadetTunnel *t = cls;
+
+  GNUNET_MQ_inject_message (t->mq,
+                            msg);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called if we had an error processing
+ * an incoming decrypted message.
+ *
+ * @param cls the `struct CadetTunnel`
+ * @param error error code
+ */
+static void
+decrypted_error_cb (void *cls,
+                    enum GNUNET_MQ_Error error)
+{
+  GNUNET_break_op (0);
+}
+
+
+/**
+ * Create a tunnel to @a destionation.  Must only be called
+ * from within #GCP_get_tunnel().
+ *
+ * @param destination where to create the tunnel to
+ * @return new tunnel to @a destination
+ */
+struct CadetTunnel *
+GCT_create_tunnel (struct CadetPeer *destination)
+{
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_fixed_size (plaintext_keepalive,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE,
+                             struct GNUNET_MessageHeader,
+                             NULL),
+    GNUNET_MQ_hd_var_size (plaintext_data,
+                           GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA,
+                           struct GNUNET_CADET_ChannelAppDataMessage,
+                           NULL),
+    GNUNET_MQ_hd_fixed_size (plaintext_data_ack,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK,
+                             struct GNUNET_CADET_ChannelDataAckMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_open,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN,
+                             struct GNUNET_CADET_ChannelOpenMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
+                             struct GNUNET_CADET_ChannelManageMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_destroy,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
+                             struct GNUNET_CADET_ChannelManageMessage,
+                             NULL),
+    GNUNET_MQ_handler_end ()
+  };
+  struct CadetTunnel *t;
+
+  t = GNUNET_new (struct CadetTunnel);
+  new_ephemeral (t);
+  t->ax.kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
+  t->destination = destination;
+  t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
+  t->maintain_connections_task
+    = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
+                                t);
+  t->mq = GNUNET_MQ_queue_for_callbacks (NULL,
+                                         NULL,
+                                         NULL,
+                                         NULL,
+                                         handlers,
+                                         &decrypted_error_cb,
+                                         t);
+  t->mst = GNUNET_MST_create (&handle_decrypted,
+                              t);
+  return t;
+}
+
+
+/**
+ * Add a @a connection to the @a tunnel.
+ *
+ * @param t a tunnel
+ * @param cid connection identifer to use for the connection
+ * @param path path to use for the connection
  */
 void
-GCT_handle_kx (struct CadetTConnection *ct,
-               const struct GNUNET_CADET_KX *msg)
+GCT_add_inbound_connection (struct CadetTunnel *t,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                            struct CadetPeerPath *path)
 {
-  GNUNET_break (0); // not implemented
+  struct CadetTConnection *ct;
+
+  ct = GNUNET_new (struct CadetTConnection);
+  ct->created = GNUNET_TIME_absolute_get ();
+  ct->t = t;
+  ct->cc = GCC_create_inbound (t->destination,
+                               path,
+                               ct,
+                               cid,
+                               &connection_ready_cb,
+                               t);
+  /* FIXME: schedule job to kill connection (and path?)  if it takes
+     too long to get ready! (And track performance data on how long
+     other connections took with the tunnel!)
+     => Note: to be done within 'connection'-logic! */
+  GNUNET_CONTAINER_DLL_insert (t->connection_head,
+                               t->connection_tail,
+                               ct);
+  t->num_connections++;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Tunnel %s has new connection %s\n",
+       GCT_2s (t),
+       GCC_2s (ct->cc));
 }
 
 
@@ -1483,20 +2255,49 @@ GCT_handle_kx (struct CadetTConnection *ct,
  */
 void
 GCT_handle_encrypted (struct CadetTConnection *ct,
-                      const struct GNUNET_CADET_Encrypted *msg)
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
 {
   struct CadetTunnel *t = ct->t;
   uint16_t size = ntohs (msg->header.size);
   char cbuf [size] GNUNET_ALIGN;
   ssize_t decrypted_size;
-  const struct GNUNET_MessageHeader *msgh;
-  unsigned int off;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Tunnel %s received %u bytes of encrypted data in state %d\n",
+       GCT_2s (t),
+       (unsigned int) size,
+       t->estate);
+
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+    /* We did not even SEND our KX, how can the other peer
+       send us encrypted data? */
+    GNUNET_break_op (0);
+    return;
+  case CADET_TUNNEL_KEY_SENT:
+    /* We did not get the KX of the other peer, but that
+       might have been lost.  Ask for KX again. */
+    GNUNET_STATISTICS_update (stats,
+                              "# received encrypted without KX",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+    t->kx_task = GNUNET_SCHEDULER_add_now (&retry_kx,
+                                           t);
+    return;
+  case CADET_TUNNEL_KEY_PING:
+    /* Great, first payload, we might graduate to OK */
+  case CADET_TUNNEL_KEY_OK:
+  case CADET_TUNNEL_KEY_REKEY:
+    break;
+  }
 
   GNUNET_STATISTICS_update (stats,
                             "# received encrypted",
                             1,
                             GNUNET_NO);
-
   decrypted_size = t_ax_decrypt_and_validate (t,
                                               cbuf,
                                               msg,
@@ -1504,52 +2305,29 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
 
   if (-1 == decrypted_size)
   {
+    GNUNET_break_op (0);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Tunnel %s failed to decrypt and validate encrypted data\n",
+         GCT_2s (t));
     GNUNET_STATISTICS_update (stats,
                               "# unable to decrypt",
                               1,
                               GNUNET_NO);
-    if (CADET_TUNNEL_KEY_PING <= t->estate)
-    {
-      GNUNET_break_op (0);
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-           "Wrong crypto, tunnel %s\n",
-           GCT_2s (t));
-      GCT_debug (t,
-                 GNUNET_ERROR_TYPE_WARNING);
-    }
     return;
   }
-
-  GCT_change_estate (t,
-                     CADET_TUNNEL_KEY_OK);
-
-#if 0
-  /* FIXME: this is bad, as the structs returned from
-     this loop may be unaligned, see util's MST for
-     how to do this right.
-     => Change MST API to use new MQ-style handlers! */
-  off = 0;
-  while (off + sizeof (struct GNUNET_MessageHeader) <= decrypted_size)
+  if (CADET_TUNNEL_KEY_PING == t->estate)
   {
-    uint16_t msize;
-
-    msgh = (const struct GNUNET_MessageHeader *) &cbuf[off];
-    msize = ntohs (msgh->size);
-    if (msize < sizeof (struct GNUNET_MessageHeader))
-    {
-      GNUNET_break_op (0);
-      return;
-    }
-    if (off + msize < decrypted_size)
-    {
-      GNUNET_break_op (0);
-      return;
-    }
-    handle_decrypted (t,
-                      msgh);
-    off += msize;
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_OK);
+    trigger_transmissions (t);
   }
-#endif
+  /* The MST will ultimately call #handle_decrypted() on each message. */
+  GNUNET_break_op (GNUNET_OK ==
+                   GNUNET_MST_from_buffer (t->mst,
+                                           cbuf,
+                                           decrypted_size,
+                                           GNUNET_YES,
+                                           GNUNET_NO));
 }
 
 
@@ -1572,14 +2350,16 @@ GCT_send (struct CadetTunnel *t,
   struct CadetTunnelQueueEntry *tq;
   uint16_t payload_size;
   struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_Encrypted *ax_msg;
-
-  /* FIXME: what about KX not yet being ready? (see "is_ready()" check in old code!) */
+  struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
 
   payload_size = ntohs (message->size);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Encrypting %u bytes of for tunnel %s\n",
+       (unsigned int) payload_size,
+       GCT_2s (t));
   env = GNUNET_MQ_msg_extra (ax_msg,
                              payload_size,
-                             GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED);
+                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
   t_ax_encrypt (t,
                 &ax_msg[1],
                 message,
@@ -1595,12 +2375,11 @@ GCT_send (struct CadetTunnel *t,
           0,
           &t->ax.HKs,
           &ax_msg->hmac);
-  // ax_msg->pid = htonl (GCC_get_pid (c, fwd));  // FIXME: connection flow-control not (re)implemented yet!
 
   tq = GNUNET_malloc (sizeof (*tq));
   tq->t = t;
   tq->env = env;
-  tq->cid = &ax_msg->cid;
+  tq->cid = &ax_msg->cid; /* will initialize 'ax_msg->cid' once we know the connection */
   tq->cont = cont;
   tq->cont_cls = cont_cls;
   GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
@@ -1618,17 +2397,18 @@ GCT_send (struct CadetTunnel *t,
  * function is called. Once the continuation is called, the message is
  * no longer in the queue!
  *
- * @param q Handle to the queue entry to cancel.
+ * @param tq Handle to the queue entry to cancel.
  */
 void
-GCT_send_cancel (struct CadetTunnelQueueEntry *q)
+GCT_send_cancel (struct CadetTunnelQueueEntry *tq)
 {
-  struct CadetTunnel *t = q->t;
+  struct CadetTunnel *t = tq->t;
 
   GNUNET_CONTAINER_DLL_remove (t->tq_head,
                                t->tq_tail,
-                               q);
-  GNUNET_free (q);
+                               tq);
+  GNUNET_MQ_discard (tq->env);
+  GNUNET_free (tq);
 }
 
 
@@ -1735,68 +2515,6 @@ debug_channel (void *cls,
 }
 
 
-/**
- * Get string description for tunnel connectivity state.
- *
- * @param cs Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-cstate2s (enum CadetTunnelCState cs)
-{
-  static char buf[32];
-
-  switch (cs)
-  {
-    case CADET_TUNNEL_NEW:
-      return "CADET_TUNNEL_NEW";
-    case CADET_TUNNEL_SEARCHING:
-      return "CADET_TUNNEL_SEARCHING";
-    case CADET_TUNNEL_WAITING:
-      return "CADET_TUNNEL_WAITING";
-    case CADET_TUNNEL_READY:
-      return "CADET_TUNNEL_READY";
-    case CADET_TUNNEL_SHUTDOWN:
-      return "CADET_TUNNEL_SHUTDOWN";
-    default:
-      SPRINTF (buf, "%u (UNKNOWN STATE)", cs);
-      return buf;
-  }
-}
-
-
-/**
- * Get string description for tunnel encryption state.
- *
- * @param es Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-estate2s (enum CadetTunnelEState es)
-{
-  static char buf[32];
-
-  switch (es)
-  {
-    case CADET_TUNNEL_KEY_UNINITIALIZED:
-      return "CADET_TUNNEL_KEY_UNINITIALIZED";
-    case CADET_TUNNEL_KEY_SENT:
-      return "CADET_TUNNEL_KEY_SENT";
-    case CADET_TUNNEL_KEY_PING:
-      return "CADET_TUNNEL_KEY_PING";
-    case CADET_TUNNEL_KEY_OK:
-      return "CADET_TUNNEL_KEY_OK";
-    case CADET_TUNNEL_KEY_REKEY:
-      return "CADET_TUNNEL_KEY_REKEY";
-    default:
-      SPRINTF (buf, "%u (UNKNOWN STATE)", es);
-      return buf;
-  }
-}
-
-
 #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
 
 
@@ -1820,9 +2538,8 @@ GCT_debug (const struct CadetTunnel *t,
     return;
 
   LOG2 (level,
-        "TTT TUNNEL TOWARDS %s in cstate %s, estate %s tq_len: %u #cons: %u\n",
+        "TTT TUNNEL TOWARDS %s in estate %s tq_len: %u #cons: %u\n",
         GCT_2s (t),
-        cstate2s (t->cstate),
         estate2s (t->estate),
         t->tq_len,
         t->num_connections);