diff options
-rw-r--r-- | interface-ip.c | 48 | ||||
-rw-r--r-- | interface-ip.h | 2 |
2 files changed, 29 insertions, 21 deletions
diff --git a/interface-ip.c b/interface-ip.c index 220f4a0..5533615 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -440,32 +440,37 @@ static void interface_handle_subnet_route(struct interface *iface, struct device_addr *addr, bool add) { struct device *dev = iface->l3_dev.dev; - struct device_route route; bool v6 = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET6); + struct device_route *r = &addr->subnet; if (addr->flags & DEVADDR_OFFLINK) return; - memset(&route, 0, sizeof(route)); - route.iface = iface; - route.flags = addr->flags; - route.mask = addr->mask; - memcpy(&route.addr, &addr->addr, sizeof(route.addr)); - clear_if_addr(&route.addr, route.mask); - - if (add) { - route.flags |= DEVADDR_KERNEL; - system_del_route(dev, &route); + if (!add) { + if (!addr->subnet.iface) + return; - route.flags &= ~DEVADDR_KERNEL; - route.metric = iface->metric; - route.table = (v6) ? iface->ip6table : iface->ip4table; - if (route.table) - route.flags |= DEVROUTE_SRCTABLE; - system_add_route(dev, &route); - } else { - system_del_route(dev, &route); + system_del_route(dev, r); + memset(r, 0, sizeof(*r)); + return; } + + r->iface = iface; + r->flags = addr->flags; + r->mask = addr->mask; + memcpy(&r->addr, &addr->addr, sizeof(r->addr)); + clear_if_addr(&r->addr, r->mask); + + r->flags |= DEVADDR_KERNEL; + system_del_route(dev, r); + + r->flags &= ~DEVADDR_KERNEL; + r->metric = iface->metric; + r->table = (v6) ? iface->ip6table : iface->ip4table; + if (r->table) + r->flags |= DEVROUTE_SRCTABLE; + + system_add_route(dev, r); } static void @@ -1230,10 +1235,11 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) if (enabled) { system_add_address(dev, addr); - if (iface->metric) - interface_handle_subnet_route(iface, addr, true); addr->policy_table = (v6) ? iface->ip6table : iface->ip4table; + if (iface->metric || addr->policy_table) + interface_handle_subnet_route(iface, addr, true); + if (addr->policy_table) set_ip_source_policy(true, v6, IPRULE_PRIORITY_ADDR, &addr->addr, (v6) ? 128 : 32, addr->policy_table, NULL, NULL); diff --git a/interface-ip.h b/interface-ip.h index f24b0ec..bbef62c 100644 --- a/interface-ip.h +++ b/interface-ip.h @@ -110,6 +110,8 @@ struct device_addr { bool failed; unsigned int policy_table; + struct device_route subnet; + /* ipv4 only */ uint32_t broadcast; uint32_t point_to_point; |