From 269f25d3bac5ab871d8044935eacc15cfeadeec6 Mon Sep 17 00:00:00 2001
From: Dimitri Staessens <dimitri@ouroboros.rocks>
Date: Sun, 12 Feb 2023 21:05:40 +0100
Subject: ipcpd: refactor IPCP configuration

The ipcp configuration struct now has internal structures for the
different IPCPs and for IPCP components of the unicast IPCP.

Split the very long IPCP main loop into individual handler functions.

Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
---
 include/ouroboros/ipcp.h           |  61 ++--
 include/ouroboros/sockets.h.in     |   4 +
 src/ipcpd/broadcast/main.c         |  16 +-
 src/ipcpd/common/enroll.c          |  50 +--
 src/ipcpd/eth/eth.c                |  31 +-
 src/ipcpd/ipcp.c                   | 631 ++++++++++++++++++++-----------------
 src/ipcpd/ipcp.h                   |   2 +-
 src/ipcpd/local/main.c             |   6 +-
 src/ipcpd/udp/main.c               |  48 +--
 src/ipcpd/unicast/dt.c             |  17 +-
 src/ipcpd/unicast/dt.h             |   6 +-
 src/ipcpd/unicast/main.c           |  22 +-
 src/lib/ipcp_config.proto          |  42 ++-
 src/lib/irm.c                      |  70 ++--
 src/tools/irm/irm_ipcp_bootstrap.c |  35 +-
 15 files changed, 537 insertions(+), 504 deletions(-)

diff --git a/include/ouroboros/ipcp.h b/include/ouroboros/ipcp.h
index 857f4f5d..e2ae0c0e 100644
--- a/include/ouroboros/ipcp.h
+++ b/include/ouroboros/ipcp.h
@@ -29,10 +29,7 @@
 
 #define LAYER_NAME_SIZE 255
 
-/*
- * NOTE: the IRMd uses this order to select an IPCP
- * for flow allocation.
- */
+/* NOTE: The IRMd uses this order to select an IPCP for flow allocation. */
 enum ipcp_type {
         IPCP_LOCAL = 0,
         IPCP_UNICAST,
@@ -66,6 +63,31 @@ enum pol_dir_hash {
         DIR_HASH_SHA3_512
 };
 
+struct dt_config {
+        uint8_t          addr_size;
+        uint8_t          eid_size;
+        uint8_t          max_ttl;
+        enum pol_routing routing_type;
+};
+
+/* IPCP configuration */
+struct uni_config {
+        struct dt_config    dt;
+        enum pol_addr_auth  addr_auth_type;
+        enum pol_cong_avoid cong_avoid;
+};
+
+struct eth_config {
+        char *   dev;
+        uint16_t ethertype; /* DIX only*/
+};
+
+struct udp_config {
+        uint32_t ip_addr;
+        uint32_t dns_addr;
+        uint16_t port;
+};
+
 /* Info reported back to the IRMd about the layer on enrollment */
 struct layer_info {
         char layer_name[LAYER_NAME_SIZE + 1];
@@ -74,29 +96,14 @@ struct layer_info {
 
 /* Structure to configure the first IPCP */
 struct ipcp_config {
-        struct layer_info   layer_info;
-
-        enum ipcp_type      type;
-
-        /* Unicast */
-        uint8_t             addr_size;
-        uint8_t             eid_size;
-        uint8_t             max_ttl;
-
-        enum pol_addr_auth  addr_auth_type;
-        enum pol_routing    routing_type;
-        enum pol_cong_avoid cong_avoid;
-
-        /* UDP */
-        uint32_t            ip_addr;
-        uint32_t            dns_addr;
-        uint16_t            port;
-
-        /* Ethernet */
-        char *              dev;
-
-        /* Ethernet DIX */
-        uint16_t            ethertype;
+        struct layer_info layer_info;
+        enum ipcp_type    type;
+
+        union {
+                struct uni_config unicast;
+                struct udp_config udp;
+                struct eth_config eth;
+        };
 };
 
 #endif /* OUROBOROS_IPCP_H */
diff --git a/include/ouroboros/sockets.h.in b/include/ouroboros/sockets.h.in
index 554fcc0a..b1e714f4 100644
--- a/include/ouroboros/sockets.h.in
+++ b/include/ouroboros/sockets.h.in
@@ -30,6 +30,10 @@
 #include "ipcp_config.pb-c.h"
 typedef IpcpConfigMsg ipcp_config_msg_t;
 typedef LayerInfoMsg layer_info_msg_t;
+typedef DtConfigMsg dt_config_msg_t;
+typedef EthConfigMsg eth_config_msg_t;
+typedef UdpConfigMsg udp_config_msg_t;
+typedef UniConfigMsg uni_config_msg_t;
 
 #include "irmd_messages.pb-c.h"
 typedef IrmMsg irm_msg_t;
diff --git a/src/ipcpd/broadcast/main.c b/src/ipcpd/broadcast/main.c
index 2b8b90a5..d0becc63 100644
--- a/src/ipcpd/broadcast/main.c
+++ b/src/ipcpd/broadcast/main.c
@@ -56,36 +56,24 @@ struct ipcp ipcpi;
 
 static int initialize_components(const struct ipcp_config * conf)
 {
-        ipcpi.layer_name = strdup(conf->layer_info.layer_name);
-        if (ipcpi.layer_name == NULL) {
-                log_err("Failed to set layer name.");
-                goto fail_layer_name;
-        }
-
+        strcpy(ipcpi.layer_name, conf->layer_info.layer_name);
         ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo;
 
         assert(ipcp_dir_hash_len() != 0);
 
         if (dt_init()) {
                 log_err("Failed to initialize forwarding component.");
-                goto fail_dt;
+                return -1;
         }
 
         ipcp_set_state(IPCP_INIT);
 
         return 0;
-
- fail_dt:
-        free(ipcpi.layer_name);
- fail_layer_name:
-        return -1;
 }
 
 static void finalize_components(void)
 {
         dt_fini();
-
-        free(ipcpi.layer_name);
 }
 
 static int start_components(void)
diff --git a/src/ipcpd/common/enroll.c b/src/ipcpd/common/enroll.c
index c71dc4cc..745829e7 100644
--- a/src/ipcpd/common/enroll.c
+++ b/src/ipcpd/common/enroll.c
@@ -74,7 +74,9 @@ static int send_rcv_enroll_msg(int fd)
         ssize_t         delta_t;
         struct timespec t0;
         struct timespec rtt;
-
+#ifdef BUILD_IPCP_UNICAST
+        uni_config_msg_t * uni_cfg_msg;
+#endif
         req.code = ENROLL_CODE__ENROLL_REQ;
 
         len = enroll_msg__get_packed_size(&req);
@@ -132,12 +134,14 @@ static int send_rcv_enroll_msg(int fd)
                reply->conf->layer_info->layer_name);
         enroll.conf.type           = reply->conf->ipcp_type;
 #ifdef BUILD_IPCP_UNICAST
-        enroll.conf.addr_size      = reply->conf->addr_size;
-        enroll.conf.eid_size       = reply->conf->eid_size;
-        enroll.conf.max_ttl        = reply->conf->max_ttl;
-        enroll.conf.addr_auth_type = reply->conf->addr_auth_type;
-        enroll.conf.routing_type   = reply->conf->routing_type;
-        enroll.conf.cong_avoid     = reply->conf->cong_avoid;
+        uni_cfg_msg = reply->conf->unicast;
+
+        enroll.conf.unicast.dt.addr_size    = uni_cfg_msg->dt->addr_size;
+        enroll.conf.unicast.dt.eid_size     = uni_cfg_msg->dt->eid_size;
+        enroll.conf.unicast.dt.max_ttl      = uni_cfg_msg->dt->max_ttl;
+        enroll.conf.unicast.dt.routing_type = uni_cfg_msg->dt->routing_type;
+        enroll.conf.unicast.addr_auth_type  = uni_cfg_msg->addr_auth_type;
+        enroll.conf.unicast.cong_avoid      = uni_cfg_msg->cong_avoid;
 #endif
         enroll.conf.layer_info.dir_hash_algo
                 = reply->conf->layer_info->dir_hash_algo;
@@ -151,6 +155,10 @@ static ssize_t enroll_pack(uint8_t ** buf)
         enroll_msg_t      msg        = ENROLL_MSG__INIT;
         ipcp_config_msg_t config     = IPCP_CONFIG_MSG__INIT;
         layer_info_msg_t  layer_info = LAYER_INFO_MSG__INIT;
+#ifdef BUILD_IPCP_UNICAST
+        dt_config_msg_t   dt_cfg_msg  = DT_CONFIG_MSG__INIT;
+        uni_config_msg_t  uni_cfg_msg = UNI_CONFIG_MSG__INIT;
+#endif
         struct timespec   now;
         ssize_t           len;
 
@@ -161,28 +169,24 @@ static ssize_t enroll_pack(uint8_t ** buf)
         msg.t_sec      = now.tv_sec;
         msg.has_t_nsec = true;
         msg.t_nsec     = now.tv_nsec;
-        msg.conf       = &config;
 
-        config.ipcp_type          = enroll.conf.type;
+        config.ipcp_type           = enroll.conf.type;
 #ifdef BUILD_IPCP_UNICAST
-        config.has_addr_size      = true;
-        config.addr_size          = enroll.conf.addr_size;
-        config.has_eid_size       = true;
-        config.eid_size           = enroll.conf.eid_size;
-        config.has_max_ttl        = true;
-        config.max_ttl            = enroll.conf.max_ttl;
-        config.has_addr_auth_type = true;
-        config.addr_auth_type     = enroll.conf.addr_auth_type;
-        config.has_routing_type   = true;
-        config.routing_type       = enroll.conf.routing_type;
-        config.has_cong_avoid     = true;
-        config.cong_avoid         = enroll.conf.cong_avoid;
+        dt_cfg_msg.addr_size       = enroll.conf.unicast.dt.addr_size;
+        dt_cfg_msg.eid_size        = enroll.conf.unicast.dt.eid_size;
+        dt_cfg_msg.max_ttl         = enroll.conf.unicast.dt.max_ttl;
+        dt_cfg_msg.routing_type    = enroll.conf.unicast.dt.routing_type;
+        uni_cfg_msg.dt             = &dt_cfg_msg;
+        uni_cfg_msg.addr_auth_type = enroll.conf.unicast.addr_auth_type;
+        uni_cfg_msg.cong_avoid     = enroll.conf.unicast.cong_avoid;
+        config.unicast             = &uni_cfg_msg;
 #endif
-        config.layer_info         = &layer_info;
-
         layer_info.layer_name     = (char *) enroll.conf.layer_info.layer_name;
         layer_info.dir_hash_algo  = enroll.conf.layer_info.dir_hash_algo;
 
+        config.layer_info = &layer_info;
+        msg.conf          = &config;
+
         len = enroll_msg__get_packed_size(&msg);
 
         *buf = malloc(len);
diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c
index 582351f8..6e0cb179 100644
--- a/src/ipcpd/eth/eth.c
+++ b/src/ipcpd/eth/eth.c
@@ -1281,31 +1281,27 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
         assert(conf->type == THIS_TYPE);
 
         ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo;
-        ipcpi.layer_name = strdup(conf->layer_info.layer_name);
-        if (ipcpi.layer_name == NULL) {
-                log_err("Failed to set layer name");
-                return -ENOMEM;
-        }
+        strcpy(ipcpi.layer_name, conf->layer_info.layer_name);
 
-        if (conf->dev == NULL) {
+        if (conf->eth.dev == NULL) {
                 log_err("Device name is NULL.");
                 return -1;
         }
 
-        if (strlen(conf->dev) >= IFNAMSIZ) {
-                log_err("Invalid device name: %s.", conf->dev);
+        if (strlen(conf->eth.dev) >= IFNAMSIZ) {
+                log_err("Invalid device name: %s.", conf->eth.dev);
                 return -1;
         }
 
         memset(&ifr, 0, sizeof(ifr));
-        strcpy(ifr.ifr_name, conf->dev);
+        strcpy(ifr.ifr_name, conf->eth.dev);
 
 #ifdef BUILD_ETH_DIX
-        if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF) {
+        if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) {
                 log_err("Invalid Ethertype.");
                 return -1;
         }
-        eth_data.ethertype = htons(conf->ethertype);
+        eth_data.ethertype = htons(conf->eth.ethertype);
 #endif
 
 #if defined(__FreeBSD__) || defined(__APPLE__)
@@ -1315,9 +1311,9 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
         }
 
         for (ifa = ifaddr, idx = 0; ifa != NULL; ifa = ifa->ifa_next, ++idx) {
-                if (strcmp(ifa->ifa_name, conf->dev))
+                if (strcmp(ifa->ifa_name, conf->eth.dev))
                         continue;
-                log_dbg("Interface %s found.", conf->dev);
+                log_dbg("Interface %s found.", conf->eth.dev);
 
     #if defined(HAVE_NETMAP) || defined(HAVE_BPF)
                 memcpy(eth_data.hw_addr,
@@ -1352,7 +1348,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
         log_dbg("Device MTU is %d.", ifr.ifr_mtu);
 
         eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr.ifr_mtu);
-        if (memcmp(conf->dev, "lo", 2) == 0 && eth_data.mtu > IPCP_ETH_LO_MTU) {
+        if (memcmp(conf->eth.dev, "lo", 2) == 0 &&
+                   eth_data.mtu > IPCP_ETH_LO_MTU) {
                 log_dbg("Using loopback interface. MTU restricted to %d.",
                          IPCP_ETH_LO_MTU);
                 eth_data.mtu = IPCP_ETH_LO_MTU;
@@ -1376,7 +1373,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
 
         close(skfd);
 
-        idx = if_nametoindex(conf->dev);
+        idx = if_nametoindex(conf->eth.dev);
         if (idx == 0) {
                 log_err("Failed to retrieve interface index.");
                 return -1;
@@ -1386,7 +1383,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
 
 #if defined(HAVE_NETMAP)
         strcpy(ifn, "netmap:");
-        strcat(ifn, conf->dev);
+        strcat(ifn, conf->eth.dev);
 
         eth_data.nmd = nm_open(ifn, NULL, 0, NULL);
         if (eth_data.nmd == NULL) {
@@ -1526,7 +1523,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
 
 #if defined(BUILD_ETH_DIX)
         log_dbg("Bootstrapped IPCP over DIX Ethernet with pid %d "
-                "and Ethertype 0x%X.", getpid(), conf->ethertype);
+                "and Ethertype 0x%X.", getpid(), conf->eth.ethertype);
 #elif defined(BUILD_ETH_LLC)
         log_dbg("Bootstrapped IPCP over Ethernet with LLC with pid %d.",
                 getpid());
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c
index de68f2f2..1e777637 100644
--- a/src/ipcpd/ipcp.c
+++ b/src/ipcpd/ipcp.c
@@ -261,23 +261,329 @@ static void free_msg(void * o)
         ipcp_msg__free_unpacked((ipcp_msg_t *) o, NULL);
 }
 
+
+static void handle_bootstrap(ipcp_config_msg_t * conf_msg,
+                             layer_info_msg_t *  layer_info_msg,
+                             ipcp_msg_t *        ret_msg)
+{
+        struct ipcp_config conf;
+        enum ipcp_type     ipcp_type;
+        uni_config_msg_t * uni_cfg_msg;
+
+        if (ipcpi.ops->ipcp_bootstrap == NULL) {
+                log_err("Bootstrap unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        if (ipcp_get_state() != IPCP_INIT) {
+                log_err("IPCP in wrong state.");
+                ret_msg->result = -EIPCPSTATE;
+                return;
+        }
+
+        conf.type = conf_msg->ipcp_type;
+
+        strcpy(conf.layer_info.layer_name, conf_msg->layer_info->layer_name);
+
+        ipcp_type = conf_msg->ipcp_type;
+
+        switch(ipcp_type) {
+        case IPCP_LOCAL:
+                break;
+        case IPCP_UNICAST:
+                uni_cfg_msg = conf_msg->unicast;
+
+                conf.unicast.dt.addr_size    = uni_cfg_msg->dt->addr_size;
+                conf.unicast.dt.eid_size     = uni_cfg_msg->dt->eid_size;
+                conf.unicast.dt.max_ttl      = uni_cfg_msg->dt->max_ttl;
+                conf.unicast.dt.routing_type = uni_cfg_msg->dt->routing_type;
+                conf.unicast.addr_auth_type  = uni_cfg_msg->addr_auth_type;
+                conf.unicast.cong_avoid      = uni_cfg_msg->cong_avoid;
+                break;
+        case IPCP_ETH_DIX:
+                conf.eth.ethertype = conf_msg->eth->ethertype;
+                /* FALLTHRU */
+        case IPCP_ETH_LLC:
+                conf.eth.dev = conf_msg->eth->dev;
+                break;
+        case IPCP_UDP:
+                conf.udp.ip_addr  = conf_msg->udp->ip_addr;
+                conf.udp.dns_addr = conf_msg->udp->dns_addr;
+                conf.udp.port     = conf_msg->udp->port;
+                conf.layer_info.dir_hash_algo = HASH_MD5;
+                break;
+        case IPCP_BROADCAST:
+                conf.layer_info.dir_hash_algo = HASH_SHA3_256;
+                break;
+        default:
+                log_err("Unknown IPCP type: %d.", conf_msg->ipcp_type);
+                ret_msg->result = -EIPCP;
+                return;
+        }
+
+        /* UDP and broadcast use fixed hash algorithm. */
+        if (ipcp_type != IPCP_UDP && ipcp_type != IPCP_BROADCAST) {
+                switch(conf_msg->layer_info->dir_hash_algo) {
+                case DIR_HASH_SHA3_224:
+                        conf.layer_info.dir_hash_algo = HASH_SHA3_224;
+                        break;
+                case DIR_HASH_SHA3_256:
+                        conf.layer_info.dir_hash_algo = HASH_SHA3_256;
+                        break;
+                case DIR_HASH_SHA3_384:
+                        conf.layer_info.dir_hash_algo = HASH_SHA3_384;
+                        break;
+                case DIR_HASH_SHA3_512:
+                        conf.layer_info.dir_hash_algo = HASH_SHA3_512;
+                        break;
+                default:
+                        assert(false);
+                }
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_bootstrap(&conf);
+        if (ret_msg->result == 0) {
+                layer_info_msg->layer_name = strdup(conf.layer_info.layer_name);
+                layer_info_msg->dir_hash_algo = conf.layer_info.dir_hash_algo;
+                ret_msg->layer_info           = layer_info_msg;
+        }
+}
+
+static void handle_enroll(const char *       dst,
+                          layer_info_msg_t * layer_info_msg,
+                          ipcp_msg_t *       ret_msg)
+{
+        struct layer_info info;
+
+        if (ipcpi.ops->ipcp_enroll == NULL) {
+                log_err("Enroll unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        if (ipcp_get_state() != IPCP_INIT) {
+                log_err("IPCP in wrong state.");
+                ret_msg->result = -EIPCPSTATE;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_enroll(dst, &info);
+        if (ret_msg->result == 0) {
+                layer_info_msg->layer_name = strdup(info.layer_name);
+                layer_info_msg->dir_hash_algo = info.dir_hash_algo;
+                ret_msg->layer_info           = layer_info_msg;
+
+        }
+}
+
+static void handle_connect(const char * dst,
+                           const char * comp,
+                           qosspec_t    qs,
+                           ipcp_msg_t * ret_msg)
+{
+        if (ipcpi.ops->ipcp_connect == NULL) {
+                log_err("Connect unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_connect(dst, comp, qs);
+}
+
+static void handle_disconnect(const char * dst,
+                              const char * comp,
+                              ipcp_msg_t * ret_msg)
+{
+        if (ipcpi.ops->ipcp_disconnect == NULL) {
+                log_err("Disconnect unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_disconnect(dst, comp);
+}
+
+static void handle_reg(const uint8_t * hash,
+                       ipcp_msg_t *    ret_msg)
+{
+
+        if (ipcpi.ops->ipcp_reg == NULL) {
+                log_err("Registration unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_reg(hash);
+}
+
+static void handle_unreg(const uint8_t * hash,
+                         ipcp_msg_t *    ret_msg)
+{
+        if (ipcpi.ops->ipcp_unreg == NULL) {
+                log_err("Unregistration unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_unreg(hash);
+}
+
+static void handle_query(const uint8_t * hash,
+                         ipcp_msg_t * ret_msg)
+{
+        if (ipcpi.ops->ipcp_query == NULL) {
+                log_err("Directory query unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        if (ipcp_get_state() != IPCP_OPERATIONAL) {
+                log_err("IPCP in wrong state.");
+                ret_msg->result = -EIPCPSTATE;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_query(hash);
+}
+
+static void handle_flow_alloc(pid_t        pid,
+                              int          flow_id,
+                              uint8_t *    dst,
+                              qosspec_t    qs,
+                              void *       data,
+                              size_t       len,
+                              ipcp_msg_t * ret_msg)
+{
+        int fd;
+
+        if (ipcpi.ops->ipcp_flow_alloc == NULL) {
+                log_err("Flow allocation unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        if (ipcp_get_state() != IPCP_OPERATIONAL) {
+                log_err("IPCP in wrong state.");
+                ret_msg->result = -EIPCPSTATE;
+                return;
+        }
+
+        fd = np1_flow_alloc(pid, flow_id);
+        if (fd < 0) {
+                log_err("Failed allocating fd on flow_id %d.", flow_id);
+                ret_msg->result = -EFLOWDOWN;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_flow_alloc(fd, dst, qs, data, len);
+}
+
+
+static void handle_flow_join(pid_t           pid,
+                             int             flow_id,
+                             const uint8_t * dst,
+                             qosspec_t       qs,
+                             ipcp_msg_t *    ret_msg)
+{
+        int fd;
+
+        if (ipcpi.ops->ipcp_flow_join == NULL) {
+                log_err("Broadcast unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        if (ipcp_get_state() != IPCP_OPERATIONAL) {
+                log_err("IPCP in wrong state.");
+                ret_msg->result = -EIPCPSTATE;
+                return;
+        }
+
+        fd = np1_flow_alloc(pid, flow_id);
+        if (fd < 0) {
+                log_err("Failed allocating fd on flow_id %d.", flow_id);
+                ret_msg->result = -1;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_flow_join(fd, dst, qs);
+}
+
+static void handle_flow_alloc_resp(int          resp,
+                                   int          flow_id,
+                                   const void * data,
+                                   size_t       len,
+                                   ipcp_msg_t * ret_msg)
+{
+        int fd = -1;
+
+        if (ipcpi.ops->ipcp_flow_alloc_resp == NULL) {
+                log_err("Flow_alloc_resp unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        if (ipcp_get_state() != IPCP_OPERATIONAL) {
+                log_err("IPCP in wrong state.");
+                ret_msg->result = -EIPCPSTATE;
+                return;
+        }
+
+        if (resp == 0) {
+                fd = np1_flow_resp(flow_id);
+                if (fd < 0) {
+                        log_warn("Flow_id %d is not known.", flow_id);
+                        ret_msg->result = -1;
+                        return;
+                }
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_flow_alloc_resp(fd, resp, data, len);
+}
+
+static void handle_flow_dealloc(int          flow_id,
+                                int          timeo_sec,
+                                ipcp_msg_t * ret_msg)
+{
+        int fd;
+
+        if (ipcpi.ops->ipcp_flow_dealloc == NULL) {
+                log_err("Flow deallocation unsupported.");
+                ret_msg->result = -ENOTSUP;
+                return;
+        }
+
+        if (ipcp_get_state() != IPCP_OPERATIONAL) {
+                log_err("IPCP in wrong state.");
+                ret_msg->result = -EIPCPSTATE;
+                return;
+        }
+
+        fd = np1_flow_dealloc(flow_id, timeo_sec);
+        if (fd < 0) {
+                log_warn("Could not deallocate flow_id %d.", flow_id);
+                ret_msg->result = -1;
+                return;
+        }
+
+        ret_msg->result = ipcpi.ops->ipcp_flow_dealloc(fd);
+}
+
+
 static void * mainloop(void * o)
 {
         int                 sfd;
         buffer_t            buffer;
-        struct ipcp_config  conf;
-        struct layer_info   info;
-        ipcp_config_msg_t * conf_msg;
         ipcp_msg_t *        msg;
 
         (void) o;
 
         while (true) {
-                ipcp_msg_t          ret_msg    = IPCP_MSG__INIT;
-                layer_info_msg_t    layer_info = LAYER_INFO_MSG__INIT;
-                int                 fd         = -1;
-                struct cmd *        cmd;
-                qosspec_t           qs;
+                ipcp_msg_t       ret_msg        = IPCP_MSG__INIT;
+                layer_info_msg_t layer_info_msg = LAYER_INFO_MSG__INIT;
+                qosspec_t        qs;
+                struct cmd *     cmd;
 
                 ret_msg.code = IPCP_MSG_CODE__IPCP_REPLY;
 
@@ -308,327 +614,68 @@ static void * mainloop(void * o)
                 pthread_cleanup_push(__cleanup_close_ptr, &sfd);
                 pthread_cleanup_push(free_msg, msg);
 
+                ret_msg.has_result = true;
+
                 switch (msg->code) {
                 case IPCP_MSG_CODE__IPCP_BOOTSTRAP:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_bootstrap == NULL) {
-                                log_err("Bootstrap unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
-                        if (ipcp_get_state() != IPCP_INIT) {
-                                log_err("IPCP in wrong state.");
-                                ret_msg.result = -EIPCPSTATE;
-                                break;
-                        }
-
-                        conf_msg = msg->conf;
-                        conf.type = conf_msg->ipcp_type;
-                        strcpy(conf.layer_info.layer_name,
-                               conf_msg->layer_info->layer_name);
-
-                        switch(conf_msg->ipcp_type) {
-                        case IPCP_LOCAL:
-                                break;
-                        case IPCP_UNICAST:
-                                conf.addr_size      = conf_msg->addr_size;
-                                conf.eid_size       = conf_msg->eid_size;
-                                conf.max_ttl        = conf_msg->max_ttl;
-                                conf.addr_auth_type = conf_msg->addr_auth_type;
-                                conf.routing_type   = conf_msg->routing_type;
-                                conf.cong_avoid     = conf_msg->cong_avoid;
-                                break;
-                        case IPCP_ETH_DIX:
-                                conf.ethertype = conf_msg->ethertype;
-                                /* FALLTHRU */
-                        case IPCP_ETH_LLC:
-                                conf.dev = conf_msg->dev;
-                                break;
-                        case IPCP_UDP:
-                                conf.ip_addr  = conf_msg->ip_addr;
-                                conf.dns_addr = conf_msg->dns_addr;
-                                conf.port     = conf_msg->port;
-                                conf.layer_info.dir_hash_algo = HASH_MD5;
-                                layer_info.dir_hash_algo      = HASH_MD5;
-                                break;
-                        case IPCP_BROADCAST:
-                                conf.layer_info.dir_hash_algo = HASH_SHA3_256;
-                                layer_info.dir_hash_algo      = HASH_SHA3_256;
-                                break;
-                        default:
-                                log_err("Unknown IPCP type: %d.",
-                                        conf_msg->ipcp_type);
-                                ret_msg.result = -EIPCP;
-                                goto exit; /* break from outer switch/case */
-                        }
-
-                        /* UDP and broadcast use fixed hash algorithm. */
-                        if (conf_msg->ipcp_type != IPCP_UDP &&
-                            conf_msg->ipcp_type != IPCP_BROADCAST) {
-                                switch(conf_msg->layer_info->dir_hash_algo) {
-                                case DIR_HASH_SHA3_224:
-                                        conf.layer_info.dir_hash_algo =
-                                                HASH_SHA3_224;
-                                        break;
-                                case DIR_HASH_SHA3_256:
-                                        conf.layer_info.dir_hash_algo =
-                                                HASH_SHA3_256;
-                                        break;
-                                case DIR_HASH_SHA3_384:
-                                        conf.layer_info.dir_hash_algo =
-                                                HASH_SHA3_384;
-                                        break;
-                                case DIR_HASH_SHA3_512:
-                                        conf.layer_info.dir_hash_algo =
-                                                HASH_SHA3_512;
-                                        break;
-                                default:
-                                        assert(false);
-                                }
-
-                                layer_info.dir_hash_algo =
-                                        conf.layer_info.dir_hash_algo;
-                        }
-
-                        ret_msg.result = ipcpi.ops->ipcp_bootstrap(&conf);
-                        if (ret_msg.result == 0) {
-                                ret_msg.layer_info = &layer_info;
-                                layer_info.layer_name =
-                                        conf.layer_info.layer_name;
-                        }
+                        handle_bootstrap(msg->conf, &layer_info_msg, &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_ENROLL:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_enroll == NULL) {
-                                log_err("Enroll unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
-                        if (ipcp_get_state() != IPCP_INIT) {
-                                log_err("IPCP in wrong state.");
-                                ret_msg.result = -EIPCPSTATE;
-                                break;
-                        }
-
-                        ret_msg.result = ipcpi.ops->ipcp_enroll(msg->dst,
-                                                                &info);
-                        if (ret_msg.result == 0) {
-                                ret_msg.layer_info       = &layer_info;
-                                layer_info.dir_hash_algo = info.dir_hash_algo;
-                                layer_info.layer_name    = info.layer_name;
-                        }
+                        handle_enroll(msg->dst, &layer_info_msg, &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_CONNECT:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_connect == NULL) {
-                                log_err("Connect unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
                         qs = msg_to_spec(msg->qosspec);
-                        ret_msg.result = ipcpi.ops->ipcp_connect(msg->dst,
-                                                                 msg->comp,
-                                                                 qs);
+                        handle_connect(msg->dst, msg->comp, qs, &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_DISCONNECT:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_disconnect == NULL) {
-                                log_err("Disconnect unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
-                        ret_msg.result = ipcpi.ops->ipcp_disconnect(msg->dst,
-                                                                    msg->comp);
+                        handle_disconnect(msg->dst, msg->comp, &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_REG:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_reg == NULL) {
-                                log_err("Registration unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
                         assert(msg->hash.len == ipcp_dir_hash_len());
-
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_reg(msg->hash.data);
+                        handle_reg(msg->hash.data, &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_UNREG:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_unreg == NULL) {
-                                log_err("Unregistration unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
                         assert(msg->hash.len == ipcp_dir_hash_len());
-
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_unreg(msg->hash.data);
+                        handle_unreg(msg->hash.data, &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_QUERY:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_query == NULL) {
-                                log_err("Directory query unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
                         assert(msg->hash.len == ipcp_dir_hash_len());
-
-                        if (ipcp_get_state() != IPCP_OPERATIONAL) {
-                                log_err("IPCP in wrong state.");
-                                ret_msg.result = -EIPCPSTATE;
-                                break;
-                        }
-
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_query(msg->hash.data);
+                        handle_query(msg->hash.data, &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_FLOW_ALLOC:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_flow_alloc == NULL) {
-                                log_err("Flow allocation unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
                         assert(msg->hash.len == ipcp_dir_hash_len());
                         assert(msg->pk.len > 0 ? msg->pk.data != NULL
                                                : msg->pk.data == NULL);
-
-                        if (ipcp_get_state() != IPCP_OPERATIONAL) {
-                                log_err("IPCP in wrong state.");
-                                ret_msg.result = -EIPCPSTATE;
-                                break;
-                        }
-
-                        fd = np1_flow_alloc(msg->pid,
-                                            msg->flow_id);
-                        if (fd < 0) {
-                                log_err("Failed allocating fd on flow_id %d.",
-                                        msg->flow_id);
-                                ret_msg.result = -1;
-                                break;
-                        }
-
                         qs = msg_to_spec(msg->qosspec);
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_flow_alloc(fd,
-                                                           msg->hash.data,
-                                                           qs,
-                                                           msg->pk.data,
-                                                           msg->pk.len);
+                        handle_flow_alloc(msg->pid, msg->flow_id,
+                                          msg->hash.data, qs,
+                                          msg->pk.data, msg->pk.len,
+                                          &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_FLOW_JOIN:
-                        ret_msg.has_result = true;
-
-                        if (ipcpi.ops->ipcp_flow_join == NULL) {
-                                log_err("Broadcast unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
                         assert(msg->hash.len == ipcp_dir_hash_len());
-
-                        if (ipcp_get_state() != IPCP_OPERATIONAL) {
-                                log_err("IPCP in wrong state.");
-                                ret_msg.result = -EIPCPSTATE;
-                                break;
-                        }
-
-                        fd = np1_flow_alloc(msg->pid,
-                                            msg->flow_id);
-                        if (fd < 0) {
-                                log_err("Failed allocating fd on flow_id %d.",
-                                        msg->flow_id);
-                                ret_msg.result = -1;
-                                break;
-                        }
-
                         qs = msg_to_spec(msg->qosspec);
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_flow_join(fd,
-                                                          msg->hash.data,
-                                                          qs);
+                        handle_flow_join(msg->pid, msg->flow_id,
+                                         msg->hash.data, qs, &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP:
-                        ret_msg.has_result = true;
-                        if (ipcpi.ops->ipcp_flow_alloc_resp == NULL) {
-                                log_err("Flow_alloc_resp unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
-                        if (ipcp_get_state() != IPCP_OPERATIONAL) {
-                                log_err("IPCP in wrong state.");
-                                ret_msg.result = -EIPCPSTATE;
-                                break;
-                        }
-
-                        if (!msg->response) {
-                                fd = np1_flow_resp(msg->flow_id);
-                                if (fd < 0) {
-                                        log_warn("Port_id %d is not known.",
-                                                 msg->flow_id);
-                                        ret_msg.result = -1;
-                                        break;
-                                }
-                        }
-
                         assert(msg->pk.len > 0 ? msg->pk.data != NULL
-                               : msg->pk.data == NULL);
+                                               : msg->pk.data == NULL);
 
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_flow_alloc_resp(fd,
-                                                                msg->response,
-                                                                msg->pk.data,
-                                                                msg->pk.len);
+                        handle_flow_alloc_resp(msg->response, msg->flow_id,
+                                               msg->pk.data, msg->pk.len,
+                                               &ret_msg);
                         break;
                 case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
-                        ret_msg.has_result = true;
-                        if (ipcpi.ops->ipcp_flow_dealloc == NULL) {
-                                log_err("Flow deallocation unsupported.");
-                                ret_msg.result = -ENOTSUP;
-                                break;
-                        }
-
-                        if (ipcp_get_state() != IPCP_OPERATIONAL) {
-                                log_err("IPCP in wrong state.");
-                                ret_msg.result = -EIPCPSTATE;
-                                break;
-                        }
-
-                        fd = np1_flow_dealloc(msg->flow_id, msg->timeo_sec);
-                        if (fd < 0) {
-                                log_warn("Could not deallocate flow_id %d.",
-                                        msg->flow_id);
-                                ret_msg.result = -1;
-                                break;
-                        }
-
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_flow_dealloc(fd);
+                        handle_flow_dealloc(msg->flow_id, msg->timeo_sec,
+                                            &ret_msg);
                         break;
                 default:
-                        ret_msg.has_result = true;
                         ret_msg.result     = -1;
                         log_err("Unknown message code: %d.", msg->code);
                         break;
                 }
-        exit:
+
                 pthread_cleanup_pop(true);
                 pthread_cleanup_pop(false);
 
@@ -650,12 +697,16 @@ static void * mainloop(void * o)
 
                 ipcp_msg__pack(&ret_msg, buffer.data);
 
+                if (ret_msg.layer_info != NULL)
+                        free(ret_msg.layer_info->layer_name);
+
                 pthread_cleanup_push(__cleanup_close_ptr, &sfd);
+                pthread_cleanup_push(free, buffer.data)
 
                 if (write(sfd, buffer.data, buffer.len) == -1)
                         log_warn("Failed to send reply message");
 
-                free(buffer.data);
+                pthread_cleanup_pop(true);
                 pthread_cleanup_pop(true);
 
                 tpm_inc(ipcpi.tpm);
diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h
index 37d5b972..9e7a7223 100644
--- a/src/ipcpd/ipcp.h
+++ b/src/ipcpd/ipcp.h
@@ -85,7 +85,7 @@ extern struct ipcp {
         char *             name;
 
         enum ipcp_type     type;
-        char *             layer_name;
+        char               layer_name[LAYER_NAME_SIZE + 1];
 
         uint64_t           dt_addr;
 
diff --git a/src/ipcpd/local/main.c b/src/ipcpd/local/main.c
index c1e95d23..f43d4713 100644
--- a/src/ipcpd/local/main.c
+++ b/src/ipcpd/local/main.c
@@ -145,11 +145,7 @@ static int ipcp_local_bootstrap(const struct ipcp_config * conf)
         assert(conf->type == THIS_TYPE);
 
         ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo;
-        ipcpi.layer_name = strdup(conf->layer_info.layer_name);
-        if (ipcpi.layer_name == NULL) {
-                log_err("Failed to set layer name");
-                return -ENOMEM;
-        }
+        strcpy(ipcpi.layer_name,conf->layer_info.layer_name);
 
         ipcp_set_state(IPCP_OPERATIONAL);
 
diff --git a/src/ipcpd/udp/main.c b/src/ipcpd/udp/main.c
index fe25e17e..1a7725c1 100644
--- a/src/ipcpd/udp/main.c
+++ b/src/ipcpd/udp/main.c
@@ -591,6 +591,12 @@ static void * ipcp_udp_packet_writer(void * o)
         return (void *) 1;
 }
 
+static const char * inet4_ntop(const void * addr,
+                         char *       buf)
+{
+        return inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN);
+}
+
 static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
 {
         char ipstr[INET_ADDRSTRLEN];
@@ -602,21 +608,15 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
         assert(conf->type == THIS_TYPE);
 
         ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo;
-        ipcpi.layer_name = strdup(conf->layer_info.layer_name);
-        if (ipcpi.layer_name == NULL) {
-                log_err("Failed to set layer name");
-                return -ENOMEM;
-        }
+        strcpy(ipcpi.layer_name, conf->layer_info.layer_name);
 
-        if (inet_ntop(AF_INET, &conf->ip_addr, ipstr, INET_ADDRSTRLEN)
-            == NULL) {
+        if (inet4_ntop(&conf->udp.ip_addr, ipstr) == NULL) {
                 log_err("Failed to convert IP address");
                 return -1;
         }
 
-        if (conf->dns_addr != 0) {
-                if (inet_ntop(AF_INET, &conf->dns_addr, dnsstr, INET_ADDRSTRLEN)
-                    == NULL) {
+        if (conf->udp.dns_addr != 0) {
+                if (inet4_ntop(&conf->udp.dns_addr, dnsstr) == NULL) {
                         log_err("Failed to convert DNS address");
                         return -1;
                 }
@@ -636,15 +636,15 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
 
         memset((char *) &udp_data.s_saddr, 0, sizeof(udp_data.s_saddr));
         udp_data.s_saddr.sin_family      = AF_INET;
-        udp_data.s_saddr.sin_addr.s_addr = conf->ip_addr;
-        udp_data.s_saddr.sin_port        = htons(conf->port);
+        udp_data.s_saddr.sin_addr.s_addr = conf->udp.ip_addr;
+        udp_data.s_saddr.sin_port        = htons(conf->udp.port);
 
         if (bind(udp_data.s_fd, SADDR, SADDR_SIZE) < 0) {
                 log_err("Couldn't bind to %s.", ipstr);
                 goto fail_bind;
         }
 
-        udp_data.dns_addr = conf->dns_addr;
+        udp_data.dns_addr = conf->udp.dns_addr;
 
         ipcp_set_state(IPCP_OPERATIONAL);
 
@@ -670,11 +670,11 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
                 }
         }
 
-        sprintf(portstr, "%d", conf->port);
+        sprintf(portstr, "%d", conf->udp.port);
 
         log_dbg("Bootstrapped IPCP over UDP with pid %d.", getpid());
         log_dbg("Bound to IP address %s.", ipstr);
-        log_dbg("Using port %u.", conf->port);
+        log_dbg("Using port %u.", conf->udp.port);
         log_dbg("DNS server address is %s.", dnsstr);
 
         return 0;
@@ -759,7 +759,7 @@ static uint32_t ddns_resolve(char *   name,
         char *   addr_str = "Address:";
         uint32_t ip_addr  = 0;
 
-        if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN) == NULL)
+        if (inet4_ntop(&dns_addr, dnsstr) == NULL)
                 return 0;
 
         if (pipe(pipe_fd)) {
@@ -855,14 +855,12 @@ static int ipcp_udp_reg(const uint8_t * hash)
         if (dns_addr != 0) {
                 ip_addr = udp_data.s_saddr.sin_addr.s_addr;
 
-                if (inet_ntop(AF_INET, &ip_addr,
-                              ipstr, INET_ADDRSTRLEN) == NULL) {
+                if (inet4_ntop(&ip_addr, ipstr) == NULL) {
                         free(hashstr);
                         return -1;
                 }
 
-                if (inet_ntop(AF_INET, &dns_addr,
-                              dnsstr, INET_ADDRSTRLEN) == NULL) {
+                if (inet4_ntop(&dns_addr, dnsstr) == NULL) {
                         free(hashstr);
                         return -1;
                 }
@@ -908,8 +906,7 @@ static int ipcp_udp_unreg(const uint8_t * hash)
         dns_addr = udp_data.dns_addr;
 
         if (dns_addr != 0) {
-                if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN)
-                    == NULL) {
+                if (inet4_ntop(&dns_addr, dnsstr) == NULL) {
                         free(hashstr);
                         return -1;
                 }
@@ -1002,13 +999,16 @@ static int ipcp_udp_flow_alloc(int             fd,
         assert(dst);
 
         if (!shim_data_dir_has(udp_data.shim_data, dst)) {
-                log_dbg("Could not resolve destination.");
+                log_err("Could not resolve destination.");
                 return -1;
         }
 
         ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst);
 
-        inet_ntop(AF_INET, &ip_addr, ipstr, INET_ADDRSTRLEN);
+        if (inet4_ntop(&ip_addr, ipstr) == NULL) {
+                log_err("Could not convert IP address.");
+                return -1;
+        }
         log_dbg("Destination UDP ipcp resolved at %s.", ipstr);
 
         memset((char *) &r_saddr, 0, sizeof(r_saddr));
diff --git a/src/ipcpd/unicast/dt.c b/src/ipcpd/unicast/dt.c
index 48940a2b..60975aed 100644
--- a/src/ipcpd/unicast/dt.c
+++ b/src/ipcpd/unicast/dt.c
@@ -563,10 +563,7 @@ static void * dt_conn_handle(void * o)
         return 0;
 }
 
-int dt_init(enum pol_routing pr,
-            uint8_t          addr_size,
-            uint8_t          eid_size,
-            uint8_t          max_ttl)
+int dt_init(struct dt_config cfg)
 {
         int              i;
         int              j;
@@ -582,14 +579,14 @@ int dt_init(enum pol_routing pr,
         info.pref_syntax  = PROTO_FIXED;
         info.addr         = ipcpi.dt_addr;
 
-        if (eid_size != 8) { /* only support 64 bits from now */
+        if (cfg.eid_size != 8) { /* only support 64 bits from now */
                 log_warn("Invalid EID size. Only 64 bit is supported.");
-                eid_size = 8;
+                cfg.eid_size = 8;
         }
 
-        dt_pci_info.addr_size = addr_size;
-        dt_pci_info.eid_size  = eid_size;
-        dt_pci_info.max_ttl   = max_ttl;
+        dt_pci_info.addr_size = cfg.addr_size;
+        dt_pci_info.eid_size  = cfg.eid_size;
+        dt_pci_info.max_ttl   = cfg.max_ttl;
 
         dt_pci_info.qc_o      = dt_pci_info.addr_size;
         dt_pci_info.ttl_o     = dt_pci_info.qc_o + QOS_LEN;
@@ -607,7 +604,7 @@ int dt_init(enum pol_routing pr,
                 goto fail_connmgr_comp_init;
         }
 
-        pp = routing_init(pr);
+        pp = routing_init(cfg.routing_type);
         if (pp < 0) {
                 log_err("Failed to init routing.");
                 goto fail_routing;
diff --git a/src/ipcpd/unicast/dt.h b/src/ipcpd/unicast/dt.h
index 5ad8cceb..478c79ea 100644
--- a/src/ipcpd/unicast/dt.h
+++ b/src/ipcpd/unicast/dt.h
@@ -31,11 +31,7 @@
 #define DT_PROTO     "dtp"
 #define INVALID_ADDR 0
 
-int  dt_init(enum pol_routing pr,
-             uint8_t          addr_size,
-             uint8_t          eid_size,
-             uint8_t          max_ttl
-);
+int  dt_init(struct dt_config cfg);
 
 void dt_fini(void);
 
diff --git a/src/ipcpd/unicast/main.c b/src/ipcpd/unicast/main.c
index 4d2ef1f2..1318ec2f 100644
--- a/src/ipcpd/unicast/main.c
+++ b/src/ipcpd/unicast/main.c
@@ -59,18 +59,13 @@ struct ipcp ipcpi;
 
 static int initialize_components(const struct ipcp_config * conf)
 {
-        ipcpi.layer_name = strdup(conf->layer_info.layer_name);
-        if (ipcpi.layer_name == NULL) {
-                log_err("Failed to set layer name.");
-                goto fail_layer_name;
-        }
-
+        strcpy(ipcpi.layer_name, conf->layer_info.layer_name);
         ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo;
 
         assert(ipcp_dir_hash_len() != 0);
 
-        if (addr_auth_init(conf->addr_auth_type,
-                           &conf->addr_size)) {
+        if (addr_auth_init(conf->unicast.addr_auth_type,
+                           &conf->unicast.dt.addr_size)) {
                 log_err("Failed to init address authority.");
                 goto fail_addr_auth;
         }
@@ -83,15 +78,12 @@ static int initialize_components(const struct ipcp_config * conf)
 
         log_dbg("IPCP got address %" PRIu64 ".", ipcpi.dt_addr);
 
-        if (ca_init(conf->cong_avoid)) {
+        if (ca_init(conf->unicast.cong_avoid)) {
                 log_err("Failed to initialize congestion avoidance.");
                 goto fail_ca;
         }
 
-        if (dt_init(conf->routing_type,
-                    conf->addr_size,
-                    conf->eid_size,
-                    conf->max_ttl)) {
+        if (dt_init(conf->unicast.dt)) {
                 log_err("Failed to initialize data transfer component.");
                 goto fail_dt;
         }
@@ -119,8 +111,6 @@ static int initialize_components(const struct ipcp_config * conf)
  fail_ca:
         addr_auth_fini();
  fail_addr_auth:
-        free(ipcpi.layer_name);
- fail_layer_name:
         return -1;
 }
 
@@ -135,8 +125,6 @@ static void finalize_components(void)
         ca_fini();
 
         addr_auth_fini();
-
-        free(ipcpi.layer_name);
 }
 
 static int start_components(void)
diff --git a/src/lib/ipcp_config.proto b/src/lib/ipcp_config.proto
index 812d909b..c6481b09 100644
--- a/src/lib/ipcp_config.proto
+++ b/src/lib/ipcp_config.proto
@@ -27,24 +27,36 @@ message layer_info_msg {
         required uint32 dir_hash_algo =  2;
 }
 
+message dt_config_msg {
+        required uint32 addr_size    = 1;
+        required uint32 eid_size     = 2;
+        required uint32 max_ttl      = 3;
+        required uint32 routing_type = 4;
+}
+
+message uni_config_msg {
+        required dt_config_msg dt      = 1;
+        required uint32 addr_auth_type = 2;
+        required uint32 cong_avoid     = 3;
+}
+
+message eth_config_msg {
+        required string dev       = 1;
+        optional uint32 ethertype = 2;
+}
+
+message udp_config_msg {
+        required uint32 ip_addr  = 1;
+        required uint32 port     = 2;
+        required uint32 dns_addr = 3; /* set to 0 if unused */
+}
+
 message ipcp_config_msg {
         required layer_info_msg layer_info =  1;
         required int32 ipcp_type           =  2;
-        // Config for unicast IPCP
-        optional uint32 addr_size          =  3;
-        optional uint32 eid_size           =  4;
-        optional uint32 max_ttl            =  5;
-        optional uint32 addr_auth_type     =  6;
-        optional uint32 routing_type       =  7;
-        optional uint32 cong_avoid         =  8;
-        // Config for UDP
-        optional uint32 ip_addr            =  9;
-        optional uint32 dns_addr           = 10;
-        optional uint32 port               = 11;
-        // Config for the Ethernet
-        optional string dev                = 12;
-        // Config for DIX Ethernet
-        optional uint32 ethertype          = 13;
+        optional uni_config_msg unicast    =  3;
+        optional udp_config_msg udp        =  4;
+        optional eth_config_msg eth        =  5;
 }
 
 enum enroll_code {
diff --git a/src/lib/irm.c b/src/lib/irm.c
index dbc1c556..2a8aa05c 100644
--- a/src/lib/irm.c
+++ b/src/lib/irm.c
@@ -98,11 +98,15 @@ int irm_destroy_ipcp(pid_t pid)
 int irm_bootstrap_ipcp(pid_t                      pid,
                        const struct ipcp_config * conf)
 {
-        irm_msg_t         msg        = IRM_MSG__INIT;
-        ipcp_config_msg_t config     = IPCP_CONFIG_MSG__INIT;
-        layer_info_msg_t  layer_info = LAYER_INFO_MSG__INIT;
-        irm_msg_t *       recv_msg   = NULL;
-        int               ret        = -1;
+        irm_msg_t         msg            = IRM_MSG__INIT;
+        ipcp_config_msg_t cfg_msg        = IPCP_CONFIG_MSG__INIT;
+        layer_info_msg_t  layer_info_msg = LAYER_INFO_MSG__INIT;
+        dt_config_msg_t   dt_cfg_msg     = DT_CONFIG_MSG__INIT;
+        uni_config_msg_t  uni_cfg_msg    = UNI_CONFIG_MSG__INIT;
+        eth_config_msg_t  eth_cfg_msg    = ETH_CONFIG_MSG__INIT;
+        udp_config_msg_t  udp_cfg_msg    = UDP_CONFIG_MSG__INIT;
+        irm_msg_t *       recv_msg       = NULL;
+        int               ret            = -1;
 
         if (pid == -1 || conf == NULL)
                 return -EINVAL;
@@ -111,54 +115,46 @@ int irm_bootstrap_ipcp(pid_t                      pid,
         msg.has_pid = true;
         msg.pid     = pid;
 
-        config.layer_info     = &layer_info;
-        msg.conf              = &config;
-        layer_info.layer_name = (char *) conf->layer_info.layer_name;
-
-        config.ipcp_type = conf->type;
-
-        if (conf->type != IPCP_UDP)
-                layer_info.dir_hash_algo  = conf->layer_info.dir_hash_algo;
+        cfg_msg.ipcp_type = conf->type;
+        layer_info_msg.layer_name = (char *) conf->layer_info.layer_name;
+        layer_info_msg.dir_hash_algo  = conf->layer_info.dir_hash_algo;
 
         switch (conf->type) {
         case IPCP_UNICAST:
-                config.has_addr_size      = true;
-                config.addr_size          = conf->addr_size;
-                config.has_eid_size       = true;
-                config.eid_size           = conf->eid_size;
-                config.has_max_ttl        = true;
-                config.max_ttl            = conf->max_ttl;
-                config.has_addr_auth_type = true;
-                config.addr_auth_type     = conf->addr_auth_type;
-                config.has_routing_type   = true;
-                config.routing_type       = conf->routing_type;
-                config.has_cong_avoid     = true;
-                config.cong_avoid         = conf->cong_avoid;
+                dt_cfg_msg.addr_size       = conf->unicast.dt.addr_size;
+                dt_cfg_msg.eid_size        = conf->unicast.dt.eid_size;
+                dt_cfg_msg.max_ttl         = conf->unicast.dt.max_ttl;
+                dt_cfg_msg.routing_type    = conf->unicast.dt.routing_type;
+                uni_cfg_msg.dt             = &dt_cfg_msg;
+                uni_cfg_msg.addr_auth_type = conf->unicast.addr_auth_type;
+                uni_cfg_msg.cong_avoid     = conf->unicast.cong_avoid;
+                cfg_msg.unicast            = &uni_cfg_msg;
                 break;
         case IPCP_UDP:
-                config.has_ip_addr  = true;
-                config.ip_addr      = conf->ip_addr;
-                config.has_dns_addr = true;
-                config.dns_addr     = conf->dns_addr;
-                config.has_port     = true;
-                config.port         = conf->port;
+                udp_cfg_msg.ip_addr  = conf->udp.ip_addr;
+                udp_cfg_msg.dns_addr = conf->udp.dns_addr;
+                udp_cfg_msg.port     = conf->udp.port;
+                cfg_msg.udp          = &udp_cfg_msg;
                 break;
         case IPCP_LOCAL:
                 /* FALLTHRU */
         case IPCP_BROADCAST:
                 break;
-        case IPCP_ETH_LLC:
-                config.dev = conf->dev;
-                break;
         case IPCP_ETH_DIX:
-                config.dev = conf->dev;
-                config.has_ethertype = true;
-                config.ethertype = conf->ethertype;
+                eth_cfg_msg.has_ethertype = true;
+                eth_cfg_msg.ethertype     = conf->eth.ethertype;
+                /* FALLTHRU */
+        case IPCP_ETH_LLC:
+                eth_cfg_msg.dev = conf->eth.dev;
+                cfg_msg.eth = &eth_cfg_msg;
                 break;
         default:
                 return -EIPCPTYPE;
         }
 
+        cfg_msg.layer_info = &layer_info_msg;
+        msg.conf           = &cfg_msg;
+
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
                 return -EIRMD;
diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c
index 32b3cea3..2e90b82c 100644
--- a/src/tools/irm/irm_ipcp_bootstrap.c
+++ b/src/tools/irm/irm_ipcp_bootstrap.c
@@ -292,6 +292,7 @@ int do_bootstrap_ipcp(int     argc,
                                 printf("Types do not match.\n\n");
                                 goto fail;
                         }
+
                         conf.type = ipcps[i].type;
 
                         if (autobind && (conf.type != IPCP_UNICAST &&
@@ -302,40 +303,36 @@ int do_bootstrap_ipcp(int     argc,
                         }
 
                         if (strlen(layer) > LAYER_NAME_SIZE) {
-                                printf("Layer name too big.\n\n");
+                                printf("Layer name too long.\n\n");
                                 goto fail_usage;
                         }
 
                         strcpy(conf.layer_info.layer_name, layer);
-                        if (conf.type != IPCP_UDP)
-                                conf.layer_info.dir_hash_algo = hash_algo;
+                        conf.layer_info.dir_hash_algo = hash_algo;
 
                         switch (conf.type) {
                         case IPCP_UNICAST:
-                                conf.addr_size      = addr_size;
-                                conf.eid_size       = eid_size;
-                                conf.max_ttl        = max_ttl;
-                                conf.addr_auth_type = addr_auth_type;
-                                conf.routing_type   = routing_type;
-                                conf.cong_avoid     = cong_avoid;
+                                conf.unicast.dt.addr_size    = addr_size;
+                                conf.unicast.dt.eid_size     = eid_size;
+                                conf.unicast.dt.max_ttl      = max_ttl;
+                                conf.unicast.dt.routing_type = routing_type;
+                                conf.unicast.addr_auth_type  = addr_auth_type;
+                                conf.unicast.cong_avoid      = cong_avoid;
                                 break;
                         case IPCP_UDP:
                                 if (ip_addr == 0)
                                         goto fail_usage;
-                                conf.ip_addr  = ip_addr;
-                                conf.dns_addr = dns_addr;
-                                conf.port     = port;
-                                break;
-                        case IPCP_ETH_LLC:
-                                if (dev == NULL)
-                                        goto fail_usage;
-                                conf.dev = dev;
+                                conf.udp.ip_addr  = ip_addr;
+                                conf.udp.dns_addr = dns_addr;
+                                conf.udp.port     = port;
                                 break;
                         case IPCP_ETH_DIX:
+                                conf.eth.ethertype = ethertype;
+                                /* FALLTHRU */
+                        case IPCP_ETH_LLC:
                                 if (dev == NULL)
                                         goto fail_usage;
-                                conf.dev = dev;
-                                conf.ethertype = ethertype;
+                                conf.eth.dev = dev;
                                 break;
                         case IPCP_BROADCAST:
                                 /* FALLTHRU */
-- 
cgit v1.2.3