device: Don't call set_state for external device in device_claim
[project/netifd.git] / interface-ip.c
index 1a22ce6..7f8a451 100644 (file)
@@ -442,6 +442,9 @@ interface_handle_subnet_route(struct interface *iface, struct device_addr *addr,
        struct device *dev = iface->l3_dev.dev;
        struct device_route route;
 
+       if (addr->flags & DEVADDR_OFFLINK)
+               return;
+
        memset(&route, 0, sizeof(route));
        route.iface = iface;
        route.flags = addr->flags;
@@ -453,14 +456,11 @@ interface_handle_subnet_route(struct interface *iface, struct device_addr *addr,
                route.flags |= DEVADDR_KERNEL;
                system_del_route(dev, &route);
 
-               if (!(addr->flags & DEVADDR_OFFLINK)) {
-                       route.flags &= ~DEVADDR_KERNEL;
-                       route.metric = iface->metric;
-                       system_add_route(dev, &route);
-               }
+               route.flags &= ~DEVADDR_KERNEL;
+               route.metric = iface->metric;
+               system_add_route(dev, &route);
        } else {
-               if (!(addr->flags & DEVADDR_OFFLINK))
-                       system_del_route(dev, &route);
+               system_del_route(dev, &route);
        }
 }
 
@@ -562,7 +562,7 @@ interface_update_proto_addr(struct vlist_tree *tree,
                                }
                        }
 
-                       if ((a_new->flags & DEVADDR_OFFLINK) || iface->metric)
+                       if (iface->metric)
                                interface_handle_subnet_route(iface, a_new, true);
                }
        }
@@ -710,7 +710,9 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
        struct device *l3_downlink = iface->l3_dev.dev;
 
        struct device_addr addr;
+       struct device_route route;
        memset(&addr, 0, sizeof(addr));
+       memset(&route, 0, sizeof(route));
 
        if (IN6_IS_ADDR_UNSPECIFIED(&assignment->addr)) {
                addr.addr.in6 = prefix->addr;
@@ -722,15 +724,14 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
                addr.addr.in6 = assignment->addr;
 
        addr.mask = assignment->length;
-       addr.flags = DEVADDR_INET6;
+       addr.flags = DEVADDR_INET6 | DEVADDR_OFFLINK;
        addr.preferred_until = prefix->preferred_until;
        addr.valid_until = prefix->valid_until;
 
-       if (addr.mask < 64) {
-               addr.mask = 64;
-               system_del_address(l3_downlink, &addr);
-               addr.mask = assignment->length;
-       }
+       route.flags = DEVADDR_INET6;
+       route.mask = addr.mask < 64 ? 64 : addr.mask;
+       route.addr = addr.addr;
+       clear_if_addr(&route.addr, route.mask);
 
        if (!add && assignment->enabled) {
                time_t now = system_get_rtime();
@@ -738,8 +739,6 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
                if (!addr.valid_until || addr.valid_until - now > 7200)
                        addr.valid_until = now + 7200;
 
-               system_del_address(l3_downlink, &addr); // Work around dangling prefix routes
-
                if (prefix->iface) {
                        if (prefix->iface->ip6table)
                                set_ip_source_policy(false, true, IPRULE_PRIORITY_NW, &addr.addr,
@@ -749,16 +748,12 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
                                                        addr.mask, 0, iface, "unreachable");
                }
 
-               if (addr.mask < 64)
-                       addr.mask = 64;
-
-               interface_handle_subnet_route(iface, &addr, false);
+               system_del_route(l3_downlink, &route);
                system_add_address(l3_downlink, &addr);
 
                assignment->enabled = false;
        } else if (add && (iface->state == IFS_UP || iface->state == IFS_SETUP) &&
                        !system_add_address(l3_downlink, &addr)) {
-               interface_handle_subnet_route(iface, &addr, false);
 
                if (prefix->iface && !assignment->enabled) {
                        set_ip_source_policy(true, true, IPRULE_PRIORITY_REJECT, &addr.addr,
@@ -769,15 +764,14 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
                                                addr.mask, prefix->iface->ip6table, iface, NULL);
                }
 
-               if (addr.mask < 64)
-                       addr.mask = 64;
+               route.metric = iface->metric;
+               system_add_route(l3_downlink, &route);
 
-               interface_handle_subnet_route(iface, &addr, true);
+               if (uplink && uplink->l3_dev.dev && !(l3_downlink->settings.flags & DEV_OPT_MTU6)) {
+                       int mtu = system_update_ipv6_mtu(uplink->l3_dev.dev, 0);
+                       int mtu_old = system_update_ipv6_mtu(l3_downlink, 0);
 
-               if (uplink && uplink->l3_dev.dev) {
-                       int mtu = system_update_ipv6_mtu(
-                                       uplink->l3_dev.dev, 0);
-                       if (mtu > 0)
+                       if (mtu > 0 && mtu_old > mtu)
                                system_update_ipv6_mtu(l3_downlink, mtu);
                }
 
@@ -1228,7 +1222,7 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
 
                if (enabled) {
                        system_add_address(dev, addr);
-                       if ((addr->flags & DEVADDR_OFFLINK) || iface->metric)
+                       if (iface->metric)
                                interface_handle_subnet_route(iface, addr, true);
                } else {
                        interface_handle_subnet_route(iface, addr, false);