aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-05-27 04:37:49 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-06-04 15:02:34 -0400
commit4bed72e4f5502ea3322f0a00794815fa58951abe (patch)
treefd652d01822746a84d5812bbe2ee0661fbd3b86f /net/ipv6/addrconf.c
parentbaa2bfb8aef24bb7fe1875b256918724b3884662 (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/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c97
1 files changed, 50 insertions, 47 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;