interface: fix restart after reload with external devices
authorFelix Fietkau <nbd@openwrt.org>
Thu, 24 Jul 2014 09:12:48 +0000 (11:12 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 24 Jul 2014 09:12:50 +0000 (11:12 +0200)
When an interface goes down, the main_dev is reset to NULL.
Track an externally added device separately to be able to bring it back
up.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
interface.c
interface.h

index 4c92f10962db451fe23bbceb6a82c48d34ac4c7c..e66b58a1da658b876f1af4a939592f4924f2396e 100644 (file)
@@ -307,6 +307,13 @@ interface_set_link_state(struct interface *iface, bool new_state)
        interface_check_state(iface);
 }
 
+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)
 {
@@ -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,8 @@ interface_cleanup(struct interface *iface)
 {
        struct interface_user *dep, *tmp;
 
+       device_remove_user(&iface->ext_dev);
+
        if (iface->parent_iface.iface)
                interface_remove_user(&iface->parent_iface);
 
@@ -653,6 +664,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));
@@ -807,6 +819,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;
 
@@ -835,6 +850,7 @@ interface_add_link(struct interface *iface, struct device *dev)
                        return UBUS_STATUS_NOT_SUPPORTED;
        }
 
+       device_add_user(&iface->ext_dev, dev);
        interface_set_main_dev(iface, dev);
        iface->main_dev.hotplug = true;
        return 0;
index 6cfe2645edcd0b5dec77bd131ebfd51aaa1a0caf..1cd7e96d3c7ceab7fda80ccda9a271852111e3d0 100644 (file)
@@ -119,6 +119,7 @@ struct interface {
 
        /* main interface that the interface is bound to */
        struct device_user main_dev;
+       struct device_user ext_dev;
 
        /* interface that layer 3 communication will go through */
        struct device_user l3_dev;