do not clear device state for devices created by proto-up with address-external set
[project/netifd.git] / device.c
index ccba9d3..428d001 100644 (file)
--- a/device.c
+++ b/device.c
@@ -41,6 +41,20 @@ const struct config_param_list device_attr_list = {
        .params = dev_attrs,
 };
 
+static int __devlock = 0;
+
+void device_lock(void)
+{
+       __devlock++;
+}
+
+void device_unlock(void)
+{
+       __devlock--;
+       if (!__devlock)
+               device_free_unused(NULL);
+}
+
 static struct device *
 simple_device_create(const char *name, struct blob_attr *attr)
 {
@@ -172,6 +186,8 @@ alias_notify_device(const char *name, struct device *dev)
 {
        struct alias_device *alias;
 
+       device_lock();
+
        alias = avl_find_element(&aliases, name, alias, avl);
        if (!alias)
                return;
@@ -179,8 +195,7 @@ alias_notify_device(const char *name, struct device *dev)
        alias->cleanup = !dev;
        if (dev) {
                if (dev != alias->dep.dev) {
-                       if (alias->dep.dev)
-                               device_remove_user(&alias->dep);
+                       device_remove_user(&alias->dep);
                        strcpy(alias->dev.ifname, dev->ifname);
                        device_add_user(&alias->dep, dev);
                }
@@ -190,6 +205,8 @@ alias_notify_device(const char *name, struct device *dev)
 
        if (!dev && alias->dep.dev && !alias->dep.dev->active)
                device_remove_user(&alias->dep);
+
+       device_unlock();
 }
 
 static int set_device_state(struct device *dev, bool state)
@@ -291,12 +308,13 @@ int device_init(struct device *dev, const struct device_type *type, const char *
 }
 
 static struct device *
-device_create_default(const char *name)
+device_create_default(const char *name, bool external)
 {
        struct device *dev;
 
        D(DEVICE, "Create simple device '%s'\n", name);
        dev = calloc(1, sizeof(*dev));
+       dev->external = external;
        device_init(dev, &simple_device_type, name);
        dev->default_config = true;
        return dev;
@@ -315,7 +333,7 @@ device_alias_get(const char *name)
 }
 
 struct device *
-device_get(const char *name, bool create)
+device_get(const char *name, int create)
 {
        struct device *dev;
 
@@ -332,7 +350,7 @@ device_get(const char *name, bool create)
        if (!create)
                return NULL;
 
-       return device_create_default(name);
+       return device_create_default(name, create > 1);
 }
 
 static void
@@ -386,7 +404,7 @@ void device_add_user(struct device_user *dep, struct device *dev)
 static void
 __device_free_unused(struct device *dev)
 {
-       if (!list_empty(&dev->users) || dev->current_config || config_init)
+       if (!list_empty(&dev->users) || dev->current_config || __devlock)
                return;
 
        device_free(dev);
@@ -396,6 +414,10 @@ void device_remove_user(struct device_user *dep)
 {
        struct device *dev = dep->dev;
 
+       if (!dep->dev)
+               return;
+
+       dep->hotplug = false;
        if (dep->claimed)
                device_release(dep);
 
@@ -430,7 +452,7 @@ device_init_pending(void)
        }
 }
 
-enum dev_change_type
+static enum dev_change_type
 device_reload_config(struct device *dev, struct blob_attr *attr)
 {
        struct blob_attr *tb[__DEV_ATTR_MAX];
@@ -442,7 +464,7 @@ device_reload_config(struct device *dev, struct blob_attr *attr)
        if (cfg == &device_attr_list) {
                memset(tb, 0, sizeof(tb));
 
-               if (dev->config)
+               if (attr)
                        blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb,
                                blob_data(attr), blob_len(attr));
 
@@ -452,9 +474,9 @@ device_reload_config(struct device *dev, struct blob_attr *attr)
                return DEV_CONFIG_RECREATE;
 }
 
-static enum dev_change_type
-device_check_config(struct device *dev, const struct device_type *type,
-                   struct blob_attr *attr)
+enum dev_change_type
+device_set_config(struct device *dev, const struct device_type *type,
+                 struct blob_attr *attr)
 {
        if (type != dev->type)
                return DEV_CONFIG_RECREATE;
@@ -506,7 +528,7 @@ device_reset_old(void)
                if (dev->type != &simple_device_type)
                        continue;
 
-               ndev = device_create_default(dev->ifname);
+               ndev = device_create_default(dev->ifname, dev->external);
                device_replace(ndev, dev);
        }
 }
@@ -525,7 +547,7 @@ device_create(const char *name, const struct device_type *type,
        odev = device_get(name, false);
        if (odev) {
                odev->current_config = true;
-               change = device_check_config(odev, type, config);
+               change = device_set_config(odev, type, config);
                switch (change) {
                case DEV_CONFIG_APPLIED:
                        D(DEVICE, "Device '%s': config applied\n", odev->ifname);