interface: warn if ip6hint is truncated
[project/netifd.git] / interface.c
index 4cefe6454dae6c8c94989e0065250661b64e26e1..2fa0613167ad82e4ff9db79aa7c415fd27c51a05 100644 (file)
@@ -269,6 +269,7 @@ mark_interface_down(struct interface *iface)
        iface->state = IFS_DOWN;
        switch (state) {
        case IFS_UP:
+       case IFS_TEARDOWN:
                interface_event(iface, IFEV_DOWN);
                break;
        case IFS_SETUP:
@@ -342,11 +343,11 @@ interface_check_state(struct interface *iface)
        case IFS_UP:
        case IFS_SETUP:
                if (!iface->enabled || !link_state) {
-                       interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, false);
+                       iface->state = IFS_TEARDOWN;
                        if (iface->dynamic)
                                __set_config_state(iface, IFC_REMOVE);
 
-                       mark_interface_down(iface);
+                       interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, false);
                }
                break;
        case IFS_DOWN:
@@ -496,7 +497,7 @@ interface_add_assignment_classes(struct interface *iface, struct blob_attr *list
                if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
                        continue;
 
-               if (!blobmsg_check_attr(cur, NULL))
+               if (!blobmsg_check_attr(cur, false))
                        continue;
 
                struct interface_assignment_class *c = malloc(sizeof(*c) + blobmsg_data_len(cur));
@@ -862,9 +863,15 @@ interface_alloc(const char *name, struct blob_attr *config, bool dynamic)
        }
 
        iface->assignment_hint = -1;
-       if ((cur = tb[IFACE_ATTR_IP6HINT]))
-               iface->assignment_hint = strtol(blobmsg_get_string(cur), NULL, 16) &
-                               ~((1 << (64 - iface->assignment_length)) - 1);
+       if ((cur = tb[IFACE_ATTR_IP6HINT])) {
+               int32_t assignment_hint = strtol(blobmsg_get_string(cur), NULL, 16);
+
+               iface->assignment_hint = assignment_hint & ~((1 << (64 - iface->assignment_length)) - 1);
+
+               if (iface->assignment_hint != assignment_hint)
+                       netifd_log_message(L_WARNING, "Using truncated assignment hint %d (0x%x) for interface '%s'\n",
+                                          iface->assignment_hint, iface->assignment_hint, iface->name);
+       }
 
        if ((cur = tb[IFACE_ATTR_IP6CLASS]))
                interface_add_assignment_classes(iface, cur);
@@ -892,7 +899,7 @@ static bool __interface_add(struct interface *iface, struct blob_attr *config, b
 {
        struct blob_attr *tb[IFACE_ATTR_MAX];
        struct blob_attr *cur;
-       char *name = iface->dynamic ? strdup(iface->name) : NULL;
+       char *name = NULL;
 
        blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb,
                      blob_data(config), blob_len(config));
@@ -908,6 +915,13 @@ static bool __interface_add(struct interface *iface, struct blob_attr *config, b
                        iface->ifname = blobmsg_data(cur);
        }
 
+       if (iface->dynamic) {
+               name = strdup(iface->name);
+
+               if (!name)
+                       return false;
+       }
+
        iface->config = config;
        vlist_add(&interfaces, &iface->node, iface->name);
 
@@ -915,11 +929,9 @@ static bool __interface_add(struct interface *iface, struct blob_attr *config, b
                iface = vlist_find(&interfaces, name, iface, node);
                free(name);
 
-               if (!iface)
-                       return false;
-
                /* Don't delete dynamic interface on reload */
-               iface->node.version = -1;
+               if (iface)
+                       iface->node.version = -1;
        }
 
        return true;
@@ -1192,7 +1204,7 @@ static void
 interface_change_config(struct interface *if_old, struct interface *if_new)
 {
        struct blob_attr *old_config = if_old->config;
-       bool reload = false, reload_ip = false;
+       bool reload = false, reload_ip = false, update_prefix_delegation = false;
 
 #define FIELD_CHANGED_STR(field)                                       \
                ((!!if_old->field != !!if_new->field) ||                \
@@ -1242,6 +1254,11 @@ interface_change_config(struct interface *if_old, struct interface *if_new)
        if_old->force_link = if_new->force_link;
        if_old->dns_metric = if_new->dns_metric;
 
+       if (if_old->proto_ip.no_delegation != if_new->proto_ip.no_delegation) {
+               if_old->proto_ip.no_delegation = if_new->proto_ip.no_delegation;
+               update_prefix_delegation = true;
+       }
+
        if_old->proto_ip.no_dns = if_new->proto_ip.no_dns;
        interface_replace_dns(&if_old->config_ip, &if_new->config_ip);
 
@@ -1271,6 +1288,9 @@ interface_change_config(struct interface *if_old, struct interface *if_new)
                interface_ip_set_enabled(&if_old->config_ip, config_ip_enabled);
        }
 
+       if (update_prefix_delegation)
+               interface_update_prefix_delegation(&if_old->proto_ip);
+
        interface_write_resolv_conf();
        if (if_old->main_dev.dev)
                interface_check_state(if_old);