[PATCH v2] lib: Simplify reg/unreg API

  • From: Dimitri Staessens <dimitri.staessens@xxxxxxxx>
  • To: ouroboros@xxxxxxxxxxxxx
  • Date: Thu, 22 Mar 2018 11:02:15 +0100

The reg/unreg API is simplified to registering and unregisterging a
single name with a single IPCP. The functionality associated with
registering names was moved from the IRMd to the irm tool. The
function to list IPCPs was simplified to return all IPCPs in the
system with their basic properties needed for management.

The above changes led to some needed changes in the irm tool and the
management functions that were depending on the previous behaviour of
list_ipcps.

Command line functionality to list IPCPs in the system is also added
to the irm tool.

Some older code was refactored.

Signed-off-by: Dimitri Staessens <dimitri.staessens@xxxxxxxx>
---
 doc/man/ouroboros.8                 |  15 +-
 include/ouroboros/irm.h             |  28 +-
 include/ouroboros/sockets.h         |   3 +-
 src/ipcpd/ipcp.c                    |  12 +-
 src/irmd/ipcp.c                     |  24 +-
 src/irmd/main.c                     | 768 +++++++++++++++++++-----------------
 src/irmd/proc_table.c               |   2 +-
 src/irmd/prog_table.c               |   4 +-
 src/irmd/registry.c                 |  31 +-
 src/irmd/registry.h                 |   2 -
 src/irmd/utils.c                    |  71 ----
 src/irmd/utils.h                    |   8 -
 src/lib/dev.c                       |   9 +-
 src/lib/ipcpd_messages.proto        |   5 +-
 src/lib/irm.c                       | 135 +++----
 src/lib/irmd_messages.proto         |  40 +-
 src/tools/irm/CMakeLists.txt        |   1 +
 src/tools/irm/irm_bind_ipcp.c       |  27 +-
 src/tools/irm/irm_ipcp.c            |   1 +
 src/tools/irm/irm_ipcp_bootstrap.c  | 202 ++++++----
 src/tools/irm/irm_ipcp_connect.c    |  45 ++-
 src/tools/irm/irm_ipcp_create.c     |   8 +-
 src/tools/irm/irm_ipcp_destroy.c    |  33 +-
 src/tools/irm/irm_ipcp_disconnect.c |  45 ++-
 src/tools/irm/irm_ipcp_enroll.c     |  84 ++--
 src/tools/irm/irm_ipcp_list.c       | 158 ++++++++
 src/tools/irm/irm_ops.h             |   3 +
 src/tools/irm/irm_register.c        |  60 ++-
 src/tools/irm/irm_unbind_ipcp.c     |  32 +-
 src/tools/irm/irm_unregister.c      |  59 ++-
 src/tools/irm/irm_utils.c           |  75 +++-
 src/tools/irm/irm_utils.h           |  43 ++
 32 files changed, 1226 insertions(+), 807 deletions(-)
 create mode 100644 src/tools/irm/irm_ipcp_list.c

diff --git a/doc/man/ouroboros.8 b/doc/man/ouroboros.8
index 063f5e8..95d17a0 100644
--- a/doc/man/ouroboros.8
+++ b/doc/man/ouroboros.8
@@ -272,6 +272,11 @@ disconnects \fIcomponent\fR (\fBdt\fR or \fBmgmt\fR) of a 
normal IPCP
 with name \fIname\fR from that component of the destination IPCP within the
 same layer.
 .RE
+
+\fBirm ipcp list\fR type \fItype\fR name \fIname\fR layer \fIlayer\fR
+.RS 4
+lists IPCPs in the system. You can filter by type, by name or by layer.
+.RE
 .RE
 
 .SH IRM COMMANDS
@@ -329,15 +334,17 @@ not accept future flow allocation requests for \fIname\fR.
 .RE
 
 .PP
-\fBirm reg\fR name \fIname\fR layer \fIlayer\fR [layer \fIlayer\fR ...]
+\fBirm reg\fR name \fIname\fR \fIipcp\fR ipcp [\fIipcp\fR ...]
+layer [layer \fIlayer\fR ...]
 .RS 4
-Register name \fIname\fR in layers \fIlayer\fR.
+Register name \fIname\fR in ipcps \fIipcp\fR ipcp and layers \fIlayer\fR.
 .RE
 
 .PP
-\fBirm unreg\fR name \fIname\fR layer \fIlayer\fR [layer \fIlayer\fR ...]
+\fBirm unreg\fR name \fIname\fR \fIipcp\fR ipcp [\fIipcp\fR ...]
+layer [layer \fIlayer\fR ...]
 .RS 4
-Unregister name \fIname\fR in layers \fIlayer\fR.
+Unregister name \fIname\fR in ipcps \fIipcp\fR ipcp and layers \fIlayer\fR.
 .RE
 
 .SH TERMINOLOGY
diff --git a/include/ouroboros/irm.h b/include/ouroboros/irm.h
index ed0b2f7..fe6d2e9 100644
--- a/include/ouroboros/irm.h
+++ b/include/ouroboros/irm.h
@@ -35,19 +35,27 @@
 /* Name binding options. */
 #define BIND_AUTO   0x01
 
+#define NAME_SIZE 256
+#define LAYER_SIZE LAYER_NAME_SIZE
+
+struct ipcp_info {
+        pid_t          pid;
+        enum ipcp_type type;
+        char           name[NAME_SIZE];
+        char           layer[LAYER_SIZE];;
+};
+
 __BEGIN_DECLS
 
 pid_t   irm_create_ipcp(const char *   name,
-                        enum ipcp_type ipcp_type);
+                        enum ipcp_type type);
 
 int     irm_destroy_ipcp(pid_t pid);
 
-/* pids is an out-parameter */
-ssize_t irm_list_ipcps(const char * name,
-                       pid_t **     pids);
+ssize_t irm_list_ipcps(struct ipcp_info ** ipcps);
 
 int     irm_enroll_ipcp(pid_t        pid,
-                        const char * layer_name);
+                        const char * dst);
 
 int     irm_bootstrap_ipcp(pid_t                      pid,
                            const struct ipcp_config * conf);
@@ -75,13 +83,11 @@ int     irm_bind_process(pid_t        pid,
 int     irm_unbind_process(pid_t        pid,
                            const char * name);
 
-int     irm_reg(const char *  name,
-                char **       layers,
-                size_t        len);
+int     irm_reg(pid_t        pid,
+                const char * name);
 
-int     irm_unreg(const char * name,
-                  char **      layers,
-                  size_t       len);
+int     irm_unreg(pid_t        pid,
+                  const char * name);
 
 __END_DECLS
 
diff --git a/include/ouroboros/sockets.h b/include/ouroboros/sockets.h
index da3e36d..36ea4da 100644
--- a/include/ouroboros/sockets.h
+++ b/include/ouroboros/sockets.h
@@ -31,6 +31,7 @@ typedef LayerInfoMsg layer_info_msg_t;
 
 #include "irmd_messages.pb-c.h"
 typedef IrmMsg irm_msg_t;
+typedef IpcpInfoMsg ipcp_info_msg_t;
 
 #include "ipcpd_messages.pb-c.h"
 typedef IpcpMsg ipcp_msg_t;
@@ -39,7 +40,7 @@ typedef IpcpMsg ipcp_msg_t;
 #define SOCK_PATH_SUFFIX ".sock"
 
 #define IRM_SOCK_PATH SOCK_PATH "irm" SOCK_PATH_SUFFIX
-#define IRM_MSG_BUF_SIZE 256
+#define IRM_MSG_BUF_SIZE 2048
 
 #define IPCP_SOCK_PATH_PREFIX SOCK_PATH "ipcp"
 #define IPCP_MSG_BUF_SIZE IRM_MSG_BUF_SIZE
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c
index b0ce87c..d834997 100644
--- a/src/ipcpd/ipcp.c
+++ b/src/ipcpd/ipcp.c
@@ -312,7 +312,7 @@ static void * mainloop(void * o)
                                 break;
                         }
 
-                        ret_msg.result = ipcpi.ops->ipcp_enroll(msg->dst_name,
+                        ret_msg.result = ipcpi.ops->ipcp_enroll(msg->dst,
                                                                 &info);
                         if (ret_msg.result == 0) {
                                 ret_msg.layer_info       = &layer_info;
@@ -329,9 +329,8 @@ static void * mainloop(void * o)
                                 break;
                         }
 
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_connect(msg->dst_name,
-                                                        msg->comp_name);
+                        ret_msg.result = ipcpi.ops->ipcp_connect(msg->dst,
+                                                                 msg->comp);
                         break;
                 case IPCP_MSG_CODE__IPCP_DISCONNECT:
                         ret_msg.has_result = true;
@@ -342,9 +341,8 @@ static void * mainloop(void * o)
                                 break;
                         }
 
-                        ret_msg.result =
-                                ipcpi.ops->ipcp_disconnect(msg->dst_name,
-                                                           msg->comp_name);
+                        ret_msg.result = ipcpi.ops->ipcp_disconnect(msg->dst,
+                                                                    msg->comp);
                         break;
                 case IPCP_MSG_CODE__IPCP_REG:
                         ret_msg.has_result = true;
diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c
index efb5fbf..49bf13c 100644
--- a/src/irmd/ipcp.c
+++ b/src/irmd/ipcp.c
@@ -253,8 +253,8 @@ int ipcp_enroll(pid_t               pid,
         if (dst == NULL)
                 return -EINVAL;
 
-        msg.code     = IPCP_MSG_CODE__IPCP_ENROLL;
-        msg.dst_name = (char *) dst;
+        msg.code = IPCP_MSG_CODE__IPCP_ENROLL;
+        msg.dst  = (char *) dst;
 
         recv_msg = send_recv_ipcp_msg(pid, &msg);
         if (recv_msg == NULL)
@@ -292,11 +292,11 @@ int ipcp_connect(pid_t        pid,
         ipcp_msg_t * recv_msg = NULL;
         int          ret      = -1;
 
-        msg.code      = IPCP_MSG_CODE__IPCP_CONNECT;
-        msg.dst_name  = (char *) dst;
-        msg.comp_name = (char *) component;
-        msg.has_pid   = true;
-        msg.pid       = pid;
+        msg.code    = IPCP_MSG_CODE__IPCP_CONNECT;
+        msg.dst     = (char *) dst;
+        msg.comp    = (char *) component;
+        msg.has_pid = true;
+        msg.pid     = pid;
 
         recv_msg = send_recv_ipcp_msg(pid, &msg);
         if (recv_msg == NULL)
@@ -321,11 +321,11 @@ int ipcp_disconnect(pid_t        pid,
         ipcp_msg_t * recv_msg = NULL;
         int          ret      = -1;
 
-        msg.code      = IPCP_MSG_CODE__IPCP_DISCONNECT;
-        msg.dst_name  = (char *) dst;
-        msg.comp_name = (char *) component;
-        msg.has_pid   = true;
-        msg.pid       = pid;
+        msg.code    = IPCP_MSG_CODE__IPCP_DISCONNECT;
+        msg.dst     = (char *) dst;
+        msg.comp    = (char *) component;
+        msg.has_pid = true;
+        msg.pid     = pid;
 
         recv_msg = send_recv_ipcp_msg(pid, &msg);
         if (recv_msg == NULL)
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 411df6d..5e80421 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -83,11 +83,11 @@ struct ipcp_entry {
         pid_t            pid;
         enum ipcp_type   type;
         enum hash_algo   dir_hash_algo;
-        char *           layer_name;
+        char *           layer;
 
-        enum init_state  init_state;
-        pthread_cond_t   init_cond;
-        pthread_mutex_t  init_lock;
+        enum init_state  state;
+        pthread_cond_t   cond;
+        pthread_mutex_t  lock;
 };
 
 enum irm_state {
@@ -107,6 +107,7 @@ struct {
         struct list_head     registry;     /* registered names known     */
 
         struct list_head     ipcps;        /* list of ipcps in system    */
+        size_t               n_ipcps;      /* number of ipcps            */
 
         struct list_head     proc_table;   /* processes                  */
         struct list_head     prog_table;   /* programs known             */
@@ -197,47 +198,116 @@ static struct irm_flow * get_irm_flow_n(pid_t n_pid)
         return NULL;
 }
 
-static struct ipcp_entry * ipcp_entry_create(void)
+static struct ipcp_entry * ipcp_entry_create(const char *   name,
+                                             enum ipcp_type type)
 {
-        struct ipcp_entry * e = malloc(sizeof(*e));
+        struct ipcp_entry * e;
+        pthread_condattr_t  cattr;
+
+        e = malloc(sizeof(*e));
         if (e == NULL)
-                return NULL;
+                goto fail_malloc;
+
+        e->layer = NULL;
+        e->type  = type;
+        e->state = IPCP_BOOT;
+        e->name  = strdup(name);
+        if (e->name == NULL)
+                goto fail_name;
+
+        if (pthread_condattr_init(&cattr))
+                goto fail_cattr;
+#ifndef __APPLE__
+        pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
+#endif
+        if (pthread_cond_init(&e->cond, &cattr))
+                goto fail_cond;
+
+        if (pthread_mutex_init(&e->lock, NULL))
+                goto fail_mutex;
 
-        e->name       = NULL;
-        e->layer_name = NULL;
 
         list_head_init(&e->next);
 
+        pthread_condattr_destroy(&cattr);
+
         return e;
+
+ fail_mutex:
+        pthread_cond_destroy(&e->cond);
+ fail_cond:
+        pthread_condattr_destroy(&cattr);
+ fail_cattr:
+        free(e->name);
+ fail_name:
+        free(e);
+ fail_malloc:
+        return NULL;
 }
 
 static void ipcp_entry_destroy(struct ipcp_entry * e)
 {
         assert(e);
 
-        pthread_mutex_lock(&e->init_lock);
+        pthread_mutex_lock(&e->lock);
 
-        while (e->init_state == IPCP_BOOT)
-                pthread_cond_wait(&e->init_cond, &e->init_lock);
+        while (e->state == IPCP_BOOT)
+                pthread_cond_wait(&e->cond, &e->lock);
 
-        pthread_mutex_unlock(&e->init_lock);
+        pthread_mutex_unlock(&e->lock);
 
-        if (e->name != NULL)
-                free(e->name);
+        free(e->name);
+        free(e->layer);
+        free(e);
+}
 
-        if (e->layer_name != NULL)
-                free(e->layer_name);
+static void ipcp_entry_set_state(struct ipcp_entry * e,
+                                 enum init_state     state)
+{
+        pthread_mutex_lock(&e->lock);
+        e->state = state;
+        pthread_cond_broadcast(&e->cond);
+        pthread_mutex_unlock(&e->lock);
+}
 
-        free(e);
+static int ipcp_entry_wait_boot(struct ipcp_entry * e)
+{
+        int             ret = 0;
+        struct timespec dl;
+        struct timespec to = {SOCKET_TIMEOUT / 1000,
+                              (SOCKET_TIMEOUT % 1000) * MILLION};
+
+        clock_gettime(PTHREAD_COND_CLOCK, &dl);
+        ts_add(&dl, &to, &dl);
+
+        pthread_mutex_lock(&e->lock);
+
+        while (e->state == IPCP_BOOT && ret != ETIMEDOUT)
+                ret = pthread_cond_timedwait(&e->cond, &e->lock, &dl);
+
+        if (ret == ETIMEDOUT) {
+                kill(e->pid, SIGTERM);
+                e->state = IPCP_NULL;
+                pthread_cond_signal(&e->cond);
+        }
+
+        if (e->state != IPCP_LIVE) {
+                pthread_mutex_unlock(&e->lock);
+                return -1;
+        }
+
+        pthread_mutex_unlock(&e->lock);
+
+        return 0;
 }
 
 static struct ipcp_entry * get_ipcp_entry_by_pid(pid_t pid)
 {
-        struct list_head * p = NULL;
+        struct list_head * p;
 
         list_for_each(p, &irmd.ipcps) {
                 struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
-                if (pid == e->pid)
+                if (e->pid == pid)
                         return e;
         }
 
@@ -246,7 +316,7 @@ static struct ipcp_entry * get_ipcp_entry_by_pid(pid_t pid)
 
 static struct ipcp_entry * get_ipcp_entry_by_name(const char * name)
 {
-        struct list_head * p = NULL;
+        struct list_head * p;
 
         list_for_each(p, &irmd.ipcps) {
                 struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
@@ -264,15 +334,18 @@ static struct ipcp_entry * get_ipcp_by_dst_name(const 
char * name,
         struct list_head * h;
         uint8_t *          hash;
         pid_t              pid;
+        size_t             len;
 
         pthread_rwlock_rdlock(&irmd.reg_lock);
 
         list_for_each_safe(p, h, &irmd.ipcps) {
                 struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
-                if (e->layer_name == NULL || e->pid == src)
+                if (e->layer == NULL || e->pid == src)
                         continue;
 
-                hash = malloc(IPCP_HASH_LEN(e));
+                len = IPCP_HASH_LEN(e);
+
+                hash = malloc(len);
                 if  (hash == NULL)
                         return NULL;
 
@@ -282,7 +355,7 @@ static struct ipcp_entry * get_ipcp_by_dst_name(const char 
* name,
 
                 pthread_rwlock_unlock(&irmd.reg_lock);
 
-                if (ipcp_query(pid, hash, IPCP_HASH_LEN(e)) == 0) {
+                if (ipcp_query(pid, hash, len) == 0) {
                         free(hash);
                         return e;
                 }
@@ -297,134 +370,89 @@ static struct ipcp_entry * get_ipcp_by_dst_name(const 
char * name,
         return NULL;
 }
 
-static pid_t create_ipcp(char *         name,
-                         enum ipcp_type ipcp_type)
+static pid_t create_ipcp(const char *   name,
+                         enum ipcp_type type)
 {
-        struct pid_el *     ppid  = NULL;
-        struct ipcp_entry * tmp   = NULL;
-        struct list_head *  p     = NULL;
-        struct ipcp_entry * entry = NULL;
-        int                 ret   = 0;
-        pthread_condattr_t  cattr;
-        struct timespec     dl;
-        struct timespec     to = {SOCKET_TIMEOUT / 1000,
-                                  (SOCKET_TIMEOUT % 1000) * MILLION};
-        pid_t               ipcp_pid;
-
-        ppid = malloc(sizeof(*ppid));
-        if (ppid == NULL)
-                return -ENOMEM;
+        struct pid_el *     ppid;
+        struct ipcp_entry * entry;
+        struct list_head *  p;
+        pid_t               pid;
 
-        pthread_rwlock_wrlock(&irmd.reg_lock);
+        pthread_rwlock_rdlock(&irmd.reg_lock);
 
         entry = get_ipcp_entry_by_name(name);
         if (entry != NULL) {
                 pthread_rwlock_unlock(&irmd.reg_lock);
-                free(ppid);
                 log_err("IPCP by that name already exists.");
-                return -1;
-        }
-
-        ppid->pid = ipcp_create(name, ipcp_type);
-        if (ppid->pid == -1) {
-                pthread_rwlock_unlock(&irmd.reg_lock);
-                free(ppid);
-                log_err("Failed to create IPCP.");
-                return -1;
+                return -EPERM;
         }
 
-        tmp = ipcp_entry_create();
-        if (tmp == NULL) {
-                pthread_rwlock_unlock(&irmd.reg_lock);
-                free(ppid);
-                return -1;
-        }
+        pthread_rwlock_unlock(&irmd.reg_lock);
 
-        list_head_init(&tmp->next);
+        ppid = malloc(sizeof(*ppid));
+        if (ppid == NULL)
+                goto fail_ppid;
 
-        tmp->name = strdup(name);
-        if (tmp->name == NULL) {
-                ipcp_entry_destroy(tmp);
-                pthread_rwlock_unlock(&irmd.reg_lock);
-                free(ppid);
-                return -1;
+        entry = ipcp_entry_create(name, type);
+        if (entry == NULL) {
+                log_err("Failed to create IPCP entry.");
+                goto fail_ipcp_entry;
         }
 
-        pthread_condattr_init(&cattr);
-#ifndef __APPLE__
-        pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
-
-        pthread_cond_init(&tmp->init_cond, &cattr);
-
-        pthread_condattr_destroy(&cattr);
+        pid = ipcp_create(name, type);
+        if (pid == -1) {
+                log_err("Failed to create IPCP.");
+                goto fail_ipcp;
+        }
 
-        pthread_mutex_init(&tmp->init_lock, NULL);
+        entry->pid = pid;
 
-        tmp->pid           = ppid->pid;
-        tmp->layer_name    = NULL;
-        tmp->type          = ipcp_type;
-        tmp->init_state    = IPCP_BOOT;
-        tmp->dir_hash_algo = -1;
-        ipcp_pid           = tmp->pid;
+        pthread_rwlock_wrlock(&irmd.reg_lock);
 
         list_for_each(p, &irmd.ipcps) {
-                struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
-                if (e->type > ipcp_type)
+                if (list_entry(p, struct ipcp_entry, next)->type > type)
                         break;
         }
 
-        list_add_tail(&tmp->next, p);
+        list_add_tail(&entry->next, p);
+        ++irmd.n_ipcps;
 
+        ppid->pid = entry->pid;
         list_add(&ppid->next, &irmd.spawned_pids);
 
         pthread_rwlock_unlock(&irmd.reg_lock);
 
-        pthread_mutex_lock(&tmp->init_lock);
-
-        clock_gettime(PTHREAD_COND_CLOCK, &dl);
-        ts_add(&dl, &to, &dl);
-
-        while (tmp->init_state == IPCP_BOOT && ret != -ETIMEDOUT)
-                ret = -pthread_cond_timedwait(&tmp->init_cond,
-                                              &tmp->init_lock,
-                                              &dl);
-
-        if (ret == -ETIMEDOUT) {
-                kill(tmp->pid, SIGKILL);
-                tmp->init_state = IPCP_NULL;
-                pthread_cond_signal(&tmp->init_cond);
-                pthread_mutex_unlock(&tmp->init_lock);
-                log_err("IPCP %d failed to respond.", ipcp_pid);
+        /* IRMd maintainance will clean up if booting fails. */
+        if (ipcp_entry_wait_boot(entry)) {
+                log_err("IPCP %d failed to boot.", pid);
                 return -1;
         }
 
-        pthread_mutex_unlock(&tmp->init_lock);
+        log_info("Created IPCP %d.", pid);
 
-        log_info("Created IPCP %d.", ipcp_pid);
+        return pid;
 
-        return ipcp_pid;
+        ipcp_destroy(pid);
+ fail_ipcp:
+        ipcp_entry_destroy(entry);
+ fail_ipcp_entry:
+        free(ppid);
+ fail_ppid:
+        return -1;
 }
 
 static int create_ipcp_r(pid_t pid,
                          int   result)
 {
-        struct list_head * pos = NULL;
-
-        if (result != 0)
-                return result;
+        struct list_head * p;
 
         pthread_rwlock_rdlock(&irmd.reg_lock);
 
-        list_for_each(pos, &irmd.ipcps) {
-                struct ipcp_entry * e =
-                        list_entry(pos, struct ipcp_entry, next);
-
+        list_for_each(p, &irmd.ipcps) {
+                struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
                 if (e->pid == pid) {
-                        pthread_mutex_lock(&e->init_lock);
-                        e->init_state = IPCP_LIVE;
-                        pthread_cond_broadcast(&e->init_cond);
-                        pthread_mutex_unlock(&e->init_lock);
+                        ipcp_entry_set_state(e, result ? IPCP_NULL : 
IPCP_LIVE);
+                        break;
                 }
         }
 
@@ -435,12 +463,12 @@ static int create_ipcp_r(pid_t pid,
 
 static void clear_spawned_process(pid_t pid)
 {
-        struct list_head * pos = NULL;
-        struct list_head * n   = NULL;
+        struct list_head * p;
+        struct list_head * h;
 
-        list_for_each_safe(pos, n, &(irmd.spawned_pids)) {
-                struct pid_el * a = list_entry(pos, struct pid_el, next);
-                if (pid == a->pid) {
+        list_for_each_safe(p, h, &(irmd.spawned_pids)) {
+                struct pid_el * a = list_entry(p, struct pid_el, next);
+                if (a->pid == pid) {
                         list_del(&a->next);
                         free(a);
                 }
@@ -449,22 +477,20 @@ static void clear_spawned_process(pid_t pid)
 
 static int destroy_ipcp(pid_t pid)
 {
-        struct list_head * pos = NULL;
-        struct list_head * n   = NULL;
+        struct list_head * p;
+        struct list_head * h;
 
         pthread_rwlock_wrlock(&irmd.reg_lock);
 
-        list_for_each_safe(pos, n, &(irmd.ipcps)) {
-                struct ipcp_entry * tmp =
-                        list_entry(pos, struct ipcp_entry, next);
-
-                if (pid == tmp->pid) {
+        list_for_each_safe(p, h, &irmd.ipcps) {
+                struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
+                if (e->pid == pid) {
                         clear_spawned_process(pid);
                         if (ipcp_destroy(pid))
                                 log_err("Could not destroy IPCP.");
-                        list_del(&tmp->next);
-                        ipcp_entry_destroy(tmp);
-
+                        list_del(&e->next);
+                        ipcp_entry_destroy(e);
+                        --irmd.n_ipcps;
                         log_info("Destroyed IPCP %d.", pid);
                 }
         }
@@ -477,7 +503,7 @@ static int destroy_ipcp(pid_t pid)
 static int bootstrap_ipcp(pid_t               pid,
                           ipcp_config_msg_t * conf)
 {
-        struct ipcp_entry * entry = NULL;
+        struct ipcp_entry * entry;
         struct layer_info   info;
 
         pthread_rwlock_wrlock(&irmd.reg_lock);
@@ -501,8 +527,8 @@ static int bootstrap_ipcp(pid_t               pid,
                 return -1;
         }
 
-        entry->layer_name = strdup(info.layer_name);
-        if (entry->layer_name == NULL) {
+        entry->layer = strdup(info.layer_name);
+        if (entry->layer == NULL) {
                 pthread_rwlock_unlock(&irmd.reg_lock);
                 log_warn("Failed to set name of layer.");
                 return -ENOMEM;
@@ -519,7 +545,7 @@ static int bootstrap_ipcp(pid_t               pid,
 }
 
 static int enroll_ipcp(pid_t  pid,
-                       char * dst_name)
+                       char * dst)
 {
         struct ipcp_entry * entry = NULL;
         struct layer_info   info;
@@ -533,7 +559,7 @@ static int enroll_ipcp(pid_t  pid,
                 return -1;
         }
 
-        if (entry->layer_name != NULL) {
+        if (entry->layer != NULL) {
                 pthread_rwlock_unlock(&irmd.reg_lock);
                 log_err("IPCP in wrong state");
                 return -1;
@@ -541,7 +567,7 @@ static int enroll_ipcp(pid_t  pid,
 
         pthread_rwlock_unlock(&irmd.reg_lock);
 
-        if (ipcp_enroll(pid, dst_name, &info) < 0) {
+        if (ipcp_enroll(pid, dst, &info) < 0) {
                 log_err("Could not enroll IPCP %d.", pid);
                 return -1;
         }
@@ -555,8 +581,8 @@ static int enroll_ipcp(pid_t  pid,
                 return -1;
         }
 
-        entry->layer_name = strdup(info.layer_name);
-        if (entry->layer_name == NULL) {
+        entry->layer = strdup(info.layer_name);
+        if (entry->layer == NULL) {
                 pthread_rwlock_unlock(&irmd.reg_lock);
                 log_err("Failed to strdup layer_name.");
                 return -ENOMEM;
@@ -648,13 +674,13 @@ static int bind_program(char *   prog,
                         int      argc,
                         char **  argv)
 {
-        char * progs;
-        char * progn;
-        char ** argv_dup = NULL;
-        int i;
-        char * name_dup = NULL;
-        struct prog_entry * e = NULL;
-        struct reg_entry * re = NULL;
+        char *              progs;
+        char *              progn;
+        char **             argv_dup = NULL;
+        int                 i;
+        char *              name_dup = NULL;
+        struct prog_entry * e        = NULL;
+        struct reg_entry *  re       = NULL;
 
         if (prog == NULL || name == NULL)
                 return -EINVAL;
@@ -662,7 +688,6 @@ static int bind_program(char *   prog,
         pthread_rwlock_wrlock(&irmd.reg_lock);
 
         e = prog_table_get(&irmd.prog_table, path_strip(prog));
-
         if (e == NULL) {
                 progs = strdup(path_strip(prog));
                 if (progs == NULL) {
@@ -704,9 +729,7 @@ static int bind_program(char *   prog,
                         argvfree(argv_dup);
                         return -ENOMEM;
                 }
-
                 prog_table_add(&irmd.prog_table, e);
-
         }
 
         name_dup = strdup(name);
@@ -835,68 +858,78 @@ static int unbind_process(pid_t        pid,
         return 0;
 }
 
-static ssize_t list_ipcps(char *   name,
-                          pid_t ** pids)
+static ssize_t list_ipcps(ipcp_info_msg_t *** ipcps,
+                          size_t *            n_ipcps)
 {
-        struct list_head * pos = NULL;
-        size_t count = 0;
-        int i = 0;
+        struct list_head * p;
+        int                i = 0;
 
         pthread_rwlock_rdlock(&irmd.reg_lock);
 
-        list_for_each(pos, &irmd.ipcps) {
-                struct ipcp_entry * tmp =
-                        list_entry(pos, struct ipcp_entry, next);
-                if (wildcard_match(name, tmp->name) == 0)
-                        count++;
-        }
+        *n_ipcps = irmd.n_ipcps;
 
-        if (count == 0) {
+        if (*n_ipcps == 0) {
                 pthread_rwlock_unlock(&irmd.reg_lock);
                 return 0;
         }
 
-        *pids = malloc(count * sizeof(**pids));
-        if (*pids == NULL) {
+        *ipcps = malloc(irmd.n_ipcps * sizeof(**ipcps));
+        if (*ipcps == NULL) {
                 pthread_rwlock_unlock(&irmd.reg_lock);
+                *n_ipcps = 0;
                 return -1;
         }
 
-        list_for_each(pos, &irmd.ipcps) {
-                struct ipcp_entry * tmp =
-                        list_entry(pos, struct ipcp_entry, next);
-                if (wildcard_match(name, tmp->name) == 0)
-                        (*pids)[i++] = tmp->pid;
-        }
+        list_for_each(p, &irmd.ipcps) {
+                struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
+                (*ipcps)[i] = malloc(sizeof(***ipcps));
+                if ((*ipcps)[i] == NULL)
+                        goto fail_malloc;
+
+                ipcp_info_msg__init((*ipcps)[i]);
+                (*ipcps)[i]->name = strdup(e->name);
+                if ((*ipcps)[i]->name == NULL)
+                        goto fail_mem;
+
+                (*ipcps)[i]->layer = strdup(
+                        e->layer != NULL ? e->layer : "Not enrolled");
+                if ((*ipcps)[i]->layer == NULL)
+                        goto fail_mem;
+
+                (*ipcps)[i]->pid    = e->pid;
+                (*ipcps)[i++]->type = e->type;
+       }
 
         pthread_rwlock_unlock(&irmd.reg_lock);
 
-        return count;
+        return 0;
+
+ fail_mem:
+        while (i > 0) {
+                free((*ipcps)[i]->layer);
+                free((*ipcps)[i]->name);
+                free(*ipcps[--i]);
+        }
+        free(*ipcps);
+        *n_ipcps = 0;
+        return -ENOMEM;
+
+ fail_malloc:
+        while (i > 0)
+                free(*ipcps[--i]);
+        free(*ipcps);
+        *n_ipcps = 0;
+        return -ENOMEM;
 }
 
-static int name_reg(const char *  name,
-                    char **       layers,
-                    size_t        len)
+static int irm_update_name(const char * name)
 {
-        size_t i;
-        int ret = 0;
-        struct list_head * p = NULL;
-
-        assert(name);
-        assert(len);
-        assert(layers);
-        assert(layers[0]);
+        struct list_head * p;
 
         pthread_rwlock_wrlock(&irmd.reg_lock);
 
-        if (list_is_empty(&irmd.ipcps)) {
-                pthread_rwlock_unlock(&irmd.reg_lock);
-                return -1;
-        }
-
         if (!registry_has_name(&irmd.registry, name)) {
-                struct reg_entry * re =
-                        registry_add_name(&irmd.registry, name);
+                struct reg_entry * re = registry_add_name(&irmd.registry, 
name);
                 if (re == NULL) {
                         log_err("Failed creating registry entry for %s.", 
name);
                         pthread_rwlock_unlock(&irmd.reg_lock);
@@ -906,11 +939,11 @@ static int name_reg(const char *  name,
                 /* check the tables for client programs */
                 list_for_each(p, &irmd.proc_table) {
                         struct list_head * q;
-                        struct proc_entry * e =
-                                list_entry(p, struct proc_entry, next);
+                        struct proc_entry * e;
+                        e = list_entry(p, struct proc_entry, next);
                         list_for_each(q, &e->names) {
-                                struct str_el * s =
-                                        list_entry(q, struct str_el, next);
+                                struct str_el * s;
+                                s = list_entry(q, struct str_el, next);
                                 if (!strcmp(s->str, name))
                                         reg_entry_add_pid(re, e->pid);
                         }
@@ -918,145 +951,145 @@ static int name_reg(const char *  name,
 
                 list_for_each(p, &irmd.prog_table) {
                         struct list_head * q;
-                        struct prog_entry * e =
-                                list_entry(p, struct prog_entry, next);
+                        struct prog_entry * e;
+                        e = list_entry(p, struct prog_entry, next);
                         list_for_each(q, &e->names) {
-                                struct str_el * s =
-                                        list_entry(q, struct str_el, next);
+                                struct str_el * s;
+                                s = list_entry(q, struct str_el, next);
                                 if (!strcmp(s->str, name))
                                         reg_entry_add_prog(re, e);
                         }
                 }
         }
 
-        list_for_each(p, &irmd.ipcps) {
-                struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
-                if (e->layer_name == NULL)
-                        continue;
+        pthread_rwlock_unlock(&irmd.reg_lock);
 
-                for (i = 0; i < len; ++i) {
-                        uint8_t * hash;
-                        pid_t     pid;
-                        size_t    len;
+        return 0;
+}
 
-                        if (wildcard_match(layers[i], e->layer_name))
-                                continue;
+static int name_reg(pid_t         pid,
+                    const char *  name)
+{
+        size_t              len;
+        struct ipcp_entry * ipcp;
+        uint8_t *           hash;
+        int                 err;
 
-                        hash = malloc(IPCP_HASH_LEN(e));
-                        if (hash == NULL)
-                                break;
+        assert(name);
 
-                        str_hash(e->dir_hash_algo, hash, name);
+        pthread_rwlock_wrlock(&irmd.reg_lock);
 
-                        pid = e->pid;
-                        len = IPCP_HASH_LEN(e);
+        ipcp = get_ipcp_entry_by_pid(pid);
+        if (ipcp == NULL) {
+                err = -EIPCP;
+                goto fail;
+        }
 
-                        pthread_rwlock_unlock(&irmd.reg_lock);
+        if (ipcp->layer == NULL) {
+                err = -EPERM;
+                goto fail;
+        }
 
-                        if (ipcp_reg(pid, hash, len)) {
-                                log_err("Could not register " HASH_FMT
-                                        " with IPCP %d.",
-                                        HASH_VAL(hash), pid);
-                                pthread_rwlock_wrlock(&irmd.reg_lock);
-                                free(hash);
-                                break;
-                        }
+        len = IPCP_HASH_LEN(ipcp);
 
-                        pthread_rwlock_wrlock(&irmd.reg_lock);
+        hash = malloc(len);
+        if (hash == NULL) {
+                err = -ENOMEM;
+                goto fail;
+        }
 
-                        log_info("Registered %s in %s as " HASH_FMT ".",
-                                 name, e->layer_name, HASH_VAL(hash));
-                        ++ret;
+        str_hash(ipcp->dir_hash_algo, hash, name);
+        pthread_rwlock_unlock(&irmd.reg_lock);
 
-                        free(hash);
-                }
+        if (ipcp_reg(pid, hash, len)) {
+                log_err("Could not register " HASH_FMT " with IPCP %d.",
+                        HASH_VAL(hash), pid);
+                free(hash);
+                return -1;
         }
 
-        pthread_rwlock_unlock(&irmd.reg_lock);
+        irm_update_name(name);
 
-        return (ret > 0 ? 0 : -1);
+        log_info("Registered %s with IPCP %d as " HASH_FMT ".",
+                 name, pid, HASH_VAL(hash));
+
+        free(hash);
+
+        return 0;
+
+fail:
+        pthread_rwlock_unlock(&irmd.reg_lock);
+        return err;
 }
 
-static int name_unreg(const char *  name,
-                      char **       layers,
-                      size_t        len)
+static int name_unreg(pid_t         pid,
+                      const char *  name)
 {
-        size_t i;
-        int ret = 0;
-        struct list_head * pos = NULL;
+        struct ipcp_entry * ipcp;
+        int                 err;
+        uint8_t *           hash;
+        size_t              len;
 
         assert(name);
-        assert(len);
-        assert(layers);
-        assert(layers[0]);
 
         pthread_rwlock_wrlock(&irmd.reg_lock);
 
-        list_for_each(pos, &irmd.ipcps) {
-                struct ipcp_entry * e =
-                        list_entry(pos, struct ipcp_entry, next);
-
-                if (e->layer_name == NULL)
-                        continue;
-
-                for (i = 0; i < len; ++i) {
-                        uint8_t * hash;
-                        pid_t     pid;
-                        size_t    len;
+        ipcp = get_ipcp_entry_by_pid(pid);
+        if (ipcp == NULL) {
+                err = -EIPCP;
+                goto fail;
+        }
 
-                        if (wildcard_match(layers[i], e->layer_name))
-                                continue;
+        if (ipcp->layer == NULL) {
+                err = -EPERM;
+                goto fail;
+        }
 
-                        hash = malloc(IPCP_HASH_LEN(e));
-                        if  (hash == NULL)
-                                break;
+        len = IPCP_HASH_LEN(ipcp);
 
-                        str_hash(e->dir_hash_algo, hash, name);
+        hash = malloc(len);
+        if  (hash == NULL) {
+                err = -ENOMEM;
+                goto fail;
+        }
 
-                        pid = e->pid;
-                        len = IPCP_HASH_LEN(e);
+        str_hash(ipcp->dir_hash_algo, hash, name);
 
-                        pthread_rwlock_unlock(&irmd.reg_lock);
+        pthread_rwlock_unlock(&irmd.reg_lock);
 
-                        if (ipcp_unreg(pid, hash, len)) {
-                                log_err("Could not unregister %s with IPCP 
%d.",
-                                        name, pid);
-                                pthread_rwlock_wrlock(&irmd.reg_lock);
-                                free(hash);
-                                break;
-                        }
+        if (ipcp_unreg(pid, hash, len)) {
+                log_err("Could not unregister %s with IPCP %d.", name, pid);
+                free(hash);
+                return -1;
+        }
 
-                        pthread_rwlock_wrlock(&irmd.reg_lock);
+        log_info("Unregistered %s from %d.", name, pid);
 
-                        log_info("Unregistered %s from %s.",
-                                 name, e->layer_name);
-                        ++ret;
+        free(hash);
 
-                        free(hash);
-                }
-        }
+        return 0;
 
+ fail:
         pthread_rwlock_unlock(&irmd.reg_lock);
-
-        return (ret > 0 ? 0 : -1);
+        return err;
 }
 
 static int proc_announce(pid_t  pid,
                          char * prog)
 {
-        struct proc_entry * e = NULL;
-        struct prog_entry * a = NULL;
-        char * prog_dup;
-        if (prog == NULL)
-                return -EINVAL;
+        struct proc_entry * e;
+        struct prog_entry * a;
+        char *              prog_dup;
+
+        assert(prog);
 
         prog_dup = strdup(prog);
-        if (prog_dup == NULL) {
+        if (prog_dup == NULL)
                 return -ENOMEM;
-        }
 
         e = proc_entry_create(pid, prog_dup);
         if (e == NULL) {
+                free(prog_dup);
                 return -ENOMEM;
         }
 
@@ -1065,7 +1098,6 @@ static int proc_announce(pid_t  pid,
         proc_table_add(&irmd.proc_table, e);
 
         /* Copy listen names from program if it exists. */
-
         a = prog_table_get(&irmd.prog_table, e->prog);
         if (a != NULL) {
                 struct list_head * p;
@@ -1876,17 +1908,24 @@ static void * mainloop(void * o)
         (void) o;
 
         while (true) {
-                irm_msg_t         ret_msg = IRM_MSG__INIT;
+                irm_msg_t       * ret_msg;
                 struct irm_flow * e       = NULL;
-                pid_t *           pids    = NULL;
                 struct timespec * timeo   = NULL;
                 struct timespec   ts      = {0, 0};
                 struct cmd *      cmd;
 
-                ret_msg.code = IRM_MSG_CODE__IRM_REPLY;
+                ret_msg = malloc(sizeof(*ret_msg));
+                if (ret_msg == NULL)
+                        return (void *) -1;
+
+                irm_msg__init(ret_msg);
+
+                ret_msg->code = IRM_MSG_CODE__IRM_REPLY;
+
 
                 pthread_mutex_lock(&irmd.cmd_lock);
 
+                pthread_cleanup_push(free_msg, ret_msg);
                 pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
                                      &irmd.cmd_lock);
 
@@ -1897,6 +1936,7 @@ static void * mainloop(void * o)
                 list_del(&cmd->next);
 
                 pthread_cleanup_pop(true);
+                pthread_cleanup_pop(false);
 
                 msg = irm_msg__unpack(NULL, cmd->len, cmd->cbuf);
                 sfd = cmd->fd;
@@ -1905,6 +1945,7 @@ static void * mainloop(void * o)
 
                 if (msg == NULL) {
                         close(sfd);
+                        irm_msg__free_unpacked(ret_msg, NULL);
                         continue;
                 }
 
@@ -1920,151 +1961,144 @@ static void * mainloop(void * o)
 
                 pthread_cleanup_push(close_ptr, &sfd);
                 pthread_cleanup_push(free_msg, msg);
+                pthread_cleanup_push(free_msg, ret_msg);
 
                 switch (msg->code) {
                 case IRM_MSG_CODE__IRM_CREATE_IPCP:
-                        ret_msg.has_result = true;
-                        ret_msg.result = create_ipcp(msg->dst_name,
-                                                     msg->ipcp_type);
+                        ret_msg->has_result = true;
+                        ret_msg->result = create_ipcp(msg->name, 
msg->ipcp_type);
                         break;
                 case IRM_MSG_CODE__IPCP_CREATE_R:
-                        ret_msg.has_result = true;
-                        ret_msg.result = create_ipcp_r(msg->pid, msg->result);
+                        ret_msg->has_result = true;
+                        ret_msg->result = create_ipcp_r(msg->pid, msg->result);
                         break;
                 case IRM_MSG_CODE__IRM_DESTROY_IPCP:
-                        ret_msg.has_result = true;
-                        ret_msg.result = destroy_ipcp(msg->pid);
+                        ret_msg->has_result = true;
+                        ret_msg->result = destroy_ipcp(msg->pid);
                         break;
                 case IRM_MSG_CODE__IRM_BOOTSTRAP_IPCP:
-                        ret_msg.has_result = true;
-                        ret_msg.result = bootstrap_ipcp(msg->pid, msg->conf);
+                        ret_msg->has_result = true;
+                        ret_msg->result = bootstrap_ipcp(msg->pid, msg->conf);
                         break;
                 case IRM_MSG_CODE__IRM_ENROLL_IPCP:
-                        ret_msg.has_result = true;
-                        ret_msg.result = enroll_ipcp(msg->pid,
-                                                     msg->layer_name[0]);
+                        ret_msg->has_result = true;
+                        ret_msg->result = enroll_ipcp(msg->pid, msg->dst);
                         break;
                 case IRM_MSG_CODE__IRM_CONNECT_IPCP:
-                        ret_msg.has_result = true;
-                        ret_msg.result = connect_ipcp(msg->pid,
-                                                      msg->dst_name,
-                                                      msg->comp_name);
+                        ret_msg->has_result = true;
+                        ret_msg->result = connect_ipcp(msg->pid,
+                                                      msg->dst,
+                                                      msg->comp);
                         break;
                 case IRM_MSG_CODE__IRM_DISCONNECT_IPCP:
-                        ret_msg.has_result = true;
-                        ret_msg.result = disconnect_ipcp(msg->pid,
-                                                         msg->dst_name,
-                                                         msg->comp_name);
+                        ret_msg->has_result = true;
+                        ret_msg->result = disconnect_ipcp(msg->pid,
+                                                          msg->dst,
+                                                          msg->comp);
                         break;
                 case IRM_MSG_CODE__IRM_BIND_PROGRAM:
-                        ret_msg.has_result = true;
-                        ret_msg.result = bind_program(msg->prog_name,
-                                                      msg->dst_name,
-                                                      msg->opts,
-                                                      msg->n_args,
-                                                      msg->args);
+                        ret_msg->has_result = true;
+                        ret_msg->result = bind_program(msg->prog,
+                                                       msg->name,
+                                                       msg->opts,
+                                                       msg->n_args,
+                                                       msg->args);
                         break;
                 case IRM_MSG_CODE__IRM_UNBIND_PROGRAM:
-                        ret_msg.has_result = true;
-                        ret_msg.result = unbind_program(msg->prog_name,
-                                                        msg->dst_name);
+                        ret_msg->has_result = true;
+                        ret_msg->result = unbind_program(msg->prog, msg->name);
                         break;
                 case IRM_MSG_CODE__IRM_PROC_ANNOUNCE:
-                        ret_msg.has_result = true;
-                        ret_msg.result = proc_announce(msg->pid,
-                                                       msg->prog_name);
+                        ret_msg->has_result = true;
+                        ret_msg->result = proc_announce(msg->pid, msg->prog);
                         break;
                 case IRM_MSG_CODE__IRM_BIND_PROCESS:
-                        ret_msg.has_result = true;
-                        ret_msg.result = bind_process(msg->pid, msg->dst_name);
+                        ret_msg->has_result = true;
+                        ret_msg->result = bind_process(msg->pid, msg->name);
                         break;
                 case IRM_MSG_CODE__IRM_UNBIND_PROCESS:
-                        ret_msg.has_result = true;
-                        ret_msg.result = unbind_process(msg->pid,
-                                                        msg->dst_name);
+                        ret_msg->has_result = true;
+                        ret_msg->result = unbind_process(msg->pid, msg->name);
                         break;
                 case IRM_MSG_CODE__IRM_LIST_IPCPS:
-                        ret_msg.has_result = true;
-                        ret_msg.n_pids = list_ipcps(msg->dst_name, &pids);
-                        ret_msg.pids = pids;
+                        ret_msg->has_result = true;
+                        ret_msg->result = list_ipcps(&ret_msg->ipcps,
+                                                     &ret_msg->n_ipcps);
                         break;
                 case IRM_MSG_CODE__IRM_REG:
-                        ret_msg.has_result = true;
-                        ret_msg.result = name_reg(msg->dst_name,
-                                                  msg->layer_name,
-                                                  msg->n_layer_name);
+                        ret_msg->has_result = true;
+                        ret_msg->result = name_reg(msg->pid, msg->name);
                         break;
                 case IRM_MSG_CODE__IRM_UNREG:
-                        ret_msg.has_result = true;
-                        ret_msg.result = name_unreg(msg->dst_name,
-                                                    msg->layer_name,
-                                                    msg->n_layer_name);
+                        ret_msg->has_result = true;
+                        ret_msg->result = name_unreg(msg->pid, msg->name);
                         break;
                 case IRM_MSG_CODE__IRM_FLOW_ACCEPT:
-                        ret_msg.has_result = true;
-                        ret_msg.result = flow_accept(msg->pid, timeo, &e);
-                        if (ret_msg.result == 0) {
-                                ret_msg.has_port_id = true;
-                                ret_msg.port_id     = e->port_id;
-                                ret_msg.has_pid     = true;
-                                ret_msg.pid         = e->n_1_pid;
-                                ret_msg.has_qoscube = true;
-                                ret_msg.qoscube     = e->qc;
+                        ret_msg->has_result = true;
+                        ret_msg->result = flow_accept(msg->pid, timeo, &e);
+                        if (ret_msg->result == 0) {
+                                ret_msg->has_port_id = true;
+                                ret_msg->port_id     = e->port_id;
+                                ret_msg->has_pid     = true;
+                                ret_msg->pid         = e->n_1_pid;
+                                ret_msg->has_qoscube = true;
+                                ret_msg->qoscube     = e->qc;
                         }
                         break;
                 case IRM_MSG_CODE__IRM_FLOW_ALLOC:
-                        ret_msg.has_result = true;
-                        ret_msg.result = flow_alloc(msg->pid, msg->dst_name,
-                                                    msg->qoscube, timeo, &e);
-                        if (ret_msg.result == 0) {
-                                ret_msg.has_port_id = true;
-                                ret_msg.port_id     = e->port_id;
-                                ret_msg.has_pid     = true;
-                                ret_msg.pid         = e->n_1_pid;
+                        ret_msg->has_result = true;
+                        ret_msg->result = flow_alloc(msg->pid, msg->dst,
+                                                     msg->qoscube, timeo, &e);
+                        if (ret_msg->result == 0) {
+                                ret_msg->has_port_id = true;
+                                ret_msg->port_id     = e->port_id;
+                                ret_msg->has_pid     = true;
+                                ret_msg->pid         = e->n_1_pid;
                         }
                         break;
                 case IRM_MSG_CODE__IRM_FLOW_DEALLOC:
-                        ret_msg.has_result = true;
-                        ret_msg.result = flow_dealloc(msg->pid, msg->port_id);
+                        ret_msg->has_result = true;
+                        ret_msg->result = flow_dealloc(msg->pid, msg->port_id);
                         break;
                 case IRM_MSG_CODE__IPCP_FLOW_REQ_ARR:
                         e = flow_req_arr(msg->pid,
                                          msg->hash.data,
                                          msg->qoscube);
-                        ret_msg.has_result = true;
+                        ret_msg->has_result = true;
                         if (e == NULL) {
-                                ret_msg.result = -1;
+                                ret_msg->result = -1;
                                 break;
                         }
-                        ret_msg.has_port_id = true;
-                        ret_msg.port_id     = e->port_id;
-                        ret_msg.has_pid     = true;
-                        ret_msg.pid         = e->n_pid;
+                        ret_msg->has_port_id = true;
+                        ret_msg->port_id     = e->port_id;
+                        ret_msg->has_pid     = true;
+                        ret_msg->pid         = e->n_pid;
                         break;
                 case IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY:
-                        ret_msg.has_result = true;
-                        ret_msg.result = flow_alloc_reply(msg->port_id,
-                                                          msg->response);
+                        ret_msg->has_result = true;
+                        ret_msg->result = flow_alloc_reply(msg->port_id,
+                                                           msg->response);
                         break;
                 default:
                         log_err("Don't know that message code.");
                         break;
                 }
 
+                pthread_cleanup_pop(false);
                 pthread_cleanup_pop(true);
                 pthread_cleanup_pop(false);
 
-                if (ret_msg.result == -EPIPE || !ret_msg.has_result) {
+                if (ret_msg->result == -EPIPE || !ret_msg->has_result) {
+                        irm_msg__free_unpacked(ret_msg, NULL);
                         close(sfd);
                         tpm_inc(irmd.tpm);
                         continue;
                 }
 
-                buffer.len = irm_msg__get_packed_size(&ret_msg);
+                buffer.len = irm_msg__get_packed_size(ret_msg);
                 if (buffer.len == 0) {
                         log_err("Failed to calculate length of reply 
message.");
-                        if (pids != NULL)
-                                free(pids);
+                        irm_msg__free_unpacked(ret_msg, NULL);
                         close(sfd);
                         tpm_inc(irmd.tpm);
                         continue;
@@ -2072,22 +2106,20 @@ static void * mainloop(void * o)
 
                 buffer.data = malloc(buffer.len);
                 if (buffer.data == NULL) {
-                        if (pids != NULL)
-                                free(pids);
+                        irm_msg__free_unpacked(ret_msg, NULL);
                         close(sfd);
                         tpm_inc(irmd.tpm);
                         continue;
                 }
 
-                irm_msg__pack(&ret_msg, buffer.data);
+                irm_msg__pack(ret_msg, buffer.data);
 
-                if (pids != NULL)
-                        free(pids);
+                irm_msg__free_unpacked(ret_msg, NULL);
 
                 pthread_cleanup_push(close_ptr, &sfd);
 
                 if (write(sfd, buffer.data, buffer.len) == -1)
-                        if (ret_msg.result != -EIRMD)
+                        if (ret_msg->result != -EIRMD)
                                 log_warn("Failed to send reply message.");
 
                 free(buffer.data);
diff --git a/src/irmd/proc_table.c b/src/irmd/proc_table.c
index beda2f6..e8d0844 100644
--- a/src/irmd/proc_table.c
+++ b/src/irmd/proc_table.c
@@ -166,7 +166,7 @@ void proc_entry_del_name(struct proc_entry * e,
 
         list_for_each_safe(p, h, &e->names) {
                 struct str_el * s = list_entry(p, struct str_el, next);
-                if (!wildcard_match(name, s->str)) {
+                if (!strcmp(name, s->str)) {
                         list_del(&s->next);
                         if (s->str != NULL)
                                 free(s->str);
diff --git a/src/irmd/prog_table.c b/src/irmd/prog_table.c
index 563e7e1..bd69e15 100644
--- a/src/irmd/prog_table.c
+++ b/src/irmd/prog_table.c
@@ -115,7 +115,7 @@ void prog_entry_del_name(struct prog_entry * e,
 
         list_for_each_safe(p, h, &e->names) {
                 struct str_el * s = list_entry(p, struct str_el, next);
-                if (!wildcard_match(name, s->str)) {
+                if (!strcmp(name, s->str)) {
                         list_del(&s->next);
                         if (s->str != NULL)
                                 free(s->str);
@@ -146,7 +146,7 @@ void prog_table_del(struct list_head * prog_table,
 
         list_for_each_safe(p, h, prog_table) {
                 struct prog_entry * e = list_entry(p, struct prog_entry, next);
-                if (!wildcard_match(prog, e->prog)) {
+                if (!strcmp(prog, e->prog)) {
                         list_del(&e->next);
                         prog_entry_destroy(e);
                 }
diff --git a/src/irmd/registry.c b/src/irmd/registry.c
index 6da3605..145a745 100644
--- a/src/irmd/registry.c
+++ b/src/irmd/registry.c
@@ -44,7 +44,9 @@
 
 static struct reg_entry * reg_entry_create(void)
 {
-        struct reg_entry * e = malloc(sizeof(*e));
+        struct reg_entry * e;
+
+        e = malloc(sizeof(*e));
         if (e == NULL)
                 return NULL;
 
@@ -59,8 +61,8 @@ static int reg_entry_init(struct reg_entry * e,
 {
         pthread_condattr_t cattr;
 
-        if (e == NULL || name == NULL)
-                return -1;
+        assert(e);
+        assert(name);
 
         list_head_init(&e->next);
         list_head_init(&e->reg_progs);
@@ -69,20 +71,29 @@ static int reg_entry_init(struct reg_entry * e,
         e->name = name;
 
         if (pthread_condattr_init(&cattr))
-                return -1;
+                goto fail_cattr;
 
 #ifndef __APPLE__
         pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
 #endif
         if (pthread_cond_init(&e->state_cond, &cattr))
-                return -1;
+                goto fail_cond;
 
         if (pthread_mutex_init(&e->state_lock, NULL))
-                return -1;
+                goto fail_mutex;
+
+        pthread_condattr_destroy(&cattr);
 
         e->state = REG_NAME_IDLE;
 
         return 0;
+
+ fail_mutex:
+        pthread_cond_destroy(&e->state_cond);
+ fail_cond:
+        pthread_condattr_destroy(&cattr);
+ fail_cattr:
+        return -1;
 }
 
 static void cancel_reg_entry_destroy(void * o)
@@ -199,12 +210,12 @@ int reg_entry_add_prog(struct reg_entry *  e,
 void reg_entry_del_prog(struct reg_entry * e,
                         const char *       prog)
 {
-        struct list_head * p = NULL;
-        struct list_head * h = NULL;
+        struct list_head * p;
+        struct list_head * h;
 
         list_for_each_safe(p, h, &e->reg_progs) {
                 struct str_el * e = list_entry(p, struct str_el, next);
-                if (!wildcard_match(prog, e->str)) {
+                if (!strcmp(prog, e->str)) {
                         list_del(&e->next);
                         free(e->str);
                         free(e);
@@ -470,7 +481,7 @@ struct reg_entry * registry_get_entry(struct list_head * 
registry,
 
         list_for_each(p, registry) {
                 struct reg_entry * e = list_entry(p, struct reg_entry, next);
-                if (!wildcard_match(name, e->name))
+                if (!strcmp(name, e->name))
                         return e;
         }
 
diff --git a/src/irmd/registry.h b/src/irmd/registry.h
index c570be3..62d90c3 100644
--- a/src/irmd/registry.h
+++ b/src/irmd/registry.h
@@ -55,8 +55,6 @@ struct reg_entry {
         struct list_head    next;
         char *              name;
 
-        /* layers in which this name is registered */
-        struct list_head    layers;
         /* Programs that can be instantiated by the irmd */
         struct list_head    reg_progs;
         /* Processes that are listening for this name */
diff --git a/src/irmd/utils.c b/src/irmd/utils.c
index a13fa48..c2bda58 100644
--- a/src/irmd/utils.c
+++ b/src/irmd/utils.c
@@ -62,74 +62,3 @@ char ** argvdup(char ** argv)
         argv_dup[argc] = NULL;
         return argv_dup;
 }
-
-/*
- * Copyright (c) 1989, 1993, 1994
- *      The Regents of the University of California.  All rights reserved.
- *
- * Wildcard Match code below is derived from software contributed to Berkeley 
by
- * Guido van Rossum.
- *
- * Copyright (c) 2011 The FreeBSD Foundation
- * All rights reserved.
- * Portions of this software were developed by David Chisnall
- * under sponsorship from the FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * wildcard_match is based on the fnmatch function from POSIX.2.
- * Implementation based on that one from FreeBSD.
- */
-
-int wildcard_match(const char * pattern, const char * string)
-{
-        char c;
-
-        /* For loop? Why not Zoidberg? */
-        for (;;) {
-                switch (c = *pattern++) {
-                case '\0':
-                        return (*string == '\0' ? 0 : -1);
-                case '*':
-                        c = *pattern;
-
-                        if (c == '\0')
-                                return 0;
-
-                        /* General case, use recursion. */
-                        while ((c = *string) != '\0') {
-                                if (!wildcard_match(pattern, string))
-                                        return 0;
-                                ++string;
-                        }
-                        return -1;
-                default:
-                        if (c != *string)
-                                return -1;
-                        string++;
-                        break;
-                }
-        }
-}
diff --git a/src/irmd/utils.h b/src/irmd/utils.h
index 01a58e3..763e654 100644
--- a/src/irmd/utils.h
+++ b/src/irmd/utils.h
@@ -20,11 +20,6 @@
  * Foundation, Inc., http://www.fsf.org/about/contact/.
  */
 
-/*
- * Checks whether the string argument matches the pattern argument,
- * which is a wildcard pattern.
- */
-
 #ifndef OUROBOROS_IRMD_UTILS_H
 #define OUROBOROS_IRMD_UTILS_H
 
@@ -40,9 +35,6 @@ struct pid_el {
         pid_t            pid;
 };
 
-int     wildcard_match(const char * pattern,
-                       const char * string);
-
 /* functions for copying and destroying arguments list */
 char ** argvdup(char ** argv);
 
diff --git a/src/lib/dev.c b/src/lib/dev.c
index d076678..d9589b0 100644
--- a/src/lib/dev.c
+++ b/src/lib/dev.c
@@ -209,9 +209,8 @@ static int proc_announce(char * prog)
 
         msg.code    = IRM_MSG_CODE__IRM_PROC_ANNOUNCE;
         msg.has_pid = true;
-
-        msg.pid       = ai.pid;
-        msg.prog_name = prog;
+        msg.pid     = ai.pid;
+        msg.prog    = prog;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL) {
@@ -550,7 +549,7 @@ int flow_accept(qosspec_t *             qs,
         return fd;
 }
 
-int flow_alloc(const char *            dst_name,
+int flow_alloc(const char *            dst,
                qosspec_t *             qs,
                const struct timespec * timeo)
 {
@@ -560,7 +559,7 @@ int flow_alloc(const char *            dst_name,
         int         fd;
 
         msg.code        = IRM_MSG_CODE__IRM_FLOW_ALLOC;
-        msg.dst_name    = (char *) dst_name;
+        msg.dst         = (char *) dst;
         msg.has_pid     = true;
         msg.has_qoscube = true;
         msg.pid         = ai.pid;
diff --git a/src/lib/ipcpd_messages.proto b/src/lib/ipcpd_messages.proto
index 2d3bad7..de78d80 100644
--- a/src/lib/ipcpd_messages.proto
+++ b/src/lib/ipcpd_messages.proto
@@ -40,15 +40,14 @@ enum ipcp_msg_code {
 
 message ipcp_msg {
         required ipcp_msg_code code        =  1;
-        optional string name               =  2;
         optional bytes hash                =  3;
         optional int32 port_id             =  4;
-        optional string dst_name           =  5;
+        optional string dst                =  5;
         optional uint32 qoscube            =  6;
         optional ipcp_config_msg conf      =  7;
         optional int32 pid                 =  8;
         optional layer_info_msg layer_info =  9;
         optional int32 response            = 10;
-        optional string comp_name          = 11;
+        optional string comp               = 11;
         optional int32 result              = 12;
 };
diff --git a/src/lib/irm.c b/src/lib/irm.c
index c12ab89..724ce49 100644
--- a/src/lib/irm.c
+++ b/src/lib/irm.c
@@ -34,7 +34,7 @@
 #include <sys/stat.h>
 
 pid_t irm_create_ipcp(const char *   name,
-                      enum ipcp_type ipcp_type)
+                      enum ipcp_type type)
 {
         irm_msg_t   msg      = IRM_MSG__INIT;
         irm_msg_t * recv_msg = NULL;
@@ -44,9 +44,9 @@ pid_t irm_create_ipcp(const char *   name,
                 return -EINVAL;
 
         msg.code          = IRM_MSG_CODE__IRM_CREATE_IPCP;
-        msg.dst_name      = (char *) name;
+        msg.name          = (char *) name;
         msg.has_ipcp_type = true;
-        msg.ipcp_type     = ipcp_type;
+        msg.ipcp_type     = type;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
@@ -54,7 +54,7 @@ pid_t irm_create_ipcp(const char *   name,
 
         if (!recv_msg->has_result) {
                 irm_msg__free_unpacked(recv_msg, NULL);
-                return -1;
+                return -EIRMD;
         }
 
         ret = recv_msg->result;
@@ -174,8 +174,8 @@ int irm_connect_ipcp(pid_t        pid,
         int         ret;
 
         msg.code      = IRM_MSG_CODE__IRM_CONNECT_IPCP;
-        msg.dst_name  = (char *) dst;
-        msg.comp_name = (char *) component;
+        msg.dst       = (char *) dst;
+        msg.comp      = (char *) component;
         msg.has_pid   = true;
         msg.pid       = pid;
 
@@ -202,11 +202,11 @@ int irm_disconnect_ipcp(pid_t        pid,
         irm_msg_t * recv_msg = NULL;
         int         ret;
 
-        msg.code      = IRM_MSG_CODE__IRM_DISCONNECT_IPCP;
-        msg.dst_name  = (char *) dst;
-        msg.comp_name = (char *) component;
-        msg.has_pid   = true;
-        msg.pid       = pid;
+        msg.code    = IRM_MSG_CODE__IRM_DISCONNECT_IPCP;
+        msg.dst     = (char *) dst;
+        msg.comp    = (char *) component;
+        msg.has_pid = true;
+        msg.pid     = pid;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
@@ -223,38 +223,47 @@ int irm_disconnect_ipcp(pid_t        pid,
         return ret;
 }
 
-ssize_t irm_list_ipcps(const char * name,
-                       pid_t **     pids)
+ssize_t irm_list_ipcps(struct ipcp_info ** ipcps)
 {
         irm_msg_t msg        = IRM_MSG__INIT;
-        irm_msg_t * recv_msg = NULL;
-        size_t nr            = 0;
+        irm_msg_t * recv_msg;
+        size_t nr;
         size_t i;
 
-        if (pids == NULL)
+        if (ipcps == NULL)
                 return -EINVAL;
 
+        *ipcps = NULL;
+
         msg.code     = IRM_MSG_CODE__IRM_LIST_IPCPS;
-        msg.dst_name = (char *) name;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
                 return -EIRMD;
 
-        if (recv_msg->pids == NULL) {
+        if (recv_msg->ipcps == NULL) {
                 irm_msg__free_unpacked(recv_msg, NULL);
-                return -1;
+                return 0;
+        }
+
+        nr = recv_msg->n_ipcps;
+        if (nr == 0) {
+                irm_msg__free_unpacked(recv_msg, NULL);
+                 return 0;
         }
 
-        nr = recv_msg->n_pids;
-        *pids = malloc(nr * sizeof(pid_t));
-        if (*pids == NULL) {
+        *ipcps = malloc(nr * sizeof(**ipcps));
+        if (*ipcps == NULL) {
                 irm_msg__free_unpacked(recv_msg, NULL);
                 return -ENOMEM;
         }
 
-        for (i = 0; i < nr; i++)
-                (*pids)[i] = recv_msg->pids[i];
+        for (i = 0; i < nr; i++) {
+                (*ipcps)[i].pid   = recv_msg->ipcps[i]->pid;
+                (*ipcps)[i].type  = recv_msg->ipcps[i]->type;
+                strcpy((*ipcps)[i].name, recv_msg->ipcps[i]->name);
+                strcpy((*ipcps)[i].layer, recv_msg->ipcps[i]->layer);
+        }
 
         irm_msg__free_unpacked(recv_msg, NULL);
 
@@ -262,30 +271,23 @@ ssize_t irm_list_ipcps(const char * name,
 }
 
 int irm_enroll_ipcp(pid_t        pid,
-                    const char * layer_name)
+                    const char * dst)
 {
         irm_msg_t   msg      = IRM_MSG__INIT;
         irm_msg_t * recv_msg = NULL;
         int         ret      = -1;
 
-        if (pid == -1 || layer_name == NULL)
+        if (pid == -1 || dst == NULL)
                 return -EINVAL;
 
         msg.code         = IRM_MSG_CODE__IRM_ENROLL_IPCP;
         msg.has_pid      = true;
         msg.pid          = pid;
-        msg.n_layer_name = 1;
-        msg.layer_name   = malloc(sizeof(*(msg.layer_name)));
-        if (msg.layer_name == NULL)
-                return -ENOMEM;
-
-        msg.layer_name[0] = (char *) layer_name;
+        msg.dst        = (char *) dst;
 
         recv_msg = send_recv_irm_msg(&msg);
-        if (recv_msg == NULL) {
-                free(msg.layer_name);
+        if (recv_msg == NULL)
                 return -EIRMD;
-        }
 
         if (!recv_msg->has_result) {
                 irm_msg__free_unpacked(recv_msg, NULL);
@@ -295,7 +297,6 @@ int irm_enroll_ipcp(pid_t        pid,
         ret = recv_msg->result;
         irm_msg__free_unpacked(recv_msg, NULL);
 
-        free(msg.layer_name);
         return ret;
 }
 
@@ -403,9 +404,9 @@ int irm_bind_program(const char * prog,
                 return ret;
         }
 
-        msg.code      = IRM_MSG_CODE__IRM_BIND_PROGRAM;
-        msg.dst_name  = (char *) name;
-        msg.prog_name = full_name;
+        msg.code = IRM_MSG_CODE__IRM_BIND_PROGRAM;
+        msg.name = (char *) name;
+        msg.prog = full_name;
 
         if (argv != NULL) {
                 msg.n_args = argc;
@@ -443,10 +444,10 @@ int irm_bind_process(pid_t        pid,
         if (name == NULL)
                 return -EINVAL;
 
-        msg.code     = IRM_MSG_CODE__IRM_BIND_PROCESS;
-        msg.has_pid  = true;
-        msg.pid      = pid;
-        msg.dst_name = (char *) name;
+        msg.code    = IRM_MSG_CODE__IRM_BIND_PROCESS;
+        msg.has_pid = true;
+        msg.pid     = pid;
+        msg.name    = (char *) name;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
@@ -473,9 +474,9 @@ int irm_unbind_program(const char * prog,
         if (name == NULL)
                 return -EINVAL;
 
-        msg.code      = IRM_MSG_CODE__IRM_UNBIND_PROGRAM;
-        msg.prog_name = (char *) prog;
-        msg.dst_name  = (char *) name;
+        msg.code = IRM_MSG_CODE__IRM_UNBIND_PROGRAM;
+        msg.prog = (char *) prog;
+        msg.name = (char *) name;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
@@ -502,10 +503,10 @@ int irm_unbind_process(pid_t        pid,
         if (name == NULL)
                 return -EINVAL;
 
-        msg.code = IRM_MSG_CODE__IRM_UNBIND_PROCESS;
-        msg.has_pid  = true;
-        msg.pid      = pid;
-        msg.dst_name = (char *) name;
+        msg.code    = IRM_MSG_CODE__IRM_UNBIND_PROCESS;
+        msg.has_pid = true;
+        msg.pid     = pid;
+        msg.name    = (char *) name;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
@@ -522,23 +523,20 @@ int irm_unbind_process(pid_t        pid,
         return ret;
 }
 
-int irm_reg(const char * name,
-            char **      layers,
-            size_t       len)
+int irm_reg(pid_t        pid,
+            const char * name)
 {
         irm_msg_t   msg      = IRM_MSG__INIT;
         irm_msg_t * recv_msg = NULL;
         int         ret      = -1;
 
-        if (name == NULL || layers == NULL || len == 0)
+        if (name == NULL)
                 return -EINVAL;
 
-        msg.code = IRM_MSG_CODE__IRM_REG;
-
-        msg.dst_name = (char *) name;
-
-        msg.layer_name   = layers;
-        msg.n_layer_name = len;
+        msg.code    = IRM_MSG_CODE__IRM_REG;
+        msg.has_pid = true;
+        msg.pid     = pid;
+        msg.name    = (char *) name;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
@@ -556,23 +554,20 @@ int irm_reg(const char * name,
 }
 
 
-int irm_unreg(const char * name,
-              char **      layers,
-              size_t       len)
+int irm_unreg(pid_t        pid,
+              const char * name)
 {
         irm_msg_t   msg      = IRM_MSG__INIT;
         irm_msg_t * recv_msg = NULL;
         int         ret      = -1;
 
-        if (name == NULL || layers == NULL || len == 0)
+        if (name == NULL)
                 return -EINVAL;
 
-        msg.code = IRM_MSG_CODE__IRM_UNREG;
-
-        msg.dst_name = (char *) name;
-
-        msg.layer_name   = (char **) layers;
-        msg.n_layer_name = len;
+        msg.code    = IRM_MSG_CODE__IRM_UNREG;
+        msg.has_pid = true;
+        msg.pid     = pid;
+        msg.name    = (char *) name;
 
         recv_msg = send_recv_irm_msg(&msg);
         if (recv_msg == NULL)
diff --git a/src/lib/irmd_messages.proto b/src/lib/irmd_messages.proto
index 51b1502..16dfe82 100644
--- a/src/lib/irmd_messages.proto
+++ b/src/lib/irmd_messages.proto
@@ -48,23 +48,31 @@ enum irm_msg_code {
         IRM_REPLY             = 21;
 };
 
+message ipcp_info_msg {
+        required uint32 pid   = 1;
+        required uint32 type  = 2;
+        required string name  = 3;
+        required string layer = 4;
+};
+
 message irm_msg {
         required irm_msg_code code    =  1;
-        optional string prog_name     =  2;
+        optional string prog          =  2;
         optional sint32 pid           =  3;
-        optional uint32 ipcp_type     =  4;
-        repeated string layer_name    =  5;
-        repeated string args          =  6;
-        optional sint32 response      =  7;
-        optional string dst_name      =  8;
-        optional bytes  hash          =  9;
-        optional sint32 port_id       = 10;
-        optional sint32 qoscube       = 11;
-        optional ipcp_config_msg conf = 12;
-        optional uint32 opts          = 13;
-        repeated sint32 pids          = 14;
-        optional uint32 timeo_sec     = 15;
-        optional uint32 timeo_nsec    = 16;
-        optional string comp_name     = 17;
-        optional sint32 result        = 18;
+        optional string name          =  4;
+        optional uint32 ipcp_type     =  5;
+        optional string layer         =  6;
+        repeated string args          =  7;
+        optional sint32 response      =  8;
+        optional string dst           =  9;
+        optional bytes  hash          = 10;
+        optional sint32 port_id       = 11;
+        optional sint32 qoscube       = 12;
+        optional ipcp_config_msg conf = 13;
+        optional uint32 opts          = 14;
+        repeated ipcp_info_msg ipcps  = 15;
+        optional uint32 timeo_sec     = 16;
+        optional uint32 timeo_nsec    = 17;
+        optional string comp          = 18;
+        optional sint32 result        = 19;
 };
diff --git a/src/tools/irm/CMakeLists.txt b/src/tools/irm/CMakeLists.txt
index e87bd0a..ca32e9c 100644
--- a/src/tools/irm/CMakeLists.txt
+++ b/src/tools/irm/CMakeLists.txt
@@ -14,6 +14,7 @@ set(SOURCE_FILES
   irm_ipcp_destroy.c
   irm_ipcp_bootstrap.c
   irm_ipcp_enroll.c
+  irm_ipcp_list.c
   irm_ipcp_connect.c
   irm_ipcp_disconnect.c
   irm_unbind_program.c
diff --git a/src/tools/irm/irm_bind_ipcp.c b/src/tools/irm/irm_bind_ipcp.c
index 2fcacec..a30b419 100644
--- a/src/tools/irm/irm_bind_ipcp.c
+++ b/src/tools/irm/irm_bind_ipcp.c
@@ -45,6 +45,8 @@
 #include "irm_ops.h"
 #include "irm_utils.h"
 
+#include <string.h>
+
 static void usage(void)
 {
         printf("Usage: irm bind ipcp <name> name <name>\n");
@@ -53,13 +55,11 @@ static void usage(void)
 int do_bind_ipcp(int     argc,
                  char ** argv)
 {
-        char * ipcp = NULL;
-        char * name = NULL;
-
-        pid_t * pids = NULL;
-        ssize_t len  = 0;
-
-        int i;
+        char *             ipcp = NULL;
+        char *             name = NULL;
+        struct ipcp_info * ipcps;
+        ssize_t            len;
+        ssize_t            i;
 
         while (argc > 0) {
                 if (matches(*argv, "name") == 0) {
@@ -85,12 +85,17 @@ int do_bind_ipcp(int     argc,
                 return -1;
         }
 
-        len = irm_list_ipcps(ipcp, &pids);
-
+        len = irm_list_ipcps(&ipcps);
         for (i = 0; i < len; ++i)
-                irm_bind_process(pids[i], name);
+                if (strcmp(ipcps[i].name, ipcp) == 0) {
+                        if (irm_bind_process(ipcps[i].pid, name)) {
+                                free(ipcps);
+                                return -1;
+                        }
+                        break;
+                }
 
-        free(pids);
+        free(ipcps);
 
         return 0;
 }
diff --git a/src/tools/irm/irm_ipcp.c b/src/tools/irm/irm_ipcp.c
index a791f6a..89aa414 100644
--- a/src/tools/irm/irm_ipcp.c
+++ b/src/tools/irm/irm_ipcp.c
@@ -68,6 +68,7 @@ static const struct cmd {
         { "enroll",     do_enroll_ipcp },
         { "connect",    do_connect_ipcp },
         { "disconnect", do_disconnect_ipcp },
+        { "list",       do_list_ipcp},
         { "help",       do_help },
         { NULL,         NULL }
 };
diff --git a/src/tools/irm/irm_ipcp_bootstrap.c 
b/src/tools/irm/irm_ipcp_bootstrap.c
index 4eeedbd..07dcea0 100644
--- a/src/tools/irm/irm_ipcp_bootstrap.c
+++ b/src/tools/irm/irm_ipcp_bootstrap.c
@@ -36,6 +36,12 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <ouroboros/irm.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -43,10 +49,6 @@
 #ifdef __FreeBSD__
 #include <sys/socket.h>
 #endif
-#include <ouroboros/irm.h>
-
-#include "irm_ops.h"
-#include "irm_utils.h"
 
 #define NORMAL                 "normal"
 #define UDP                    "udp"
@@ -83,7 +85,7 @@ static void usage(void)
         printf("Usage: irm ipcp bootstrap\n"
                "                name <ipcp name>\n"
                "                layer <layer name>\n"
-               "                type [TYPE]\n"
+               "                [type [TYPE]]\n"
                "where TYPE = {" NORMAL " " LOCAL " "
                UDP " " ETH_LLC " " ETH_DIX " " RAPTOR "},\n\n"
                "if TYPE == " NORMAL "\n"
@@ -132,8 +134,8 @@ static void usage(void)
 int do_bootstrap_ipcp(int     argc,
                       char ** argv)
 {
-        char *             name           = NULL;
-        pid_t              pid;
+        char *             ipcp           = NULL;
+        pid_t              pid            = -1;
         struct ipcp_config conf;
         uint8_t            addr_size      = DEFAULT_ADDR_SIZE;
         uint8_t            eid_size       = DEFAULT_EID_SIZE;
@@ -145,10 +147,11 @@ int do_bootstrap_ipcp(int     argc,
         uint32_t           ip_addr        = 0;
         uint32_t           dns_addr       = DEFAULT_DDNS;
         char *             ipcp_type      = NULL;
-        char *             layer_name     = NULL;
+        enum ipcp_type     type;
+        char *             layer          = NULL;
         char *             dev            = NULL;
         uint16_t           ethertype      = DEFAULT_ETHERTYPE;
-        pid_t *            pids           = NULL;
+        struct ipcp_info * ipcps;
         ssize_t            len            = 0;
         int                i              = 0;
         bool               autobind       = false;
@@ -159,9 +162,9 @@ int do_bootstrap_ipcp(int     argc,
                 if (matches(*argv, "type") == 0) {
                         ipcp_type = *(argv + 1);
                 } else if (matches(*argv, "layer") == 0) {
-                        layer_name = *(argv + 1);
+                        layer = *(argv + 1);
                 } else if (matches(*argv, "name") == 0) {
-                        name = *(argv + 1);
+                        ipcp = *(argv + 1);
                 } else if (matches(*argv, "hash") == 0) {
                         if (strcmp(*(argv + 1), SHA3_224) == 0)
                                 hash_algo = DIR_HASH_SHA3_224;
@@ -231,98 +234,133 @@ int do_bootstrap_ipcp(int     argc,
                 argv += cargs;
         }
 
-        if (name == NULL || layer_name == NULL || ipcp_type == NULL) {
+        if (ipcp == NULL || layer == NULL) {
                 usage();
                 return -1;
         }
 
-        strcpy(conf.layer_info.layer_name, layer_name);
-        if (strcmp(ipcp_type, UDP) != 0)
-                conf.layer_info.dir_hash_algo = hash_algo;
-
-        if (strcmp(ipcp_type, NORMAL) == 0) {
-                conf.type           = IPCP_NORMAL;
-                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.pff_type       = pff_type;
-        } else if (strcmp(ipcp_type, UDP) == 0) {
-                conf.type = IPCP_UDP;
-                if (ip_addr == 0) {
-                        usage();
-                        return -1;
-                }
-                conf.ip_addr = ip_addr;
-                conf.dns_addr = dns_addr;
-        } else if (strcmp(ipcp_type, LOCAL) == 0) {
-                conf.type = IPCP_LOCAL;
-        } else if (strcmp(ipcp_type, RAPTOR) == 0) {
-                conf.type = IPCP_RAPTOR;
-        } else if (strcmp(ipcp_type, ETH_LLC) == 0) {
-                conf.type = IPCP_ETH_LLC;
-                if (dev == NULL) {
-                        usage();
-                        return -1;
-                }
-                conf.dev = dev;
-        } else if (strcmp(ipcp_type, ETH_DIX) == 0) {
-                conf.type = IPCP_ETH_DIX;
-                if (dev == NULL) {
-                        usage();
-                        return -1;
+        len = irm_list_ipcps(&ipcps);
+        for (i = 0; i < len; i++) {
+                if (wildcard_match(ipcps[i].name, ipcp) == 0) {
+                        pid = ipcps[i].pid;
+                        break;
                 }
-                conf.dev = dev;
-                conf.ethertype = ethertype;
-        } else {
-                usage();
-                return -1;
         }
 
-        if (autobind && conf.type != IPCP_NORMAL) {
-                printf("Can only bind normal IPCPs, autobind disabled.\n");
-                autobind = false;
-        }
+        if (pid == -1) {
+                if (ipcp_type == NULL) {
+                        printf("No IPCPs matching %s found.\n\n", ipcp);
+                        goto fail;
+                } else {
+                        if (strcmp(ipcp_type, NORMAL) == 0)
+                                type = IPCP_NORMAL;
+                        else if (strcmp(ipcp_type, UDP) == 0)
+                                type = IPCP_UDP;
+                        else if (strcmp(ipcp_type, ETH_LLC) == 0)
+                                type = IPCP_ETH_LLC;
+                        else if (strcmp(ipcp_type, ETH_DIX) == 0)
+                                type = IPCP_ETH_DIX;
+                        else if (strcmp(ipcp_type, LOCAL) == 0)
+                                type = IPCP_LOCAL;
+                        else if (strcmp(ipcp_type, RAPTOR) == 0)
+                                type = IPCP_RAPTOR;
+                        else goto fail_usage;
+                }
 
-        len = irm_list_ipcps(name, &pids);
-        if (len <= 0) {
-                pid = irm_create_ipcp(name, conf.type);
-                if (pid <= 0)
-                        return -1;
-                len = irm_list_ipcps(name, &pids);
+                pid = irm_create_ipcp(ipcp, type);
+                if (pid < 0)
+                        goto fail;
+                free(ipcps);
+                len = irm_list_ipcps(&ipcps);
         }
 
         for (i = 0; i < len; i++) {
-                if (autobind && irm_bind_process(pids[i], name)) {
-                        printf("Failed to bind %d to %s.\n", pids[i], name);
-                        free(pids);
-                        return -1;
-                }
+                if (wildcard_match(ipcps[i].name, ipcp) == 0) {
+                        pid = ipcps[i].pid;
+                        if (ipcp_type != NULL && type != ipcps[i].type) {
+                                printf("Types do not match.\n\n");
+                                goto fail;
+                        }
+                        conf.type = ipcps[i].type;
 
-                if (autobind && irm_bind_process(pids[i], layer_name)) {
-                        printf("Failed to bind %d to %s.\n",
-                               pids[i], layer_name);
-                        irm_unbind_process(pids[i], name);
-                        free(pids);
-                        return -1;
-                }
+                        if (autobind && conf.type != IPCP_NORMAL) {
+                                printf("Can only bind normal IPCPs, "
+                                       "autobind disabled.\n");
+                                autobind = false;
+                        }
+
+                        strcpy(conf.layer_info.layer_name, layer);
+                        if (conf.type == IPCP_UDP)
+                                conf.layer_info.dir_hash_algo = hash_algo;
 
-                if (irm_bootstrap_ipcp(pids[i], &conf)) {
-                        if (autobind) {
-                                irm_unbind_process(pids[i], name);
-                                irm_unbind_process(pids[i], layer_name);
+                        switch (conf.type) {
+                        case IPCP_NORMAL:
+                                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.pff_type       = pff_type;
+                                break;
+                        case IPCP_UDP:
+                                if (ip_addr == 0)
+                                        goto fail_usage;
+                                conf.ip_addr = ip_addr;
+                                conf.dns_addr = dns_addr;
+                                break;
+                        case IPCP_ETH_LLC:
+                                if (dev == NULL)
+                                        goto fail_usage;
+                                conf.dev = dev;
+                                break;
+                        case IPCP_ETH_DIX:
+                                if (dev == NULL)
+                                        goto fail_usage;
+                                conf.dev = dev;
+                                conf.ethertype = ethertype;
+                                break;
+                        case IPCP_LOCAL:
+                                /* FALLTHRU */
+                        case IPCP_RAPTOR:
+                                break;
+                        default:
+                                assert(false);
+                                break;
+                        }
+
+                        if (autobind && irm_bind_process(pid, ipcp)) {
+                                printf("Failed to bind %d to %s.\n", pid, 
ipcp);
+                                goto fail;
+                        }
+
+                        if (autobind && irm_bind_process(pid, layer)) {
+                                printf("Failed to bind %d to %s.\n",
+                                       pid, layer);
+                                irm_unbind_process(pid, ipcp);
+                                goto fail;
+                        }
+
+                        if (irm_bootstrap_ipcp(pid, &conf)) {
+                                if (autobind) {
+                                        irm_unbind_process(pid, ipcp);
+                                        irm_unbind_process(pid, layer);
+                                }
+                                goto fail;
                         }
-                        free(pids);
-                        return -1;
                 }
         }
 
-        free(pids);
+        free(ipcps);
 
         return 0;
 
  unknown_param:
         printf("Unknown parameter for %s: \"%s\".\n", *argv, *(argv + 1));
         return -1;
+
+ fail_usage:
+        usage();
+ fail:
+        free(ipcps);
+        return -1;
 }
diff --git a/src/tools/irm/irm_ipcp_connect.c b/src/tools/irm/irm_ipcp_connect.c
index b9cad57..42c0735 100644
--- a/src/tools/irm/irm_ipcp_connect.c
+++ b/src/tools/irm/irm_ipcp_connect.c
@@ -60,19 +60,21 @@ static void usage(void)
 int do_connect_ipcp(int     argc,
                     char ** argv)
 {
-        char *  name      = NULL;
-        char *  dst_name  = NULL;
-        char *  comp_name = NULL;
-        pid_t * pids      = NULL;
-        ssize_t len       = 0;
+        char *             ipcp = NULL;
+        char *             dst  = NULL;
+        char *             comp = NULL;
+        struct ipcp_info * ipcps;
+        ssize_t            len  = 0;
+        pid_t              pid  = -1;
+        ssize_t            i;
 
         while (argc > 0) {
                 if (matches(*argv, "name") == 0) {
-                        name = *(argv + 1);
+                        ipcp = *(argv + 1);
                 } else if (matches(*argv, "dst") == 0) {
-                        dst_name = *(argv + 1);
+                        dst = *(argv + 1);
                 } else if (matches(*argv, "component") == 0) {
-                        comp_name = *(argv + 1);
+                        comp = *(argv + 1);
                 } else {
                         printf("\"%s\" is unknown, try \"irm "
                                "ipcpi connect\".\n", *argv);
@@ -83,28 +85,29 @@ int do_connect_ipcp(int     argc,
                 argv += 2;
         }
 
-        if (name == NULL || dst_name == NULL || comp_name == NULL) {
+        if (ipcp == NULL || dst == NULL || comp == NULL) {
                 usage();
                 return -1;
         }
 
-        len = irm_list_ipcps(name, &pids);
-        if (len != 1)
+        len = irm_list_ipcps(&ipcps);
+        for (i = 0; i < len; i++)
+                if (strcmp(ipcps[i].name, ipcp) == 0)
+                        pid = ipcps[i].pid;
+
+        free(ipcps);
+
+        if (pid == -1)
                 return -1;
 
-        if (!strcmp(comp_name, DT))
-                comp_name = DT_COMP;
+        if (!strcmp(comp, DT))
+                comp = DT_COMP;
 
-        if (!strcmp(comp_name , MGMT))
-                comp_name = MGMT_COMP;
+        if (!strcmp(comp , MGMT))
+                comp = MGMT_COMP;
 
-        if (irm_connect_ipcp(pids[0], dst_name, comp_name)) {
-                free(pids);
+        if (irm_connect_ipcp(pid, dst, comp))
                 return -1;
-        }
-
-        if (pids != NULL)
-                free(pids);
 
         return 0;
 }
diff --git a/src/tools/irm/irm_ipcp_create.c b/src/tools/irm/irm_ipcp_create.c
index 6da853b..c886696 100644
--- a/src/tools/irm/irm_ipcp_create.c
+++ b/src/tools/irm/irm_ipcp_create.c
@@ -47,6 +47,7 @@
 #define NORMAL  "normal"
 #define UDP     "udp"
 #define ETH_LLC "eth-llc"
+#define ETH_DIX "eth-dix"
 #define LOCAL   "local"
 #define RAPTOR  "raptor"
 
@@ -59,7 +60,8 @@ static void usage(void)
                UDP " " ETH_LLC " " RAPTOR "}\n");
 }
 
-int do_create_ipcp(int argc, char ** argv)
+int do_create_ipcp(int     argc,
+                   char ** argv)
 {
         char * ipcp_type = NULL;
         char * ipcp_name = NULL;
@@ -94,6 +96,8 @@ int do_create_ipcp(int argc, char ** argv)
                 type = IPCP_LOCAL;
         else if (strcmp(ipcp_type, ETH_LLC) == 0)
                 type = IPCP_ETH_LLC;
+        else if (strcmp(ipcp_type, ETH_DIX) == 0)
+                type = IPCP_ETH_DIX;
         else if (strcmp(ipcp_type, RAPTOR) == 0)
                 type = IPCP_RAPTOR;
         else {
@@ -102,7 +106,7 @@ int do_create_ipcp(int argc, char ** argv)
         }
 
         pid = irm_create_ipcp(ipcp_name, type);
-        if (pid == 0)
+        if (pid <= 0)
                 return -1;
 
         return 0;
diff --git a/src/tools/irm/irm_ipcp_destroy.c b/src/tools/irm/irm_ipcp_destroy.c
index 4c37f52..cb86b16 100644
--- a/src/tools/irm/irm_ipcp_destroy.c
+++ b/src/tools/irm/irm_ipcp_destroy.c
@@ -44,22 +44,25 @@
 #include "irm_ops.h"
 #include "irm_utils.h"
 
+#include <string.h>
+
 static void usage(void)
 {
         printf("Usage: irm ipcp destroy\n"
                "                name <ipcp name>\n");
 }
 
-int do_destroy_ipcp(int argc, char ** argv)
+int do_destroy_ipcp(int     argc,
+                    char ** argv)
 {
-        char *  name = NULL;
-        pid_t * pids;
-        ssize_t len = 0;
-        int     i = 0;
+        char *             ipcp = NULL;
+        struct ipcp_info * ipcps;
+        ssize_t            len;
+        int                i;
 
         while (argc > 0) {
                 if (matches(*argv, "name") == 0) {
-                        name = *(argv + 1);
+                        ipcp = *(argv + 1);
                 } else {
                         printf("\"%s\" is unknown, try \"irm "
                                "ipcp destroy\".\n", *argv);
@@ -70,20 +73,26 @@ int do_destroy_ipcp(int argc, char ** argv)
                 argv += 2;
         }
 
-        if (name == NULL) {
+        if (ipcp == NULL) {
                 usage();
                 return -1;
         }
 
-        len = irm_list_ipcps(name, &pids);
+        len = irm_list_ipcps(&ipcps);
         if (len <= 0)
-                return -1;
+                goto fail;
 
         for (i = 0; i < len; i++)
-                if (irm_destroy_ipcp(pids[i]))
-                        return -1;
+                if (strcmp(ipcps[i].name, ipcp) == 0) {
+                        if (irm_destroy_ipcp(ipcps[i].pid))
+                                goto fail_destroy;
+                        break;
+                }
 
-        free(pids);
 
         return 0;
+ fail_destroy:
+        free(ipcps);
+ fail:
+        return -1;
 }
diff --git a/src/tools/irm/irm_ipcp_disconnect.c 
b/src/tools/irm/irm_ipcp_disconnect.c
index 8b5eb59..73f1588 100644
--- a/src/tools/irm/irm_ipcp_disconnect.c
+++ b/src/tools/irm/irm_ipcp_disconnect.c
@@ -60,19 +60,21 @@ static void usage(void)
 int do_disconnect_ipcp(int     argc,
                        char ** argv)
 {
-        char *  name      = NULL;
-        char *  dst_name  = NULL;
-        char *  comp_name = NULL;
-        pid_t * pids      = NULL;
-        ssize_t len       = 0;
+        char *             ipcp = NULL;
+        char *             dst  = NULL;
+        char *             comp = NULL;
+        struct ipcp_info * ipcps;
+        ssize_t            len  = 0;
+        pid_t              pid  = -1;
+        ssize_t            i;
 
         while (argc > 0) {
                 if (matches(*argv, "name") == 0) {
-                        name = *(argv + 1);
+                        ipcp = *(argv + 1);
                 } else if (matches(*argv, "dst") == 0) {
-                        dst_name = *(argv + 1);
+                        dst = *(argv + 1);
                 } else if (matches(*argv, "component") == 0) {
-                        comp_name = *(argv + 1);
+                        comp = *(argv + 1);
                 } else {
                         printf("\"%s\" is unknown, try \"irm "
                                "ipcpi connect\".\n", *argv);
@@ -83,28 +85,29 @@ int do_disconnect_ipcp(int     argc,
                 argv += 2;
         }
 
-        if (name == NULL || dst_name == NULL || comp_name == NULL) {
+        if (ipcp == NULL || dst == NULL || comp == NULL) {
                 usage();
                 return -1;
         }
 
-        len = irm_list_ipcps(name, &pids);
-        if (len != 1)
+        len = irm_list_ipcps(&ipcps);
+        for (i = 0; i < len; i++)
+                if (strcmp(ipcps[i].name, ipcp) == 0)
+                        pid = ipcps[i].pid;
+
+        free(ipcps);
+
+        if (pid == -1)
                 return -1;
 
-        if (!strcmp(comp_name, DT))
-                comp_name = DT_COMP;
+        if (!strcmp(comp, DT))
+                comp = DT_COMP;
 
-        if (!strcmp(comp_name , MGMT))
-                comp_name = MGMT_COMP;
+        if (!strcmp(comp , MGMT))
+                comp = MGMT_COMP;
 
-        if (irm_disconnect_ipcp(pids[0], dst_name, comp_name)) {
-                free(pids);
+        if (irm_disconnect_ipcp(pid, dst, comp))
                 return -1;
-        }
-
-        if (pids != NULL)
-                free(pids);
 
         return 0;
 }
diff --git a/src/tools/irm/irm_ipcp_enroll.c b/src/tools/irm/irm_ipcp_enroll.c
index 8b89709..c1628af 100644
--- a/src/tools/irm/irm_ipcp_enroll.c
+++ b/src/tools/irm/irm_ipcp_enroll.c
@@ -44,6 +44,8 @@
 #include "irm_ops.h"
 #include "irm_utils.h"
 
+#include <string.h>
+
 static void usage(void)
 {
         printf("Usage: irm ipcp enroll\n"
@@ -52,23 +54,24 @@ static void usage(void)
                "                [autobind]\n");
 }
 
-int do_enroll_ipcp(int argc, char ** argv)
+int do_enroll_ipcp(int     argc,
+                   char ** argv)
 {
-        char *  name       = NULL;
-        char *  layer_name = NULL;
-        pid_t * pids       = NULL;
-        pid_t   pid;
-        ssize_t len        = 0;
-        int     i          = 0;
-        bool    autobind   = false;
-        int     cargs;
+        char *             ipcp     = NULL;
+        char *             layer    = NULL;
+        struct ipcp_info * ipcps;
+        pid_t              pid      = -1;
+        ssize_t            len      = 0;
+        int                i        = 0;
+        bool               autobind = false;
+        int                cargs;
 
         while (argc > 0) {
                 cargs = 2;
                 if (matches(*argv, "name") == 0) {
-                        name = *(argv + 1);
+                        ipcp = *(argv + 1);
                 } else if (matches(*argv, "layer") == 0) {
-                        layer_name = *(argv + 1);
+                        layer = *(argv + 1);
                 } else if (matches(*argv, "autobind") == 0) {
                         autobind = true;
                         cargs = 1;
@@ -82,42 +85,53 @@ int do_enroll_ipcp(int argc, char ** argv)
                 argv += cargs;
         }
 
-        if (layer_name == NULL || name == NULL) {
+        if (layer == NULL || ipcp == NULL) {
                 usage();
                 return -1;
         }
 
-        len = irm_list_ipcps(name, &pids);
-        if (len <= 0) {
-                pid = irm_create_ipcp(name, IPCP_NORMAL);
-                if (pid == 0)
-                        return -1;
-                len = irm_list_ipcps(name, &pids);
+        len = irm_list_ipcps(&ipcps);
+        for (i = 0; i < len; i++)
+                if (wildcard_match(ipcps[i].name, ipcp) == 0 &&
+                    ipcps[i].type == IPCP_NORMAL)
+                        pid = ipcps[i].pid;
+
+        if (pid < 0) {
+                pid = irm_create_ipcp(ipcp, IPCP_NORMAL);
+                if (pid < 0)
+                        goto fail;
+                free(ipcps);
+                len = irm_list_ipcps(&ipcps);
         }
 
         for (i = 0; i < len; i++) {
-                if (autobind && irm_bind_process(pids[i], name)) {
-                        free(pids);
-                        return -1;
-                }
+                if (ipcps[i].type != IPCP_NORMAL)
+                        continue;
+                if (wildcard_match(ipcps[i].name, ipcp) == 0) {
+                        pid = ipcps[i].pid;
+                        if (autobind && irm_bind_process(pid, ipcp)) {
+                                printf("Failed to bind %d to %s.\n", pid, 
ipcp);
+                                goto fail;
+                        }
 
-                if (irm_enroll_ipcp(pids[i], layer_name)) {
-                        if (autobind)
-                                irm_unbind_process(pids[i], name);
-                        free(pids);
-                        return -1;
-                }
+                        if (irm_enroll_ipcp(pid, layer)) {
+                                if (autobind)
+                                        irm_unbind_process(pid, ipcp);
+                                goto fail;
+                        }
 
-                if (autobind && irm_bind_process(pids[i], layer_name)) {
-                        printf("Failed to bind %d to %s.\n",
-                               pids[i], layer_name);
-                        free(pids);
-                        return -1;
+                        if (autobind && irm_bind_process(pid, layer)) {
+                                printf("Failed to bind %d to %s.\n", pid, 
layer);
+                                goto fail;
+                        }
                 }
         }
 
-        if (pids != NULL)
-                free(pids);
+        free(ipcps);
 
         return 0;
+
+ fail:
+        free(ipcps);
+        return -1;
 }
diff --git a/src/tools/irm/irm_ipcp_list.c b/src/tools/irm/irm_ipcp_list.c
new file mode 100644
index 0000000..e16ca52
--- /dev/null
+++ b/src/tools/irm/irm_ipcp_list.c
@@ -0,0 +1,158 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2018
+ *
+ * Create IPC Processes
+ *
+ *    Dimitri Staessens <dimitri.staessens@xxxxxxxx>
+ *    Sander Vrijders   <sander.vrijders@xxxxxxxx>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/irm.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NORMAL  "normal"
+#define UDP     "udp"
+#define ETH_LLC "eth-llc"
+#define ETH_DIX "eth-dix"
+#define LOCAL   "local"
+#define RAPTOR  "raptor"
+
+static void usage(void)
+{
+        printf("Usage: irm ipcp list\n"
+               "                [name  <ipcp name>]\n"
+               "                [layer <layer_name>]\n\n"
+               "                [type [TYPE]]\n\n"
+               "where TYPE = {" NORMAL " " LOCAL " "
+               UDP " " ETH_LLC " " ETH_DIX " " RAPTOR "}\n");
+}
+
+static char * str_type(enum ipcp_type type)
+{
+        switch(type) {
+        case IPCP_NORMAL:
+                return NORMAL;
+        case IPCP_ETH_LLC:
+                return ETH_LLC;
+        case IPCP_ETH_DIX:
+                return ETH_DIX;
+        case IPCP_UDP:
+                return UDP;
+        case IPCP_RAPTOR:
+                return RAPTOR;
+        case IPCP_LOCAL:
+                return LOCAL;
+        default:
+                return "UNKNOWN";
+        }
+};
+
+int do_list_ipcp(int     argc,
+                 char ** argv)
+{
+        char *             ipcp_type = NULL;
+        char *             ipcp_name = NULL;
+        enum ipcp_type     type      = -1;
+        struct ipcp_info * ipcps;
+        ssize_t            len;
+        ssize_t            i;
+
+        while (argc > 0) {
+                if (matches(*argv, "type") == 0) {
+                        ipcp_type = *(argv + 1);
+                } else if (matches(*argv, "name") == 0) {
+                        ipcp_name = *(argv + 1);
+                } else {
+                        printf("\"%s\" is unknown, try \"irm "
+                               "ipcp list\".\n", *argv);
+                        return -1;
+                }
+
+                argc -= 2;
+                argv += 2;
+        }
+
+        if (ipcp_type != NULL) {
+                if (strcmp(ipcp_type, NORMAL) == 0)
+                        type = IPCP_NORMAL;
+                else if (strcmp(ipcp_type, UDP) == 0)
+                        type = IPCP_UDP;
+                else if (strcmp(ipcp_type, LOCAL) == 0)
+                        type = IPCP_LOCAL;
+                else if (strcmp(ipcp_type, ETH_LLC) == 0)
+                        type = IPCP_ETH_LLC;
+                else if (strcmp(ipcp_type, ETH_DIX) == 0)
+                        type = IPCP_ETH_DIX;
+                else if (strcmp(ipcp_type, RAPTOR) == 0)
+                        type = IPCP_RAPTOR;
+                else {
+                        usage();
+                        return -1;
+                }
+        }
+
+        len = irm_list_ipcps(&ipcps);
+        if (len == 0) {
+                printf("No IPCPs in system.\n\n");
+                return 0;
+        }
+
+        /* FIXME: Implement filtering based on type and name. */
+        (void) type;
+        (void) ipcp_name;
+
+        printf("+---------+----------------------+------------+"
+               "----------------------+\n");
+        printf("| %7s | %20s | %10s | %20s |\n", "pid", "name", "type", 
"layer");
+        printf("+---------+----------------------+------------+"
+               "----------------------+\n");
+
+        for (i = 0; i < len; i++)
+                printf("| %7d | %20s | %10s | %20s |\n",
+                       ipcps[i].pid,
+                       ipcps[i].name,
+                       str_type(ipcps[i].type),
+                       ipcps[i].layer);
+
+        printf("+---------+----------------------+------------+"
+               "----------------------+\n\n");
+
+        free(ipcps);
+
+        return 0;
+}
diff --git a/src/tools/irm/irm_ops.h b/src/tools/irm/irm_ops.h
index a2cb539..7403543 100644
--- a/src/tools/irm/irm_ops.h
+++ b/src/tools/irm/irm_ops.h
@@ -57,6 +57,9 @@ int do_connect_ipcp(int     argc,
 int do_disconnect_ipcp(int     argc,
                        char ** argv);
 
+int do_list_ipcp(int     argc,
+                 char ** argv);
+
 int bind_cmd(int     argc,
              char ** argv);
 
diff --git a/src/tools/irm/irm_register.c b/src/tools/irm/irm_register.c
index 574c222..c00c597 100644
--- a/src/tools/irm/irm_register.c
+++ b/src/tools/irm/irm_register.c
@@ -38,29 +38,42 @@
 
 #include <ouroboros/irm.h>
 
-#include <stdio.h>
 
 #include "irm_ops.h"
 #include "irm_utils.h"
 
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define MAX_IPCPS  128
 #define MAX_LAYERS 128
 
 static void usage(void)
 {
         printf("Usage: irm register\n"
                "           name <name>\n"
+               "           ipcp <ipcp to register with>\n"
+               "           [ipcp <ipcp to register with>]\n"
+               "           [... (maximum %d ipcps)]\n"
                "           layer <layer to register with>\n"
                "           [layer <layer to register with>]\n"
                "           [... (maximum %d layers)]\n"
-               , MAX_LAYERS);
+               , MAX_IPCPS, MAX_LAYERS);
 }
 
 
-int do_register(int argc, char ** argv)
+int do_register(int     argc,
+                char ** argv)
 {
-        char * name = NULL;
-        char * layers[MAX_LAYERS];
-        size_t layers_len = 0;
+        char *             name       = NULL;
+        char *             layers[MAX_LAYERS];
+        size_t             layers_len = 0;
+        char *             ipcp[MAX_IPCPS];
+        size_t             ipcp_len   = 0;
+        struct ipcp_info * ipcps;
+        size_t             len;
+        size_t             i;
 
         while (argc > 0) {
                 if (matches(*argv, "name") == 0) {
@@ -71,6 +84,12 @@ int do_register(int argc, char ** argv)
                                 printf("Too many layers specified\n");
                                 return -1;
                         }
+                } else if (matches(*argv, "ipcp") == 0) {
+                        ipcp[ipcp_len++] = *(argv + 1);
+                        if (ipcp_len > MAX_IPCPS) {
+                                printf("Too many IPCPs specified\n");
+                                return -1;
+                        }
                 } else {
                         printf("\"%s\" is unknown, try \"irm "
                                "register\".\n", *argv);
@@ -81,10 +100,35 @@ int do_register(int argc, char ** argv)
                 argv += 2;
         }
 
-        if (layers_len < 1 || name == NULL) {
+        if ((layers_len < 1 && ipcp_len < 1) || name == NULL) {
                 usage();
                 return -1;
         }
 
-        return irm_reg(name, layers, layers_len);
+        len = irm_list_ipcps(&ipcps);
+        for (i = 0; i < len; ++i) {
+                size_t j;
+                for (j = 0; j < layers_len; j++) {
+                        if (wildcard_match(ipcps[i].layer, layers[j]) == 0) {
+                                if (irm_reg(ipcps[i].pid, name)) {
+                                        free(ipcps);
+                                        return -1;
+                                }
+                                break;
+                        }
+                }
+                for (j = 0; j < ipcp_len; j++) {
+                        if (wildcard_match(ipcps[i].name, ipcp[j]) == 0) {
+                                if (irm_reg(ipcps[i].pid, name)) {
+                                        free(ipcps);
+                                        return -1;
+                                }
+                                break;
+                        }
+                }
+        }
+
+        free(ipcps);
+
+        return 0;
 }
diff --git a/src/tools/irm/irm_unbind_ipcp.c b/src/tools/irm/irm_unbind_ipcp.c
index f804da9..9b2a930 100644
--- a/src/tools/irm/irm_unbind_ipcp.c
+++ b/src/tools/irm/irm_unbind_ipcp.c
@@ -45,6 +45,8 @@
 #include "irm_ops.h"
 #include "irm_utils.h"
 
+#include <string.h>
+
 static void usage(void)
 {
         printf("Usage: irm unbind ipcp <name>\n"
@@ -52,15 +54,14 @@ static void usage(void)
                "\n");
 }
 
-int do_unbind_ipcp(int argc, char ** argv)
+int do_unbind_ipcp(int     argc,
+                   char ** argv)
 {
-        char * ipcp = NULL;
-        char * name = NULL;
-
-        pid_t * pids = NULL;
-        ssize_t len  = 0;
-
-        int i;
+        char *             ipcp = NULL;
+        char *             name = NULL;
+        struct ipcp_info * ipcps;
+        ssize_t            len;
+        ssize_t            i;
 
         while (argc > 0) {
                 if (matches(*argv, "name") == 0) {
@@ -81,17 +82,22 @@ int do_unbind_ipcp(int argc, char ** argv)
                 --argc;
         }
 
-        if (ipcp == NULL) {
+        if (ipcp == NULL || name  == NULL) {
                 usage();
                 return -1;
         }
 
-        len = irm_list_ipcps(ipcp, &pids);
-
+        len = irm_list_ipcps(&ipcps);
         for (i = 0; i < len; ++i)
-                irm_unbind_process(pids[i], name);
+                if (strcmp(ipcps[i].name, ipcp) == 0) {
+                        if (irm_unbind_process(ipcps[i].pid, name)) {
+                                free(ipcps);
+                                return -1;
+                        }
+                        break;
+                }
 
-        free(pids);
+        free(ipcps);
 
         return 0;
 }
diff --git a/src/tools/irm/irm_unregister.c b/src/tools/irm/irm_unregister.c
index 3b16116..637ab10 100644
--- a/src/tools/irm/irm_unregister.c
+++ b/src/tools/irm/irm_unregister.c
@@ -36,31 +36,41 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdio.h>
-#include <string.h>
-
 #include <ouroboros/irm.h>
 
 #include "irm_ops.h"
 #include "irm_utils.h"
 
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define MAX_IPCPS  128
 #define MAX_LAYERS 128
 
 static void usage(void)
 {
         printf("Usage: irm unregister\n"
                "           name <name>\n"
+               "           ipcp <ipcp to register with>\n"
+               "           [ipcp <ipcp to register with>]\n"
+               "           [... (maximum %d ipcps)]\n"
                "           layer <layer to unregister from>\n"
                "           [layer <layer to unregister from>]\n"
                "           [... (maximum %d layers)]\n"
-               , MAX_LAYERS);
+               , MAX_IPCPS, MAX_LAYERS);
 }
 
 int do_unregister(int argc, char ** argv)
 {
-        char * layers[MAX_LAYERS];
-        size_t layers_len = 0;
-        char * name = NULL;
+        char *             name       = NULL;
+        char *             layers[MAX_LAYERS];
+        size_t             layers_len = 0;
+        char *             ipcp[MAX_IPCPS];
+        size_t             ipcp_len   = 0;
+        struct ipcp_info * ipcps;
+        size_t             len;
+        size_t             i;
 
         while (argc > 0) {
                 if (matches(*argv, "name") == 0) {
@@ -71,6 +81,12 @@ int do_unregister(int argc, char ** argv)
                                 printf("Too many layers specified\n");
                                 return -1;
                         }
+                } else if (matches(*argv, "ipcp") == 0) {
+                        ipcp[ipcp_len++] = *(argv + 1);
+                        if (ipcp_len > MAX_IPCPS) {
+                                printf("Too many IPCPs specified\n");
+                                return -1;
+                        }
                 } else {
                         printf("\"%s\" is unknown, try \"irm "
                                "unregister\".\n", *argv);
@@ -81,10 +97,35 @@ int do_unregister(int argc, char ** argv)
                 argv += 2;
         }
 
-        if (layers_len == 0 || name == NULL) {
+        if ((layers_len < 1 && ipcp_len < 1) || name == NULL) {
                 usage();
                 return -1;
         }
 
-        return irm_unreg(name, layers, layers_len);
+        len = irm_list_ipcps(&ipcps);
+        for (i = 0; i < len; ++i) {
+                size_t j;
+                for (j = 0; j < layers_len; j++) {
+                        if (wildcard_match(ipcps[i].layer, layers[j]) == 0) {
+                                if (irm_unreg(ipcps[i].pid, name)) {
+                                        free(ipcps);
+                                        return -1;
+                                }
+                                break;
+                        }
+                }
+                for (j = 0; j < ipcp_len; j++) {
+                        if (wildcard_match(ipcps[i].name, ipcp[j]) == 0) {
+                                if (irm_unreg(ipcps[i].pid, name)) {
+                                        free(ipcps);
+                                        return -1;
+                                }
+                                break;
+                        }
+                }
+        }
+
+        free(ipcps);
+
+        return 0;
 }
diff --git a/src/tools/irm/irm_utils.c b/src/tools/irm/irm_utils.c
index 573eab7..c5ea924 100644
--- a/src/tools/irm/irm_utils.c
+++ b/src/tools/irm/irm_utils.c
@@ -36,9 +36,48 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Wildcard Match code below is derived from software contributed to Berkeley 
by
+ * Guido van Rossum.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * wildcard_match is based on the fnmatch function from POSIX.2.
+ * Implementation based on that one from FreeBSD.
+ */
+
+
 #include <string.h>
-#include <stdbool.h>
-#include <stdlib.h>
 
 #include "irm_utils.h"
 
@@ -52,3 +91,35 @@ int matches(const char * cmd,
 
         return memcmp(pattern, cmd, len);
 }
+
+int wildcard_match(const char * pattern,
+                   const char * string)
+{
+        char c;
+
+        /* For loop? Why not Zoidberg? */
+        for (;;) {
+                switch (c = *pattern++) {
+                case '\0':
+                        return (*string == '\0' ? 0 : -1);
+                case '*':
+                        c = *pattern;
+
+                        if (c == '\0')
+                                return 0;
+
+                        /* General case, use recursion. */
+                        while ((c = *string) != '\0') {
+                                if (!wildcard_match(pattern, string))
+                                        return 0;
+                                ++string;
+                        }
+                        return -1;
+                default:
+                        if (c != *string)
+                                return -1;
+                        string++;
+                        break;
+                }
+        }
+}
diff --git a/src/tools/irm/irm_utils.h b/src/tools/irm/irm_utils.h
index 9f24c4b..03113f1 100644
--- a/src/tools/irm/irm_utils.h
+++ b/src/tools/irm/irm_utils.h
@@ -36,10 +36,53 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Wildcard Match code below is derived from software contributed to Berkeley 
by
+ * Guido van Rossum.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * wildcard_match is based on the fnmatch function from POSIX.2.
+ * Implementation based on that one from FreeBSD.
+ */
+
 #ifndef OUROBOROS_TOOLS_IRM_UTILS_H
 #define OUROBOROS_TOOLS_IRM_UTILS_H
 
 int matches(const char * cmd,
             const char * pattern);
 
+int wildcard_match(const char * pattern,
+                   const char * string);
+
 #endif /* OUROBOROS_TOOLS_IRM_UTILS_H */
-- 
2.16.2


Other related posts: