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

ncd: implement modular interface types

ambrop7 15 лет назад
Родитель
Сommit
2f6ed0a90f

+ 1 - 0
blog_channels.txt

@@ -19,3 +19,4 @@ BDHCPClient 4
 NCDIfConfig 4
 NCDIfConfig 4
 BUnixSignal 4
 BUnixSignal 4
 BProcess 4
 BProcess 4
+ncd_interface_physical 4

+ 4 - 0
generated/blog_channel_ncd_interface_physical.h

@@ -0,0 +1,4 @@
+#ifdef BLOG_CURRENT_CHANNEL
+#undef BLOG_CURRENT_CHANNEL
+#endif
+#define BLOG_CURRENT_CHANNEL BLOG_CHANNEL_ncd_interface_physical

+ 2 - 1
generated/blog_channels_defines.h

@@ -19,4 +19,5 @@
 #define BLOG_CHANNEL_NCDIfConfig 18
 #define BLOG_CHANNEL_NCDIfConfig 18
 #define BLOG_CHANNEL_BUnixSignal 19
 #define BLOG_CHANNEL_BUnixSignal 19
 #define BLOG_CHANNEL_BProcess 20
 #define BLOG_CHANNEL_BProcess 20
-#define BLOG_NUM_CHANNELS 21
+#define BLOG_CHANNEL_ncd_interface_physical 21
+#define BLOG_NUM_CHANNELS 22

+ 1 - 0
generated/blog_channels_list.h

@@ -19,3 +19,4 @@
 {.name = "NCDIfConfig", .loglevel = 4},
 {.name = "NCDIfConfig", .loglevel = 4},
 {.name = "BUnixSignal", .loglevel = 4},
 {.name = "BUnixSignal", .loglevel = 4},
 {.name = "BProcess", .loglevel = 4},
 {.name = "BProcess", .loglevel = 4},
+{.name = "ncd_interface_physical", .loglevel = 4},

+ 1 - 0
ncd/CMakeLists.txt

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

+ 51 - 0
ncd/NCDInterfaceModule.h

@@ -0,0 +1,51 @@
+/**
+ * @file NCDInterfaceModule.h
+ * @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.
+ */
+
+#ifndef BADVPN_NCD_NCDINTERFACEMODULE_H
+#define BADVPN_NCD_NCDINTERFACEMODULE_H
+
+#include <system/BReactor.h>
+#include <ncdconfig/NCDConfig.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);
+
+struct NCDInterfaceModule_ncd_params {
+    BReactor *reactor;
+    struct NCDConfig_interfaces *conf;
+    NCDInterfaceModule_handler_event handler_event;
+    void *user;
+};
+
+typedef void * (*NCDInterfaceModule_func_new) (struct NCDInterfaceModule_ncd_params params, int *initial_up_state);
+typedef void (*NCDInterfaceModule_func_free) (void *o);
+
+struct NCDInterfaceModule {
+    const char *type;
+    NCDInterfaceModule_func_new func_new;
+    NCDInterfaceModule_func_free func_free;
+};
+
+#endif

+ 232 - 0
ncd/interface_modules/interface_physical.c

@@ -0,0 +1,232 @@
+/**
+ * @file interface_physical.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 <stdlib.h>
+#include <string.h>
+
+#include <misc/dead.h>
+#include <system/DebugObject.h>
+#include <system/BLog.h>
+#include <ncd/NCDInterfaceModule.h>
+#include <ncd/NCDIfConfig.h>
+#include <ncd/NCDInterfaceMonitor.h>
+
+#include <generated/blog_channel_ncd_interface_physical.h>
+
+#define STATE_WAITDEVICE 1
+#define STATE_WAITLINK 2
+#define STATE_FINISHED 3
+
+struct instance {
+    struct NCDInterfaceModule_ncd_params params;
+    NCDInterfaceMonitor monitor;
+    int state;
+    DebugObject d_obj;
+    #ifndef NDEBUG
+    dead_t d_dead;
+    #endif
+};
+
+static void instance_log (struct instance *o, int level, const char *fmt, ...)
+{
+    va_list vl;
+    va_start(vl, fmt);
+    BLog_Append("interface %s: ", o->params.conf->name);
+    BLog_LogToChannelVarArg(BLOG_CURRENT_CHANNEL, level, fmt, vl);
+    va_end(vl);
+}
+
+static void report_event (struct instance *o, int event)
+{
+    o->params.handler_event(o->params.user, event);
+    return;
+}
+
+static void report_error (struct instance *o)
+{
+    #ifndef NDEBUG
+    DEAD_ENTER(o->d_dead)
+    #endif
+    
+    report_event(o, 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);
+    
+    if (!(flags&NCDIFCONFIG_FLAG_EXISTS)) {
+        instance_log(o, BLOG_INFO, "device doesn't exist");
+        
+        // waiting for device
+        o->state = STATE_WAITDEVICE;
+    } else {
+        if ((flags&NCDIFCONFIG_FLAG_UP)) {
+            instance_log(o, BLOG_ERROR, "device already up - NOT configuring");
+            return 0;
+        }
+        
+        // set interface up
+        if (!NCDIfConfig_set_up(o->params.conf->name)) {
+            instance_log(o, BLOG_ERROR, "failed to set device up");
+            return 0;
+        }
+        
+        instance_log(o, BLOG_INFO, "waiting for link");
+        
+        // waiting for link
+        o->state = STATE_WAITLINK;
+    }
+    
+    return 1;
+}
+
+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)) {
+        return;
+    }
+    
+    if (!(if_flags&NCDIFCONFIG_FLAG_EXISTS)) {
+        if (o->state > STATE_WAITDEVICE) {
+            int prev_state = o->state;
+            
+            instance_log(o, BLOG_INFO, "device down");
+            
+            // set state
+            o->state = STATE_WAITDEVICE;
+            
+            // report
+            if (prev_state == STATE_FINISHED) {
+                report_event(o, NCDINTERFACEMODULE_EVENT_DOWN);
+                return;
+            }
+        }
+    } else {
+        if (o->state == STATE_WAITDEVICE) {
+            instance_log(o, BLOG_INFO, "device up");
+            
+            if (!try_start(o)) {
+                report_error(o);
+                return;
+            }
+            
+            return;
+        }
+        
+        if ((if_flags&NCDIFCONFIG_FLAG_RUNNING)) {
+            if (o->state == STATE_WAITLINK) {
+                instance_log(o, BLOG_INFO, "link up");
+                
+                // set state
+                o->state = STATE_FINISHED;
+                
+                // report
+                report_event(o, NCDINTERFACEMODULE_EVENT_UP);
+                return;
+            }
+        } else {
+            if (o->state == STATE_FINISHED) {
+                instance_log(o, BLOG_INFO, "link down");
+                
+                // set state
+                o->state = STATE_WAITLINK;
+                
+                // report
+                report_event(o, NCDINTERFACEMODULE_EVENT_DOWN);
+                return;
+            }
+        }
+    }
+}
+
+static void * func_new (struct NCDInterfaceModule_ncd_params params, int *initial_up_state)
+{
+    // allocate instance
+    struct instance *o = malloc(sizeof(*o));
+    if (!o) {
+        BLog(BLOG_ERROR, "failed to allocate instance");
+        goto fail0;
+    }
+    
+    // init arguments
+    o->params = params;
+    
+    // init monitor
+    if (!NCDInterfaceMonitor_Init(&o->monitor, o->params.reactor, (NCDInterfaceMonitor_handler)monitor_handler, o)) {
+        instance_log(o, BLOG_ERROR, "NCDInterfaceMonitor_Init failed");
+        goto fail1;
+    }
+    
+    if (!try_start(o)) {
+        goto fail2;
+    }
+    
+    DebugObject_Init(&o->d_obj);
+    #ifndef NDEBUG
+    DEAD_INIT(o->d_dead);
+    #endif
+    
+    *initial_up_state = 0;
+    return o;
+    
+fail2:
+    NCDInterfaceMonitor_Free(&o->monitor);
+fail1:
+    free(o);
+fail0:
+    return NULL;
+}
+
+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);
+    }
+    
+    // free monitor
+    NCDInterfaceMonitor_Free(&o->monitor);
+    
+    // free instance
+    free(o);
+}
+
+const struct NCDInterfaceModule ncd_interface_physical = {
+    .type = "physical",
+    .func_new = func_new,
+    .func_free = func_free
+};

+ 113 - 131
ncd/ncd.c

@@ -40,7 +40,7 @@
 #include <dhcpclient/BDHCPClient.h>
 #include <dhcpclient/BDHCPClient.h>
 #include <ncdconfig/NCDConfigParser.h>
 #include <ncdconfig/NCDConfigParser.h>
 #include <ncd/NCDIfConfig.h>
 #include <ncd/NCDIfConfig.h>
-#include <ncd/NCDInterfaceMonitor.h>
+#include <ncd/NCDInterfaceModule.h>
 
 
 #ifndef BADVPN_USE_WINAPI
 #ifndef BADVPN_USE_WINAPI
 #include <system/BLog_syslog.h>
 #include <system/BLog_syslog.h>
@@ -53,14 +53,20 @@
 #define LOGGER_STDOUT 1
 #define LOGGER_STDOUT 1
 #define LOGGER_SYSLOG 2
 #define LOGGER_SYSLOG 2
 
 
-#define INTERFACE_TYPE_PHYSICAL 1
-
 #define INTERFACE_STATE_WAITDEPS 1
 #define INTERFACE_STATE_WAITDEPS 1
 #define INTERFACE_STATE_RESETTING 2
 #define INTERFACE_STATE_RESETTING 2
-#define INTERFACE_STATE_WAITDEVICE 3
-#define INTERFACE_STATE_WAITLINK 4
-#define INTERFACE_STATE_DHCP 5
-#define INTERFACE_STATE_FINISHED 6
+#define INTERFACE_STATE_WAITMODULE 3
+#define INTERFACE_STATE_DHCP 4
+#define INTERFACE_STATE_FINISHED 5
+
+// interface modules
+extern const struct NCDInterfaceModule ncd_interface_physical;
+
+// interface modules list
+const struct NCDInterfaceModule *interface_modules[] = {
+    &ncd_interface_physical,
+    NULL
+};
 
 
 // command-line options
 // command-line options
 struct {
 struct {
@@ -79,12 +85,12 @@ struct {
 struct interface {
 struct interface {
     LinkedList2Node list_node; // node in interfaces
     LinkedList2Node list_node; // node in interfaces
     struct NCDConfig_interfaces *conf;
     struct NCDConfig_interfaces *conf;
-    int type;
+    const struct NCDInterfaceModule *module;
     int state;
     int state;
     BTimer reset_timer;
     BTimer reset_timer;
     LinkedList2 deps_out;
     LinkedList2 deps_out;
     LinkedList2 deps_in;
     LinkedList2 deps_in;
-    int up;
+    void *module_instance;
     int have_dhcp;
     int have_dhcp;
     BDHCPClient dhcp;
     BDHCPClient dhcp;
     LinkedList2 ipv4_addresses;
     LinkedList2 ipv4_addresses;
@@ -123,9 +129,6 @@ BReactor ss;
 // configuration
 // configuration
 struct NCDConfig_interfaces *configuration;
 struct NCDConfig_interfaces *configuration;
 
 
-// interface monitor
-NCDInterfaceMonitor monitor;
-
 // interfaces
 // interfaces
 LinkedList2 interfaces;
 LinkedList2 interfaces;
 
 
@@ -142,15 +145,17 @@ static void free_interfaces (void);
 static int set_dns_servers (void);
 static int set_dns_servers (void);
 static int dns_qsort_comparator (const void *v1, const void *v2);
 static int dns_qsort_comparator (const void *v1, const void *v2);
 static struct interface * find_interface (const char *name);
 static struct interface * find_interface (const char *name);
-static void monitor_handler (void *unused, const char *ifname, int if_flags);
 static int interface_init (struct NCDConfig_interfaces *conf);
 static int interface_init (struct NCDConfig_interfaces *conf);
 static void interface_free (struct interface *iface);
 static void interface_free (struct interface *iface);
 static void interface_down_to (struct interface *iface, int state);
 static void interface_down_to (struct interface *iface, int state);
 static void interface_reset (struct interface *iface);
 static void interface_reset (struct interface *iface);
 static void interface_start (struct interface *iface);
 static void interface_start (struct interface *iface);
-static void interface_link_up (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_log (struct interface *iface, int level, const char *fmt, ...);
 static void interface_reset_timer_handler (struct interface *iface);
 static void interface_reset_timer_handler (struct interface *iface);
+static int interface_module_init (struct interface *iface, int *initial_up_state);
+static void interface_module_free (struct interface *iface);
+static void interface_module_handler_event (struct interface *iface, int event);
 static void interface_dhcp_handler (struct interface *iface, int event);
 static void interface_dhcp_handler (struct interface *iface, int event);
 static void interface_remove_dependencies (struct interface *iface);
 static void interface_remove_dependencies (struct interface *iface);
 static int interface_add_dependency (struct interface *iface, struct interface *dst);
 static int interface_add_dependency (struct interface *iface, struct interface *dst);
@@ -158,8 +163,6 @@ static void remove_dependency (struct dependency *d);
 static int interface_dependencies_satisfied (struct interface *iface);
 static int interface_dependencies_satisfied (struct interface *iface);
 static void interface_satisfy_incoming_depenencies (struct interface *iface);
 static void interface_satisfy_incoming_depenencies (struct interface *iface);
 static void interface_unsatisfy_incoming_depenencies (struct interface *iface);
 static void interface_unsatisfy_incoming_depenencies (struct interface *iface);
-static int interface_set_up (struct interface *iface);
-static void interface_set_down (struct interface *iface);
 static int interface_configure_ipv4 (struct interface *iface);
 static int interface_configure_ipv4 (struct interface *iface);
 static void interface_deconfigure_ipv4 (struct interface *iface);
 static void interface_deconfigure_ipv4 (struct interface *iface);
 static int interface_add_ipv4_addresses (struct interface *iface);
 static int interface_add_ipv4_addresses (struct interface *iface);
@@ -276,12 +279,6 @@ int main (int argc, char **argv)
     // fee config file memory
     // fee config file memory
     free(file);
     free(file);
     
     
-    // init interface monitor
-    if (!NCDInterfaceMonitor_Init(&monitor, &ss, monitor_handler, NULL)) {
-        BLog(BLOG_ERROR, "NCDInterfaceMonitor_Init failed");
-        goto fail4;
-    }
-    
     // init interfaces list
     // init interfaces list
     LinkedList2_Init(&interfaces);
     LinkedList2_Init(&interfaces);
     
     
@@ -298,8 +295,6 @@ int main (int argc, char **argv)
     goto event_loop;
     goto event_loop;
     
     
 fail5:
 fail5:
-    NCDInterfaceMonitor_Free(&monitor);
-fail4:
     NCDConfig_free_interfaces(configuration);
     NCDConfig_free_interfaces(configuration);
 fail3:
 fail3:
     BSignal_RemoveHandler();
     BSignal_RemoveHandler();
@@ -338,9 +333,6 @@ void terminate (void)
     // free interfaces
     // free interfaces
     free_interfaces();
     free_interfaces();
     
     
-    // free interface monitor
-    NCDInterfaceMonitor_Free(&monitor);
-    
     // free configuration
     // free configuration
     NCDConfig_free_interfaces(configuration);
     NCDConfig_free_interfaces(configuration);
     
     
@@ -603,48 +595,6 @@ struct interface * find_interface (const char *name)
     return NULL;
     return NULL;
 }
 }
 
 
-void monitor_handler (void *unused, const char *ifname, int if_flags)
-{
-    struct interface *iface = find_interface(ifname);
-    if (!iface) {
-        return;
-    }
-    
-    if (!(if_flags&NCDIFCONFIG_FLAG_EXISTS)) {
-        if (iface->state > INTERFACE_STATE_WAITDEVICE) {
-            interface_log(iface, BLOG_INFO, "device down");
-            
-            interface_down_to(iface, INTERFACE_STATE_WAITDEVICE);
-        }
-    } else {
-        if (iface->state == INTERFACE_STATE_RESETTING || iface->state == INTERFACE_STATE_WAITDEVICE) {
-            interface_log(iface, BLOG_INFO, "device up");
-        
-            // stop reset timer (if it was resetting)
-            BReactor_RemoveTimer(&ss, &iface->reset_timer);
-            
-            // start
-            interface_start(iface);
-            
-            return;
-        }
-        
-        if ((if_flags&NCDIFCONFIG_FLAG_RUNNING)) {
-            if (iface->state == INTERFACE_STATE_WAITLINK) {
-                interface_log(iface, BLOG_INFO, "link up");
-                
-                interface_link_up(iface);
-            }
-        } else {
-            if (iface->state > INTERFACE_STATE_WAITLINK) {
-                interface_log(iface, BLOG_INFO, "link down");
-                
-                interface_down_to(iface, INTERFACE_STATE_WAITLINK);
-            }
-        }
-    }
-}
-
 int interface_init (struct NCDConfig_interfaces *conf)
 int interface_init (struct NCDConfig_interfaces *conf)
 {
 {
     // check for existing interface
     // check for existing interface
@@ -663,7 +613,7 @@ int interface_init (struct NCDConfig_interfaces *conf)
     // set conf
     // set conf
     iface->conf = conf;
     iface->conf = conf;
     
     
-    // set type
+    // find interface module
     struct NCDConfig_statements *type_st = NCDConfig_find_statement(conf->statements, "type");
     struct NCDConfig_statements *type_st = NCDConfig_find_statement(conf->statements, "type");
     if (!type_st) {
     if (!type_st) {
         interface_log(iface, BLOG_ERROR, "missing type");
         interface_log(iface, BLOG_ERROR, "missing type");
@@ -674,13 +624,17 @@ int interface_init (struct NCDConfig_interfaces *conf)
         interface_log(iface, BLOG_ERROR, "type: wrong arity");
         interface_log(iface, BLOG_ERROR, "type: wrong arity");
         goto fail1;
         goto fail1;
     }
     }
-    if (!strcmp(type, "physical")) {
-        iface->type = INTERFACE_TYPE_PHYSICAL;
+    const struct NCDInterfaceModule **m;
+    for (m = interface_modules; *m; m++) {
+        if (!strcmp((*m)->type, type)) {
+            break;
+        }
     }
     }
-    else {
+    if (!*m) {
         interface_log(iface, BLOG_ERROR, "type: unknown value");
         interface_log(iface, BLOG_ERROR, "type: unknown value");
         goto fail1;
         goto fail1;
     }
     }
+    iface->module = *m;
     
     
     // init reset timer
     // init reset timer
     BTimer_Init(&iface->reset_timer, INTERFACE_RETRY_TIME, (BTimer_handler)interface_reset_timer_handler, iface);
     BTimer_Init(&iface->reset_timer, INTERFACE_RETRY_TIME, (BTimer_handler)interface_reset_timer_handler, iface);
@@ -714,8 +668,8 @@ int interface_init (struct NCDConfig_interfaces *conf)
     // init incoming dependencies list
     // init incoming dependencies list
     LinkedList2_Init(&iface->deps_in);
     LinkedList2_Init(&iface->deps_in);
     
     
-    // set not up
-    iface->up = 0;
+    // set no module instance
+    iface->module_instance = NULL;
     
     
     // set no DHCP
     // set no DHCP
     iface->have_dhcp = 0;
     iface->have_dhcp = 0;
@@ -756,9 +710,9 @@ void interface_free (struct interface *iface)
         BDHCPClient_Free(&iface->dhcp);
         BDHCPClient_Free(&iface->dhcp);
     }
     }
     
     
-    // set down
-    if (iface->up) {
-        interface_set_down(iface);
+    // free module instance
+    if (iface->module_instance) {
+        interface_module_free(iface);
     }
     }
     
     
     // remove from interfaces list
     // remove from interfaces list
@@ -792,9 +746,9 @@ void interface_down_to (struct interface *iface, int state)
         iface->have_dhcp = 0;
         iface->have_dhcp = 0;
     }
     }
     
     
-    // set down
-    if (state < INTERFACE_STATE_WAITLINK && iface->up) {
-        interface_set_down(iface);
+    // free module instance
+    if (state < INTERFACE_STATE_WAITMODULE && iface->module_instance) {
+        interface_module_free(iface);
     }
     }
     
     
     // start/stop reset timer
     // start/stop reset timer
@@ -818,7 +772,7 @@ void interface_reset (struct interface *iface)
 void interface_start (struct interface *iface)
 void interface_start (struct interface *iface)
 {
 {
     ASSERT(!BTimer_IsRunning(&iface->reset_timer))
     ASSERT(!BTimer_IsRunning(&iface->reset_timer))
-    ASSERT(!iface->up)
+    ASSERT(!iface->module_instance)
     ASSERT(!iface->have_dhcp)
     ASSERT(!iface->have_dhcp)
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_addresses))
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_addresses))
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_routes))
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_routes))
@@ -833,31 +787,21 @@ void interface_start (struct interface *iface)
         return;
         return;
     }
     }
     
     
-    // query interface state
-    int flags = NCDIfConfig_query(iface->conf->name);
-    
-    if (!(flags&NCDIFCONFIG_FLAG_EXISTS)) {
-        interface_log(iface, BLOG_INFO, "device doesn't exist");
-        
-        // waiting for device
-        iface->state = INTERFACE_STATE_WAITDEVICE;
-        return;
-    }
-    
-    if ((flags&NCDIFCONFIG_FLAG_UP)) {
-        interface_log(iface, BLOG_ERROR, "device already up - NOT configuring");
+    // init module
+    int initial_up_state;
+    if (!interface_module_init(iface, &initial_up_state)) {
         goto fail;
         goto fail;
     }
     }
     
     
-    // set interface up
-    if (!interface_set_up(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 link");
-    
-    // waiting for link
-    iface->state = INTERFACE_STATE_WAITLINK;
+    interface_module_up(iface);
     
     
     return;
     return;
     
     
@@ -865,9 +809,9 @@ fail:
     interface_reset(iface);
     interface_reset(iface);
 }
 }
 
 
-void interface_link_up (struct interface *iface)
+void interface_module_up (struct interface *iface)
 {
 {
-    ASSERT(iface->up)
+    ASSERT(iface->module_instance)
     ASSERT(!iface->have_dhcp)
     ASSERT(!iface->have_dhcp)
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_addresses))
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_addresses))
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_routes))
     ASSERT(LinkedList2_IsEmpty(&iface->ipv4_routes))
@@ -930,6 +874,71 @@ void interface_reset_timer_handler (struct interface *iface)
     interface_start(iface);
     interface_start(iface);
 }
 }
 
 
+int interface_module_init (struct interface *iface, int *initial_up_state)
+{
+    ASSERT(!iface->module_instance)
+    
+    struct NCDInterfaceModule_ncd_params params = { 
+        .reactor = &ss,
+        .conf = iface->conf, 
+        .handler_event = (NCDInterfaceModule_handler_event)interface_module_handler_event, 
+        .user = iface
+    };
+    
+    // call module function new
+    if (!(iface->module_instance = iface->module->func_new(params, initial_up_state))) {
+        interface_log(iface, BLOG_ERROR, "failed to inizialice module instance");
+        return 0;
+    }
+    
+    ASSERT(*initial_up_state == 0 || *initial_up_state == 1)
+    
+    return 1;
+}
+
+void interface_module_free (struct interface *iface)
+{
+    ASSERT(iface->module_instance)
+    
+    // call module function free
+    iface->module->func_free(iface->module_instance);
+    
+    iface->module_instance = NULL;
+}
+
+void interface_module_handler_event (struct interface *iface, int event)
+{
+    ASSERT(iface->module_instance)
+    ASSERT(iface->state >= INTERFACE_STATE_WAITMODULE)
+    
+    switch (event) {
+        case NCDINTERFACEMODULE_EVENT_UP: {
+            ASSERT(iface->state == INTERFACE_STATE_WAITMODULE)
+            
+            interface_log(iface, BLOG_INFO, "module up");
+            
+            interface_module_up(iface);
+        } break;
+        
+        case NCDINTERFACEMODULE_EVENT_DOWN: {
+            ASSERT(iface->state > INTERFACE_STATE_WAITMODULE)
+            
+            interface_log(iface, BLOG_INFO, "module down");
+            
+            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_dhcp_handler (struct interface *iface, int event)
 void interface_dhcp_handler (struct interface *iface, int event)
 {
 {
     ASSERT(iface->have_dhcp)
     ASSERT(iface->have_dhcp)
@@ -1066,33 +1075,6 @@ void interface_unsatisfy_incoming_depenencies (struct interface *iface)
     }
     }
 }
 }
 
 
-int interface_set_up (struct interface *iface)
-{
-    ASSERT(!iface->up)
-    
-    // set up
-    if (!NCDIfConfig_set_up(iface->conf->name)) {
-        interface_log(iface, BLOG_ERROR, "failed to set up");
-        return 0;
-    }
-    
-    iface->up = 1;
-    
-    return 1;
-}
-
-void interface_set_down (struct interface *iface)
-{
-    ASSERT(iface->up)
-    
-    // set down
-    if (!NCDIfConfig_set_down(iface->conf->name)) {
-        interface_log(iface, BLOG_ERROR, "failed to set down");
-    }
-    
-    iface->up = 0;
-}
-
 int interface_configure_ipv4 (struct interface *iface)
 int interface_configure_ipv4 (struct interface *iface)
 {
 {
     ASSERT(!(iface->have_dhcp) || BDHCPClient_IsUp(&iface->dhcp))
     ASSERT(!(iface->have_dhcp) || BDHCPClient_IsUp(&iface->dhcp))