proto-shell: handle the "available" config flag
[project/netifd.git] / interface.c
index f5d8821..787d7d9 100644 (file)
@@ -93,6 +93,8 @@ 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
@@ -102,30 +104,6 @@ mark_interface_down(struct interface *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)
 {
@@ -206,6 +184,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 +220,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 +235,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,10 +268,6 @@ 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)
@@ -403,6 +377,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 +390,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
@@ -465,8 +454,10 @@ interface_update_complete(struct interface *iface)
 
        interface_ip_update_complete(&iface->proto_ip);
        vlist_for_each_element(&iface->config_ip.route, route, node) {
-               if (iface->l3_dev->dev)
+               if (iface->l3_dev->dev) {
                        system_add_route(iface->l3_dev->dev, route);
+                       route->enabled = true;
+               }
        }
 }
 
@@ -486,8 +477,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;
@@ -527,8 +519,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);
        }
 }