[PATCH 1/1] ipv6 addrconf:fix preferred lifetime state-changing behavior while valid_lft is infinity
From: <hidden>
Date: 2013-12-12 10:02:29
Subsystem:
networking [general], networking [ipv4/ipv6], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds
From: Yasushi Asano <redacted> Fixed a problem with setting the lifetime of an IPv6 address. When setting preferred_lft to a value not zero or infinity, while valid_lft is infinity(0xffffffff) preferred lifetime is set to forever and does not update. Therefore preferred lifetime never becomes deprecated. valid lifetime and preferred lifetime should be set independently, even if valid lifetime is infinity, preferred lifetime must expire correctly (meaning it must eventually become deprecated) Signed-off-by: Yasushi Asano <redacted> --- net/ipv6/addrconf.c | 34 ++++++++++++++++++++-------------- 1 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3c3425e..17b4097 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c@@ -948,18 +948,22 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) if (!onlink) onlink = -1; - spin_lock(&ifa->lock); - - lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ); - /* - * Note: Because this address is - * not permanent, lifetime < - * LONG_MAX / HZ here. - */ - if (time_before(expires, - ifa->tstamp + lifetime * HZ)) - expires = ifa->tstamp + lifetime * HZ; - spin_unlock(&ifa->lock); + if (ifp->valid_lft != + INFINITY_LIFE_TIME) { + spin_lock(&ifa->lock); + + lifetime = addrconf_timeout_fixup( + ifa->valid_lft, HZ); + /* + * Note: Because this address is + * not permanent, lifetime < + * LONG_MAX / HZ here. + */ + if (time_before(expires, + ifa->tstamp + lifetime * HZ)) + expires = ifa->tstamp + lifetime * HZ; + spin_unlock(&ifa->lock); + } } } }
@@ -2415,7 +2419,6 @@ static int inet6_addr_add(struct net *net, int ifindex, } else { expires = 0; flags = 0; - ifa_flags |= IFA_F_PERMANENT; } timeout = addrconf_timeout_fixup(prefered_lft, HZ);
@@ -3497,8 +3500,12 @@ restart: ifp->flags |= IFA_F_DEPRECATED; } - if (time_before(ifp->tstamp + ifp->valid_lft * HZ, next)) - next = ifp->tstamp + ifp->valid_lft * HZ; + if (ifp->valid_lft != INFINITY_LIFE_TIME) { + if (time_before(ifp->tstamp + + ifp->valid_lft * HZ, next)) + next = ifp->tstamp + + ifp->valid_lft * HZ; + } spin_unlock(&ifp->lock);
@@ -3635,7 +3642,6 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, } else { expires = 0; flags = 0; - ifa_flags |= IFA_F_PERMANENT; } timeout = addrconf_timeout_fixup(prefered_lft, HZ);