diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
| -rw-r--r-- | net/ipv6/addrconf.c | 107 |
1 files changed, 58 insertions, 49 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3a835578fd1..147588f4c7c 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); |
| @@ -2027,7 +2026,7 @@ err_exit: | |||
| 2027 | * Manual configuration of address on an interface | 2026 | * Manual configuration of address on an interface |
| 2028 | */ | 2027 | */ |
| 2029 | static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | 2028 | static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, |
| 2030 | int plen, __u8 ifa_flags, __u32 prefered_lft, | 2029 | unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, |
| 2031 | __u32 valid_lft) | 2030 | __u32 valid_lft) |
| 2032 | { | 2031 | { |
| 2033 | struct inet6_ifaddr *ifp; | 2032 | struct inet6_ifaddr *ifp; |
| @@ -2036,9 +2035,13 @@ 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 | ||
| 2042 | if (plen > 128) | ||
| 2043 | return -EINVAL; | ||
| 2044 | |||
| 2042 | /* check the lifetime */ | 2045 | /* check the lifetime */ |
| 2043 | if (!valid_lft || prefered_lft > valid_lft) | 2046 | if (!valid_lft || prefered_lft > valid_lft) |
| 2044 | return -EINVAL; | 2047 | return -EINVAL; |
| @@ -2052,22 +2055,23 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
| 2052 | 2055 | ||
| 2053 | scope = ipv6_addr_scope(pfx); | 2056 | scope = ipv6_addr_scope(pfx); |
| 2054 | 2057 | ||
| 2055 | if (valid_lft == INFINITY_LIFE_TIME) { | 2058 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
| 2056 | ifa_flags |= IFA_F_PERMANENT; | 2059 | if (addrconf_finite_timeout(timeout)) { |
| 2057 | flags = 0; | 2060 | expires = jiffies_to_clock_t(timeout * HZ); |
| 2058 | expires = 0; | 2061 | valid_lft = timeout; |
| 2059 | } else { | ||
| 2060 | if (valid_lft >= 0x7FFFFFFF/HZ) | ||
| 2061 | valid_lft = 0x7FFFFFFF/HZ; | ||
| 2062 | flags = RTF_EXPIRES; | 2062 | flags = RTF_EXPIRES; |
| 2063 | expires = jiffies_to_clock_t(valid_lft * HZ); | 2063 | } else { |
| 2064 | expires = 0; | ||
| 2065 | flags = 0; | ||
| 2066 | ifa_flags |= IFA_F_PERMANENT; | ||
| 2064 | } | 2067 | } |
| 2065 | 2068 | ||
| 2066 | if (prefered_lft == 0) | 2069 | timeout = addrconf_timeout_fixup(prefered_lft, HZ); |
| 2067 | ifa_flags |= IFA_F_DEPRECATED; | 2070 | if (addrconf_finite_timeout(timeout)) { |
| 2068 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | 2071 | if (timeout == 0) |
| 2069 | (prefered_lft != INFINITY_LIFE_TIME)) | 2072 | ifa_flags |= IFA_F_DEPRECATED; |
| 2070 | prefered_lft = 0x7FFFFFFF/HZ; | 2073 | prefered_lft = timeout; |
| 2074 | } | ||
| 2071 | 2075 | ||
| 2072 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); | 2076 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); |
| 2073 | 2077 | ||
| @@ -2095,12 +2099,15 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
| 2095 | } | 2099 | } |
| 2096 | 2100 | ||
| 2097 | static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, | 2101 | static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, |
| 2098 | int plen) | 2102 | unsigned int plen) |
| 2099 | { | 2103 | { |
| 2100 | struct inet6_ifaddr *ifp; | 2104 | struct inet6_ifaddr *ifp; |
| 2101 | struct inet6_dev *idev; | 2105 | struct inet6_dev *idev; |
| 2102 | struct net_device *dev; | 2106 | struct net_device *dev; |
| 2103 | 2107 | ||
| 2108 | if (plen > 128) | ||
| 2109 | return -EINVAL; | ||
| 2110 | |||
| 2104 | dev = __dev_get_by_index(net, ifindex); | 2111 | dev = __dev_get_by_index(net, ifindex); |
| 2105 | if (!dev) | 2112 | if (!dev) |
| 2106 | return -ENODEV; | 2113 | return -ENODEV; |
| @@ -3169,26 +3176,28 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
| 3169 | { | 3176 | { |
| 3170 | u32 flags; | 3177 | u32 flags; |
| 3171 | clock_t expires; | 3178 | clock_t expires; |
| 3179 | unsigned long timeout; | ||
| 3172 | 3180 | ||
| 3173 | if (!valid_lft || (prefered_lft > valid_lft)) | 3181 | if (!valid_lft || (prefered_lft > valid_lft)) |
| 3174 | return -EINVAL; | 3182 | return -EINVAL; |
| 3175 | 3183 | ||
| 3176 | if (valid_lft == INFINITY_LIFE_TIME) { | 3184 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
| 3177 | ifa_flags |= IFA_F_PERMANENT; | 3185 | if (addrconf_finite_timeout(timeout)) { |
| 3178 | flags = 0; | 3186 | expires = jiffies_to_clock_t(timeout * HZ); |
| 3179 | expires = 0; | 3187 | valid_lft = timeout; |
| 3180 | } else { | ||
| 3181 | if (valid_lft >= 0x7FFFFFFF/HZ) | ||
| 3182 | valid_lft = 0x7FFFFFFF/HZ; | ||
| 3183 | flags = RTF_EXPIRES; | 3188 | flags = RTF_EXPIRES; |
| 3184 | expires = jiffies_to_clock_t(valid_lft * HZ); | 3189 | } else { |
| 3190 | expires = 0; | ||
| 3191 | flags = 0; | ||
| 3192 | ifa_flags |= IFA_F_PERMANENT; | ||
| 3185 | } | 3193 | } |
| 3186 | 3194 | ||
| 3187 | if (prefered_lft == 0) | 3195 | timeout = addrconf_timeout_fixup(prefered_lft, HZ); |
| 3188 | ifa_flags |= IFA_F_DEPRECATED; | 3196 | if (addrconf_finite_timeout(timeout)) { |
| 3189 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | 3197 | if (timeout == 0) |
| 3190 | (prefered_lft != INFINITY_LIFE_TIME)) | 3198 | ifa_flags |= IFA_F_DEPRECATED; |
| 3191 | prefered_lft = 0x7FFFFFFF/HZ; | 3199 | prefered_lft = timeout; |
| 3200 | } | ||
| 3192 | 3201 | ||
| 3193 | spin_lock_bh(&ifp->lock); | 3202 | spin_lock_bh(&ifp->lock); |
| 3194 | 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; |
