summaryrefslogtreecommitdiff
path: root/src/network/networkd-ndisc.c
diff options
context:
space:
mode:
authorhendrikw01 <hendrik@gestorf.com>2017-03-31 15:10:59 +0200
committerLennart Poettering <lennart@poettering.net>2017-03-31 15:10:59 +0200
commit6554550f35a7976f9110aff94743d3576d5f02dd (patch)
treec899aa5d75943a966c1c51bf3b90eeeaaa50b9c2 /src/network/networkd-ndisc.c
parent510cb1ce89d8ce3310e7ca514dd35986964d6f01 (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/network/networkd-ndisc.c')
-rw-r--r--src/network/networkd-ndisc.c30
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) {