Просмотр исходного кода

ncd: Improve interface module interface. Support routes without a gateway. NCDIfConfig: add functions for creating and removing TUN/TAP devices.

ambrop7 15 лет назад
Родитель
Сommit
501ea0f98b
7 измененных файлов с 402 добавлено и 164 удалено
  1. 1 0
      ncd/CMakeLists.txt
  2. 96 17
      ncd/NCDIfConfig.c
  3. 5 2
      ncd/NCDIfConfig.h
  4. 152 0
      ncd/NCDInterfaceModule.c
  5. 35 39
      ncd/NCDInterfaceModule.h
  6. 36 58
      ncd/interface_modules/interface_physical.c
  7. 77 48
      ncd/ncd.c

+ 1 - 0
ncd/CMakeLists.txt

@@ -2,6 +2,7 @@ add_executable(badvpn-ncd
     ncd.c
     NCDIfConfig.c
     NCDInterfaceMonitor.c
+    NCDInterfaceModule.c
     interface_modules/interface_physical.c
 )
 target_link_libraries(badvpn-ncd system dhcpclient ncdconfig)

+ 96 - 17
ncd/NCDIfConfig.c

@@ -29,7 +29,11 @@
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <sys/ioctl.h>
-
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/if_tun.h>
+  
 #include <misc/debug.h>
 #include <system/BLog.h>
 
@@ -140,34 +144,36 @@ int NCDIfConfig_remove_ipv4_addr (const char *ifname, struct ipv4_ifaddr ifaddr)
     return !run_command(cmd);
 }
 
-int NCDIfConfig_add_ipv4_route (struct ipv4_ifaddr dest, uint32_t gateway, int metric, const char *device)
+static int route_cmd (const char *cmdtype, struct ipv4_ifaddr dest, const uint32_t *gateway, int metric, const char *device)
 {
     ASSERT(dest.prefix >= 0)
     ASSERT(dest.prefix <= 32)
     
     uint8_t *d_addr = (uint8_t *)&dest.addr;
-    uint8_t *g_addr = (uint8_t *)&gateway;
+    
+    char gwstr[60];
+    if (gateway) {
+        const uint8_t *g_addr = (uint8_t *)gateway;
+        sprintf(gwstr, " gw %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, g_addr[0], g_addr[1], g_addr[2], g_addr[3]);
+    } else {
+        sprintf(gwstr, "");
+    }
     
     char cmd[100];
-    sprintf(cmd, ROUTE_CMD" add -net %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8"/%d gw %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8" metric %d dev %s",
-            d_addr[0], d_addr[1], d_addr[2], d_addr[3], dest.prefix, g_addr[0], g_addr[1], g_addr[2], g_addr[3], metric, device);
+    sprintf(cmd, ROUTE_CMD" %s -net %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8"/%d%s metric %d dev %s",
+            cmdtype, d_addr[0], d_addr[1], d_addr[2], d_addr[3], dest.prefix, gwstr, metric, device);
     
     return !run_command(cmd);
 }
 
-int NCDIfConfig_remove_ipv4_route (struct ipv4_ifaddr dest, uint32_t gateway, int metric, const char *device)
+int NCDIfConfig_add_ipv4_route (struct ipv4_ifaddr dest, const uint32_t *gateway, int metric, const char *device)
 {
-    ASSERT(dest.prefix >= 0)
-    ASSERT(dest.prefix <= 32)
-    
-    uint8_t *d_addr = (uint8_t *)&dest.addr;
-    uint8_t *g_addr = (uint8_t *)&gateway;
-    
-    char cmd[100];
-    sprintf(cmd, ROUTE_CMD" del -net %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8"/%d gw %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8" metric %d dev %s",
-            d_addr[0], d_addr[1], d_addr[2], d_addr[3], dest.prefix, g_addr[0], g_addr[1], g_addr[2], g_addr[3], metric, device);
-    
-    return !run_command(cmd);
+    return route_cmd("add", dest, gateway, metric, device);
+}
+
+int NCDIfConfig_remove_ipv4_route (struct ipv4_ifaddr dest, const uint32_t *gateway, int metric, const char *device)
+{
+    return route_cmd("del", dest, gateway, metric, device);
 }
 
 int NCDIfConfig_set_dns_servers (uint32_t *servers, size_t num_servers)
@@ -213,3 +219,76 @@ fail1:
 fail0:
     return 0;
 }
+
+static int open_tuntap (const char *ifname, int flags)
+{
+    int fd = open("/dev/net/tun", O_RDWR);
+    if (fd < 0) {
+         BLog(BLOG_ERROR, "open tun failed");
+         return -1;
+    }
+    
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = flags;
+    snprintf(ifr.ifr_name, IFNAMSIZ, "%s", ifname);
+    
+    if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
+        BLog(BLOG_ERROR, "TUNSETIFF failed");
+        close(fd);
+        return -1;
+    }
+    
+    return fd;
+}
+
+int NCDIfConfig_make_tuntap (const char *ifname, const char *owner, int tun)
+{
+    int fd;
+    if ((fd = open_tuntap(ifname, (tun ? IFF_TUN : IFF_TAP))) < 0) {
+        goto fail0;
+    }
+    
+    if (owner) {
+        if (ioctl(fd, TUNSETOWNER, owner) < 0) {
+            BLog(BLOG_ERROR, "TUNSETOWNER failed");
+            goto fail1;
+        }
+    }
+    
+    if (ioctl(fd, TUNSETPERSIST, (void *)1) < 0) {
+        BLog(BLOG_ERROR, "TUNSETPERSIST failed");
+        goto fail1;
+    }
+    
+    close(fd);
+    
+    return 1;
+    
+fail1:
+    close(fd);
+fail0:
+    return 0;
+}
+
+int NCDIfConfig_remove_tuntap (const char *ifname, int tun)
+{
+    int fd;
+    if ((fd = open_tuntap(ifname, (tun ? IFF_TUN : IFF_TAP))) < 0) {
+        goto fail0;
+    }
+    
+    if (ioctl(fd, TUNSETPERSIST, (void *)0) < 0) {
+        BLog(BLOG_ERROR, "TUNSETPERSIST failed");
+        goto fail1;
+    }
+    
+    close(fd);
+    
+    return 1;
+    
+fail1:
+    close(fd);
+fail0:
+    return 0;
+}

+ 5 - 2
ncd/NCDIfConfig.h

@@ -39,9 +39,12 @@ int NCDIfConfig_set_down (const char *ifname);
 int NCDIfConfig_add_ipv4_addr (const char *ifname, struct ipv4_ifaddr ifaddr);
 int NCDIfConfig_remove_ipv4_addr (const char *ifname, struct ipv4_ifaddr ifaddr);
 
-int NCDIfConfig_add_ipv4_route (struct ipv4_ifaddr dest, uint32_t gateway, int metric, const char *device);
-int NCDIfConfig_remove_ipv4_route (struct ipv4_ifaddr dest, uint32_t gateway, int metric, const char *device);
+int NCDIfConfig_add_ipv4_route (struct ipv4_ifaddr dest, const uint32_t *gateway, int metric, const char *device);
+int NCDIfConfig_remove_ipv4_route (struct ipv4_ifaddr dest, const uint32_t *gateway, int metric, const char *device);
 
 int NCDIfConfig_set_dns_servers (uint32_t *servers, size_t num_servers);
 
+int NCDIfConfig_make_tuntap (const char *ifname, const char *owner, int tun);
+int NCDIfConfig_remove_tuntap (const char *ifname, int tun);
+
 #endif

+ 152 - 0
ncd/NCDInterfaceModule.c

@@ -0,0 +1,152 @@
+/**
+ * @file NCDInterfaceModule.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <ncd/NCDInterfaceModule.h>
+
+static void event_job_handler (NCDInterfaceModuleInst *n)
+{
+    DebugObject_Access(&n->d_obj);
+    
+    n->handler_event(n->user, (n->up ? NCDINTERFACEMODULE_EVENT_UP : NCDINTERFACEMODULE_EVENT_DOWN));
+    return;
+}
+
+static void finish_job_handler (NCDInterfaceModuleInst *n)
+{
+    ASSERT(n->finishing)
+    DebugObject_Access(&n->d_obj);
+    
+    n->m->func_finish(n->inst_user);
+    return;
+}
+
+int NCDInterfaceModuleInst_Init (
+    NCDInterfaceModuleInst *n, const struct NCDInterfaceModule *m, BReactor *reactor, BProcessManager *manager,
+    struct NCDConfig_interfaces *conf, NCDInterfaceModule_handler_event handler_event,
+    NCDInterfaceModule_handler_error handler_error,
+    void *user
+)
+{
+    // init arguments
+    n->m = m;
+    n->reactor = reactor;
+    n->manager = manager;
+    n->conf = conf;
+    n->handler_event = handler_event;
+    n->handler_error = handler_error;
+    n->user = user;
+    
+    // init event job
+    BPending_Init(&n->event_job, BReactor_PendingGroup(n->reactor), (BPending_handler)event_job_handler, n);
+    
+    // init finish job
+    BPending_Init(&n->finish_job, BReactor_PendingGroup(n->reactor), (BPending_handler)finish_job_handler, n);
+    
+    // set not up
+    n->up = 0;
+    
+    // set not finishing
+    n->finishing = 0;
+    
+    // init backend
+    if (!(n->inst_user = n->m->func_new(n))) {
+        goto fail1;
+    }
+    
+    DebugObject_Init(&n->d_obj);
+    #ifndef NDEBUG
+    DEAD_INIT(n->d_dead);
+    #endif
+    
+    return 1;
+    
+fail1:
+    BPending_Free(&n->finish_job);
+    BPending_Free(&n->event_job);
+    return 0;
+}
+
+void NCDInterfaceModuleInst_Free (NCDInterfaceModuleInst *n)
+{
+    DebugObject_Free(&n->d_obj);
+    #ifndef NDEBUG
+    DEAD_KILL(n->d_dead);
+    #endif
+    
+    // free backend
+    n->m->func_free(n->inst_user);
+    
+    // free finish job
+    BPending_Free(&n->finish_job);
+    
+    // free event job
+    BPending_Free(&n->event_job);
+}
+
+void NCDInterfaceModuleInst_Finish (NCDInterfaceModuleInst *n)
+{
+    ASSERT(!n->finishing)
+    DebugObject_Access(&n->d_obj);
+    
+    // set finishing
+    n->finishing = 1;
+    
+    // set job
+    BPending_Set(&n->finish_job);
+}
+
+void NCDInterfaceModuleInst_Backend_Event (NCDInterfaceModuleInst *n, int event)
+{
+    ASSERT(event == NCDINTERFACEMODULE_EVENT_UP || event == NCDINTERFACEMODULE_EVENT_DOWN)
+    ASSERT((event == NCDINTERFACEMODULE_EVENT_UP) == !n->up)
+    ASSERT(!BPending_IsSet(&n->event_job))
+    ASSERT(!n->finishing)
+    
+    // change up state
+    n->up = !n->up;
+    
+    // set job
+    BPending_Set(&n->event_job);
+}
+
+void NCDInterfaceModuleInst_Backend_Error (NCDInterfaceModuleInst *n)
+{
+    #ifndef NDEBUG
+    DEAD_ENTER(n->d_dead)
+    #endif
+    
+    n->handler_error(n->user);
+    
+    #ifndef NDEBUG
+    ASSERT(DEAD_KILLED)
+    DEAD_LEAVE(n->d_dead);
+    #endif
+}
+
+void NCDInterfaceModuleInst_Backend_Log (NCDInterfaceModuleInst *n, int level, const char *fmt, ...)
+{
+    va_list vl;
+    va_start(vl, fmt);
+    BLog_Append("interface %s: module: ", n->conf->name);
+    BLog_LogToChannelVarArg(BLOG_CURRENT_CHANNEL, level, fmt, vl);
+    va_end(vl);
+}

+ 35 - 39
ncd/NCDInterfaceModule.h

@@ -27,64 +27,60 @@
 
 #include <system/BReactor.h>
 #include <system/BLog.h>
+#include <system/BProcess.h>
+#include <system/BPending.h>
 #include <ncdconfig/NCDConfig.h>
 
 #include <generated/blog_channel_ncd.h>
 
 #define NCDINTERFACEMODULE_EVENT_UP 1
 #define NCDINTERFACEMODULE_EVENT_DOWN 2
-#define NCDINTERFACEMODULE_EVENT_ERROR 3
 
 typedef void (*NCDInterfaceModule_handler_event) (void *user, int event);
+typedef void (*NCDInterfaceModule_handler_error) (void *user);
 
-struct NCDInterfaceModuleNCD {
+struct NCDInterfaceModule;
+
+typedef struct {
+    const struct NCDInterfaceModule *m;
     BReactor *reactor;
+    BProcessManager *manager;
     struct NCDConfig_interfaces *conf;
     NCDInterfaceModule_handler_event handler_event;
+    NCDInterfaceModule_handler_error handler_error;
     void *user;
-};
-
-static void NCDInterfaceModuleNCD_Event (const struct NCDInterfaceModuleNCD *n, int event);
-static void NCDInterfaceModuleNCD_Log (const struct NCDInterfaceModuleNCD *n, int level, const char *fmt, ...);
-
-typedef void * (*NCDInterfaceModule_func_new) (struct NCDInterfaceModuleNCD params, int *initial_up_state);
+    BPending event_job;
+    BPending finish_job;
+    int up;
+    int finishing;
+    void *inst_user;
+    DebugObject d_obj;
+    #ifndef NDEBUG
+    dead_t d_dead;
+    #endif
+} NCDInterfaceModuleInst;
+
+int NCDInterfaceModuleInst_Init (
+    NCDInterfaceModuleInst *n, const struct NCDInterfaceModule *m, BReactor *reactor, BProcessManager *manager,
+    struct NCDConfig_interfaces *conf, NCDInterfaceModule_handler_event handler_event,
+    NCDInterfaceModule_handler_error handler_error,
+    void *user
+);
+void NCDInterfaceModuleInst_Free (NCDInterfaceModuleInst *n);
+void NCDInterfaceModuleInst_Finish (NCDInterfaceModuleInst *n);
+void NCDInterfaceModuleInst_Backend_Event (NCDInterfaceModuleInst *n, int event);
+void NCDInterfaceModuleInst_Backend_Error (NCDInterfaceModuleInst *n);
+void NCDInterfaceModuleInst_Backend_Log (NCDInterfaceModuleInst *n, int level, const char *fmt, ...);
+
+typedef void * (*NCDInterfaceModule_func_new) (NCDInterfaceModuleInst *params);
 typedef void (*NCDInterfaceModule_func_free) (void *o);
+typedef void (*NCDInterfaceModule_func_finish) (void *o);
 
 struct NCDInterfaceModule {
     const char *type;
     NCDInterfaceModule_func_new func_new;
     NCDInterfaceModule_func_free func_free;
+    NCDInterfaceModule_func_finish func_finish;
 };
 
-static void * NCDInterfaceModule_New (const struct NCDInterfaceModule *m, struct NCDInterfaceModuleNCD params, int *initial_up_state);
-static void NCDInterfaceModule_Free (const struct NCDInterfaceModule *m, void *o);
-
-void NCDInterfaceModuleNCD_Event (const struct NCDInterfaceModuleNCD *n, int event)
-{
-    ASSERT(event == NCDINTERFACEMODULE_EVENT_UP || event == NCDINTERFACEMODULE_EVENT_DOWN ||
-           event == NCDINTERFACEMODULE_EVENT_ERROR)
-    
-    n->handler_event(n->user, event);
-    return;
-}
-
-void NCDInterfaceModuleNCD_Log (const struct NCDInterfaceModuleNCD *n, int level, const char *fmt, ...)
-{
-    va_list vl;
-    va_start(vl, fmt);
-    BLog_Append("interface %s: module: ", n->conf->name);
-    BLog_LogToChannelVarArg(BLOG_CURRENT_CHANNEL, level, fmt, vl);
-    va_end(vl);
-}
-
-void * NCDInterfaceModule_New (const struct NCDInterfaceModule *m, struct NCDInterfaceModuleNCD params, int *initial_up_state)
-{
-    return m->func_new(params, initial_up_state);
-}
-
-void NCDInterfaceModule_Free (const struct NCDInterfaceModule *m, void *o)
-{
-    m->func_free(o);
-}
-
 #endif

+ 36 - 58
ncd/interface_modules/interface_physical.c

@@ -18,13 +18,15 @@
  * 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.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * @section DESCRIPTION
+ * 
+ * Physical interface backend.
  */
 
 #include <stdlib.h>
 #include <string.h>
 
-#include <misc/dead.h>
-#include <system/DebugObject.h>
 #include <ncd/NCDInterfaceModule.h>
 #include <ncd/NCDIfConfig.h>
 #include <ncd/NCDInterfaceMonitor.h>
@@ -34,52 +36,34 @@
 #define STATE_FINISHED 3
 
 struct instance {
-    struct NCDInterfaceModuleNCD params;
+    NCDInterfaceModuleInst *i;
     NCDInterfaceMonitor monitor;
     int state;
-    DebugObject d_obj;
-    #ifndef NDEBUG
-    dead_t d_dead;
-    #endif
 };
 
-static void report_error (struct instance *o)
-{
-    #ifndef NDEBUG
-    DEAD_ENTER(o->d_dead)
-    #endif
-    
-    NCDInterfaceModuleNCD_Event(&o->params, NCDINTERFACEMODULE_EVENT_ERROR);
-    
-    #ifndef NDEBUG
-    ASSERT(DEAD_KILLED)
-    DEAD_LEAVE(o->d_dead);
-    #endif
-}
-
 static int try_start (struct instance *o)
 {
     // query interface state
-    int flags = NCDIfConfig_query(o->params.conf->name);
+    int flags = NCDIfConfig_query(o->i->conf->name);
     
     if (!(flags&NCDIFCONFIG_FLAG_EXISTS)) {
-        NCDInterfaceModuleNCD_Log(&o->params, BLOG_INFO, "device doesn't exist");
+        NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_INFO, "device doesn't exist");
         
         // waiting for device
         o->state = STATE_WAITDEVICE;
     } else {
         if ((flags&NCDIFCONFIG_FLAG_UP)) {
-            NCDInterfaceModuleNCD_Log(&o->params, BLOG_ERROR, "device already up - NOT configuring");
+            NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_ERROR, "device already up - NOT configuring");
             return 0;
         }
         
         // set interface up
-        if (!NCDIfConfig_set_up(o->params.conf->name)) {
-            NCDInterfaceModuleNCD_Log(&o->params, BLOG_ERROR, "failed to set device up");
+        if (!NCDIfConfig_set_up(o->i->conf->name)) {
+            NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_ERROR, "failed to set device up");
             return 0;
         }
         
-        NCDInterfaceModuleNCD_Log(&o->params, BLOG_INFO, "waiting for link");
+        NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_INFO, "waiting for link");
         
         // waiting for link
         o->state = STATE_WAITLINK;
@@ -90,9 +74,7 @@ static int try_start (struct instance *o)
 
 static void monitor_handler (struct instance *o, const char *ifname, int if_flags)
 {
-    DebugObject_Access(&o->d_obj);
-    
-    if (strcmp(ifname, o->params.conf->name)) {
+    if (strcmp(ifname, o->i->conf->name)) {
         return;
     }
     
@@ -100,23 +82,22 @@ static void monitor_handler (struct instance *o, const char *ifname, int if_flag
         if (o->state > STATE_WAITDEVICE) {
             int prev_state = o->state;
             
-            NCDInterfaceModuleNCD_Log(&o->params, BLOG_INFO, "device down");
+            NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_INFO, "device down");
             
             // set state
             o->state = STATE_WAITDEVICE;
             
             // report
             if (prev_state == STATE_FINISHED) {
-                NCDInterfaceModuleNCD_Event(&o->params, NCDINTERFACEMODULE_EVENT_DOWN);
-                return;
+                NCDInterfaceModuleInst_Backend_Event(o->i, NCDINTERFACEMODULE_EVENT_DOWN);
             }
         }
     } else {
         if (o->state == STATE_WAITDEVICE) {
-            NCDInterfaceModuleNCD_Log(&o->params, BLOG_INFO, "device up");
+            NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_INFO, "device up");
             
             if (!try_start(o)) {
-                report_error(o);
+                NCDInterfaceModuleInst_Backend_Error(o->i);
                 return;
             }
             
@@ -125,45 +106,43 @@ static void monitor_handler (struct instance *o, const char *ifname, int if_flag
         
         if ((if_flags&NCDIFCONFIG_FLAG_RUNNING)) {
             if (o->state == STATE_WAITLINK) {
-                NCDInterfaceModuleNCD_Log(&o->params, BLOG_INFO, "link up");
+                NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_INFO, "link up");
                 
                 // set state
                 o->state = STATE_FINISHED;
                 
                 // report
-                NCDInterfaceModuleNCD_Event(&o->params, NCDINTERFACEMODULE_EVENT_UP);
-                return;
+                NCDInterfaceModuleInst_Backend_Event(o->i, NCDINTERFACEMODULE_EVENT_UP);
             }
         } else {
             if (o->state == STATE_FINISHED) {
-                NCDInterfaceModuleNCD_Log(&o->params, BLOG_INFO, "link down");
+                NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_INFO, "link down");
                 
                 // set state
                 o->state = STATE_WAITLINK;
                 
                 // report
-                NCDInterfaceModuleNCD_Event(&o->params, NCDINTERFACEMODULE_EVENT_DOWN);
-                return;
+                NCDInterfaceModuleInst_Backend_Event(o->i, NCDINTERFACEMODULE_EVENT_DOWN);
             }
         }
     }
 }
 
-static void * func_new (struct NCDInterfaceModuleNCD params, int *initial_up_state)
+static void * func_new (NCDInterfaceModuleInst *i)
 {
     // allocate instance
     struct instance *o = malloc(sizeof(*o));
     if (!o) {
-        NCDInterfaceModuleNCD_Log(&params, BLOG_ERROR, "failed to allocate instance");
+        NCDInterfaceModuleInst_Backend_Log(i, BLOG_ERROR, "failed to allocate instance");
         goto fail0;
     }
     
     // init arguments
-    o->params = params;
+    o->i = i;
     
     // init monitor
-    if (!NCDInterfaceMonitor_Init(&o->monitor, o->params.reactor, (NCDInterfaceMonitor_handler)monitor_handler, o)) {
-        NCDInterfaceModuleNCD_Log(&o->params, BLOG_ERROR, "NCDInterfaceMonitor_Init failed");
+    if (!NCDInterfaceMonitor_Init(&o->monitor, o->i->reactor, (NCDInterfaceMonitor_handler)monitor_handler, o)) {
+        NCDInterfaceModuleInst_Backend_Log(o->i, BLOG_ERROR, "NCDInterfaceMonitor_Init failed");
         goto fail1;
     }
     
@@ -171,12 +150,6 @@ static void * func_new (struct NCDInterfaceModuleNCD params, int *initial_up_sta
         goto fail2;
     }
     
-    DebugObject_Init(&o->d_obj);
-    #ifndef NDEBUG
-    DEAD_INIT(o->d_dead);
-    #endif
-    
-    *initial_up_state = 0;
     return o;
     
 fail2:
@@ -190,14 +163,10 @@ fail0:
 static void func_free (void *vo)
 {
     struct instance *o = vo;
-    DebugObject_Free(&o->d_obj);
-    #ifndef NDEBUG
-    DEAD_KILL(o->d_dead);
-    #endif
     
     // set interface down
     if (o->state > STATE_WAITDEVICE) {
-        NCDIfConfig_set_down(o->params.conf->name);
+        NCDIfConfig_set_down(o->i->conf->name);
     }
     
     // free monitor
@@ -207,8 +176,17 @@ static void func_free (void *vo)
     free(o);
 }
 
+static void func_finish (void *vo)
+{
+    struct instance *o = vo;
+    
+    NCDInterfaceModuleInst_Backend_Error(o->i);
+    return;
+}
+
 const struct NCDInterfaceModule ncd_interface_physical = {
     .type = "physical",
     .func_new = func_new,
-    .func_free = func_free
+    .func_free = func_free,
+    .func_finish = func_finish
 };

+ 77 - 48
ncd/ncd.c

@@ -35,6 +35,7 @@
 #include <structure/LinkedList2.h>
 #include <system/BLog.h>
 #include <system/BReactor.h>
+#include <system/BProcess.h>
 #include <system/BSignal.h>
 #include <system/BSocket.h>
 #include <dhcpclient/BDHCPClient.h>
@@ -90,7 +91,8 @@ struct interface {
     BTimer reset_timer;
     LinkedList2 deps_out;
     LinkedList2 deps_in;
-    void *module_instance;
+    int have_module_instance;
+    NCDInterfaceModuleInst module_instance;
     int have_dhcp;
     BDHCPClient dhcp;
     LinkedList2 ipv4_addresses;
@@ -113,6 +115,7 @@ struct ipv4_addr_entry {
 struct ipv4_route_entry {
     LinkedList2Node list_node; // node in interface.ipv4_routes
     struct ipv4_ifaddr dest;
+    int have_gateway;
     uint32_t gateway;
     int metric;
 };
@@ -126,6 +129,9 @@ struct ipv4_dns_entry {
 // reactor
 BReactor ss;
 
+// process manager
+BProcessManager manager;
+
 // configuration
 struct NCDConfig_interfaces *configuration;
 
@@ -153,9 +159,10 @@ static void interface_start (struct interface *iface);
 static void interface_module_up (struct interface *iface);
 static void interface_log (struct interface *iface, int level, const char *fmt, ...);
 static void interface_reset_timer_handler (struct interface *iface);
-static int interface_module_init (struct interface *iface, int *initial_up_state);
+static int interface_module_init (struct interface *iface);
 static void interface_module_free (struct interface *iface);
 static void interface_module_handler_event (struct interface *iface, int event);
+static void interface_module_handler_error (struct interface *iface);
 static void interface_dhcp_handler (struct interface *iface, int event);
 static void interface_remove_dependencies (struct interface *iface);
 static int interface_add_dependency (struct interface *iface, struct interface *dst);
@@ -173,11 +180,11 @@ static int interface_add_ipv4_dns_servers (struct interface *iface);
 static void interface_remove_ipv4_dns_servers (struct interface *iface);
 static int interface_add_ipv4_addr (struct interface *iface, struct ipv4_ifaddr ifaddr);
 static void interface_remove_ipv4_addr (struct interface *iface, struct ipv4_addr_entry *entry);
-static int interface_add_ipv4_route (struct interface *iface, struct ipv4_ifaddr dest, uint32_t gateway, int metric);
+static int interface_add_ipv4_route (struct interface *iface, struct ipv4_ifaddr dest, const uint32_t *gateway, int metric);
 static void interface_remove_ipv4_route (struct interface *iface, struct ipv4_route_entry *entry);
 static struct ipv4_addr_entry * interface_add_ipv4_addr_entry (struct interface *iface, struct ipv4_ifaddr ifaddr);
 static void interface_remove_ipv4_addr_entry (struct interface *iface, struct ipv4_addr_entry *entry);
-static struct ipv4_route_entry * interface_add_ipv4_route_entry (struct interface *iface, struct ipv4_ifaddr dest, uint32_t gateway, int metric);
+static struct ipv4_route_entry * interface_add_ipv4_route_entry (struct interface *iface, struct ipv4_ifaddr dest, const uint32_t *gateway, int metric);
 static void interface_remove_ipv4_route_entry (struct interface *iface, struct ipv4_route_entry *entry);
 static struct ipv4_dns_entry * interface_add_ipv4_dns_entry (struct interface *iface, uint32_t addr, int priority);
 static void interface_remove_ipv4_dns_entry (struct interface *iface, struct ipv4_dns_entry *entry);
@@ -250,6 +257,12 @@ int main (int argc, char **argv)
         goto fail1;
     }
     
+    // init process manager
+    if (!BProcessManager_Init(&manager, &ss)) {
+        BLog(BLOG_ERROR, "BProcessManager_Init failed");
+        goto fail1a;
+    }
+    
     // setup signal handler
     if (!BSignal_Init(&ss, signal_handler, NULL)) {
         BLog(BLOG_ERROR, "BSignal_Init failed");
@@ -294,6 +307,8 @@ fail5:
 fail3:
     BSignal_Finish();
 fail2:
+    BProcessManager_Free(&manager);
+fail1a:
     BReactor_Free(&ss);
 fail1:
     BLog(BLOG_ERROR, "initialization failed");
@@ -334,6 +349,9 @@ void terminate (void)
     // remove signal handler
     BSignal_Finish();
     
+    // free process manager
+    BProcessManager_Free(&manager);
+    
     // exit reactor
     BReactor_Quit(&ss, 1);
 }
@@ -664,7 +682,7 @@ int interface_init (struct NCDConfig_interfaces *conf)
     LinkedList2_Init(&iface->deps_in);
     
     // set no module instance
-    iface->module_instance = NULL;
+    iface->have_module_instance = 0;
     
     // set no DHCP
     iface->have_dhcp = 0;
@@ -706,7 +724,7 @@ void interface_free (struct interface *iface)
     }
     
     // free module instance
-    if (iface->module_instance) {
+    if (iface->have_module_instance) {
         interface_module_free(iface);
     }
     
@@ -742,7 +760,7 @@ void interface_down_to (struct interface *iface, int state)
     }
     
     // free module instance
-    if (state < INTERFACE_STATE_WAITMODULE && iface->module_instance) {
+    if (state < INTERFACE_STATE_WAITMODULE && iface->have_module_instance) {
         interface_module_free(iface);
     }
     
@@ -767,7 +785,7 @@ void interface_reset (struct interface *iface)
 void interface_start (struct interface *iface)
 {
     ASSERT(!BTimer_IsRunning(&iface->reset_timer))
-    ASSERT(!iface->module_instance)
+    ASSERT(!iface->have_module_instance)
     ASSERT(!iface->have_dhcp)
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_addresses))
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_routes))
@@ -783,20 +801,14 @@ void interface_start (struct interface *iface)
     }
     
     // init module
-    int initial_up_state;
-    if (!interface_module_init(iface, &initial_up_state)) {
+    if (!interface_module_init(iface)) {
         goto fail;
     }
     
-    if (!initial_up_state) {
-        interface_log(iface, BLOG_INFO, "waiting for module");
-        
-        // waiting for module
-        iface->state = INTERFACE_STATE_WAITMODULE;
-        return;
-    }
+    interface_log(iface, BLOG_INFO, "waiting for module");
     
-    interface_module_up(iface);
+    // waiting for module
+    iface->state = INTERFACE_STATE_WAITMODULE;
     
     return;
     
@@ -806,7 +818,7 @@ fail:
 
 void interface_module_up (struct interface *iface)
 {
-    ASSERT(iface->module_instance)
+    ASSERT(iface->have_module_instance)
     ASSERT(!iface->have_dhcp)
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_addresses))
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_routes))
@@ -869,39 +881,37 @@ void interface_reset_timer_handler (struct interface *iface)
     interface_start(iface);
 }
 
-int interface_module_init (struct interface *iface, int *initial_up_state)
+int interface_module_init (struct interface *iface)
 {
-    ASSERT(!iface->module_instance)
-    
-    struct NCDInterfaceModuleNCD params = { 
-        .reactor = &ss,
-        .conf = iface->conf, 
-        .handler_event = (NCDInterfaceModule_handler_event)interface_module_handler_event, 
-        .user = iface
-    };
-    
-    if (!(iface->module_instance = NCDInterfaceModule_New(iface->module, params, initial_up_state))) {
-        interface_log(iface, BLOG_ERROR, "failed to inizialice module instance");
+    ASSERT(!iface->have_module_instance)
+    
+    if (!NCDInterfaceModuleInst_Init(
+        &iface->module_instance, iface->module, &ss, &manager, iface->conf,
+        (NCDInterfaceModule_handler_event)interface_module_handler_event,
+        (NCDInterfaceModule_handler_error)interface_module_handler_error,
+        iface
+    )) {
+        interface_log(iface, BLOG_ERROR, "failed to initialize module instance");
         return 0;
     }
     
-    ASSERT(*initial_up_state == 0 || *initial_up_state == 1)
+    iface->have_module_instance = 1;
     
     return 1;
 }
 
 void interface_module_free (struct interface *iface)
 {
-    ASSERT(iface->module_instance)
+    ASSERT(iface->have_module_instance)
     
-    NCDInterfaceModule_Free(iface->module, iface->module_instance);
+    NCDInterfaceModuleInst_Free(&iface->module_instance);
     
-    iface->module_instance = NULL;
+    iface->have_module_instance = 0;
 }
 
 void interface_module_handler_event (struct interface *iface, int event)
 {
-    ASSERT(iface->module_instance)
+    ASSERT(iface->have_module_instance)
     ASSERT(iface->state >= INTERFACE_STATE_WAITMODULE)
     
     switch (event) {
@@ -921,17 +931,21 @@ void interface_module_handler_event (struct interface *iface, int event)
             interface_down_to(iface, INTERFACE_STATE_WAITMODULE);
         } break;
         
-        case NCDINTERFACEMODULE_EVENT_ERROR: {
-            interface_log(iface, BLOG_INFO, "module error");
-            
-            interface_reset(iface);
-        } break;
-        
         default:
             ASSERT(0);
     }
 }
 
+void interface_module_handler_error (struct interface *iface)
+{
+    ASSERT(iface->have_module_instance)
+    ASSERT(iface->state >= INTERFACE_STATE_WAITMODULE)
+    
+    interface_log(iface, BLOG_INFO, "module error");
+            
+    interface_reset(iface);
+}
+
 void interface_dhcp_handler (struct interface *iface, int event)
 {
     ASSERT(iface->have_dhcp)
@@ -1194,6 +1208,7 @@ int interface_add_ipv4_routes (struct interface *iface)
             return 0;
         }
         
+        int have_gateway;
         uint32_t gateway;
         
         // is gateway a DHCP router?
@@ -1209,19 +1224,28 @@ int interface_add_ipv4_routes (struct interface *iface)
                 interface_log(iface, BLOG_ERROR, "ipv4.route: (%s,%s,%s): gateway: DHCP did not provide a router", dest_str, gateway_str, metric_str);
                 return 0;
             }
-        } else {
+            
+            have_gateway = 1;
+        }
+        else if (!strcmp(gateway_str, "none")) {
+            // no gateway
+            have_gateway = 0;
+        }
+        else {
             // parse gateway string
             if (!ipaddr_parse_ipv4_addr(gateway_str, strlen(gateway_str), &gateway)) {
                 interface_log(iface, BLOG_ERROR, "ipv4.route: (%s,%s,%s): gateway: wrong format", dest_str, gateway_str, metric_str);
                 return 0;
             }
+            
+            have_gateway = 1;
         }
         
         // parse metric string
         int metric = atoi(metric_str);
         
         // add this address
-        if (!interface_add_ipv4_route(iface, dest, gateway, metric)) {
+        if (!interface_add_ipv4_route(iface, dest, (have_gateway ? &gateway : NULL), metric)) {
             interface_log(iface, BLOG_ERROR, "ipv4.route: (%s,%s,%s): failed to add", dest_str, gateway_str, metric_str);
             return 0;
         }
@@ -1345,7 +1369,7 @@ void interface_remove_ipv4_addr (struct interface *iface, struct ipv4_addr_entry
     interface_remove_ipv4_addr_entry(iface, entry);
 }
 
-int interface_add_ipv4_route (struct interface *iface, struct ipv4_ifaddr dest, uint32_t gateway, int metric)
+int interface_add_ipv4_route (struct interface *iface, struct ipv4_ifaddr dest, const uint32_t *gateway, int metric)
 {
     // add address entry
     struct ipv4_route_entry *entry = interface_add_ipv4_route_entry(iface, dest, gateway, metric);
@@ -1367,7 +1391,7 @@ int interface_add_ipv4_route (struct interface *iface, struct ipv4_ifaddr dest,
 void interface_remove_ipv4_route (struct interface *iface, struct ipv4_route_entry *entry)
 {
     // remove the route
-    if (!NCDIfConfig_remove_ipv4_route(entry->dest, entry->gateway, entry->metric, iface->conf->name)) {
+    if (!NCDIfConfig_remove_ipv4_route(entry->dest, (entry->have_gateway ? &entry->gateway : NULL), entry->metric, iface->conf->name)) {
         interface_log(iface, BLOG_ERROR, "failed to remove ipv4 route");
     }
     
@@ -1402,7 +1426,7 @@ void interface_remove_ipv4_addr_entry (struct interface *iface, struct ipv4_addr
     free(entry);
 }
 
-struct ipv4_route_entry * interface_add_ipv4_route_entry (struct interface *iface, struct ipv4_ifaddr dest, uint32_t gateway, int metric)
+struct ipv4_route_entry * interface_add_ipv4_route_entry (struct interface *iface, struct ipv4_ifaddr dest, const uint32_t *gateway, int metric)
 {
     // allocate entry
     struct ipv4_route_entry *entry = malloc(sizeof(*entry));
@@ -1412,7 +1436,12 @@ struct ipv4_route_entry * interface_add_ipv4_route_entry (struct interface *ifac
     
     // set info
     entry->dest = dest;
-    entry->gateway = gateway;
+    if (gateway) {
+        entry->have_gateway = 1;
+        entry->gateway = *gateway;
+    } else {
+        entry->have_gateway = 0;
+    }
     entry->metric = metric;
     
     // add to list