interface: cancel the remove timer on cleanup
[project/netifd.git] / interface.c
index ea25208..df04ce3 100644 (file)
@@ -308,6 +308,13 @@ interface_set_link_state(struct interface *iface, bool new_state)
 }
 
 static void
+interface_ext_cb(struct device_user *dep, enum device_event ev)
+{
+       if (ev == DEV_EVENT_REMOVE)
+               device_remove_user(dep);
+}
+
+static void
 interface_cb(struct device_user *dep, enum device_event ev)
 {
        struct interface *iface;
@@ -491,6 +498,8 @@ interface_claim_device(struct interface *iface)
        } else if (iface->ifname &&
                !(iface->proto_handler->flags & PROTO_FLAG_NODEV)) {
                dev = device_get(iface->ifname, true);
+       } else {
+               dev = iface->ext_dev.dev;
        }
 
        if (dev)
@@ -518,6 +527,9 @@ interface_cleanup(struct interface *iface)
 {
        struct interface_user *dep, *tmp;
 
+       uloop_timeout_cancel(&iface->remove_timer);
+       device_remove_user(&iface->ext_dev);
+
        if (iface->parent_iface.iface)
                interface_remove_user(&iface->parent_iface);
 
@@ -641,6 +653,7 @@ interface_alloc(const char *name, struct blob_attr *config)
        struct blob_attr *cur;
        const char *proto_name = NULL;
        char *iface_name;
+       bool force_link = false;
 
        iface = calloc_a(sizeof(*iface), &iface_name, strlen(name) + 1);
        iface->name = strcpy(iface_name, name);
@@ -653,6 +666,7 @@ interface_alloc(const char *name, struct blob_attr *config)
        iface->config_ip.enabled = false;
 
        iface->main_dev.cb = interface_cb;
+       iface->ext_dev.cb = interface_ext_cb;
 
        blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb,
                      blob_data(config), blob_len(config));
@@ -661,9 +675,11 @@ interface_alloc(const char *name, struct blob_attr *config)
                proto_name = blobmsg_data(cur);
 
        proto_attach_interface(iface, proto_name);
+       if (iface->proto_handler->flags & PROTO_FLAG_FORCE_LINK_DEFAULT)
+               force_link = true;
 
        iface->autostart = blobmsg_get_bool_default(tb[IFACE_ATTR_AUTO], true);
-       iface->force_link = blobmsg_get_bool_default(tb[IFACE_ATTR_FORCE_LINK], false);
+       iface->force_link = blobmsg_get_bool_default(tb[IFACE_ATTR_FORCE_LINK], force_link);
        iface->proto_ip.no_defaultroute =
                !blobmsg_get_bool_default(tb[IFACE_ATTR_DEFAULTROUTE], true);
        iface->proto_ip.no_dns =
@@ -709,6 +725,7 @@ interface_alloc(const char *name, struct blob_attr *config)
 void interface_set_dynamic(struct interface *iface)
 {
        iface->dynamic = true;
+       iface->autostart = true;
        iface->node.version = -1; // Don't delete on reload
 }
 
@@ -806,6 +823,9 @@ interface_remove_link(struct interface *iface, struct device *dev)
        if (mdev && mdev->hotplug_ops)
                return mdev->hotplug_ops->del(mdev, dev);
 
+       if (dev == iface->ext_dev.dev)
+               device_remove_user(&iface->ext_dev);
+
        if (!iface->main_dev.hotplug)
                return UBUS_STATUS_INVALID_ARGUMENT;
 
@@ -816,8 +836,8 @@ interface_remove_link(struct interface *iface, struct device *dev)
        return 0;
 }
 
-int
-interface_add_link(struct interface *iface, struct device *dev)
+static int
+interface_add_link(struct interface *iface, struct device *dev, bool link_ext)
 {
        struct device *mdev = iface->main_dev.dev;
 
@@ -834,20 +854,23 @@ interface_add_link(struct interface *iface, struct device *dev)
                        return UBUS_STATUS_NOT_SUPPORTED;
        }
 
+       if (link_ext)
+               device_add_user(&iface->ext_dev, dev);
+
        interface_set_main_dev(iface, dev);
        iface->main_dev.hotplug = true;
        return 0;
 }
 
 int
-interface_handle_link(struct interface *iface, const char *name, bool add)
+interface_handle_link(struct interface *iface, const char *name, bool add, bool link_ext)
 {
        struct device *dev;
        int ret;
 
        device_lock();
 
-       dev = device_get(name, add ? 2 : 0);
+       dev = device_get(name, add ? (link_ext ? 2 : 1) : 0);
        if (!dev) {
                ret = UBUS_STATUS_NOT_FOUND;
                goto out;
@@ -859,7 +882,7 @@ interface_handle_link(struct interface *iface, const char *name, bool add)
                        device_set_config(dev, &simple_device_type, iface->config);
 
                system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
-               ret = interface_add_link(iface, dev);
+               ret = interface_add_link(iface, dev, link_ext);
        } else {
                ret = interface_remove_link(iface, dev);
        }