summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--interface-ip.c27
-rw-r--r--system-linux.c9
2 files changed, 14 insertions, 22 deletions
diff --git a/interface-ip.c b/interface-ip.c
index 18dd2fa..aec3892 100644
--- a/interface-ip.c
+++ b/interface-ip.c
@@ -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,10 +764,8 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
addr.mask, prefix->iface->ip6table, iface, NULL);
}
- if (addr.mask < 64)
- addr.mask = 64;
-
- interface_handle_subnet_route(iface, &addr, true);
+ route.metric = iface->metric;
+ system_add_route(l3_downlink, &route);
if (uplink && uplink->l3_dev.dev) {
int mtu = system_update_ipv6_mtu(
diff --git a/system-linux.c b/system-linux.c
index 08b6757..a6dde59 100644
--- a/system-linux.c
+++ b/system-linux.c
@@ -30,6 +30,7 @@
#include <linux/rtnetlink.h>
#include <linux/sockios.h>
#include <linux/ip.h>
+#include <linux/if_addr.h>
#include <linux/if_link.h>
#include <linux/if_vlan.h>
#include <linux/if_bridge.h>
@@ -47,10 +48,6 @@
#define RT_TABLE_PRELOCAL 128
#endif
-#ifndef IFA_F_NOPREFIXROUTE
-#define IFA_F_NOPREFIXROUTE 0x200
-#endif
-
#include <string.h>
#include <fcntl.h>
#include <glob.h>
@@ -1431,7 +1428,6 @@ static int system_addr(struct device *dev, struct device_addr *addr, int cmd)
.ifa_family = (alen == 4) ? AF_INET : AF_INET6,
.ifa_prefixlen = addr->mask,
.ifa_index = dev->ifindex,
- .ifa_flags = (addr->flags & DEVADDR_OFFLINK) ? IFA_F_NOPREFIXROUTE : 0,
};
struct nl_msg *msg;
@@ -1474,6 +1470,9 @@ static int system_addr(struct device *dev, struct device_addr *addr, int cmd)
}
nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
+
+ if (cmd == RTM_NEWADDR && (addr->flags & DEVADDR_OFFLINK))
+ nla_put_u32(msg, IFA_FLAGS, IFA_F_NOPREFIXROUTE);
}
return system_rtnl_call(msg);