diff options
author | hendrikw01 <hendrik@gestorf.com> | 2017-03-31 15:10:59 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2017-03-31 15:10:59 +0200 |
commit | 6554550f35a7976f9110aff94743d3576d5f02dd (patch) | |
tree | c899aa5d75943a966c1c51bf3b90eeeaaa50b9c2 /src | |
parent | 510cb1ce89d8ce3310e7ca514dd35986964d6f01 (diff) |
networkd: RFC compliant autonomous prefix handling (#5636)
Previously, `lifetime_valid` of a Router Advertisement was not handled
the way RFC4862 has specified.
In particular: Sections 5.5.3.d and 5.5.3.e
Diffstat (limited to 'src')
-rw-r--r-- | src/network/networkd-ndisc.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 4fd5d8ae70..d52b511bb5 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -27,6 +27,7 @@ #define NDISC_DNSSL_MAX 64U #define NDISC_RDNSS_MAX 64U +#define NDISC_PREFIX_LFT_MIN 7200U static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; @@ -152,13 +153,21 @@ static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) { _cleanup_address_free_ Address *address = NULL; - uint32_t lifetime_valid, lifetime_preferred; + Address *existing_address; + uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining; + usec_t time_now; unsigned prefixlen; int r; assert(link); assert(rt); + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } + r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen); if (r < 0) { log_link_error_errno(link, r, "Failed to get prefix length: %m"); @@ -207,7 +216,24 @@ static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router * address->prefixlen = prefixlen; address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR; address->cinfo.ifa_prefered = lifetime_preferred; - address->cinfo.ifa_valid = lifetime_valid; + + /* see RFC4862 section 5.5.3.e */ + r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address); + if (r > 0) { + lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC; + if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining) + address->cinfo.ifa_valid = lifetime_valid; + else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN) + address->cinfo.ifa_valid = lifetime_remaining; + else + address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN; + } else if (lifetime_valid > 0) + address->cinfo.ifa_valid = lifetime_valid; + else + return; /* see RFC4862 section 5.5.3.d */ + + if (address->cinfo.ifa_valid == 0) + return; r = address_configure(address, link, ndisc_netlink_handler, true); if (r < 0) { |