netifd: Set interface state in teardown state before launching an interface event
[project/netifd.git] / interface.c
index 4b381a4..39460e4 100644 (file)
@@ -26,7 +26,6 @@
 
 struct vlist_tree interfaces;
 static LIST_HEAD(iface_all_users);
-static unsigned int interface_serial = 0;
 
 enum {
        IFACE_ATTR_IFNAME,
@@ -151,15 +150,23 @@ interface_add_data(struct interface *iface, const struct blob_attr *data)
        if (!blobmsg_check_attr(data, true))
                return UBUS_STATUS_INVALID_ARGUMENT;
 
-       n = calloc(1, sizeof(*n) + blob_pad_len(data));
-       memcpy(n->data, data, blob_pad_len(data));
-       n->node.key = blobmsg_name(n->data);
+       const char *name = blobmsg_name(data);
+       unsigned len = blob_pad_len(data);
+
+       o = avl_find_element(&iface->data, name, o, node);
+       if (o) {
+               if (blob_pad_len(o->data) == len && !memcmp(o->data, data, len))
+                       return 0;
 
-       o = avl_find_element(&iface->data, n->node.key, o, node);
-       if (o)
                interface_data_del(iface, o);
+       }
 
+       n = calloc(1, sizeof(*n) + len);
+       memcpy(n->data, data, len);
+       n->node.key = blobmsg_name(n->data);
        avl_insert(&iface->data, &n->node);
+
+       iface->updated |= IUF_DATA;
        return 0;
 }
 
@@ -215,11 +222,14 @@ mark_interface_down(struct interface *iface)
 void
 __interface_set_down(struct interface *iface, bool force)
 {
-       switch (iface->state) {
+       enum interface_state state = iface->state;
+       switch (state) {
        case IFS_UP:
-               interface_event(iface, IFEV_DOWN);
        case IFS_SETUP:
                iface->state = IFS_TEARDOWN;
+               if (state == IFS_UP)
+                       interface_event(iface, IFEV_DOWN);
+
                interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, force);
                if (force)
                        interface_flush_state(iface);
@@ -670,13 +680,6 @@ interface_alloc(const char *name, struct blob_attr *config)
                        DPRINTF("Failed to resolve routing table: %s\n", (char *) blobmsg_data(cur));
        }
 
-       // Set a default exteranl routing table for IPv6 to do source-based-filtering
-       struct interface *iface_old = vlist_find(&interfaces, name, iface_old, node);
-       if (iface_old && iface_old->ip6table > 1000 && iface_old->ip6table < 2000)
-               iface->ip6table = iface_old->ip6table;
-       else
-               iface->ip6table = 1000 + ++interface_serial;
-
        if ((cur = tb[IFACE_ATTR_IP6TABLE])) {
                if (!system_resolve_rt_table(blobmsg_data(cur), &iface->ip6table))
                        DPRINTF("Failed to resolve routing table: %s\n", (char *) blobmsg_data(cur));
@@ -839,7 +842,7 @@ interface_handle_link(struct interface *iface, const char *name, bool add)
                if (iface->device_config)
                        device_set_config(dev, &simple_device_type, iface->config);
 
-               system_if_apply_settings(dev, &dev->settings);
+               system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
                ret = interface_add_link(iface, dev);
        } else {
                ret = interface_remove_link(iface, dev);
@@ -916,6 +919,7 @@ set_config_state(struct interface *iface, enum interface_config_state s)
 void
 interface_update_start(struct interface *iface)
 {
+       iface->updated = 0;
        interface_ip_update_start(&iface->proto_ip);
 }