-simplify logic
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
index 782a5ea8f3dbc9ff946a9d33b8d915a6322d8166..3702d99be72bea58c09f9342fffdceafb270615a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  This file is part of GNUnet
(C) 2010-2014 Christian Grothoff (and other contributing authors)
Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
 
  GNUnet is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published
@@ -42,6 +42,9 @@
 
 #define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
 
+/**
+ * After how much inactivity should a UDP session time out?
+ */
 #define UDP_SESSION_TIME_OUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
 
 /**
@@ -57,7 +60,7 @@
 /**
  * We keep a defragmentation queue per sender address.  How many
  * sender addresses do we support at the same time? Memory consumption
- * is roughly a factor of 32k * UDP_MAX_MESSAGES_IN_DEFRAG times this
+ * is roughly a factor of 32k * #UDP_MAX_MESSAGES_IN_DEFRAG times this
  * value. (So 128 corresponds to 12 MB and should suffice for
  * connecting to roughly 128 peers via UDP).
  */
@@ -102,10 +105,10 @@ struct PrettyPrinterContext
   /**
    * Timeout task
    */
-  GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+  struct GNUNET_SCHEDULER_Task *timeout_task;
 
   /**
-   * IPv6 address
+   * Is this an IPv6 address?
    */
   int ipv6;
 
@@ -155,7 +158,7 @@ struct Session
   /**
    * Session timeout task
    */
-  GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+  struct GNUNET_SCHEDULER_Task *timeout_task;
 
   /**
    * When does this session time out?
@@ -172,12 +175,6 @@ struct Session
    */
   struct GNUNET_TIME_Relative last_expected_msg_delay;
 
-  /**
-   * Address metrics (as set by the "update_address_metrics" by
-   * the environment).
-   */
-  struct GNUNET_ATS_Information ats;
-
   /**
    * Our own address.
    */
@@ -201,6 +198,11 @@ struct Session
    */
   unsigned int rc;
 
+  /**
+   * Network type of the address.
+   */
+  enum GNUNET_ATS_Network_Type scope;
+
   /**
    * Is this session about to be destroyed (sometimes we cannot
    * destroy a session immediately as below us on the stack
@@ -211,50 +213,6 @@ struct Session
 };
 
 
-/**
- * Closure for #session_cmp_it().
- */
-struct SessionCompareContext
-{
-  /**
-   * Set to session matching the address.
-   */
-  struct Session *res;
-
-  /**
-   * Address we are looking for.
-   */
-  const struct GNUNET_HELLO_Address *address;
-};
-
-
-/**
- * Closure for #process_inbound_tokenized_messages().
- */
-struct SourceInformation
-{
-  /**
-   * Sender identity.
-   */
-  struct GNUNET_PeerIdentity sender;
-
-  /**
-   * Source address.
-   */
-  const void *arg;
-
-  /**
-   * Associated session.
-   */
-  struct Session *session;
-
-  /**
-   * Number of bytes in source address.
-   */
-  size_t args;
-
-};
-
 /**
  * Closure for #find_receive_context().
  */
@@ -266,19 +224,19 @@ struct FindReceiveContext
   struct DefragContext *rc;
 
   /**
-   * Address to find.
+   * Session associated with this context.
    */
-  const struct sockaddr *addr;
+  struct Session *session;
 
   /**
-   *
+   * Address to find.
    */
-  struct Session *session;
+  const union UdpAddress *udp_addr;
 
   /**
-   * Number of bytes in @e addr.
+   * Number of bytes in @e udp_addr.
    */
-  socklen_t addr_len;
+  size_t udp_addr_len;
 
 };
 
@@ -294,26 +252,43 @@ struct DefragContext
    */
   struct GNUNET_DEFRAGMENT_Context *defrag;
 
+  /**
+   * Reference to master plugin struct.
+   */
+  struct Plugin *plugin;
+
+  /**
+   * Node in the defrag heap.
+   */
+  struct GNUNET_CONTAINER_HeapNode *hnode;
+
+  /**
+   * Who's message(s) are we defragmenting here?
+   * Only initialized once we succeeded and
+   * @e have_sender is set.
+   */
+  struct GNUNET_PeerIdentity sender;
+
   /**
    * Source address this receive context is for (allocated at the
    * end of the struct).
    */
-  const struct sockaddr *src_addr;
+  const union UdpAddress *udp_addr;
 
   /**
-   * Reference to master plugin struct.
+   * Length of @e udp_addr.
    */
-  struct Plugin *plugin;
+  size_t udp_addr_len;
 
   /**
-   * Node in the defrag heap.
+   * Network type the address belongs to.
    */
-  struct GNUNET_CONTAINER_HeapNode *hnode;
+  enum GNUNET_ATS_Network_Type network_type;
 
   /**
-   * Length of @e src_addr.
+   * Has the @e sender field been initialized yet?
    */
-  size_t addr_len;
+  int have_sender;
 };
 
 
@@ -481,7 +456,7 @@ struct UDP_MessageWrapper
 
 
 /**
- * UDP ACK Message-Packet header (after defragmentation).
+ * UDP ACK Message-Packet header.
  */
 struct UDP_ACK_Message
 {
@@ -520,6 +495,8 @@ notify_session_monitor (struct Plugin *plugin,
 
   if (NULL == plugin->sic)
     return;
+  if (GNUNET_YES == session->in_destroy)
+    return; /* already destroyed, just RC>0 left-over actions */
   memset (&info, 0, sizeof (info));
   info.state = state;
   info.is_inbound = GNUNET_SYSERR; /* hard to say */
@@ -583,7 +560,7 @@ schedule_select (struct Plugin *plugin)
           GNUNET_TIME_absolute_get_remaining (
               udpw->session->flow_delay_from_other_peer));
 
-    if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK )
+    if (plugin->select_task != NULL )
       GNUNET_SCHEDULER_cancel (plugin->select_task);
 
     /* Schedule with:
@@ -604,7 +581,7 @@ schedule_select (struct Plugin *plugin)
           GNUNET_TIME_absolute_get_remaining (
               udpw->session->flow_delay_from_other_peer));
 
-    if (GNUNET_SCHEDULER_NO_TASK != plugin->select_task_v6)
+    if (NULL != plugin->select_task_v6)
       GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
     plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (
         GNUNET_SCHEDULER_PRIORITY_DEFAULT,
@@ -623,8 +600,8 @@ schedule_select (struct Plugin *plugin)
  * to override the address again.
  *
  * @param cls closure
- * @param addr binary address
- * @param addrlen length of the address
+ * @param addr binary address (a `union UdpAddress`)
+ * @param addrlen length of the @a addr
  * @return string representing the same address
  */
 const char *
@@ -668,8 +645,13 @@ udp_address_to_string (void *cls,
   inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
 
   GNUNET_snprintf (rbuf, sizeof(rbuf),
-      (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u", PLUGIN_NAME, options,
-      buf, port);
+                   (af == AF_INET6)
+                   ? "%s.%u.[%s]:%u"
+                   : "%s.%u.%s:%u",
+                   PLUGIN_NAME,
+                   options,
+                   buf,
+                   port);
   return rbuf;
 }
 
@@ -678,7 +660,7 @@ udp_address_to_string (void *cls,
  * Function called to convert a string address to
  * a binary address.
  *
- * @param cls closure ('struct Plugin*')
+ * @param cls closure (`struct Plugin *`)
  * @param addr string address
  * @param addrlen length of the address
  * @param buf location to store the buffer
@@ -839,7 +821,8 @@ append_port (void *cls,
  * @param cls closure with the `struct Plugin *`
  * @param type name of the transport that generated the address
  * @param addr one of the addresses of the host, NULL for the last address
- *        the specific address format depends on the transport
+ *        the specific address format depends on the transport;
+ *        a `union UdpAddress`
  * @param addrlen length of the address
  * @param numeric should (IP) addresses be displayed in numeric form?
  * @param timeout after how long should we give up?
@@ -940,7 +923,8 @@ call_continuation (struct UDP_MessageWrapper *udpw,
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Calling continuation for %u byte message to `%s' with result %s\n",
-       udpw->payload_size, GNUNET_i2s (&udpw->session->target),
+       udpw->payload_size,
+       GNUNET_i2s (&udpw->session->target),
        (GNUNET_OK == result) ? "OK" : "SYSERR");
 
   if (udpw->msg_size >= udpw->payload_size)
@@ -957,63 +941,97 @@ call_continuation (struct UDP_MessageWrapper *udpw,
       if (NULL != udpw->cont)
       {
         /* Transport continuation */
-        udpw->cont (udpw->cont_cls, &udpw->session->target, result,
-            udpw->payload_size, udpw->msg_size);
+        udpw->cont (udpw->cont_cls,
+                   &udpw->session->target,
+                   result,
+                   udpw->payload_size,
+                   udpw->msg_size);
       }
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, unfragmented msgs, messages, sent, success", 1, GNUNET_NO);
+                               "# UDP, unfragmented msgs, messages, sent, success",
+                               1,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, unfragmented msgs, bytes payload, sent, success",
-          udpw->payload_size, GNUNET_NO);
+                               "# UDP, unfragmented msgs, bytes payload, sent, success",
+                               udpw->payload_size,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, unfragmented msgs, bytes overhead, sent, success", overhead,
-          GNUNET_NO);
+                               "# UDP, unfragmented msgs, bytes overhead, sent, success",
+                               overhead,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, total, bytes overhead, sent", overhead, GNUNET_NO);
+                               "# UDP, total, bytes overhead, sent",
+                               overhead,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, total, bytes payload, sent", udpw->payload_size, GNUNET_NO);
+                               "# UDP, total, bytes payload, sent",
+                               udpw->payload_size,
+                               GNUNET_NO);
       break;
     case UMT_MSG_FRAGMENTED_COMPLETE:
       GNUNET_assert(NULL != udpw->frag_ctx);
       if (udpw->frag_ctx->cont != NULL )
-        udpw->frag_ctx->cont (udpw->frag_ctx->cont_cls, &udpw->session->target,
-            GNUNET_OK, udpw->frag_ctx->payload_size,
-            udpw->frag_ctx->on_wire_size);
+        udpw->frag_ctx->cont (udpw->frag_ctx->cont_cls,
+                             &udpw->session->target,
+                             GNUNET_OK,
+                             udpw->frag_ctx->payload_size,
+                             udpw->frag_ctx->on_wire_size);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, messages, sent, success", 1, GNUNET_NO);
+                               "# UDP, fragmented msgs, messages, sent, success",
+                               1,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, bytes payload, sent, success",
-          udpw->payload_size, GNUNET_NO);
+                               "# UDP, fragmented msgs, bytes payload, sent, success",
+                               udpw->payload_size,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, bytes overhead, sent, success", overhead,
-          GNUNET_NO);
+                               "# UDP, fragmented msgs, bytes overhead, sent, success",
+                               overhead,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, total, bytes overhead, sent", overhead, GNUNET_NO);
+                               "# UDP, total, bytes overhead, sent",
+                               overhead,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, total, bytes payload, sent", udpw->payload_size, GNUNET_NO);
+                               "# UDP, total, bytes payload, sent",
+                               udpw->payload_size,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, messages, pending", -1, GNUNET_NO);
+                               "# UDP, fragmented msgs, messages, pending",
+                               -1,
+                               GNUNET_NO);
       break;
     case UMT_MSG_FRAGMENTED:
       /* Fragmented message: enqueue next fragment */
       if (NULL != udpw->cont)
-        udpw->cont (udpw->cont_cls, &udpw->session->target, result,
-            udpw->payload_size, udpw->msg_size);
+        udpw->cont (udpw->cont_cls,
+                   &udpw->session->target,
+                   result,
+                   udpw->payload_size,
+                   udpw->msg_size);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, fragments, sent, success", 1, GNUNET_NO);
+                               "# UDP, fragmented msgs, fragments, sent, success",
+                               1,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, fragments bytes, sent, success",
-          udpw->msg_size, GNUNET_NO);
+                               "# UDP, fragmented msgs, fragments bytes, sent, success",
+                               udpw->msg_size,
+                               GNUNET_NO);
       break;
     case UMT_MSG_ACK:
       /* No continuation */
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, ACK msgs, messages, sent, success", 1, GNUNET_NO);
+                               "# UDP, ACK msgs, messages, sent, success",
+                               1,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, ACK msgs, bytes overhead, sent, success", overhead,
-          GNUNET_NO);
+                               "# UDP, ACK msgs, bytes overhead, sent, success",
+                               overhead,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, total, bytes overhead, sent", overhead, GNUNET_NO);
+                               "# UDP, total, bytes overhead, sent",
+                               overhead,
+                               GNUNET_NO);
       break;
     default:
       GNUNET_break(0);
@@ -1026,50 +1044,71 @@ call_continuation (struct UDP_MessageWrapper *udpw,
     case UMT_MSG_UNFRAGMENTED:
       /* Unfragmented message: failed to send */
       if (NULL != udpw->cont)
-        udpw->cont (udpw->cont_cls, &udpw->session->target, result,
-            udpw->payload_size, overhead);
+        udpw->cont (udpw->cont_cls,
+                   &udpw->session->target,
+                   result,
+                   udpw->payload_size,
+                   overhead);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, unfragmented msgs, messages, sent, failure", 1, GNUNET_NO);
+                               "# UDP, unfragmented msgs, messages, sent, failure",
+                               1,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, unfragmented msgs, bytes payload, sent, failure",
-          udpw->payload_size, GNUNET_NO);
+                               "# UDP, unfragmented msgs, bytes payload, sent, failure",
+                               udpw->payload_size,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, unfragmented msgs, bytes overhead, sent, failure", overhead,
-          GNUNET_NO);
+                               "# UDP, unfragmented msgs, bytes overhead, sent, failure",
+                               overhead,
+                               GNUNET_NO);
       break;
     case UMT_MSG_FRAGMENTED_COMPLETE:
-      GNUNET_assert(NULL != udpw->frag_ctx);
-      if (udpw->frag_ctx->cont != NULL )
-        udpw->frag_ctx->cont (udpw->frag_ctx->cont_cls, &udpw->session->target,
-            GNUNET_SYSERR, udpw->frag_ctx->payload_size,
-            udpw->frag_ctx->on_wire_size);
+      GNUNET_assert (NULL != udpw->frag_ctx);
+      if (udpw->frag_ctx->cont != NULL)
+        udpw->frag_ctx->cont (udpw->frag_ctx->cont_cls,
+                             &udpw->session->target,
+                             GNUNET_SYSERR,
+                             udpw->frag_ctx->payload_size,
+                             udpw->frag_ctx->on_wire_size);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, messages, sent, failure", 1, GNUNET_NO);
+                               "# UDP, fragmented msgs, messages, sent, failure",
+                               1,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, bytes payload, sent, failure",
-          udpw->payload_size, GNUNET_NO);
+                               "# UDP, fragmented msgs, bytes payload, sent, failure",
+                               udpw->payload_size,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, bytes payload, sent, failure", overhead,
-          GNUNET_NO);
+                               "# UDP, fragmented msgs, bytes payload, sent, failure",
+                               overhead,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, bytes payload, sent, failure", overhead,
-          GNUNET_NO);
+                               "# UDP, fragmented msgs, bytes payload, sent, failure",
+                               overhead,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, messages, pending", -1, GNUNET_NO);
+                               "# UDP, fragmented msgs, messages, pending",
+                               -1,
+                               GNUNET_NO);
       break;
     case UMT_MSG_FRAGMENTED:
-      GNUNET_assert(NULL != udpw->frag_ctx);
+      GNUNET_assert (NULL != udpw->frag_ctx);
       /* Fragmented message: failed to send */
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, fragments, sent, failure", 1, GNUNET_NO);
+                               "# UDP, fragmented msgs, fragments, sent, failure",
+                               1,
+                               GNUNET_NO);
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, fragmented msgs, fragments bytes, sent, failure",
-          udpw->msg_size, GNUNET_NO);
+                               "# UDP, fragmented msgs, fragments bytes, sent, failure",
+                               udpw->msg_size,
+                               GNUNET_NO);
       break;
     case UMT_MSG_ACK:
       /* ACK message: failed to send */
       GNUNET_STATISTICS_update (plugin->env->stats,
-          "# UDP, ACK msgs, messages, sent, failure", 1, GNUNET_NO);
+                               "# UDP, ACK msgs, messages, sent, failure",
+                               1,
+                               GNUNET_NO);
       break;
     default:
       GNUNET_break(0);
@@ -1112,7 +1151,7 @@ check_port (struct Plugin *plugin,
  * traffic.
  *
  * @param cls closure, should be our handle to the Plugin
- * @param addr pointer to the address
+ * @param addr pointer to a `union UdpAddress`
  * @param addrlen length of @a addr
  * @return #GNUNET_OK if this is a plausible address for this peer
  *         and transport, #GNUNET_SYSERR if not
@@ -1126,8 +1165,8 @@ udp_plugin_check_address (void *cls,
   struct IPv4UdpAddress *v4;
   struct IPv6UdpAddress *v6;
 
-  if ((addrlen != sizeof(struct IPv4UdpAddress))
-      && (addrlen != sizeof(struct IPv6UdpAddress)))
+  if ( (addrlen != sizeof(struct IPv4UdpAddress)) &&
+       (addrlen != sizeof(struct IPv6UdpAddress)) )
   {
     GNUNET_break_op(0);
     return GNUNET_SYSERR;
@@ -1137,9 +1176,10 @@ udp_plugin_check_address (void *cls,
     v4 = (struct IPv4UdpAddress *) addr;
     if (GNUNET_OK != check_port (plugin, ntohs (v4->u4_port)))
       return GNUNET_SYSERR;
-    if (GNUNET_OK
-        != GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr,
-            sizeof(struct in_addr)))
+    if (GNUNET_OK !=
+        GNUNET_NAT_test_address (plugin->nat,
+                                 &v4->ipv4_addr,
+                                 sizeof (struct in_addr)))
       return GNUNET_SYSERR;
   }
   else
@@ -1228,7 +1268,14 @@ dequeue (struct Plugin *plugin,
 
 
 /**
- * FIXME.
+ * We have completed our (attempt) to transmit a message
+ * that had to be fragmented -- either because we got an
+ * ACK saying that all fragments were received, or because
+ * of timeout / disconnect.  Clean up our state.
+ *
+ * @param fc fragmentation context to clean up
+ * @param result #GNUNET_OK if we succeeded (got ACK),
+ *               #GNUNET_SYSERR if the transmission failed
  */
 static void
 fragmented_message_done (struct UDP_FragmentationContext *fc,
@@ -1262,11 +1309,13 @@ fragmented_message_done (struct UDP_FragmentationContext *fc,
     while (NULL != udpw)
     {
       tmp = udpw->next;
-      if ((udpw->frag_ctx != NULL )&& (udpw->frag_ctx == s->frag_ctx)){
-      dequeue (plugin, udpw);
-      call_continuation (udpw, GNUNET_SYSERR);
-      GNUNET_free (udpw);
-    }
+      if ( (udpw->frag_ctx != NULL) &&
+          (udpw->frag_ctx == s->frag_ctx) )
+      {
+       dequeue (plugin, udpw);
+       call_continuation (udpw, GNUNET_SYSERR);
+       GNUNET_free (udpw);
+      }
       udpw = tmp;
     }
   }
@@ -1287,7 +1336,7 @@ fragmented_message_done (struct UDP_FragmentationContext *fc,
   }
   notify_session_monitor (s->plugin,
                           s,
-                          GNUNET_TRANSPORT_SS_UP);
+                          GNUNET_TRANSPORT_SS_UPDATE);
   /* Destroy fragmentation context */
   GNUNET_FRAGMENT_context_destroy (fc->frag,
                                    &s->last_expected_msg_delay,
@@ -1302,7 +1351,7 @@ fragmented_message_done (struct UDP_FragmentationContext *fc,
  *
  * @param cls the `struct FindReceiveContext`
  * @param node internal node of the heap
- * @param element value stored at the node (a 'struct ReceiveContext')
+ * @param element value stored at the node (a `struct ReceiveContext`)
  * @param cost cost associated with the node
  * @return #GNUNET_YES if we should continue to iterate,
  *         #GNUNET_NO if not.
@@ -1316,8 +1365,10 @@ find_receive_context (void *cls,
   struct FindReceiveContext *frc = cls;
   struct DefragContext *e = element;
 
-  if ((frc->addr_len == e->addr_len)
-      && (0 == memcmp (frc->addr, e->src_addr, frc->addr_len)))
+  if ( (frc->udp_addr_len == e->udp_addr_len) &&
+       (0 == memcmp (frc->udp_addr,
+                     e->udp_addr,
+                     frc->udp_addr_len)) )
   {
     frc->rc = e;
     return GNUNET_NO;
@@ -1344,25 +1395,30 @@ udp_disconnect_session (void *cls,
   struct UDP_MessageWrapper *next;
   struct FindReceiveContext frc;
 
-  GNUNET_assert(GNUNET_YES != s->in_destroy);
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "Session %p to peer `%s' address ended\n", s,
-      GNUNET_i2s (&s->target),
-      udp_address_to_string (NULL, s->address->address, s->address->address_length));
+  GNUNET_assert (GNUNET_YES != s->in_destroy);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Session %p to peer `%s' address ended\n",
+       s,
+       GNUNET_i2s (&s->target),
+       udp_address_to_string (plugin,
+                              s->address->address,
+                              s->address->address_length));
   /* stop timeout task */
-  if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
+  if (NULL != s->timeout_task)
   {
     GNUNET_SCHEDULER_cancel (s->timeout_task);
-    s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+    s->timeout_task = NULL;
   }
   if (NULL != s->frag_ctx)
   {
     /* Remove fragmented message due to disconnect */
-    fragmented_message_done (s->frag_ctx, GNUNET_SYSERR);
+    fragmented_message_done (s->frag_ctx,
+                             GNUNET_SYSERR);
   }
 
   frc.rc = NULL;
-  frc.addr = s->address->address;
-  frc.addr_len = s->address->address_length;
+  frc.udp_addr = s->address->address;
+  frc.udp_addr_len = s->address->address_length;
   /* Lookup existing receive context for this address */
   if (NULL != plugin->defrag_ctxs)
   {
@@ -1402,7 +1458,7 @@ udp_disconnect_session (void *cls,
   }
   notify_session_monitor (s->plugin,
                           s,
-                          GNUNET_TRANSPORT_SS_DOWN);
+                          GNUNET_TRANSPORT_SS_DONE);
   plugin->env->session_end (plugin->env->cls,
                             s->address,
                             s);
@@ -1422,10 +1478,10 @@ udp_disconnect_session (void *cls,
     }
   }
 
-  GNUNET_assert(GNUNET_YES ==
-                GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
-                                                      &s->target,
-                                                      s));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
+                                                       &s->target,
+                                                       s));
   GNUNET_STATISTICS_set (plugin->env->stats,
                          "# UDP sessions active",
                          GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
@@ -1517,7 +1573,7 @@ session_timeout (void *cls,
   struct Plugin *plugin = s->plugin;
   struct GNUNET_TIME_Relative left;
 
-  s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  s->timeout_task = NULL;
   left = GNUNET_TIME_absolute_get_remaining (s->timeout);
   if (left.rel_value_us > 0)
   {
@@ -1525,17 +1581,17 @@ session_timeout (void *cls,
        the monitor, it may think we're about to die ... */
     notify_session_monitor (s->plugin,
                             s,
-                            GNUNET_TRANSPORT_SS_UP);
+                            GNUNET_TRANSPORT_SS_UPDATE);
     s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
                                                     &session_timeout,
                                                     s);
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Session %p was idle for %s, disconnecting\n",
-              s,
-              GNUNET_STRINGS_relative_time_to_string (UDP_SESSION_TIME_OUT,
-                                                      GNUNET_YES));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Session %p was idle for %s, disconnecting\n",
+       s,
+       GNUNET_STRINGS_relative_time_to_string (UDP_SESSION_TIME_OUT,
+                                               GNUNET_YES));
   /* call session destroy function */
   udp_disconnect_session (plugin, s);
 }
@@ -1551,39 +1607,15 @@ reschedule_session_timeout (struct Session *s)
 {
   if (GNUNET_YES == s->in_destroy)
     return;
-  GNUNET_assert(GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
+  GNUNET_assert(NULL != s->timeout_task);
   s->timeout = GNUNET_TIME_relative_to_absolute (UDP_SESSION_TIME_OUT);
 }
 
 
-/**
- * FIXME.
- */
-static struct Session *
-create_session (struct Plugin *plugin,
-                const struct GNUNET_HELLO_Address *address)
-{
-  struct Session *s;
-
-  s = GNUNET_new (struct Session);
-  s->address = GNUNET_HELLO_address_copy (address);
-  s->target = address->peer;
-  s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (
-      GNUNET_TIME_UNIT_MILLISECONDS, 250);
-  s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
-  s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO_ABS;
-  s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
-  s->timeout_task = GNUNET_SCHEDULER_add_delayed (UDP_SESSION_TIME_OUT,
-                                                  &session_timeout, s);
-  return s;
-}
-
-
-
 /**
  * Function obtain the network type for a session
  *
- * @param cls closure ('struct Plugin*')
+ * @param cls closure (`struct Plugin *`)
  * @param session the session
  * @return the network type
  */
@@ -1591,10 +1623,27 @@ static enum GNUNET_ATS_Network_Type
 udp_get_network (void *cls,
                  struct Session *session)
 {
-  return ntohl (session->ats.value);
+  return session->scope;
 }
 
 
+/**
+ * Closure for #session_cmp_it().
+ */
+struct SessionCompareContext
+{
+  /**
+   * Set to session matching the address.
+   */
+  struct Session *res;
+
+  /**
+   * Address we are looking for.
+   */
+  const struct GNUNET_HELLO_Address *address;
+};
+
+
 /**
  * Find a session with a matching address.
  *
@@ -1609,18 +1658,10 @@ session_cmp_it (void *cls,
                 void *value)
 {
   struct SessionCompareContext *cctx = cls;
-  const struct GNUNET_HELLO_Address *address = cctx->address;
   struct Session *s = value;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Comparing address %s <-> %s\n",
-       udp_address_to_string (NULL,
-                              address->address,
-                              address->address_length),
-       udp_address_to_string (NULL,
-                              s->address->address,
-                              s->address->address_length));
-  if (0 == GNUNET_HELLO_address_cmp(s->address, cctx->address))
+  if (0 == GNUNET_HELLO_address_cmp (s->address,
+                                     cctx->address))
   {
     cctx->res = s;
     return GNUNET_NO;
@@ -1630,20 +1671,21 @@ session_cmp_it (void *cls,
 
 
 /**
- * Creates a new outbound session the transport service will use to
- * send data to the peer
+ * Locate an existing session the transport service is using to
+ * send data to another peer.  Performs some basic sanity checks
+ * on the address and then tries to locate a matching session.
  *
  * @param cls the plugin
- * @param address the address
- * @return the session or NULL of max connections exceeded
+ * @param address the address we should locate the session by
+ * @return the session if it exists, or NULL if it is not found
  */
 static struct Session *
 udp_plugin_lookup_session (void *cls,
                            const struct GNUNET_HELLO_Address *address)
 {
-  struct Plugin * plugin = cls;
-  struct IPv6UdpAddress *udp_a6;
-  struct IPv4UdpAddress *udp_a4;
+  struct Plugin *plugin = cls;
+  const struct IPv6UdpAddress *udp_a6;
+  const struct IPv4UdpAddress *udp_a4;
   struct SessionCompareContext cctx;
 
   if ( (NULL == address->address) ||
@@ -1651,7 +1693,7 @@ udp_plugin_lookup_session (void *cls,
         (address->address_length != sizeof (struct IPv6UdpAddress))))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("Trying to create session for address of unexpected length %u (should be %u or %u)\n"),
+         "Trying to locate session for address of unexpected length %u (should be %u or %u)\n",
          address->address_length,
          sizeof (struct IPv4UdpAddress),
          sizeof (struct IPv6UdpAddress));
@@ -1660,19 +1702,19 @@ udp_plugin_lookup_session (void *cls,
 
   if (address->address_length == sizeof(struct IPv4UdpAddress))
   {
-    if (plugin->sockv4 == NULL)
+    if (NULL == plugin->sockv4)
       return NULL;
-    udp_a4 = (struct IPv4UdpAddress *) address->address;
-    if (udp_a4->u4_port == 0)
+    udp_a4 = (const struct IPv4UdpAddress *) address->address;
+    if (0 == udp_a4->u4_port)
       return NULL;
   }
 
   if (address->address_length == sizeof(struct IPv6UdpAddress))
   {
-    if (plugin->sockv6 == NULL)
+    if (NULL == plugin->sockv6)
       return NULL;
-    udp_a6 = (struct IPv6UdpAddress *) address->address;
-    if (udp_a6->u6_port == 0)
+    udp_a6 = (const struct IPv6UdpAddress *) address->address;
+    if (0 == udp_a6->u6_port)
       return NULL;
   }
 
@@ -1682,10 +1724,14 @@ udp_plugin_lookup_session (void *cls,
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Looking for existing session for peer `%s' `%s' \n",
        GNUNET_i2s (&address->peer),
-       udp_address_to_string(NULL, address->address, address->address_length));
-  GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions, &address->peer,
-      session_cmp_it, &cctx);
-  if (cctx.res != NULL )
+       udp_address_to_string (plugin,
+                              address->address,
+                              address->address_length));
+  GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
+                                              &address->peer,
+                                              &session_cmp_it,
+                                              &cctx);
+  if (NULL != cctx.res)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Found existing session %p\n",
@@ -1697,145 +1743,54 @@ udp_plugin_lookup_session (void *cls,
 
 
 /**
- * Context to lookup a session based on a IP address
- */
-struct LookupContext
-{
-  /**
-   * The result
-   */
-  struct Session *res;
-
-  /**
-   * The socket address
-   */
-  const struct sockaddr *address;
-
-  /**
-   * The socket address length
-   */
-  size_t addr_len;
-
-  /**
-   * Is a fragmentation context required for the session
-   */
-  int must_have_frag_ctx;
-};
-
-
-/**
- * Find a session with a matching address.
- * FIXME: very similar code to #udp_plugin_lookup_session() above.
- * Unify?
+ * Allocate a new session for the given endpoint address.
+ * Note that this function does not inform the service
+ * of the new session, this is the responsibility of the
+ * caller (if needed).
  *
- * @param cls the `struct LookupContext *`
- * @param key peer identity (unused)
- * @param value the `struct Session *`
- * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
+ * @param cls the `struct Plugin`
+ * @param address address of the other peer to use
+ * @param network_type network type the address belongs to
+ * @return NULL on error, otherwise session handle
  */
-static int
-lookup_session_by_sockaddr_it (void *cls,
-                               const struct GNUNET_PeerIdentity *key,
-                               void *value)
-{
-  struct LookupContext *l_ctx = cls;
-  struct Session *s = value;
-  struct IPv4UdpAddress u4;
-  struct IPv6UdpAddress u6;
-  void *arg;
-  size_t args;
-
-  /* convert address */
-  switch (l_ctx->address->sa_family)
-  {
-  case AF_INET:
-    GNUNET_assert(l_ctx->addr_len == sizeof(struct sockaddr_in));
-    memset (&u4, 0, sizeof(u4));
-    u6.options = htonl (0);
-    u4.ipv4_addr = ((struct sockaddr_in *) l_ctx->address)->sin_addr.s_addr;
-    u4.u4_port = ((struct sockaddr_in *) l_ctx->address)->sin_port;
-    arg = &u4;
-    args = sizeof(u4);
-    break;
-  case AF_INET6:
-    GNUNET_assert(l_ctx->addr_len == sizeof(struct sockaddr_in6));
-    memset (&u6, 0, sizeof(u6));
-    u6.options = htonl (0);
-    u6.ipv6_addr = ((struct sockaddr_in6 *) l_ctx->address)->sin6_addr;
-    u6.u6_port = ((struct sockaddr_in6 *) l_ctx->address)->sin6_port;
-    arg = &u6;
-    args = sizeof(u6);
-    break;
-  default:
-    GNUNET_break(0);
-    return GNUNET_YES;
-  }
-  if ( (GNUNET_YES == l_ctx->must_have_frag_ctx) &&
-       (NULL == s->frag_ctx))
-    return GNUNET_YES;
-
-  /* Does not compare peer identities but addresses */
-  if ((args == s->address->address_length) &&
-      (0 == memcmp (arg, s->address->address, args)))
-  {
-    l_ctx->res = s;
-    return GNUNET_NO;
-  }
-  return GNUNET_YES;
-}
-
-
 static struct Session *
 udp_plugin_create_session (void *cls,
-                           const struct GNUNET_HELLO_Address *address)
+                           const struct GNUNET_HELLO_Address *address,
+                           enum GNUNET_ATS_Network_Type network_type)
 {
   struct Plugin *plugin = cls;
   struct Session *s;
-  struct IPv4UdpAddress *udp_v4;
-  struct IPv6UdpAddress *udp_v6;
 
-  s = create_session (plugin, address);
-  if (sizeof (struct IPv4UdpAddress) == address->address_length)
-  {
-    struct sockaddr_in v4;
-    udp_v4 = (struct IPv4UdpAddress *) address->address;
-    memset (&v4, '\0', sizeof (v4));
-    v4.sin_family = AF_INET;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-    v4.sin_len = sizeof (struct sockaddr_in);
-#endif
-    v4.sin_port = udp_v4->u4_port;
-    v4.sin_addr.s_addr = udp_v4->ipv4_addr;
-    s->ats = plugin->env->get_address_type (plugin->env->cls,
-                                            (const struct sockaddr *) &v4,
-                                            sizeof (v4));
-  }
-  else if (sizeof (struct IPv6UdpAddress) == address->address_length)
-  {
-    struct sockaddr_in6 v6;
-    udp_v6 = (struct IPv6UdpAddress *) address->address;
-    memset (&v6, '\0', sizeof (v6));
-    v6.sin6_family = AF_INET6;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-    v6.sin6_len = sizeof (struct sockaddr_in6);
-#endif
-    v6.sin6_port = udp_v6->u6_port;
-    v6.sin6_addr = udp_v6->ipv6_addr;
-    s->ats = plugin->env->get_address_type (plugin->env->cls,
-        (const struct sockaddr *) &v6, sizeof (v6));
-  }
+  s = GNUNET_new (struct Session);
+  s->plugin = plugin;
+  s->address = GNUNET_HELLO_address_copy (address);
+  s->target = address->peer;
+  s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
+                                                              250);
+  s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
+  s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO_ABS;
+  s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
+  s->timeout = GNUNET_TIME_relative_to_absolute (UDP_SESSION_TIME_OUT);
+  s->timeout_task = GNUNET_SCHEDULER_add_delayed (UDP_SESSION_TIME_OUT,
+                                                  &session_timeout, s);
+  s->scope = network_type;
 
-  if (NULL == s)
-    return NULL; /* protocol not supported or address invalid */
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Creating new %s session %p for peer `%s' address `%s'\n",
-      GNUNET_HELLO_address_check_option (address, GNUNET_HELLO_ADDRESS_INFO_INBOUND) ? "inbound" : "outbound",
-      s, GNUNET_i2s (&address->peer),
-      udp_address_to_string( NULL,address->address,address->address_length));
-  GNUNET_assert(
-      GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (plugin->sessions, &s->target, s, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
-  GNUNET_STATISTICS_set (plugin->env->stats, "# UDP sessions active",
-      GNUNET_CONTAINER_multipeermap_size (plugin->sessions), GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating new session %p for peer `%s' address `%s'\n",
+       s,
+       GNUNET_i2s (&address->peer),
+       udp_address_to_string (plugin,
+                              address->address,
+                              address->address_length));
+  GNUNET_assert(GNUNET_OK ==
+                GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
+                                                   &s->target,
+                                                   s,
+                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+  GNUNET_STATISTICS_set (plugin->env->stats,
+                         "# UDP sessions active",
+                         GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
+                         GNUNET_NO);
   return s;
 }
 
@@ -1845,7 +1800,7 @@ udp_plugin_create_session (void *cls,
  * notify the plugin that a session is still active and in use and
  * therefore the session timeout for this session has to be updated
  *
- * @param cls closure
+ * @param cls closure with the `struct Plugin`
  * @param peer which peer was the session for
  * @param session which session is being updated
  */
@@ -1870,10 +1825,10 @@ udp_plugin_update_session_timeout (void *cls,
 
 
 /**
- * Creates a new outbound session the transport service will use to send data to the
- * peer
+ * Creates a new outbound session the transport service will use to
+ * send data to the peer.
  *
- * @param cls the plugin
+ * @param cls the `struct Plugin *`
  * @param address the address
  * @return the session or NULL of max connections exceeded
  */
@@ -1881,21 +1836,63 @@ static struct Session *
 udp_plugin_get_session (void *cls,
                         const struct GNUNET_HELLO_Address *address)
 {
+  struct Plugin *plugin = cls;
   struct Session *s;
+  enum GNUNET_ATS_Network_Type network_type;
+  struct IPv4UdpAddress *udp_v4;
+  struct IPv6UdpAddress *udp_v6;
 
   if (NULL == address)
   {
-    GNUNET_break(0);
+    GNUNET_break (0);
     return NULL;
   }
   if ( (address->address_length != sizeof(struct IPv4UdpAddress)) &&
        (address->address_length != sizeof(struct IPv6UdpAddress)) )
+  {
+    GNUNET_break_op (0);
     return NULL;
-
-  /* otherwise create new */
-  if (NULL != (s = udp_plugin_lookup_session (cls, address)))
+  }
+  if (NULL != (s = udp_plugin_lookup_session (cls,
+                                              address)))
     return s;
-  return udp_plugin_create_session (cls, address);
+
+  /* need to create new session */
+  if (sizeof (struct IPv4UdpAddress) == address->address_length)
+  {
+    struct sockaddr_in v4;
+
+    udp_v4 = (struct IPv4UdpAddress *) address->address;
+    memset (&v4, '\0', sizeof (v4));
+    v4.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    v4.sin_len = sizeof (struct sockaddr_in);
+#endif
+    v4.sin_port = udp_v4->u4_port;
+    v4.sin_addr.s_addr = udp_v4->ipv4_addr;
+    network_type = plugin->env->get_address_type (plugin->env->cls,
+                                                  (const struct sockaddr *) &v4,
+                                                  sizeof (v4));
+  }
+  if (sizeof (struct IPv6UdpAddress) == address->address_length)
+  {
+    struct sockaddr_in6 v6;
+
+    udp_v6 = (struct IPv6UdpAddress *) address->address;
+    memset (&v6, '\0', sizeof (v6));
+    v6.sin6_family = AF_INET6;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    v6.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+    v6.sin6_port = udp_v6->u6_port;
+    v6.sin6_addr = udp_v6->ipv6_addr;
+    network_type = plugin->env->get_address_type (plugin->env->cls,
+                                                  (const struct sockaddr *) &v6,
+                                                  sizeof (v6));
+  }
+  return udp_plugin_create_session (cls,
+                                   address,
+                                   network_type);
 }
 
 
@@ -1918,7 +1915,9 @@ enqueue (struct Plugin *plugin,
   else
   {
     GNUNET_STATISTICS_update (plugin->env->stats,
-        "# UDP, total, bytes in buffers", udpw->msg_size, GNUNET_NO);
+                              "# UDP, total, bytes in buffers",
+                              udpw->msg_size,
+                              GNUNET_NO);
     plugin->bytes_in_buffer += udpw->msg_size;
   }
   GNUNET_STATISTICS_update (plugin->env->stats,
@@ -2046,8 +2045,6 @@ udp_plugin_send (void *cls,
   struct UDP_MessageWrapper * udpw;
   struct UDPMessage *udp;
   char mbuf[udpmlen];
-  GNUNET_assert(plugin != NULL);
-  GNUNET_assert(s != NULL);
 
   if ( (s->address->address_length == sizeof(struct IPv6UdpAddress)) &&
        (plugin->sockv6 == NULL) )
@@ -2060,9 +2057,10 @@ udp_plugin_send (void *cls,
     GNUNET_break(0);
     return GNUNET_SYSERR;
   }
-  if (GNUNET_YES
-      != GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
-          &s->target, s))
+  if (GNUNET_YES !=
+      GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
+                                                    &s->target,
+                                                    s))
   {
     GNUNET_break(0);
     return GNUNET_SYSERR;
@@ -2071,7 +2069,7 @@ udp_plugin_send (void *cls,
        "UDP transmits %u-byte message to `%s' using address `%s'\n",
        udpmlen,
        GNUNET_i2s (&s->target),
-       udp_address_to_string (NULL,
+       udp_address_to_string (plugin,
                               s->address->address,
                               s->address->address_length));
 
@@ -2152,7 +2150,7 @@ udp_plugin_send (void *cls,
   }
   notify_session_monitor (s->plugin,
                           s,
-                          GNUNET_TRANSPORT_SS_UP);
+                          GNUNET_TRANSPORT_SS_UPDATE);
   schedule_select (plugin);
   return udpmlen;
 }
@@ -2230,7 +2228,7 @@ udp_nat_port_map_callback (void *cls,
  * to the service.
  *
  * @param cls the `struct Plugin *`
- * @param client the `struct SourceInformation *`
+ * @param client the `struct Session *`
  * @param hdr the actual message
  * @return #GNUNET_OK (always)
  */
@@ -2240,24 +2238,18 @@ process_inbound_tokenized_messages (void *cls,
                                     const struct GNUNET_MessageHeader *hdr)
 {
   struct Plugin *plugin = cls;
-  struct SourceInformation *si = client;
+  struct Session *session = client;
   struct GNUNET_TIME_Relative delay;
 
-  GNUNET_assert(si->session != NULL);
-  if (GNUNET_YES == si->session->in_destroy)
+  if (GNUNET_YES == session->in_destroy)
     return GNUNET_OK;
   /* setup ATS */
-  GNUNET_break (ntohl (si->session->ats.value) != GNUNET_ATS_NET_UNSPECIFIED);
-  reschedule_session_timeout (si->session);
+  reschedule_session_timeout (session);
   delay = plugin->env->receive (plugin->env->cls,
-                                si->session->address,
-                                si->session,
+                                session->address,
+                                session,
                                 hdr);
-  plugin->env->update_address_metrics (plugin->env->cls,
-                                       si->session->address,
-                                       si->session,
-                                       &si->session->ats, 1);
-  si->session->flow_delay_for_other_peer = delay;
+  session->flow_delay_for_other_peer = delay;
   return GNUNET_OK;
 }
 
@@ -2267,23 +2259,21 @@ process_inbound_tokenized_messages (void *cls,
  *
  * @param plugin plugin context
  * @param msg the message
- * @param sender_addr sender address
- * @param sender_addr_len number of bytes in @a sender_addr
+ * @param udp_addr sender address
+ * @param udp_addr_len number of bytes in @a udp_addr
+ * @param network_type network type the address belongs to
  */
 static void
 process_udp_message (struct Plugin *plugin,
                      const struct UDPMessage *msg,
-                     const struct sockaddr *sender_addr,
-                     socklen_t sender_addr_len)
+                     const union UdpAddress *udp_addr,
+                     size_t udp_addr_len,
+                     enum GNUNET_ATS_Network_Type network_type)
 {
-  struct SourceInformation si;
-  struct Session * s;
+  struct Session *s;
   struct GNUNET_HELLO_Address *address;
-  struct IPv4UdpAddress u4;
-  struct IPv6UdpAddress u6;
-  const void *arg;
-  size_t args;
 
+  GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network_type);
   if (0 != ntohl (msg->reserved))
   {
     GNUNET_break_op(0);
@@ -2296,55 +2286,38 @@ process_udp_message (struct Plugin *plugin,
     return;
   }
 
-  /* convert address */
-  switch (sender_addr->sa_family)
-  {
-  case AF_INET:
-    GNUNET_assert(sender_addr_len == sizeof(struct sockaddr_in));
-    memset (&u4, 0, sizeof(u4));
-    u6.options = htonl (0);
-    u4.ipv4_addr = ((struct sockaddr_in *) sender_addr)->sin_addr.s_addr;
-    u4.u4_port = ((struct sockaddr_in *) sender_addr)->sin_port;
-    arg = &u4;
-    args = sizeof(u4);
-    break;
-  case AF_INET6:
-    GNUNET_assert(sender_addr_len == sizeof(struct sockaddr_in6));
-    memset (&u6, 0, sizeof(u6));
-    u6.options = htonl (0);
-    u6.ipv6_addr = ((struct sockaddr_in6 *) sender_addr)->sin6_addr;
-    u6.u6_port = ((struct sockaddr_in6 *) sender_addr)->sin6_port;
-    arg = &u6;
-    args = sizeof(u6);
-    break;
-  default:
-    GNUNET_break(0);
-    return;
-  }
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Received message with %u bytes from peer `%s' at `%s'\n",
-      (unsigned int ) ntohs (msg->header.size), GNUNET_i2s (&msg->sender),
-      GNUNET_a2s (sender_addr, sender_addr_len));
-
-  address = GNUNET_HELLO_address_allocate ( &msg->sender, PLUGIN_NAME,
-                                            arg, args,
-                                            GNUNET_HELLO_ADDRESS_INFO_INBOUND);
-  if (NULL == (s = udp_plugin_lookup_session (plugin, address)))
-  {
-    s = udp_plugin_create_session (plugin, address);
-    plugin->env->session_start (NULL, address, s, NULL, 0);
+  address = GNUNET_HELLO_address_allocate (&msg->sender,
+                                           PLUGIN_NAME,
+                                           udp_addr,
+                                           udp_addr_len,
+                                           GNUNET_HELLO_ADDRESS_INFO_NONE);
+  if (NULL ==
+      (s = udp_plugin_lookup_session (plugin, address)))
+  {
+    s = udp_plugin_create_session (plugin,
+                                   address,
+                                   network_type);
+    plugin->env->session_start (plugin->env->cls,
+                                address,
+                                s,
+                                s->scope);
+    notify_session_monitor (s->plugin,
+                            s,
+                            GNUNET_TRANSPORT_SS_INIT);
+    notify_session_monitor (s->plugin,
+                            s,
+                            GNUNET_TRANSPORT_SS_UP);
   }
-  GNUNET_free(address);
+  GNUNET_free (address);
 
   /* iterate over all embedded messages */
-  si.session = s;
-  si.sender = msg->sender;
-  si.arg = arg;
-  si.args = args;
   s->rc++;
-  GNUNET_SERVER_mst_receive (plugin->mst, &si, (const char *) &msg[1],
-      ntohs (msg->header.size) - sizeof(struct UDPMessage), GNUNET_YES,
-      GNUNET_NO);
+  GNUNET_SERVER_mst_receive (plugin->mst,
+                             s,
+                             (const char *) &msg[1],
+                             ntohs (msg->header.size) - sizeof(struct UDPMessage),
+                             GNUNET_YES,
+                             GNUNET_NO);
   s->rc--;
   if ((0 == s->rc) && (GNUNET_YES == s->in_destroy))
     free_session (s);
@@ -2362,6 +2335,7 @@ fragment_msg_proc (void *cls,
                    const struct GNUNET_MessageHeader *msg)
 {
   struct DefragContext *rc = cls;
+  const struct UDPMessage *um;
 
   if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE)
   {
@@ -2373,10 +2347,14 @@ fragment_msg_proc (void *cls,
     GNUNET_break(0);
     return;
   }
+  um = (const struct UDPMessage *) msg;
+  rc->sender = um->sender;
+  rc->have_sender = GNUNET_YES;
   process_udp_message (rc->plugin,
-                       (const struct UDPMessage *) msg,
-                       rc->src_addr,
-                       rc->addr_len);
+                       um,
+                       rc->udp_addr,
+                       rc->udp_addr_len,
+                       rc->network_type);
 }
 
 
@@ -2398,26 +2376,32 @@ ack_proc (void *cls,
   uint32_t delay = 0;
   struct UDP_MessageWrapper *udpw;
   struct Session *s;
-  struct LookupContext l_ctx;
-
-  l_ctx.address = rc->src_addr;
-  l_ctx.addr_len = rc->addr_len;
-  l_ctx.must_have_frag_ctx = GNUNET_NO;
-  l_ctx.res = NULL;
-  GNUNET_CONTAINER_multipeermap_iterate (rc->plugin->sessions,
-                                         &lookup_session_by_sockaddr_it,
-                                         &l_ctx);
-  s = l_ctx.res;
+  struct GNUNET_HELLO_Address *address;
+
+  if (GNUNET_NO == rc->have_sender)
+  {
+    /* tried to defragment but never succeeded, hence will not ACK */
+    GNUNET_break_op (0);
+    return;
+  }
+  address = GNUNET_HELLO_address_allocate (&rc->sender,
+                                           PLUGIN_NAME,
+                                           rc->udp_addr,
+                                           rc->udp_addr_len,
+                                           GNUNET_HELLO_ADDRESS_INFO_NONE);
+  s = udp_plugin_lookup_session (rc->plugin,
+                                 address);
+  GNUNET_HELLO_address_free (address);
   if (NULL == s)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-        "Trying to transmit ACK to peer `%s' but not session found!\n",
-        GNUNET_a2s(rc->src_addr, rc->addr_len));
-
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         "Trying to transmit ACK to peer `%s' but no session found!\n",
+         udp_address_to_string (rc->plugin,
+                                rc->udp_addr,
+                                rc->udp_addr_len));
     GNUNET_CONTAINER_heap_remove_node (rc->hnode);
     GNUNET_DEFRAGMENT_context_destroy (rc->defrag);
     GNUNET_free (rc);
-
     return;
   }
   if (s->flow_delay_for_other_peer.rel_value_us <= UINT32_MAX)
@@ -2425,7 +2409,9 @@ ack_proc (void *cls,
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Sending ACK to `%s' including delay of %s\n",
-       GNUNET_a2s (rc->src_addr, (rc->src_addr->sa_family == AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)),
+       udp_address_to_string (rc->plugin,
+                              rc->udp_addr,
+                              rc->udp_addr_len),
        GNUNET_STRINGS_relative_time_to_string (s->flow_delay_for_other_peer,
                                                GNUNET_YES));
   udpw = GNUNET_malloc (sizeof (struct UDP_MessageWrapper) + msize);
@@ -2444,44 +2430,28 @@ ack_proc (void *cls,
   enqueue (rc->plugin, udpw);
   notify_session_monitor (s->plugin,
                           s,
-                          GNUNET_TRANSPORT_SS_UP);
+                          GNUNET_TRANSPORT_SS_UPDATE);
   schedule_select (rc->plugin);
 }
 
 
 /**
- * FIXME.
- */
-static void
-read_process_msg (struct Plugin *plugin,
-                  const struct GNUNET_MessageHeader *msg,
-                  const struct sockaddr *addr,
-                  socklen_t fromlen)
-{
-  if (ntohs (msg->size) < sizeof(struct UDPMessage))
-  {
-    GNUNET_break_op(0);
-    return;
-  }
-  process_udp_message (plugin,
-                       (const struct UDPMessage *) msg,
-                       addr,
-                       fromlen);
-}
-
-
-/**
- * FIXME.
+ * Handle an ACK message.
+ *
+ * @param plugin the UDP plugin
+ * @param msg the (presumed) UDP ACK message
+ * @param udp_addr sender address
+ * @param udp_addr_len number of bytes in @a udp_addr
  */
 static void
 read_process_ack (struct Plugin *plugin,
                   const struct GNUNET_MessageHeader *msg,
-                  const struct sockaddr *addr,
-                  socklen_t fromlen)
+                  const union UdpAddress *udp_addr,
+                  socklen_t udp_addr_len)
 {
   const struct GNUNET_MessageHeader *ack;
   const struct UDP_ACK_Message *udp_ack;
-  struct LookupContext l_ctx;
+  struct GNUNET_HELLO_Address *address;
   struct Session *s;
   struct GNUNET_TIME_Relative flow_delay;
 
@@ -2492,23 +2462,41 @@ read_process_ack (struct Plugin *plugin,
     return;
   }
   udp_ack = (const struct UDP_ACK_Message *) msg;
-
-  /* Lookup session based on sockaddr */
-  l_ctx.address = addr;
-  l_ctx.addr_len = fromlen;
-  l_ctx.res = NULL;
-  l_ctx.must_have_frag_ctx = GNUNET_YES;
-  GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
-      &lookup_session_by_sockaddr_it, &l_ctx);
-  s = l_ctx.res;
-  if ((NULL == s) || (NULL == s->frag_ctx))
+  address = GNUNET_HELLO_address_allocate (&udp_ack->sender,
+                                           PLUGIN_NAME,
+                                           udp_addr,
+                                           udp_addr_len,
+                                           GNUNET_HELLO_ADDRESS_INFO_NONE);
+  s = udp_plugin_lookup_session (plugin,
+                                 address);
+  if (NULL == s)
   {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "UDP session of address %s for ACK not found\n",
+         udp_address_to_string (plugin,
+                                address->address,
+                                address->address_length));
+    GNUNET_HELLO_address_free (address);
     return;
   }
+  if (NULL == s->frag_ctx)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Fragmentation context of address %s for ACK not found\n",
+         udp_address_to_string (plugin,
+                                address->address,
+                                address->address_length));
+    GNUNET_HELLO_address_free (address);
+    return;
+  }
+  GNUNET_HELLO_address_free (address);
 
   flow_delay.rel_value_us = (uint64_t) ntohl (udp_ack->delay);
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "We received a sending delay of %s\n",
-      GNUNET_STRINGS_relative_time_to_string (flow_delay, GNUNET_YES));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "We received a sending delay of %s for %s\n",
+       GNUNET_STRINGS_relative_time_to_string (flow_delay,
+                                               GNUNET_YES),
+       GNUNET_i2s (&udp_ack->sender));
   s->flow_delay_from_other_peer = GNUNET_TIME_relative_to_absolute (flow_delay);
 
   ack = (const struct GNUNET_MessageHeader *) &udp_ack[1];
@@ -2518,92 +2506,118 @@ read_process_ack (struct Plugin *plugin,
     return;
   }
 
-  if (0
-      != memcmp (&l_ctx.res->target, &udp_ack->sender,
-          sizeof(struct GNUNET_PeerIdentity)))
-    GNUNET_break(0);
-  if (GNUNET_OK != GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag, ack))
+  if (GNUNET_OK !=
+      GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag,
+                                   ack))
   {
     LOG(GNUNET_ERROR_TYPE_DEBUG,
         "UDP processes %u-byte acknowledgement from `%s' at `%s'\n",
-        (unsigned int ) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender),
-        GNUNET_a2s (addr, fromlen));
+        (unsigned int ) ntohs (msg->size),
+        GNUNET_i2s (&udp_ack->sender),
+        udp_address_to_string (plugin,
+                               udp_addr,
+                               udp_addr_len));
     /* Expect more ACKs to arrive */
     return;
   }
 
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "Message full ACK'ed\n",
-      (unsigned int ) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender),
-      GNUNET_a2s (addr, fromlen));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Message from %s at %s full ACK'ed\n",
+       GNUNET_i2s (&udp_ack->sender),
+       udp_address_to_string (plugin,
+                              udp_addr,
+                              udp_addr_len));
 
   /* Remove fragmented message after successful sending */
-  fragmented_message_done (s->frag_ctx, GNUNET_OK);
+  fragmented_message_done (s->frag_ctx,
+                           GNUNET_OK);
 }
 
 
 /**
- * FIXME.
+ * We received a fragment, process it.
+ *
+ * @param plugin our plugin
+ * @param msg a message of type #GNUNET_MESSAGE_TYPE_FRAGMENT
+ * @param udp_addr sender address
+ * @param udp_addr_len number of bytes in @a udp_addr
+ * @param network_type network type the address belongs to
  */
 static void
 read_process_fragment (struct Plugin *plugin,
                        const struct GNUNET_MessageHeader *msg,
-                       const struct sockaddr *addr,
-                       socklen_t fromlen)
+                       const union UdpAddress *udp_addr,
+                       size_t udp_addr_len,
+                       enum GNUNET_ATS_Network_Type network_type)
 {
   struct DefragContext *d_ctx;
   struct GNUNET_TIME_Absolute now;
   struct FindReceiveContext frc;
 
   frc.rc = NULL;
-  frc.addr = addr;
-  frc.addr_len = fromlen;
+  frc.udp_addr = udp_addr;
+  frc.udp_addr_len = udp_addr_len;
 
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "UDP processes %u-byte fragment from `%s'\n",
-      (unsigned int ) ntohs (msg->size), GNUNET_a2s (addr, fromlen));
   /* Lookup existing receive context for this address */
   GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs,
-      &find_receive_context, &frc);
+                                 &find_receive_context,
+                                 &frc);
   now = GNUNET_TIME_absolute_get ();
   d_ctx = frc.rc;
 
-  if (d_ctx == NULL )
+  if (NULL == d_ctx)
   {
     /* Create a new defragmentation context */
-    d_ctx = GNUNET_malloc (sizeof (struct DefragContext) + fromlen);
-    memcpy (&d_ctx[1], addr, fromlen);
-    d_ctx->src_addr = (const struct sockaddr *) &d_ctx[1];
-    d_ctx->addr_len = fromlen;
+    d_ctx = GNUNET_malloc (sizeof (struct DefragContext) + udp_addr_len);
+    memcpy (&d_ctx[1],
+            udp_addr,
+            udp_addr_len);
+    d_ctx->udp_addr = (const union UdpAddress *) &d_ctx[1];
+    d_ctx->udp_addr_len = udp_addr_len;
+    d_ctx->network_type = network_type;
     d_ctx->plugin = plugin;
     d_ctx->defrag = GNUNET_DEFRAGMENT_context_create (plugin->env->stats,
-        UDP_MTU, UDP_MAX_MESSAGES_IN_DEFRAG, d_ctx, &fragment_msg_proc,
-        &ack_proc);
-    d_ctx->hnode = GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs, d_ctx,
+                                                      UDP_MTU,
+                                                      UDP_MAX_MESSAGES_IN_DEFRAG,
+                                                      d_ctx,
+                                                      &fragment_msg_proc,
+                                                      &ack_proc);
+    d_ctx->hnode = GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs,
+                                                 d_ctx,
         (GNUNET_CONTAINER_HeapCostType) now.abs_value_us);
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Created new defragmentation context for %u-byte fragment from `%s'\n",
-        (unsigned int ) ntohs (msg->size), GNUNET_a2s (addr, fromlen));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Created new defragmentation context for %u-byte fragment from `%s'\n",
+         (unsigned int ) ntohs (msg->size),
+         udp_address_to_string (plugin,
+                                udp_addr,
+                                udp_addr_len));
   }
   else
   {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Found existing defragmentation context for %u-byte fragment from `%s'\n",
-        (unsigned int ) ntohs (msg->size), GNUNET_a2s (addr, fromlen));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Found existing defragmentation context for %u-byte fragment from `%s'\n",
+         (unsigned int ) ntohs (msg->size),
+         udp_address_to_string (plugin,
+                                udp_addr,
+                                udp_addr_len));
   }
 
-  if (GNUNET_OK == GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg))
+  if (GNUNET_OK ==
+      GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg))
   {
     /* keep this 'rc' from expiring */
-    GNUNET_CONTAINER_heap_update_cost (plugin->defrag_ctxs, d_ctx->hnode,
+    GNUNET_CONTAINER_heap_update_cost (plugin->defrag_ctxs,
+                                       d_ctx->hnode,
         (GNUNET_CONTAINER_HeapCostType) now.abs_value_us);
   }
   if (GNUNET_CONTAINER_heap_get_size (plugin->defrag_ctxs) >
-  UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG)
+      UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG)
   {
     /* remove 'rc' that was inactive the longest */
     d_ctx = GNUNET_CONTAINER_heap_remove_root (plugin->defrag_ctxs);
-    GNUNET_assert(NULL != d_ctx);
+    GNUNET_assert (NULL != d_ctx);
     GNUNET_DEFRAGMENT_context_destroy (d_ctx->defrag);
-    GNUNET_free(d_ctx);
+    GNUNET_free (d_ctx);
   }
 }
 
@@ -2623,11 +2637,20 @@ udp_select_read (struct Plugin *plugin,
   char buf[65536] GNUNET_ALIGN;
   ssize_t size;
   const struct GNUNET_MessageHeader *msg;
+  struct IPv4UdpAddress v4;
+  struct IPv6UdpAddress v6;
+  const struct sockaddr *sa;
+  const struct sockaddr_in *sa4;
+  const struct sockaddr_in6 *sa6;
+  const union UdpAddress *int_addr;
+  size_t int_addr_len;
+  enum GNUNET_ATS_Network_Type network_type;
 
   fromlen = sizeof(addr);
   memset (&addr, 0, sizeof(addr));
   size = GNUNET_NETWORK_socket_recvfrom (rsock, buf, sizeof(buf),
-      (struct sockaddr *) &addr, &fromlen);
+                                         (struct sockaddr *) &addr, &fromlen);
+  sa = (const struct sockaddr *) &addr;
 #if MINGW
   /* On SOCK_DGRAM UDP sockets recvfrom might fail with a
    * WSAECONNRESET error to indicate that previous sendto() (yes, sendto!)
@@ -2644,54 +2667,105 @@ udp_select_read (struct Plugin *plugin,
 #endif
   if (-1 == size)
   {
-    LOG(GNUNET_ERROR_TYPE_DEBUG, "UDP failed to receive data: %s\n",
-        STRERROR (errno));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "UDP failed to receive data: %s\n",
+         STRERROR (errno));
     /* Connection failure or something. Not a protocol violation. */
     return;
   }
   if (size < sizeof(struct GNUNET_MessageHeader))
   {
-    LOG(GNUNET_ERROR_TYPE_WARNING,
-        "UDP got %u bytes, which is not enough for a GNUnet message header\n",
-        (unsigned int ) size);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "UDP got %u bytes from %s, which is not enough for a GNUnet message header\n",
+         (unsigned int ) size,
+         GNUNET_a2s (sa, fromlen));
     /* _MAY_ be a connection failure (got partial message) */
     /* But it _MAY_ also be that the other side uses non-GNUnet protocol. */
     GNUNET_break_op(0);
     return;
   }
   msg = (const struct GNUNET_MessageHeader *) buf;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "UDP received %u-byte message from `%s' type %u\n", (unsigned int ) size,
-      GNUNET_a2s ((const struct sockaddr * ) &addr, fromlen),
-      ntohs (msg->type));
-
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "UDP received %u-byte message from `%s' type %u\n",
+       (unsigned int) size,
+       GNUNET_a2s (sa,
+                   fromlen),
+       ntohs (msg->type));
   if (size != ntohs (msg->size))
   {
-    GNUNET_break_op(0);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "UDP malformed message header from %s\n",
+         (unsigned int) size,
+         GNUNET_a2s (sa,
+                     fromlen));
+    GNUNET_break_op (0);
     return;
   }
   GNUNET_STATISTICS_update (plugin->env->stats,
                             "# UDP, total, bytes, received",
                             size,
                             GNUNET_NO);
+  network_type = plugin->env->get_address_type (plugin->env->cls,
+                                                sa,
+                                                fromlen);
+  switch (sa->sa_family)
+  {
+  case AF_INET:
+    sa4 = (const struct sockaddr_in *) &addr;
+    v4.options = 0;
+    v4.ipv4_addr = sa4->sin_addr.s_addr;
+    v4.u4_port = sa4->sin_port;
+    int_addr = (union UdpAddress *) &v4;
+    int_addr_len = sizeof (v4);
+    break;
+  case AF_INET6:
+    sa6 = (const struct sockaddr_in6 *) &addr;
+    v6.options = 0;
+    v6.ipv6_addr = sa6->sin6_addr;
+    v6.u6_port = sa6->sin6_port;
+    int_addr = (union UdpAddress *) &v6;
+    int_addr_len = sizeof (v6);
+    break;
+  default:
+    GNUNET_break (0);
+    return;
+  }
 
   switch (ntohs (msg->type))
   {
   case GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON:
     if (GNUNET_YES == plugin->enable_broadcasting_receiving)
-      udp_broadcast_receive (plugin, buf, size, (const struct sockaddr *) &addr,
-          fromlen);
+      udp_broadcast_receive (plugin,
+                             buf,
+                             size,
+                             int_addr,
+                             int_addr_len,
+                             network_type);
     return;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE:
-    read_process_msg (plugin, msg, (const struct sockaddr *) &addr, fromlen);
+    if (ntohs (msg->size) < sizeof(struct UDPMessage))
+    {
+      GNUNET_break_op(0);
+      return;
+    }
+    process_udp_message (plugin,
+                         (const struct UDPMessage *) msg,
+                         int_addr,
+                         int_addr_len,
+                         network_type);
     return;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK:
-    read_process_ack (plugin, msg, (const struct sockaddr *) &addr, fromlen);
+    read_process_ack (plugin,
+                      msg,
+                      int_addr,
+                      int_addr_len);
     return;
   case GNUNET_MESSAGE_TYPE_FRAGMENT:
-    read_process_fragment (plugin, msg, (const struct sockaddr *) &addr,
-        fromlen);
+    read_process_fragment (plugin,
+                           msg,
+                           int_addr,
+                           int_addr_len,
+                           network_type);
     return;
   default:
     GNUNET_break_op(0);
@@ -2701,24 +2775,30 @@ udp_select_read (struct Plugin *plugin,
 
 
 /**
- * FIXME.
+ * Removes messages from the transmission queue that have
+ * timed out, and then selects a message that should be
+ * transmitted next.
+ *
+ * @param plugin the UDP plugin
+ * @param sock which socket should we process the queue for (v4 or v6)
+ * @return message selected for transmission, or NULL for none
  */
 static struct UDP_MessageWrapper *
-remove_timeout_messages_and_select (struct UDP_MessageWrapper *head,
+remove_timeout_messages_and_select (struct Plugin *plugin,
                                     struct GNUNET_NETWORK_Handle *sock)
 {
   struct UDP_MessageWrapper *udpw = NULL;
   struct GNUNET_TIME_Relative remaining;
   struct Session *session;
-  struct Plugin *plugin;
   int removed;
 
   removed = GNUNET_NO;
-  udpw = head;
+  udpw = (sock == plugin->sockv4)
+    ? plugin->ipv4_queue_head
+    : plugin->ipv6_queue_head;
   while (NULL != udpw)
   {
     session = udpw->session;
-    plugin = session->plugin;
     /* Find messages with timeout */
     remaining = GNUNET_TIME_absolute_get_remaining (udpw->timeout);
     if (GNUNET_TIME_UNIT_ZERO.rel_value_us == remaining.rel_value_us)
@@ -2764,7 +2844,8 @@ remove_timeout_messages_and_select (struct UDP_MessageWrapper *head,
                                   "# UDP, total, messages, sent, timeout",
                                   1,
                                   GNUNET_NO);
-        call_continuation (udpw, GNUNET_SYSERR);
+        call_continuation (udpw,
+                          GNUNET_SYSERR);
         LOG (GNUNET_ERROR_TYPE_DEBUG,
              "Fragment for message for peer `%s' with size %u timed out\n",
              GNUNET_i2s (&udpw->session->target),
@@ -2779,7 +2860,8 @@ remove_timeout_messages_and_select (struct UDP_MessageWrapper *head,
                                   udpw->frag_ctx->payload_size,
                                   GNUNET_NO);
         /* Remove fragmented message due to timeout */
-        fragmented_message_done (udpw->frag_ctx, GNUNET_SYSERR);
+        fragmented_message_done (udpw->frag_ctx,
+                                GNUNET_SYSERR);
         break;
       case UMT_MSG_ACK:
         GNUNET_STATISTICS_update (plugin->env->stats,
@@ -2794,10 +2876,12 @@ remove_timeout_messages_and_select (struct UDP_MessageWrapper *head,
              "ACK Message for peer `%s' with size %u timed out\n",
              GNUNET_i2s (&udpw->session->target),
              udpw->payload_size);
-        call_continuation (udpw, GNUNET_SYSERR);
+        call_continuation (udpw,
+                          GNUNET_SYSERR);
         removed = GNUNET_YES;
-        dequeue (plugin, udpw);
-        GNUNET_free(udpw);
+        dequeue (plugin,
+                udpw);
+        GNUNET_free (udpw);
         break;
       default:
         break;
@@ -2834,8 +2918,10 @@ remove_timeout_messages_and_select (struct UDP_MessageWrapper *head,
         /* Message is delayed, try next */
         LOG (GNUNET_ERROR_TYPE_DEBUG,
              "Message for peer `%s' (%u bytes) is delayed for %s\n",
-             GNUNET_i2s (&udpw->session->target), udpw->payload_size,
-             GNUNET_STRINGS_relative_time_to_string (remaining, GNUNET_YES));
+             GNUNET_i2s (&udpw->session->target),
+            udpw->payload_size,
+             GNUNET_STRINGS_relative_time_to_string (remaining,
+                                                    GNUNET_YES));
         udpw = udpw->next;
       }
     }
@@ -2843,7 +2929,7 @@ remove_timeout_messages_and_select (struct UDP_MessageWrapper *head,
   if (GNUNET_YES == removed)
     notify_session_monitor (session->plugin,
                             session,
-                            GNUNET_TRANSPORT_SS_UP);
+                            GNUNET_TRANSPORT_SS_UPDATE);
   return udpw;
 }
 
@@ -2856,11 +2942,11 @@ analyze_send_error (struct Plugin *plugin,
                     const struct sockaddr *sa,
                     socklen_t slen, int error)
 {
-  struct GNUNET_ATS_Information type;
+  enum GNUNET_ATS_Network_Type type;
 
   type = plugin->env->get_address_type (plugin->env->cls, sa, slen);
-  if (((GNUNET_ATS_NET_LAN == ntohl (type.value))
-      || (GNUNET_ATS_NET_WAN == ntohl (type.value)))
+  if (((GNUNET_ATS_NET_LAN == type)
+       || (GNUNET_ATS_NET_WAN == type))
       && ((ENETUNREACH == errno)|| (ENETDOWN == errno)))
   {
     if (slen == sizeof (struct sockaddr_in))
@@ -2898,7 +2984,12 @@ analyze_send_error (struct Plugin *plugin,
 
 
 /**
- * FIXME.
+ * It is time to try to transmit a UDP message.  Select one
+ * and send.
+ *
+ * @param plugin the plugin
+ * @param sock which socket (v4/v6) to send on
+ * @return number of bytes transmitted, #GNUNET_SYSERR on failure
  */
 static size_t
 udp_select_send (struct Plugin *plugin,
@@ -2914,9 +3005,7 @@ udp_select_send (struct Plugin *plugin,
   struct UDP_MessageWrapper *udpw;
 
   /* Find message to send */
-  udpw = remove_timeout_messages_and_select ((sock == plugin->sockv4)
-                                             ? plugin->ipv4_queue_head
-                                             : plugin->ipv6_queue_head,
+  udpw = remove_timeout_messages_and_select (plugin,
                                              sock);
   if (NULL == udpw)
     return 0; /* No message to send */
@@ -2930,7 +3019,9 @@ udp_select_send (struct Plugin *plugin,
     a4.sin_len = sizeof (a4);
 #endif
     a4.sin_port = u4->u4_port;
-    memcpy (&a4.sin_addr, &u4->ipv4_addr, sizeof(struct in_addr));
+    memcpy (&a4.sin_addr,
+           &u4->ipv4_addr,
+           sizeof(struct in_addr));
     a = (struct sockaddr *) &a4;
     slen = sizeof (a4);
   }
@@ -2949,15 +3040,16 @@ udp_select_send (struct Plugin *plugin,
   }
   else
   {
-    call_continuation (udpw, GNUNET_OK);
-    dequeue (plugin, udpw);
+    call_continuation (udpw,
+                      GNUNET_OK);
+    dequeue (plugin,
+            udpw);
     notify_session_monitor (plugin,
                             udpw->session,
-                            GNUNET_TRANSPORT_SS_UP);
+                            GNUNET_TRANSPORT_SS_UPDATE);
     GNUNET_free (udpw);
     return GNUNET_SYSERR;
   }
-
   sent = GNUNET_NETWORK_socket_sendto (sock,
                                        udpw->msg_buf,
                                        udpw->msg_size,
@@ -2966,25 +3058,39 @@ udp_select_send (struct Plugin *plugin,
   if (GNUNET_SYSERR == sent)
   {
     /* Failure */
-    analyze_send_error (plugin, a, slen, errno);
-    call_continuation (udpw, GNUNET_SYSERR);
+    analyze_send_error (plugin,
+                       a,
+                       slen,
+                       errno);
+    call_continuation (udpw,
+                      GNUNET_SYSERR);
     GNUNET_STATISTICS_update (plugin->env->stats,
-        "# UDP, total, bytes, sent, failure", sent, GNUNET_NO);
+                             "# UDP, total, bytes, sent, failure",
+                             sent,
+                             GNUNET_NO);
     GNUNET_STATISTICS_update (plugin->env->stats,
-        "# UDP, total, messages, sent, failure", 1, GNUNET_NO);
+                             "# UDP, total, messages, sent, failure",
+                             1,
+                             GNUNET_NO);
   }
   else
   {
     /* Success */
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "UDP transmitted %u-byte message to  `%s' `%s' (%d: %s)\n",
-        (unsigned int ) (udpw->msg_size), GNUNET_i2s (&udpw->session->target),
-        GNUNET_a2s (a, slen), (int ) sent,
-        (sent < 0) ? STRERROR (errno) : "ok");
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "UDP transmitted %u-byte message to  `%s' `%s' (%d: %s)\n",
+         (unsigned int) (udpw->msg_size),
+         GNUNET_i2s (&udpw->session->target),
+         GNUNET_a2s (a, slen),
+         (int ) sent,
+         (sent < 0) ? STRERROR (errno) : "ok");
     GNUNET_STATISTICS_update (plugin->env->stats,
-        "# UDP, total, bytes, sent, success", sent, GNUNET_NO);
+                              "# UDP, total, bytes, sent, success",
+                              sent,
+                              GNUNET_NO);
     GNUNET_STATISTICS_update (plugin->env->stats,
-        "# UDP, total, messages, sent, success", 1, GNUNET_NO);
+                              "# UDP, total, messages, sent, success",
+                              1,
+                              GNUNET_NO);
     if (NULL != udpw->frag_ctx)
       udpw->frag_ctx->on_wire_size += udpw->msg_size;
     call_continuation (udpw, GNUNET_OK);
@@ -2992,8 +3098,8 @@ udp_select_send (struct Plugin *plugin,
   dequeue (plugin, udpw);
   notify_session_monitor (plugin,
                           udpw->session,
-                          GNUNET_TRANSPORT_SS_UP);
-  GNUNET_free(udpw);
+                          GNUNET_TRANSPORT_SS_UPDATE);
+  GNUNET_free (udpw);
   return sent;
 }
 
@@ -3012,7 +3118,7 @@ udp_plugin_select (void *cls,
 {
   struct Plugin *plugin = cls;
 
-  plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
+  plugin->select_task = NULL;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
   if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
@@ -3041,7 +3147,7 @@ udp_plugin_select_v6 (void *cls,
 {
   struct Plugin *plugin = cls;
 
-  plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+  plugin->select_task_v6 = NULL;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
   if (((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
@@ -3102,9 +3208,9 @@ setup_sockets (struct Plugin *plugin,
         server_addrv6.sin6_addr = in6addr_any;
 
       if (0 == plugin->port) /* autodetect */
-        server_addrv6.sin6_port = htons (
-            GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537)
-                + 32000);
+        server_addrv6.sin6_port
+          = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537)
+                   + 32000);
       else
         server_addrv6.sin6_port = htons (plugin->port);
       addrlen = sizeof(struct sockaddr_in6);
@@ -3117,20 +3223,21 @@ setup_sockets (struct Plugin *plugin,
             "Binding to IPv6 `%s'\n",
             GNUNET_a2s (server_addr, addrlen));
         /* binding */
-        if (GNUNET_OK
-            == GNUNET_NETWORK_socket_bind (plugin->sockv6, server_addr,
-                addrlen))
+        if (GNUNET_OK ==
+            GNUNET_NETWORK_socket_bind (plugin->sockv6,
+                                        server_addr,
+                                        addrlen))
           break;
         eno = errno;
         if (0 != plugin->port)
         {
-          tries = 10; /* fail */
+          tries = 10; /* fail immediately */
           break; /* bind failed on specific port */
         }
         /* autodetect */
-        server_addrv6.sin6_port = htons (
-            GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537)
-                + 32000);
+        server_addrv6.sin6_port
+          = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537)
+                   + 32000);
         tries++;
       }
       if (tries >= 10)
@@ -3139,8 +3246,11 @@ setup_sockets (struct Plugin *plugin,
         plugin->enable_ipv6 = GNUNET_NO;
         plugin->sockv6 = NULL;
       }
-
-      if (plugin->sockv6 != NULL )
+      else
+      {
+        plugin->port = ntohs (server_addrv6.sin6_port);
+      }
+      if (NULL != plugin->sockv6)
       {
         LOG (GNUNET_ERROR_TYPE_DEBUG,
              "IPv6 socket created on port %s\n",
@@ -3166,8 +3276,8 @@ setup_sockets (struct Plugin *plugin,
   {
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
                          "socket");
-    LOG(GNUNET_ERROR_TYPE_WARNING,
-        "Disabling IPv4 since it is not supported on this system!\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Disabling IPv4 since it is not supported on this system!\n");
     plugin->enable_ipv4 = GNUNET_NO;
   }
   else
@@ -3184,9 +3294,10 @@ setup_sockets (struct Plugin *plugin,
 
     if (0 == plugin->port)
       /* autodetect */
-      server_addrv4.sin_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
-                                                                33537)
-                                      + 32000);
+      server_addrv4.sin_port
+        = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
+                                           33537)
+                 + 32000);
     else
       server_addrv4.sin_port = htons (plugin->port);
 
@@ -3201,8 +3312,10 @@ setup_sockets (struct Plugin *plugin,
            GNUNET_a2s (server_addr, addrlen));
 
       /* binding */
-      if (GNUNET_OK
-          == GNUNET_NETWORK_socket_bind (plugin->sockv4, server_addr, addrlen))
+      if (GNUNET_OK ==
+          GNUNET_NETWORK_socket_bind (plugin->sockv4,
+                                      server_addr,
+                                      addrlen))
         break;
       eno = errno;
       if (0 != plugin->port)
@@ -3212,23 +3325,27 @@ setup_sockets (struct Plugin *plugin,
       }
 
       /* autodetect */
-      server_addrv4.sin_port = htons (
-          GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537)
-              + 32000);
+      server_addrv4.sin_port
+        = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537)
+                 + 32000);
       tries++;
     }
-
     if (tries >= 10)
     {
       GNUNET_NETWORK_socket_close (plugin->sockv4);
       plugin->enable_ipv4 = GNUNET_NO;
       plugin->sockv4 = NULL;
     }
+    else
+    {
+      plugin->port = ntohs (server_addrv4.sin_port);
+    }
 
     if (NULL != plugin->sockv4)
     {
-      LOG(GNUNET_ERROR_TYPE_DEBUG, "IPv4 socket created on port %s\n",
-          GNUNET_a2s (server_addr, addrlen));
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "IPv4 socket created on port %s\n",
+           GNUNET_a2s (server_addr, addrlen));
       addrs[sockets_created] = (struct sockaddr *) &server_addrv4;
       addrlens[sockets_created] = sizeof(struct sockaddr_in);
       sockets_created++;
@@ -3244,7 +3361,8 @@ setup_sockets (struct Plugin *plugin,
 
   if (0 == sockets_created)
   {
-    LOG(GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n"));
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Failed to open UDP sockets\n"));
     return 0; /* No sockets created, return */
   }
 
@@ -3307,6 +3425,9 @@ send_session_info_iter (void *cls,
   struct Plugin *plugin = cls;
   struct Session *session = value;
 
+  notify_session_monitor (plugin,
+                          session,
+                          GNUNET_TRANSPORT_SS_INIT);
   notify_session_monitor (plugin,
                           session,
                           GNUNET_TRANSPORT_SS_UP);
@@ -3390,11 +3511,13 @@ libgnunet_plugin_transport_udp_init (void *cls)
   /* Get port number: port == 0 : autodetect a port,
    * > 0 : use this port, not given : 2086 default */
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp",
+      GNUNET_CONFIGURATION_get_value_number (env->cfg,
+                                             "transport-udp",
                                              "PORT", &port))
     port = 2086;
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp",
+      GNUNET_CONFIGURATION_get_value_number (env->cfg,
+                                             "transport-udp",
                                              "ADVERTISED_PORT", &aport))
     aport = port;
   if (port > 65535)
@@ -3504,9 +3627,13 @@ libgnunet_plugin_transport_udp_init (void *cls)
   p->sessions = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
   p->defrag_ctxs = GNUNET_CONTAINER_heap_create (
       GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages, p);
-  GNUNET_BANDWIDTH_tracker_init (&p->tracker, NULL, NULL,
-      GNUNET_BANDWIDTH_value_init ((uint32_t) udp_max_bps), 30);
+  p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages,
+                                     p);
+  GNUNET_BANDWIDTH_tracker_init (&p->tracker,
+                                 NULL,
+                                 NULL,
+                                 GNUNET_BANDWIDTH_value_init ((uint32_t) udp_max_bps),
+                                 30);
   LOG(GNUNET_ERROR_TYPE_DEBUG,
       "Setting up sockets\n");
   res = setup_sockets (p,
@@ -3592,15 +3719,15 @@ libgnunet_plugin_transport_udp_done (void *cls)
     return NULL;
   }
   stop_broadcast (plugin);
-  if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK )
+  if (plugin->select_task != NULL)
   {
     GNUNET_SCHEDULER_cancel (plugin->select_task);
-    plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
+    plugin->select_task = NULL;
   }
-  if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK )
+  if (plugin->select_task_v6 != NULL)
   {
     GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
-    plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+    plugin->select_task_v6 = NULL;
   }
 
   /* Closing sockets */