proto-shell: rework task statemachine
[project/netifd.git] / interface.c
index 0f54d51..257eaca 100644 (file)
@@ -93,39 +93,19 @@ interface_flush_state(struct interface *iface)
        interface_ip_flush(&iface->proto_ip);
        if (iface->main_dev.dev)
                device_release(&iface->main_dev);
+       if (iface->l3_dev != &iface->main_dev && iface->l3_dev->dev)
+               device_release(iface->l3_dev);
 }
 
 static void
 mark_interface_down(struct interface *iface)
 {
+       if (iface->state == IFS_UP)
+               interface_event(iface, IFEV_DOWN);
        interface_flush_state(iface);
        iface->state = IFS_DOWN;
 }
 
-static int
-__interface_set_up(struct interface *iface)
-{
-       int ret;
-
-       if (iface->state != IFS_DOWN)
-               return 0;
-
-       if (iface->main_dev.dev) {
-               ret = device_claim(&iface->main_dev);
-               if (ret)
-                       return ret;
-       }
-
-       iface->state = IFS_SETUP;
-       ret = interface_proto_event(iface->proto, PROTO_CMD_SETUP, false);
-       if (ret) {
-               mark_interface_down(iface);
-               return ret;
-       }
-
-       return 0;
-}
-
 void
 __interface_set_down(struct interface *iface, bool force)
 {
@@ -135,8 +115,9 @@ __interface_set_down(struct interface *iface, bool force)
                iface->state == IFS_TEARDOWN)
                return;
 
+       if (iface->state == IFS_UP)
+               interface_event(iface, IFEV_DOWN);
        iface->state = IFS_TEARDOWN;
-       interface_event(iface, IFEV_DOWN);
        interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, force);
        if (force)
                interface_flush_state(iface);
@@ -206,6 +187,8 @@ interface_claim_device(struct interface *iface)
                if (dev)
                        device_add_user(&iface->main_dev, dev);
        }
+       if (iface->proto_handler->flags & PROTO_FLAG_INIT_AVAILABLE)
+               interface_set_available(iface, true);
 }
 
 
@@ -240,12 +223,8 @@ static void
 interface_do_reload(struct interface *iface)
 {
        interface_cleanup(iface);
-
-       interface_claim_device(iface);
        proto_init_interface(iface, iface->config);
-
-       if (iface->autostart && !config_init)
-               interface_set_up(iface);
+       interface_claim_device(iface);
 }
 
 static void
@@ -259,8 +238,10 @@ interface_handle_config_change(struct interface *iface)
                break;
        case IFC_REMOVE:
                interface_do_free(iface);
-               break;
+               return;
        }
+       if (iface->autostart && iface->available)
+               interface_set_up(iface);
 }
 
 static void
@@ -290,18 +271,15 @@ interface_proto_cb(struct interface_proto_state *state, enum interface_proto_eve
                system_flush_routes();
                mark_interface_down(iface);
                interface_handle_config_change(iface);
-               if (iface->l3_dev->dev)
-                       device_release(iface->l3_dev);
-               if (iface->autostart && iface->available)
-                       __interface_set_up(iface);
                break;
        case IFPEV_LINK_LOST:
                if (iface->state != IFS_UP)
                        return;
 
                netifd_log_message(L_NOTICE, "Interface '%s' has lost the connection\n", iface->name);
+               if (iface->state == IFS_UP)
+                       interface_event(iface, IFEV_DOWN);
                iface->state = IFS_SETUP;
-               interface_event(iface, IFEV_DOWN);
                break;
        }
 }
@@ -403,6 +381,8 @@ interface_add_link(struct interface *iface, struct device *dev)
 int
 interface_set_up(struct interface *iface)
 {
+       int ret;
+
        iface->autostart = true;
 
        if (iface->state != IFS_DOWN)
@@ -414,7 +394,20 @@ interface_set_up(struct interface *iface)
                return -1;
        }
 
-       return __interface_set_up(iface);
+       if (iface->main_dev.dev) {
+               ret = device_claim(&iface->main_dev);
+               if (ret)
+                       return ret;
+       }
+
+       iface->state = IFS_SETUP;
+       ret = interface_proto_event(iface->proto, PROTO_CMD_SETUP, false);
+       if (ret) {
+               mark_interface_down(iface);
+               return ret;
+       }
+
+       return 0;
 }
 
 int
@@ -488,8 +481,9 @@ interface_change_config(struct interface *if_old, struct interface *if_new)
        if_old->ifname = if_new->ifname;
        if_old->proto_handler = if_new->proto_handler;
 
-       if (strcmp(old_ifname, if_new->ifname) != 0 ||
-               proto != if_new->proto_handler) {
+       if ((!!old_ifname != !!if_new->ifname) ||
+           (old_ifname && strcmp(old_ifname, if_new->ifname) != 0) ||
+           proto != if_new->proto_handler) {
                D(INTERFACE, "Reload interface '%s' because of ifname/proto change\n",
                  if_old->name);
                goto reload;
@@ -529,8 +523,8 @@ interface_update(struct vlist_tree *tree, struct vlist_node *node_new,
                set_config_state(if_old, IFC_REMOVE);
        } else if (node_new) {
                D(INTERFACE, "Create interface '%s'\n", if_new->name);
-               interface_claim_device(if_new);
                proto_init_interface(if_new, if_new->config);
+               interface_claim_device(if_new);
                netifd_ubus_add_interface(if_new);
        }
 }