diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-05-27 04:37:49 -0400 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-06-04 15:02:34 -0400 |
commit | 4bed72e4f5502ea3322f0a00794815fa58951abe (patch) | |
tree | fd652d01822746a84d5812bbe2ee0661fbd3b86f /net | |
parent | baa2bfb8aef24bb7fe1875b256918724b3884662 (diff) |
[IPV6] ADDRCONF: Allow longer lifetime on 64bit archs.
- Allow longer lifetimes (>= 0x7fffffff/HZ) on 64bit archs
by using unsigned long.
- Shadow this arithmetic overflow workaround by introducing
helper functions: addrconf_timeout_fixup() and
addrconf_finite_timeout().
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/addrconf.c | 97 | ||||
-rw-r--r-- | net/ipv6/route.c | 12 |
2 files changed, 53 insertions, 56 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c3b20c5afa3e..147588f4c7c0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -731,8 +731,13 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
731 | onlink = -1; | 731 | onlink = -1; |
732 | 732 | ||
733 | spin_lock(&ifa->lock); | 733 | spin_lock(&ifa->lock); |
734 | lifetime = min_t(unsigned long, | 734 | |
735 | ifa->valid_lft, 0x7fffffffUL/HZ); | 735 | lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ); |
736 | /* | ||
737 | * Note: Because this address is | ||
738 | * not permanent, lifetime < | ||
739 | * LONG_MAX / HZ here. | ||
740 | */ | ||
736 | if (time_before(expires, | 741 | if (time_before(expires, |
737 | ifa->tstamp + lifetime * HZ)) | 742 | ifa->tstamp + lifetime * HZ)) |
738 | expires = ifa->tstamp + lifetime * HZ; | 743 | expires = ifa->tstamp + lifetime * HZ; |
@@ -1722,7 +1727,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1722 | __u32 valid_lft; | 1727 | __u32 valid_lft; |
1723 | __u32 prefered_lft; | 1728 | __u32 prefered_lft; |
1724 | int addr_type; | 1729 | int addr_type; |
1725 | unsigned long rt_expires; | ||
1726 | struct inet6_dev *in6_dev; | 1730 | struct inet6_dev *in6_dev; |
1727 | 1731 | ||
1728 | pinfo = (struct prefix_info *) opt; | 1732 | pinfo = (struct prefix_info *) opt; |
@@ -1764,28 +1768,23 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1764 | * 2) Configure prefixes with the auto flag set | 1768 | * 2) Configure prefixes with the auto flag set |
1765 | */ | 1769 | */ |
1766 | 1770 | ||
1767 | if (valid_lft == INFINITY_LIFE_TIME) | 1771 | if (pinfo->onlink) { |
1768 | rt_expires = ~0UL; | 1772 | struct rt6_info *rt; |
1769 | else if (valid_lft >= 0x7FFFFFFF/HZ) { | 1773 | unsigned long rt_expires; |
1774 | |||
1770 | /* Avoid arithmetic overflow. Really, we could | 1775 | /* Avoid arithmetic overflow. Really, we could |
1771 | * save rt_expires in seconds, likely valid_lft, | 1776 | * save rt_expires in seconds, likely valid_lft, |
1772 | * but it would require division in fib gc, that it | 1777 | * but it would require division in fib gc, that it |
1773 | * not good. | 1778 | * not good. |
1774 | */ | 1779 | */ |
1775 | rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ); | 1780 | if (HZ > USER_HZ) |
1776 | } else | 1781 | rt_expires = addrconf_timeout_fixup(valid_lft, HZ); |
1777 | rt_expires = valid_lft * HZ; | 1782 | else |
1783 | rt_expires = addrconf_timeout_fixup(valid_lft, USER_HZ); | ||
1778 | 1784 | ||
1779 | /* | 1785 | if (addrconf_finite_timeout(rt_expires)) |
1780 | * We convert this (in jiffies) to clock_t later. | 1786 | rt_expires *= HZ; |
1781 | * Avoid arithmetic overflow there as well. | ||
1782 | * Overflow can happen only if HZ < USER_HZ. | ||
1783 | */ | ||
1784 | if (HZ < USER_HZ && ~rt_expires && rt_expires > 0x7FFFFFFF / USER_HZ) | ||
1785 | rt_expires = 0x7FFFFFFF / USER_HZ; | ||
1786 | 1787 | ||
1787 | if (pinfo->onlink) { | ||
1788 | struct rt6_info *rt; | ||
1789 | rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, | 1788 | rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, |
1790 | dev->ifindex, 1); | 1789 | dev->ifindex, 1); |
1791 | 1790 | ||
@@ -1794,7 +1793,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1794 | if (valid_lft == 0) { | 1793 | if (valid_lft == 0) { |
1795 | ip6_del_rt(rt); | 1794 | ip6_del_rt(rt); |
1796 | rt = NULL; | 1795 | rt = NULL; |
1797 | } else if (~rt_expires) { | 1796 | } else if (addrconf_finite_timeout(rt_expires)) { |
1798 | /* not infinity */ | 1797 | /* not infinity */ |
1799 | rt->rt6i_expires = jiffies + rt_expires; | 1798 | rt->rt6i_expires = jiffies + rt_expires; |
1800 | rt->rt6i_flags |= RTF_EXPIRES; | 1799 | rt->rt6i_flags |= RTF_EXPIRES; |
@@ -1803,9 +1802,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1803 | rt->rt6i_expires = 0; | 1802 | rt->rt6i_expires = 0; |
1804 | } | 1803 | } |
1805 | } else if (valid_lft) { | 1804 | } else if (valid_lft) { |
1806 | int flags = RTF_ADDRCONF | RTF_PREFIX_RT; | ||
1807 | clock_t expires = 0; | 1805 | clock_t expires = 0; |
1808 | if (~rt_expires) { | 1806 | int flags = RTF_ADDRCONF | RTF_PREFIX_RT; |
1807 | if (addrconf_finite_timeout(rt_expires)) { | ||
1809 | /* not infinity */ | 1808 | /* not infinity */ |
1810 | flags |= RTF_EXPIRES; | 1809 | flags |= RTF_EXPIRES; |
1811 | expires = jiffies_to_clock_t(rt_expires); | 1810 | expires = jiffies_to_clock_t(rt_expires); |
@@ -2036,6 +2035,7 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2036 | int scope; | 2035 | int scope; |
2037 | u32 flags; | 2036 | u32 flags; |
2038 | clock_t expires; | 2037 | clock_t expires; |
2038 | unsigned long timeout; | ||
2039 | 2039 | ||
2040 | ASSERT_RTNL(); | 2040 | ASSERT_RTNL(); |
2041 | 2041 | ||
@@ -2055,22 +2055,23 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2055 | 2055 | ||
2056 | scope = ipv6_addr_scope(pfx); | 2056 | scope = ipv6_addr_scope(pfx); |
2057 | 2057 | ||
2058 | if (valid_lft == INFINITY_LIFE_TIME) { | 2058 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
2059 | ifa_flags |= IFA_F_PERMANENT; | 2059 | if (addrconf_finite_timeout(timeout)) { |
2060 | flags = 0; | 2060 | expires = jiffies_to_clock_t(timeout * HZ); |
2061 | expires = 0; | 2061 | valid_lft = timeout; |
2062 | } else { | ||
2063 | if (valid_lft >= 0x7FFFFFFF/HZ) | ||
2064 | valid_lft = 0x7FFFFFFF/HZ; | ||
2065 | flags = RTF_EXPIRES; | 2062 | flags = RTF_EXPIRES; |
2066 | expires = jiffies_to_clock_t(valid_lft * HZ); | 2063 | } else { |
2064 | expires = 0; | ||
2065 | flags = 0; | ||
2066 | ifa_flags |= IFA_F_PERMANENT; | ||
2067 | } | 2067 | } |
2068 | 2068 | ||
2069 | if (prefered_lft == 0) | 2069 | timeout = addrconf_timeout_fixup(prefered_lft, HZ); |
2070 | ifa_flags |= IFA_F_DEPRECATED; | 2070 | if (addrconf_finite_timeout(timeout)) { |
2071 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | 2071 | if (timeout == 0) |
2072 | (prefered_lft != INFINITY_LIFE_TIME)) | 2072 | ifa_flags |= IFA_F_DEPRECATED; |
2073 | prefered_lft = 0x7FFFFFFF/HZ; | 2073 | prefered_lft = timeout; |
2074 | } | ||
2074 | 2075 | ||
2075 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); | 2076 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); |
2076 | 2077 | ||
@@ -3175,26 +3176,28 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
3175 | { | 3176 | { |
3176 | u32 flags; | 3177 | u32 flags; |
3177 | clock_t expires; | 3178 | clock_t expires; |
3179 | unsigned long timeout; | ||
3178 | 3180 | ||
3179 | if (!valid_lft || (prefered_lft > valid_lft)) | 3181 | if (!valid_lft || (prefered_lft > valid_lft)) |
3180 | return -EINVAL; | 3182 | return -EINVAL; |
3181 | 3183 | ||
3182 | if (valid_lft == INFINITY_LIFE_TIME) { | 3184 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
3183 | ifa_flags |= IFA_F_PERMANENT; | 3185 | if (addrconf_finite_timeout(timeout)) { |
3184 | flags = 0; | 3186 | expires = jiffies_to_clock_t(timeout * HZ); |
3185 | expires = 0; | 3187 | valid_lft = timeout; |
3186 | } else { | ||
3187 | if (valid_lft >= 0x7FFFFFFF/HZ) | ||
3188 | valid_lft = 0x7FFFFFFF/HZ; | ||
3189 | flags = RTF_EXPIRES; | 3188 | flags = RTF_EXPIRES; |
3190 | expires = jiffies_to_clock_t(valid_lft * HZ); | 3189 | } else { |
3190 | expires = 0; | ||
3191 | flags = 0; | ||
3192 | ifa_flags |= IFA_F_PERMANENT; | ||
3191 | } | 3193 | } |
3192 | 3194 | ||
3193 | if (prefered_lft == 0) | 3195 | timeout = addrconf_timeout_fixup(prefered_lft, HZ); |
3194 | ifa_flags |= IFA_F_DEPRECATED; | 3196 | if (addrconf_finite_timeout(timeout)) { |
3195 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | 3197 | if (timeout == 0) |
3196 | (prefered_lft != INFINITY_LIFE_TIME)) | 3198 | ifa_flags |= IFA_F_DEPRECATED; |
3197 | prefered_lft = 0x7FFFFFFF/HZ; | 3199 | prefered_lft = timeout; |
3200 | } | ||
3198 | 3201 | ||
3199 | spin_lock_bh(&ifp->lock); | 3202 | spin_lock_bh(&ifp->lock); |
3200 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; | 3203 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 48534c6c0735..220cffe9e63b 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -446,7 +446,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
446 | struct route_info *rinfo = (struct route_info *) opt; | 446 | struct route_info *rinfo = (struct route_info *) opt; |
447 | struct in6_addr prefix_buf, *prefix; | 447 | struct in6_addr prefix_buf, *prefix; |
448 | unsigned int pref; | 448 | unsigned int pref; |
449 | u32 lifetime; | 449 | unsigned long lifetime; |
450 | struct rt6_info *rt; | 450 | struct rt6_info *rt; |
451 | 451 | ||
452 | if (len < sizeof(struct route_info)) { | 452 | if (len < sizeof(struct route_info)) { |
@@ -472,13 +472,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
472 | if (pref == ICMPV6_ROUTER_PREF_INVALID) | 472 | if (pref == ICMPV6_ROUTER_PREF_INVALID) |
473 | pref = ICMPV6_ROUTER_PREF_MEDIUM; | 473 | pref = ICMPV6_ROUTER_PREF_MEDIUM; |
474 | 474 | ||
475 | lifetime = ntohl(rinfo->lifetime); | 475 | lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ); |
476 | if (lifetime == 0xffffffff) { | ||
477 | /* infinity */ | ||
478 | } else if (lifetime > 0x7fffffff/HZ - 1) { | ||
479 | /* Avoid arithmetic overflow */ | ||
480 | lifetime = 0x7fffffff/HZ - 1; | ||
481 | } | ||
482 | 476 | ||
483 | if (rinfo->length == 3) | 477 | if (rinfo->length == 3) |
484 | prefix = (struct in6_addr *)rinfo->prefix; | 478 | prefix = (struct in6_addr *)rinfo->prefix; |
@@ -506,7 +500,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
506 | (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); | 500 | (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); |
507 | 501 | ||
508 | if (rt) { | 502 | if (rt) { |
509 | if (lifetime == 0xffffffff) { | 503 | if (!addrconf_finite_timeout(lifetime)) { |
510 | rt->rt6i_flags &= ~RTF_EXPIRES; | 504 | rt->rt6i_flags &= ~RTF_EXPIRES; |
511 | } else { | 505 | } else { |
512 | rt->rt6i_expires = jiffies + HZ * lifetime; | 506 | rt->rt6i_expires = jiffies + HZ * lifetime; |