summaryrefslogtreecommitdiff
path: root/src/ipcpd
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipcpd')
-rw-r--r--src/ipcpd/CMakeLists.txt28
-rw-r--r--src/ipcpd/ipcp-data.c477
-rw-r--r--src/ipcpd/ipcp-data.h91
-rw-r--r--src/ipcpd/ipcp-ops.h59
-rw-r--r--src/ipcpd/ipcp.c195
-rw-r--r--src/ipcpd/ipcp.h48
-rw-r--r--src/ipcpd/normal/CMakeLists.txt32
-rw-r--r--src/ipcpd/normal/dt_const.h (renamed from src/ipcpd/dt_const.h)0
-rw-r--r--src/ipcpd/normal/main.c (renamed from src/ipcpd/main.c)0
-rw-r--r--src/ipcpd/normal/pci.c (renamed from src/ipcpd/pci.c)2
-rw-r--r--src/ipcpd/normal/pci.h (renamed from src/ipcpd/pci.h)0
-rw-r--r--src/ipcpd/normal/shm_pci.c (renamed from src/ipcpd/shm_pci.c)2
-rw-r--r--src/ipcpd/normal/shm_pci.h (renamed from src/ipcpd/shm_pci.h)0
-rw-r--r--src/ipcpd/shim-udp/CMakeLists.txt31
-rw-r--r--src/ipcpd/shim-udp/main.c323
-rw-r--r--src/ipcpd/shim-udp/tests/CMakeLists.txt33
-rw-r--r--src/ipcpd/shim-udp/tests/shim_udp_test.c103
17 files changed, 1399 insertions, 25 deletions
diff --git a/src/ipcpd/CMakeLists.txt b/src/ipcpd/CMakeLists.txt
index bcb5b986..6311e3dc 100644
--- a/src/ipcpd/CMakeLists.txt
+++ b/src/ipcpd/CMakeLists.txt
@@ -1,26 +1,8 @@
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
-include_directories(${CMAKE_SOURCE_DIR}/include)
-include_directories(${CMAKE_BINARY_DIR}/include)
-
-set(SOURCE_FILES
+set(IPCP_SOURCES
# Add source files here
- main.c
- pci.c
- shm_pci.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/ipcp.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/ipcp-data.c
)
-add_executable (ipcpd ${SOURCE_FILES})
-
-target_link_libraries (ipcpd LINK_PUBLIC ouroboros)
-
-include(MacroAddCompileFlags)
-if (CMAKE_BUILD_TYPE MATCHES Debug)
- MACRO_ADD_COMPILE_FLAGS(ipcpd -DCONFIG_OUROBOROS_DEBUG)
-endif (CMAKE_BUILD_TYPE MATCHES Debug)
-
-install(TARGETS ipcpd RUNTIME DESTINATION bin)
-
-# Enable once ipcpd has tests
-# add_subdirectory(tests)
+add_subdirectory(normal)
+add_subdirectory(shim-udp)
diff --git a/src/ipcpd/ipcp-data.c b/src/ipcpd/ipcp-data.c
new file mode 100644
index 00000000..17649b42
--- /dev/null
+++ b/src/ipcpd/ipcp-data.c
@@ -0,0 +1,477 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * IPC process utilities
+ *
+ * Dimitri Staessens <dimitri.staessens@intec.ugent.be>
+ * Sander Vrijders <sander.vrijders@intec.ugent.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "ipcp-data.h"
+#include <ouroboros/flow.h>
+#include <ouroboros/shm_du_map.h>
+#include <ouroboros/list.h>
+#include <ouroboros/utils.h>
+
+#define OUROBOROS_PREFIX "ipcp-utils"
+
+#include <ouroboros/logs.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+struct reg_entry {
+ struct list_head list;
+ char * ap_name;
+ uint32_t reg_ap_id;
+};
+
+struct dir_entry {
+ struct list_head list;
+ char * ap_name;
+ uint64_t addr;
+};
+
+static struct reg_entry * reg_entry_create(const char * ap_name,
+ uint32_t reg_ap_id)
+{
+ struct reg_entry * entry = malloc(sizeof *entry);
+ if (entry == NULL)
+ return NULL;
+
+ entry->reg_ap_id = reg_ap_id;
+ entry->ap_name = strdup(ap_name);
+ if (entry->ap_name == NULL)
+ return NULL;
+
+ return entry;
+}
+
+static void reg_entry_destroy(struct reg_entry * entry)
+{
+ if (entry == NULL)
+ return;
+
+ free(entry->ap_name);
+ free(entry);
+}
+
+static struct dir_entry * dir_entry_create(const char * ap_name,
+ uint64_t addr)
+{
+ struct dir_entry * entry = malloc(sizeof *entry);
+ if (entry == NULL)
+ return NULL;
+
+ entry->addr = addr;
+ entry->ap_name = strdup(ap_name);
+ if (entry->ap_name == NULL)
+ return NULL;
+
+ return entry;
+}
+
+static void dir_entry_destroy(struct dir_entry * entry)
+{
+ if (entry == NULL)
+ return;
+
+ free(entry->ap_name);
+ free(entry);
+}
+
+struct ipcp_data * ipcp_data_create()
+{
+ struct ipcp_data * data = malloc(sizeof *data);
+ if (data == NULL)
+ return NULL;
+
+ data->iname = NULL;
+ data->type = 0;
+ data->dum = NULL;
+
+ return data;
+}
+
+struct ipcp_data * ipcp_data_init(struct ipcp_data * dst,
+ instance_name_t * iname,
+ enum ipcp_type ipcp_type)
+{
+ if (dst == NULL)
+ return NULL;
+
+ dst->iname = instance_name_dup(iname);
+ dst->type = ipcp_type;
+
+ dst->dum = shm_du_map_open();
+ if (dst->dum == NULL)
+ return NULL;
+
+ /* init the lists */
+ INIT_LIST_HEAD(&dst->registry);
+ INIT_LIST_HEAD(&dst->flows);
+ INIT_LIST_HEAD(&dst->directory);
+
+ /* init the mutexes */
+ pthread_mutex_init(&dst->reg_lock, NULL);
+ pthread_mutex_init(&dst->dir_lock, NULL);
+ pthread_mutex_init(&dst->flow_lock, NULL);
+
+ return dst;
+}
+
+static void clear_registry(struct ipcp_data * data)
+{
+ struct list_head * h;
+ struct list_head * t;
+ list_for_each_safe(h, t, &data->registry)
+ reg_entry_destroy(list_entry(h, struct reg_entry, list));
+}
+
+static void clear_directory(struct ipcp_data * data)
+{
+ struct list_head * h;
+ struct list_head * t;
+ list_for_each_safe(h, t, &data->directory)
+ dir_entry_destroy(list_entry(h, struct dir_entry, list));
+}
+
+static void clear_flows(struct ipcp_data * data)
+{
+ struct list_head * h;
+ struct list_head * t;
+ list_for_each_safe(h, t, &data->flows)
+ flow_destroy(list_entry(h, flow_t, list));
+
+}
+
+void ipcp_data_destroy(struct ipcp_data * data)
+{
+ if (data == NULL)
+ return;
+
+ /* FIXME: finish all pending operations here */
+
+ if (data->iname != NULL)
+ instance_name_destroy(data->iname);
+ data->iname = NULL;
+
+ if (data->dum != NULL)
+ shm_du_map_close(data->dum);
+ data->dum = NULL;
+
+ pthread_mutex_lock(&data->reg_lock);
+ pthread_mutex_lock(&data->dir_lock);
+ pthread_mutex_lock(&data->flow_lock);
+
+ /* clear the lists */
+ clear_registry(data);
+ clear_directory(data);
+ clear_flows(data);
+
+ /* no need to unlock, just free the entire thing
+ pthread_mutex_unlock(&data->flow_lock);
+ pthread_mutex_unlock(&data->dir_lock);
+ pthread_mutex_unlock(&data->reg_lock);
+ */
+
+ free(data);
+}
+
+
+
+static struct reg_entry * find_reg_entry_by_name(struct ipcp_data * data,
+ const char * ap_name)
+{
+ struct list_head * h;
+ list_for_each(h, &data->registry) {
+ struct reg_entry * e = list_entry(h, struct reg_entry, list);
+ if (!strcmp(e->ap_name, ap_name))
+ return e;
+ }
+
+ return NULL;
+}
+
+static struct reg_entry * find_reg_entry_by_id(struct ipcp_data * data,
+ uint32_t reg_ap_id)
+{
+ struct list_head * h;
+ list_for_each(h, &data->registry) {
+ struct reg_entry * e = list_entry(h, struct reg_entry, list);
+ if (e->reg_ap_id == reg_ap_id)
+ return e;
+ }
+
+ return NULL;
+}
+
+static struct dir_entry * find_dir_entry(struct ipcp_data * data,
+ const char * ap_name,
+ uint64_t addr)
+{
+ struct list_head * h;
+ list_for_each(h, &data->directory) {
+ struct dir_entry * e = list_entry(h, struct dir_entry, list);
+ if (e->addr == addr && !strcmp(e->ap_name, ap_name))
+ return e;
+ }
+
+ return NULL;
+}
+
+static struct dir_entry * find_dir_entry_any(struct ipcp_data * data,
+ const char * ap_name)
+{
+ struct list_head * h;
+ list_for_each(h, &data->directory) {
+ struct dir_entry * e = list_entry(h, struct dir_entry, list);
+ if (!strcmp(e->ap_name, ap_name))
+ return e;
+ }
+
+ return NULL;
+}
+
+bool ipcp_data_is_in_directory(struct ipcp_data * data,
+ const char * ap_name)
+{
+ return find_dir_entry_any(data, ap_name) != NULL;
+}
+
+int ipcp_data_del_reg_entry(struct ipcp_data * data,
+ uint32_t reg_ap_id)
+{
+ struct reg_entry * e;
+ if (data == NULL)
+ return -1;
+
+ pthread_mutex_lock(&data->reg_lock);
+
+ e = find_reg_entry_by_id(data, reg_ap_id);
+ if (e == NULL) {
+ pthread_mutex_unlock(&data->reg_lock);
+ return 0; /* nothing to do */
+ }
+
+ list_del(&e->list);
+
+ reg_entry_destroy(e);
+
+ pthread_mutex_unlock(&data->reg_lock);
+
+ return 0;
+}
+
+int ipcp_data_del_dir_entry(struct ipcp_data * data,
+ const char * ap_name,
+ uint64_t addr)
+{
+ struct dir_entry * e;
+ if (data == NULL)
+ return -1;
+
+ pthread_mutex_lock(&data->dir_lock);
+
+ e = find_dir_entry(data, ap_name, addr);
+ if (e == NULL) {
+ pthread_mutex_unlock(&data->dir_lock);
+ return 0; /* nothing to do */
+ }
+
+ list_del(&e->list);
+
+ dir_entry_destroy(e);
+
+ pthread_mutex_unlock(&data->dir_lock);
+
+ return 0;
+}
+
+int ipcp_data_add_reg_entry(struct ipcp_data * data,
+ char * ap_name,
+ uint32_t reg_ap_id)
+{
+ struct reg_entry * entry;
+
+ if (data == NULL || ap_name == NULL)
+ return -1;
+
+ pthread_mutex_lock(&data->reg_lock);
+
+ if (find_reg_entry_by_name(data, ap_name) ||
+ find_reg_entry_by_id(data, reg_ap_id)) {
+ pthread_mutex_unlock(&data->reg_lock);
+ return -2;
+ }
+
+ entry = reg_entry_create(ap_name, reg_ap_id);
+ if (entry == NULL) {
+ pthread_mutex_unlock(&data->reg_lock);
+ return -1;
+ }
+
+ list_add(&entry->list,&data->registry);
+
+ pthread_mutex_unlock(&data->reg_lock);
+
+ return 0;
+}
+
+int ipcp_data_add_dir_entry(struct ipcp_data * data,
+ char * ap_name,
+ uint64_t addr)
+{
+ struct dir_entry * entry;
+
+ if (data == NULL || ap_name == NULL)
+ return -1;
+
+ pthread_mutex_lock(&data->dir_lock);
+
+ if (find_dir_entry(data, ap_name, addr) != NULL) {
+ pthread_mutex_unlock(&data->dir_lock);
+ return -2;
+ }
+
+ entry = dir_entry_create(ap_name, addr);
+ if (entry == NULL) {
+ pthread_mutex_unlock(&data->dir_lock);
+ return -1;
+ }
+
+ list_add(&entry->list,&data->directory);
+
+ pthread_mutex_unlock(&data->dir_lock);
+
+ return 0;
+}
+
+bool ipcp_data_is_in_registry(struct ipcp_data * data,
+ const char * ap_name)
+{
+ return find_reg_entry_by_name(data, ap_name) != NULL;
+}
+
+uint32_t ipcp_data_get_reg_ap_id(struct ipcp_data * data,
+ const char * ap_name)
+{
+ struct reg_entry * entry;
+ uint32_t id;
+
+ pthread_mutex_lock(&data->reg_lock);
+
+ entry = find_reg_entry_by_name(data, ap_name);
+
+ if (entry == NULL) {
+ pthread_mutex_unlock(&data->reg_lock);
+ return 0; /* undefined behaviour */
+ }
+
+ id = entry->reg_ap_id;
+
+ pthread_mutex_unlock(&data->reg_lock);
+
+ return id;
+}
+
+const char * ipcp_data_get_reg_ap_name(struct ipcp_data * data,
+ uint32_t reg_ap_id)
+{
+ struct reg_entry * entry;
+ char * name;
+
+ pthread_mutex_lock(&data->reg_lock);
+
+ entry = find_reg_entry_by_id(data, reg_ap_id);
+
+ if (entry == NULL) {
+ pthread_mutex_unlock(&data->reg_lock);
+ return NULL;
+ }
+
+ name = strdup(entry->ap_name);
+ if (name == NULL) {
+ pthread_mutex_unlock(&data->reg_lock);
+ return NULL;
+ }
+
+ pthread_mutex_unlock(&data->reg_lock);
+
+ return name;
+}
+
+uint64_t ipcp_data_get_addr(struct ipcp_data * data,
+ const char * ap_name)
+{
+ struct dir_entry * entry;
+ uint64_t addr;
+
+ pthread_mutex_lock(&data->dir_lock);
+
+ entry = find_dir_entry_any(data, ap_name);
+
+ if (entry == NULL) {
+ pthread_mutex_unlock(&data->dir_lock);
+ return 0; /* undefined behaviour, 0 may be a valid address */
+ }
+
+ addr = entry->addr;
+
+ pthread_mutex_unlock(&data->dir_lock);
+
+ return addr;
+}
+
+static flow_t * find_flow(struct ipcp_data * data,
+ uint32_t port_id)
+{
+ struct list_head * h;
+ list_for_each(h, &data->flows) {
+ flow_t * f = list_entry(h, flow_t, list);
+ if (f->port_id == port_id)
+ return f;
+ }
+
+ return NULL;
+}
+
+bool ipcp_data_has_flow(struct ipcp_data * data,
+ uint32_t port_id)
+{
+ return find_flow(data, port_id) != NULL;
+}
+
+int ipcp_data_add_flow(struct ipcp_data * data,
+ flow_t * flow)
+{
+ if (data == NULL || flow == NULL)
+ return -1;
+
+ pthread_mutex_lock(&data->flow_lock);
+
+ if (ipcp_data_has_flow(data, flow->port_id)) {
+ pthread_mutex_unlock(&data->flow_lock);
+ return -2;
+ }
+
+ list_add(&flow->list,&data->flows);
+
+ pthread_mutex_unlock(&data->flow_lock);
+
+ return 0;
+}
diff --git a/src/ipcpd/ipcp-data.h b/src/ipcpd/ipcp-data.h
new file mode 100644
index 00000000..d51f3730
--- /dev/null
+++ b/src/ipcpd/ipcp-data.h
@@ -0,0 +1,91 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * Utitilies for building IPC processes
+ *
+ * Dimitri Staessens <dimitri.staessens@intec.ugent.be>
+ * Sander Vrijders <sander.vrijders@intec.ugent.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef IPCPD_IPCP_DATA_H
+#define IPCPD_IPCP_DATA_H
+
+#include <ouroboros/common.h>
+#include <ouroboros/instance_name.h>
+#include <ouroboros/list.h>
+#include <ouroboros/flow.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#include "ipcp-ops.h"
+
+struct ipcp_data {
+ instance_name_t * iname;
+ enum ipcp_type type;
+
+ struct shm_du_map * dum;
+
+ struct list_head registry;
+ pthread_mutex_t reg_lock;
+
+ struct list_head flows;
+ pthread_mutex_t flow_lock;
+
+ struct list_head directory;
+ pthread_mutex_t dir_lock;
+
+ pthread_mutex_t lock;
+};
+
+struct ipcp_data * ipcp_data_create();
+struct ipcp_data * ipcp_data_init(struct ipcp_data * dst,
+ instance_name_t * iname,
+ enum ipcp_type ipcp_type);
+void ipcp_data_destroy(struct ipcp_data * data);
+
+int ipcp_data_add_reg_entry(struct ipcp_data * data,
+ char * ap_name,
+ uint32_t reg_ap_id);
+int ipcp_data_del_reg_entry(struct ipcp_data * data,
+ uint32_t reg_ap_id);
+int ipcp_data_add_dir_entry(struct ipcp_data * data,
+ char * ap_name,
+ uint64_t addr);
+int ipcp_data_del_dir_entry(struct ipcp_data * data,
+ const char * ap_name,
+ uint64_t addr);
+bool ipcp_data_is_in_registry(struct ipcp_data * data,
+ const char * ap_name);
+uint32_t ipcp_data_get_reg_ap_id(struct ipcp_data * data,
+ const char * ap_name);
+const char * ipcp_data_get_reg_ap_name(struct ipcp_data * data,
+ uint32_t reg_ap_id);
+bool ipcp_data_is_in_directory(struct ipcp_data * data,
+ const char * ap_name);
+uint64_t ipcp_data_get_addr(struct ipcp_data * data,
+ const char * ap_name);
+bool ipcp_data_has_flow(struct ipcp_data * data,
+ uint32_t port_id);
+bool ipcp_data_has_flow_s(struct ipcp_data * data,
+ uint32_t port_id,
+ enum flow_state state);
+int ipcp_data_add_flow(struct ipcp_data * data,
+ flow_t * flow);
+int ipcp_data_remove_flow(struct ipcp_data * data,
+ uint32_t port_id);
+
+#endif /* IPCPD_IPCP_DATA_H */
diff --git a/src/ipcpd/ipcp-ops.h b/src/ipcpd/ipcp-ops.h
new file mode 100644
index 00000000..69682739
--- /dev/null
+++ b/src/ipcpd/ipcp-ops.h
@@ -0,0 +1,59 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * IPC process ops
+ *
+ * Dimitri Staessens <dimitri.staessens@intec.ugent.be>
+ * Sander Vrijders <sander.vrijders@intec.ugent.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef IPCPD_IPCP_OPS_H
+#define IPCPD_IPCP_OPS_H
+
+#include <ouroboros/common.h>
+#include <ouroboros/dif_config.h>
+#include <sys/types.h>
+
+struct ipcp_ops {
+ int (* ipcp_bootstrap)(struct dif_config * conf);
+ int (* ipcp_enroll)(char * member_name,
+ char * n_1_dif);
+ int (* ipcp_reg)(char ** dif_names,
+ size_t len);
+ int (* ipcp_unreg)(char ** dif_names,
+ size_t len);
+ int (* ipcp_ap_reg)(char * ap_name,
+ uint32_t reg_ap_id);
+ int (* ipcp_ap_unreg)(uint32_t reg_ap_id);
+ int (* ipcp_flow_alloc)(uint32_t port_id,
+ char * dst_ap_name,
+ char * src_ap_name,
+ char * src_ae_name,
+ struct qos_spec * qos);
+ int (* ipcp_flow_alloc_resp)(uint32_t port_id,
+ int result);
+ int (* ipcp_flow_dealloc)(uint32_t port_id);
+
+ /* FIXME: let's see how this will work with the shm_du_map */
+ int (* ipcp_du_write)(uint32_t port_id,
+ size_t map_index);
+
+ int (* ipcp_du_read)(uint32_t port_id,
+ size_t map_index);
+};
+
+#endif /* IPCPD_IPCP_OPS_H */
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c
new file mode 100644
index 00000000..a1276769
--- /dev/null
+++ b/src/ipcpd/ipcp.c
@@ -0,0 +1,195 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * IPC process main loop
+ *
+ * Dimitri Staessens <dimitri.staessens@intec.ugent.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ouroboros/config.h>
+#include <ouroboros/ipcp.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include "ipcp.h"
+
+#define OUROBOROS_PREFIX "ipcpd/ipcp"
+#include <ouroboros/logs.h>
+
+int ipcp_main_loop(struct ipcp * _ipcp)
+{
+ int lsockfd;
+ int sockfd;
+ uint8_t buf[IPCP_MSG_BUF_SIZE];
+
+ ipcp_msg_t * msg;
+ ssize_t count;
+ buffer_t buffer;
+ ipcp_msg_t ret_msg = IPCP_MSG__INIT;
+
+ dif_config_msg_t * conf_msg;
+ struct dif_config conf;
+
+ if (_ipcp == NULL) {
+ LOG_ERR("Invalid ipcp struct.");
+ return 1;
+ }
+
+ sockfd = server_socket_open(ipcp_sock_path(getpid()));
+ if (sockfd < 0) {
+ LOG_ERR("Could not open server socket.");
+ return 1;
+ }
+
+ while (true) {
+ ret_msg.code = IPCP_MSG_CODE__IPCP_REPLY;
+
+ lsockfd = accept(sockfd, 0, 0);
+ if (lsockfd < 0) {
+ LOG_ERR("Cannot accept new connection");
+ break;
+ }
+
+ count = read(lsockfd, buf, IPCP_MSG_BUF_SIZE);
+ if (count <= 0) {
+ LOG_ERR("Failed to read from socket");
+ close(lsockfd);
+ continue;
+ }
+
+ msg = ipcp_msg__unpack(NULL, count, buf);
+ if (msg == NULL) {
+ close(lsockfd);
+ continue;
+ }
+
+ switch (msg->code) {
+ case IPCP_MSG_CODE__IPCP_BOOTSTRAP:
+ conf_msg = msg->conf;
+ conf.type = conf_msg->ipcp_type;
+ if (conf_msg->ipcp_type == IPCP_NORMAL) {
+ conf.addr_size = conf_msg->addr_size;
+ conf.cep_id_size = conf_msg->cep_id_size;
+ conf.pdu_length_size
+ = conf_msg->pdu_length_size;
+ conf.qos_id_size = conf_msg->qos_id_size;
+ conf.seqno_size = conf_msg->seqno_size;
+ conf.ttl_size = conf_msg->seqno_size;
+ conf.chk_size = conf_msg->chk_size;
+ conf.min_pdu_size = conf_msg->min_pdu_size;
+ conf.max_pdu_size = conf_msg->max_pdu_size;
+ }
+ if (conf_msg->ipcp_type == IPCP_SHIM_UDP) {
+ conf.ip_addr = conf_msg->ip_addr;
+ conf.dns_addr = conf_msg->dns_addr;
+ }
+
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_bootstrap(&conf);
+ break;
+ case IPCP_MSG_CODE__IPCP_ENROLL:
+ if (_ipcp->ops->ipcp_enroll == NULL) {
+ LOG_ERR("ipcp_enroll unsupported.");
+ } else {
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_enroll(
+ msg->member_name, msg->n_1_dif);
+ }
+ break;
+
+ case IPCP_MSG_CODE__IPCP_REG:
+ if (_ipcp->ops->ipcp_reg == NULL) {
+ LOG_ERR("ipcp_reg unsupported.");
+
+ } else {
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_reg(
+ msg->dif_names, msg->len);
+ }
+ break;
+ case IPCP_MSG_CODE__IPCP_UNREG:
+ if (_ipcp->ops->ipcp_unreg == NULL) {
+ LOG_ERR("ipcp_unreg unsupported.");
+
+ } else {
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_unreg(
+ msg->dif_names, msg->len);
+ }
+ break;
+ case IPCP_MSG_CODE__IPCP_AP_REG:
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_ap_reg(
+ msg->ap_name, msg->reg_ap_id);
+ break;
+ case IPCP_MSG_CODE__IPCP_AP_UNREG:
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_ap_unreg(
+ msg->reg_ap_id);
+ break;
+ case IPCP_MSG_CODE__IPCP_FLOW_ALLOC:
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_flow_alloc(
+ msg->port_id,
+ msg->dst_ap_name,
+ msg->ap_name,
+ msg->ae_name,
+ NULL);
+ break;
+ case IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP:
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_flow_alloc_resp(
+ msg->port_id, msg->result);
+ break;
+ case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
+ ret_msg.has_result = true;
+ ret_msg.result = _ipcp->ops->ipcp_flow_dealloc(
+ msg->port_id);
+ break;
+ default:
+ LOG_ERR("Don't know that message code");
+ break;
+ }
+
+ ipcp_msg__free_unpacked(msg, NULL);
+
+ buffer.size = ipcp_msg__get_packed_size(&ret_msg);
+ if (buffer.size == 0) {
+ LOG_ERR("Failed to send reply message");
+ close(lsockfd);
+ continue;
+ }
+
+ buffer.data = malloc(buffer.size);
+ if (buffer.data == NULL) {
+ close(lsockfd);
+ continue;
+ }
+
+ ipcp_msg__pack(&ret_msg, buffer.data);
+
+ if (write(lsockfd, buffer.data, buffer.size) == -1) {
+ free(buffer.data);
+ close(lsockfd);
+ continue;
+ }
+
+ free(buffer.data);
+ close(lsockfd);
+ }
+
+ return 0;
+}
diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h
new file mode 100644
index 00000000..d6ddeb43
--- /dev/null
+++ b/src/ipcpd/ipcp.h
@@ -0,0 +1,48 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * IPC process structure
+ *
+ * Dimitri Staessens <dimitri.staessens@intec.ugent.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef IPCPD_IPCP_H
+#define IPCPD_IPCP_H
+
+#include "ipcp-ops.h"
+#include "ipcp-data.h"
+
+enum ipcp_state {
+ IPCP_INIT = 0,
+ IPCP_ENROLLING,
+ IPCP_BOOTSTRAPPING,
+ IPCP_ENROLLED,
+ IPCP_DISCONNECTED,
+ IPCP_SHUTDOWN
+};
+
+struct ipcp {
+ struct ipcp_data * data;
+ struct ipcp_ops * ops;
+
+ enum ipcp_state state;
+ int irmd_fd;
+};
+
+int ipcp_main_loop();
+
+#endif
diff --git a/src/ipcpd/normal/CMakeLists.txt b/src/ipcpd/normal/CMakeLists.txt
new file mode 100644
index 00000000..c13cbaa3
--- /dev/null
+++ b/src/ipcpd/normal/CMakeLists.txt
@@ -0,0 +1,32 @@
+get_filename_component(CURRENT_SOURCE_PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
+get_filename_component(CURRENT_BINARY_PARENT_DIR ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${CURRENT_SOURCE_PARENT_DIR})
+include_directories(${CURRENT_BINARY_PARENT_DIR})
+
+include_directories(${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+SET(IPCP_NORMAL_TARGET ipcpd-normal CACHE STRING "IPCP_NORMAL_TARGET")
+
+set(SOURCE_FILES
+ # Add source files here
+ main.c
+ pci.c
+)
+
+add_executable (ipcpd-normal ${SOURCE_FILES} ${IPCP_SOURCES})
+target_link_libraries (ipcpd-normal LINK_PUBLIC ouroboros)
+
+include(MacroAddCompileFlags)
+if (CMAKE_BUILD_TYPE MATCHES Debug)
+ MACRO_ADD_COMPILE_FLAGS(ipcpd-normal -DCONFIG_OUROBOROS_DEBUG)
+endif (CMAKE_BUILD_TYPE MATCHES Debug)
+
+install(TARGETS ipcpd-normal RUNTIME DESTINATION bin)
+
+# Enable once ipcp-normal has tests
+# add_subdirectory(tests)
diff --git a/src/ipcpd/dt_const.h b/src/ipcpd/normal/dt_const.h
index bc0c1466..bc0c1466 100644
--- a/src/ipcpd/dt_const.h
+++ b/src/ipcpd/normal/dt_const.h
diff --git a/src/ipcpd/main.c b/src/ipcpd/normal/main.c
index 7ffd1c48..7ffd1c48 100644
--- a/src/ipcpd/main.c
+++ b/src/ipcpd/normal/main.c
diff --git a/src/ipcpd/pci.c b/src/ipcpd/normal/pci.c
index 548e40e2..d7df52b6 100644
--- a/src/ipcpd/pci.c
+++ b/src/ipcpd/normal/pci.c
@@ -22,7 +22,7 @@
*/
#include "pci.h"
-#include <malloc.h>
+#include <stdlib.h>
#include <errno.h>
#define OUROBOROS_PREFIX "ipcp/pci"
diff --git a/src/ipcpd/pci.h b/src/ipcpd/normal/pci.h
index 3c011723..3c011723 100644
--- a/src/ipcpd/pci.h
+++ b/src/ipcpd/normal/pci.h
diff --git a/src/ipcpd/shm_pci.c b/src/ipcpd/normal/shm_pci.c
index d44e0e8f..e76d8009 100644
--- a/src/ipcpd/shm_pci.c
+++ b/src/ipcpd/normal/shm_pci.c
@@ -22,7 +22,7 @@
*/
#include "shm_pci.h"
-#include <malloc.h>
+#include <stdlib.h>
#include <errno.h>
#define SHM_PCI_HEAD_SIZE(a, b) a.addr_size * 2 + \
diff --git a/src/ipcpd/shm_pci.h b/src/ipcpd/normal/shm_pci.h
index cb8dd5dd..cb8dd5dd 100644
--- a/src/ipcpd/shm_pci.h
+++ b/src/ipcpd/normal/shm_pci.h
diff --git a/src/ipcpd/shim-udp/CMakeLists.txt b/src/ipcpd/shim-udp/CMakeLists.txt
new file mode 100644
index 00000000..27907880
--- /dev/null
+++ b/src/ipcpd/shim-udp/CMakeLists.txt
@@ -0,0 +1,31 @@
+get_filename_component(CURRENT_SOURCE_PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
+get_filename_component(CURRENT_BINARY_PARENT_DIR ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${CURRENT_SOURCE_PARENT_DIR})
+include_directories(${CURRENT_BINARY_PARENT_DIR})
+
+include_directories(${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+SET(IPCP_SHIM_UDP_TARGET ipcpd-shim-udp CACHE STRING "IPCP_SHIM_UDP_TARGET")
+
+set(SHIM_UDP_SOURCES
+ # Add source files here
+ ${CMAKE_CURRENT_SOURCE_DIR}/main.c
+)
+
+add_executable (ipcpd-shim-udp ${SHIM_UDP_SOURCES} ${IPCP_SOURCES})
+target_link_libraries (ipcpd-shim-udp LINK_PUBLIC ouroboros)
+
+include(MacroAddCompileFlags)
+if (CMAKE_BUILD_TYPE MATCHES Debug)
+ MACRO_ADD_COMPILE_FLAGS(ipcpd-shim-udp -DCONFIG_OUROBOROS_DEBUG)
+endif (CMAKE_BUILD_TYPE MATCHES Debug)
+
+install(TARGETS ipcpd-shim-udp RUNTIME DESTINATION bin)
+
+# Enable once ipcp-shim-udp has tests
+add_subdirectory(tests)
diff --git a/src/ipcpd/shim-udp/main.c b/src/ipcpd/shim-udp/main.c
new file mode 100644
index 00000000..1fb12dc0
--- /dev/null
+++ b/src/ipcpd/shim-udp/main.c
@@ -0,0 +1,323 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * Shim IPC process over UDP
+ *
+ * Dimitri Staessens <dimitri.staessens@intec.ugent.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ouroboros/config.h>
+
+#include "ipcp.h"
+#include <ouroboros/shm_du_map.h>
+#include <ouroboros/list.h>
+#include <ouroboros/flow.h>
+#include <ouroboros/utils.h>
+#include <ouroboros/ipcp.h>
+#include <ouroboros/dif_config.h>
+
+#define OUROBOROS_PREFIX "ipcpd/shim-udp"
+
+#include <ouroboros/logs.h>
+
+#include <string.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define THIS_TYPE IPCP_SHIM_UDP
+
+#define shim_data(type) ((struct ipcp_udp_data *) type->data)
+
+/* global for trapping signal */
+int irmd_pid;
+
+/* this IPCP's data */
+#ifdef MAKE_CHECK
+extern struct ipcp * _ipcp; /* defined in test */
+#else
+struct ipcp * _ipcp;
+#endif
+
+struct ipcp_udp_data {
+ /* IPCP_DATA STRUCT MUST BE FIRST!! */
+ struct ipcp_data ipcp_data;
+
+ uint32_t ip_addr;
+ uint32_t dns_addr;
+
+ pthread_mutex_t lock;
+};
+
+struct udp_flow {
+ /* FLOW MUST BE FIRST !!!! */
+ flow_t flow;
+
+ uint16_t localport;
+
+ struct sockaddr_in * remote;
+ int fd;
+};
+
+void ipcp_sig_handler(int sig, siginfo_t * info, void * c)
+{
+ switch(sig) {
+ case SIGINT:
+ case SIGTERM:
+ case SIGHUP:
+ LOG_DBG("Terminating by order of %d. Bye.", info->si_pid);
+ if (info->si_pid == irmd_pid) {
+ shm_du_map_close(_ipcp->data->dum);
+ exit(0);
+ }
+ default:
+ return;
+ }
+}
+
+struct ipcp_udp_data * ipcp_udp_data_create(char * ap_name,
+ char * ap_id)
+{
+ struct ipcp_udp_data * udp_data;
+ struct ipcp_data * data;
+ instance_name_t * instance_name;
+ enum ipcp_type ipcp_type;
+
+ instance_name = instance_name_create();
+ if (instance_name == NULL) {
+ LOG_ERR("Failed to create instance name struct.");
+ return NULL;
+ }
+
+ instance_name = instance_name_init_with(
+ instance_name, ap_name, (uint16_t)atoi(ap_id));
+
+ if (instance_name == NULL) {
+ LOG_ERR("Failed to create instance name struct.");
+ return NULL;
+ }
+
+ udp_data= malloc (sizeof *udp_data);
+ if (udp_data == NULL) {
+ LOG_DBGF("Failed to allocate.");
+ return NULL;
+ }
+
+ ipcp_type = THIS_TYPE;
+ data = (struct ipcp_data *) udp_data;
+ if (ipcp_data_init(data, instance_name, ipcp_type) == NULL) {
+ free(udp_data);
+ return NULL;
+ }
+
+ return udp_data;
+}
+
+int ipcp_udp_bootstrap(struct dif_config * conf)
+{
+ char ipstr[INET_ADDRSTRLEN];
+ char dnsstr[INET_ADDRSTRLEN];
+
+ if (conf->type != THIS_TYPE) {
+ LOG_ERR("Config doesn't match IPCP type.");
+ return -1;
+ }
+
+ if (_ipcp->state != IPCP_INIT) {
+ LOG_ERR("IPCP in wrong state.");
+ return -1;
+ }
+
+ inet_ntop(AF_INET,
+ &conf->ip_addr,
+ ipstr,
+ INET_ADDRSTRLEN);
+
+ if (conf->dns_addr != 0)
+ inet_ntop(AF_INET,
+ &conf->dns_addr,
+ dnsstr,
+ INET_ADDRSTRLEN);
+ else
+ strcpy(dnsstr, "not set");
+
+ shim_data(_ipcp)->ip_addr = conf->ip_addr;
+ shim_data(_ipcp)->dns_addr = conf->dns_addr;
+
+ _ipcp->state = IPCP_ENROLLED;
+
+ LOG_DBG("Bootstrapped shim IPCP over UDP %s-%d.",
+ _ipcp->data->iname->name, _ipcp->data->iname->id);
+
+ LOG_DBG("Bound to IP address %s.", ipstr);
+ LOG_DBG("DNS server address is %s.", dnsstr);
+
+ return 0;
+}
+
+int ipcp_udp_ap_reg(char * ap_name, uint32_t reg_ap_id)
+{
+ LOG_DBG("Registering local ap %s, %u.", ap_name, reg_ap_id);
+
+ if (_ipcp->state != IPCP_ENROLLED) {
+ LOG_DBGF("Won't register with non-enrolled IPCP.");
+ return -1;
+ }
+
+ if (ipcp_data_add_reg_entry(_ipcp->data, ap_name, reg_ap_id)) {
+ LOG_ERR("Failed to add AP to local registry.");
+ return -1;
+ }
+
+ LOG_MISSING;
+
+ return 0;
+}
+
+int ipcp_udp_ap_unreg(uint32_t reg_ap_id)
+{
+ char * name = strdup(ipcp_data_get_reg_ap_name(_ipcp->data,
+ reg_ap_id));
+ LOG_DBG("Unregistering %s.", name);
+
+ ipcp_data_del_reg_entry(_ipcp->data, reg_ap_id);
+
+ /* we are using dns */
+ LOG_MISSING;
+
+ free (name);
+
+ return 0;
+}
+
+int ipcp_udp_flow_alloc(uint32_t port_id,
+ char * dst_ap_name,
+ char * src_ap_name,
+ char * src_ae_name,
+ struct qos_spec * qos)
+{
+ return 0;
+}
+int ipcp_udp_flow_alloc_resp(uint32_t port_id,
+ int result)
+{
+ return 0;
+}
+
+int ipcp_udp_flow_dealloc(uint32_t port_id)
+{
+ return 0;
+}
+
+int ipcp_udp_du_write(uint32_t port_id,
+ size_t map_index)
+{
+ return 0;
+}
+
+int ipcp_udp_du_read(uint32_t port_id,
+ size_t map_index)
+{
+ return 0;
+}
+
+struct ipcp * ipcp_udp_create(char * ap_name, char * i_id)
+{
+ struct ipcp * i;
+ struct ipcp_udp_data * data;
+ struct ipcp_ops * ops;
+
+ i = malloc(sizeof *i);
+ if (i == NULL)
+ return NULL;
+
+ data = ipcp_udp_data_create(ap_name, i_id);
+ if (data == NULL) {
+ free(i);
+ return NULL;
+ }
+
+ ops = malloc (sizeof *ops);
+ if (ops == NULL) {
+ free(data);
+ free(i);
+ return NULL;
+ }
+
+ ops->ipcp_bootstrap = ipcp_udp_bootstrap;
+ ops->ipcp_enroll = NULL; /* shim */
+ ops->ipcp_reg = NULL; /* shim */
+ ops->ipcp_unreg = NULL; /* shim */
+ ops->ipcp_ap_reg = ipcp_udp_ap_reg;
+ ops->ipcp_ap_unreg = ipcp_udp_ap_unreg;
+ ops->ipcp_flow_alloc = ipcp_udp_flow_alloc;
+ ops->ipcp_flow_alloc_resp = ipcp_udp_flow_alloc_resp;
+ ops->ipcp_flow_dealloc = ipcp_udp_flow_dealloc;
+ ops->ipcp_du_read = ipcp_udp_du_read;
+ ops->ipcp_du_write = ipcp_udp_du_write;
+
+ i->data = (struct ipcp_data *) data;
+ i->ops = ops;
+
+ i->state = IPCP_INIT;
+
+ return i;
+}
+
+#ifndef MAKE_CHECK
+
+int main (int argc, char * argv[])
+{
+ /* argument 1: pid of irmd ? */
+ /* argument 2: ap name */
+ /* argument 3: instance id */
+ struct sigaction sig_act;
+
+ /* FIXME: clean up argument checks */
+ if (argc != 4)
+ LOG_ERR("Wrong arguments passed.");
+
+ /* store the process id of the irmd */
+ irmd_pid = atoi(argv[1]);
+
+ /* init sig_act */
+ memset (&sig_act, 0, sizeof sig_act);
+
+ /* install signal traps */
+ sig_act.sa_sigaction = &ipcp_sig_handler;
+ sig_act.sa_flags = SA_SIGINFO;
+
+ sigaction(SIGINT, &sig_act, NULL);
+ sigaction(SIGTERM, &sig_act, NULL);
+ sigaction(SIGHUP, &sig_act, NULL);
+
+ _ipcp = ipcp_udp_create(argv[2], argv[3]);
+ if (_ipcp == NULL) {
+ LOG_ERR("Won't.");
+ exit(1);
+ }
+
+ ipcp_main_loop(_ipcp);
+
+ exit(0);
+}
+
+#endif /* MAKE_CHECK */
diff --git a/src/ipcpd/shim-udp/tests/CMakeLists.txt b/src/ipcpd/shim-udp/tests/CMakeLists.txt
new file mode 100644
index 00000000..bdd7defb
--- /dev/null
+++ b/src/ipcpd/shim-udp/tests/CMakeLists.txt
@@ -0,0 +1,33 @@
+get_filename_component(PARENT_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
+get_filename_component(PARENT_BINARY_PATH ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY)
+get_filename_component(PARENT_DIR ${PARENT_SOURCE_PATH} NAME)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${PARENT_SOURCE_PATH})
+include_directories(${PARENT_BINARY_PATH})
+
+include_directories(${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+create_test_sourcelist(${PARENT_DIR}_tests test_suite.c
+ # Add new tests here
+ shim_udp_test.c
+)
+
+add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${IPCP_SOURCES} ${${PARENT_DIR}_tests})
+target_link_libraries(${PARENT_DIR}_test ouroboros)
+
+include(MacroAddCompileFlags)
+MACRO_ADD_COMPILE_FLAGS(${PARENT_DIR}_test -DMAKE_CHECK)
+
+add_dependencies(check ${PARENT_DIR}_test)
+
+set(tests_to_run ${${PARENT_DIR}_tests})
+remove(tests_to_run test_suite.c)
+
+foreach(test ${tests_to_run})
+ get_filename_component(test_name ${test} NAME_WE)
+ add_test(${test_name} ${C_TEST_PATH}/${PARENT_DIR}_test ${test_name})
+endforeach(test)
diff --git a/src/ipcpd/shim-udp/tests/shim_udp_test.c b/src/ipcpd/shim-udp/tests/shim_udp_test.c
new file mode 100644
index 00000000..427d0e1e
--- /dev/null
+++ b/src/ipcpd/shim-udp/tests/shim_udp_test.c
@@ -0,0 +1,103 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * Test of the Shim UDP IPCP Daemon
+ *
+ * Dimitri Staessens <dimitri.staessens@intec.ugent.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ouroboros/config.h>
+#include <ouroboros/dif_config.h>
+#include <ouroboros/utils.h>
+#include <ouroboros/shm_du_map.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include "main.c"
+
+#include <ouroboros/logs.h>
+
+struct ipcp * _ipcp;
+
+int shim_udp_test(int argc, char ** argv)
+{
+ /* argument 1: pid of irmd ? */
+ /* argument 2: ap name */
+ /* argument 3: instance id */
+ struct shm_du_map * dum;
+ char * ipcp_name = "test-shim-ipcp";
+ char * i_id = "1";
+ int i = 0;
+
+ char bogus[15];
+ memset (&bogus, 0, 15);
+
+ struct dif_config conf;
+ memset (&conf, 0, sizeof conf);
+ conf.dif_name = strdup("test-dif");
+ conf.type = IPCP_SHIM_UDP;
+ conf.ip_addr = 0;
+
+ dum = shm_du_map_create();
+ if (dum == NULL) {
+ LOG_ERR("Failed to create shared memory.");
+ exit(1);
+ }
+
+ _ipcp = ipcp_udp_create(ipcp_name, i_id);
+ if (_ipcp == NULL) {
+ LOG_ERR("Could not instantiate shim IPCP.");
+ shm_du_map_close(dum);
+ exit(1);
+ }
+
+ if (ipcp_udp_bootstrap (&conf)) {
+ LOG_ERR("Could not bootstrap.");
+ }
+
+ if(ipcp_udp_ap_reg("bogus ap", 1865)) {
+ LOG_ERR("Failed to register application.");
+ shm_du_map_close(dum);
+ exit(1);
+ }
+
+ if (ipcp_udp_ap_unreg(1865)) {
+ LOG_ERR("Failed to unregister application.");
+ shm_du_map_close(dum);
+ exit(1);
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ sprintf (bogus, "bogus ap %4d", i);
+ if(ipcp_udp_ap_reg(bogus, i)) {
+ LOG_ERR("Failed to register application %s.", bogus);
+ shm_du_map_close(dum);
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ if(ipcp_udp_ap_unreg(i)) {
+ LOG_ERR("Failed to unregister application %d.", i);
+ shm_du_map_close(dum);
+ exit(1);
+ }
+ }
+
+ shm_du_map_close(dum);
+
+ exit(0);
+}