diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 142 |
1 files changed, 88 insertions, 54 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e591e09e5e4e..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,41 +1768,49 @@ 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 | /* Avoid arithmetic overflow. Really, we could | ||
1768 | save rt_expires in seconds, likely valid_lft, | ||
1769 | but it would require division in fib gc, that it | ||
1770 | not good. | ||
1771 | */ | ||
1772 | if (valid_lft >= 0x7FFFFFFF/HZ) | ||
1773 | rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ); | ||
1774 | else | ||
1775 | rt_expires = valid_lft * HZ; | ||
1776 | |||
1777 | /* | ||
1778 | * We convert this (in jiffies) to clock_t later. | ||
1779 | * Avoid arithmetic overflow there as well. | ||
1780 | * Overflow can happen only if HZ < USER_HZ. | ||
1781 | */ | ||
1782 | if (HZ < USER_HZ && rt_expires > 0x7FFFFFFF / USER_HZ) | ||
1783 | rt_expires = 0x7FFFFFFF / USER_HZ; | ||
1784 | |||
1785 | if (pinfo->onlink) { | 1771 | if (pinfo->onlink) { |
1786 | struct rt6_info *rt; | 1772 | struct rt6_info *rt; |
1773 | unsigned long rt_expires; | ||
1774 | |||
1775 | /* Avoid arithmetic overflow. Really, we could | ||
1776 | * save rt_expires in seconds, likely valid_lft, | ||
1777 | * but it would require division in fib gc, that it | ||
1778 | * not good. | ||
1779 | */ | ||
1780 | if (HZ > USER_HZ) | ||
1781 | rt_expires = addrconf_timeout_fixup(valid_lft, HZ); | ||
1782 | else | ||
1783 | rt_expires = addrconf_timeout_fixup(valid_lft, USER_HZ); | ||
1784 | |||
1785 | if (addrconf_finite_timeout(rt_expires)) | ||
1786 | rt_expires *= HZ; | ||
1787 | |||
1787 | rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, | 1788 | rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, |
1788 | dev->ifindex, 1); | 1789 | dev->ifindex, 1); |
1789 | 1790 | ||
1790 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { | 1791 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { |
1791 | if (rt->rt6i_flags&RTF_EXPIRES) { | 1792 | /* Autoconf prefix route */ |
1792 | if (valid_lft == 0) { | 1793 | if (valid_lft == 0) { |
1793 | ip6_del_rt(rt); | 1794 | ip6_del_rt(rt); |
1794 | rt = NULL; | 1795 | rt = NULL; |
1795 | } else { | 1796 | } else if (addrconf_finite_timeout(rt_expires)) { |
1796 | rt->rt6i_expires = jiffies + rt_expires; | 1797 | /* not infinity */ |
1797 | } | 1798 | rt->rt6i_expires = jiffies + rt_expires; |
1799 | rt->rt6i_flags |= RTF_EXPIRES; | ||
1800 | } else { | ||
1801 | rt->rt6i_flags &= ~RTF_EXPIRES; | ||
1802 | rt->rt6i_expires = 0; | ||
1798 | } | 1803 | } |
1799 | } else if (valid_lft) { | 1804 | } else if (valid_lft) { |
1805 | clock_t expires = 0; | ||
1806 | int flags = RTF_ADDRCONF | RTF_PREFIX_RT; | ||
1807 | if (addrconf_finite_timeout(rt_expires)) { | ||
1808 | /* not infinity */ | ||
1809 | flags |= RTF_EXPIRES; | ||
1810 | expires = jiffies_to_clock_t(rt_expires); | ||
1811 | } | ||
1800 | addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, | 1812 | addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, |
1801 | dev, jiffies_to_clock_t(rt_expires), RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT); | 1813 | dev, expires, flags); |
1802 | } | 1814 | } |
1803 | if (rt) | 1815 | if (rt) |
1804 | dst_release(&rt->u.dst); | 1816 | dst_release(&rt->u.dst); |
@@ -2014,17 +2026,22 @@ err_exit: | |||
2014 | * Manual configuration of address on an interface | 2026 | * Manual configuration of address on an interface |
2015 | */ | 2027 | */ |
2016 | 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, |
2017 | int plen, __u8 ifa_flags, __u32 prefered_lft, | 2029 | unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, |
2018 | __u32 valid_lft) | 2030 | __u32 valid_lft) |
2019 | { | 2031 | { |
2020 | struct inet6_ifaddr *ifp; | 2032 | struct inet6_ifaddr *ifp; |
2021 | struct inet6_dev *idev; | 2033 | struct inet6_dev *idev; |
2022 | struct net_device *dev; | 2034 | struct net_device *dev; |
2023 | int scope; | 2035 | int scope; |
2024 | u32 flags = RTF_EXPIRES; | 2036 | u32 flags; |
2037 | clock_t expires; | ||
2038 | unsigned long timeout; | ||
2025 | 2039 | ||
2026 | ASSERT_RTNL(); | 2040 | ASSERT_RTNL(); |
2027 | 2041 | ||
2042 | if (plen > 128) | ||
2043 | return -EINVAL; | ||
2044 | |||
2028 | /* check the lifetime */ | 2045 | /* check the lifetime */ |
2029 | if (!valid_lft || prefered_lft > valid_lft) | 2046 | if (!valid_lft || prefered_lft > valid_lft) |
2030 | return -EINVAL; | 2047 | return -EINVAL; |
@@ -2038,17 +2055,23 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2038 | 2055 | ||
2039 | scope = ipv6_addr_scope(pfx); | 2056 | scope = ipv6_addr_scope(pfx); |
2040 | 2057 | ||
2041 | if (valid_lft == INFINITY_LIFE_TIME) { | 2058 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
2042 | ifa_flags |= IFA_F_PERMANENT; | 2059 | if (addrconf_finite_timeout(timeout)) { |
2060 | expires = jiffies_to_clock_t(timeout * HZ); | ||
2061 | valid_lft = timeout; | ||
2062 | flags = RTF_EXPIRES; | ||
2063 | } else { | ||
2064 | expires = 0; | ||
2043 | flags = 0; | 2065 | flags = 0; |
2044 | } else if (valid_lft >= 0x7FFFFFFF/HZ) | 2066 | ifa_flags |= IFA_F_PERMANENT; |
2045 | valid_lft = 0x7FFFFFFF/HZ; | 2067 | } |
2046 | 2068 | ||
2047 | if (prefered_lft == 0) | 2069 | timeout = addrconf_timeout_fixup(prefered_lft, HZ); |
2048 | ifa_flags |= IFA_F_DEPRECATED; | 2070 | if (addrconf_finite_timeout(timeout)) { |
2049 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | 2071 | if (timeout == 0) |
2050 | (prefered_lft != INFINITY_LIFE_TIME)) | 2072 | ifa_flags |= IFA_F_DEPRECATED; |
2051 | prefered_lft = 0x7FFFFFFF/HZ; | 2073 | prefered_lft = timeout; |
2074 | } | ||
2052 | 2075 | ||
2053 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); | 2076 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); |
2054 | 2077 | ||
@@ -2060,7 +2083,7 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2060 | spin_unlock_bh(&ifp->lock); | 2083 | spin_unlock_bh(&ifp->lock); |
2061 | 2084 | ||
2062 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, | 2085 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, |
2063 | jiffies_to_clock_t(valid_lft * HZ), flags); | 2086 | expires, flags); |
2064 | /* | 2087 | /* |
2065 | * Note that section 3.1 of RFC 4429 indicates | 2088 | * Note that section 3.1 of RFC 4429 indicates |
2066 | * that the Optimistic flag should not be set for | 2089 | * that the Optimistic flag should not be set for |
@@ -2076,12 +2099,15 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2076 | } | 2099 | } |
2077 | 2100 | ||
2078 | 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, |
2079 | int plen) | 2102 | unsigned int plen) |
2080 | { | 2103 | { |
2081 | struct inet6_ifaddr *ifp; | 2104 | struct inet6_ifaddr *ifp; |
2082 | struct inet6_dev *idev; | 2105 | struct inet6_dev *idev; |
2083 | struct net_device *dev; | 2106 | struct net_device *dev; |
2084 | 2107 | ||
2108 | if (plen > 128) | ||
2109 | return -EINVAL; | ||
2110 | |||
2085 | dev = __dev_get_by_index(net, ifindex); | 2111 | dev = __dev_get_by_index(net, ifindex); |
2086 | if (!dev) | 2112 | if (!dev) |
2087 | return -ENODEV; | 2113 | return -ENODEV; |
@@ -3148,22 +3174,30 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
3148 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | 3174 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, |
3149 | u32 prefered_lft, u32 valid_lft) | 3175 | u32 prefered_lft, u32 valid_lft) |
3150 | { | 3176 | { |
3151 | u32 flags = RTF_EXPIRES; | 3177 | u32 flags; |
3178 | clock_t expires; | ||
3179 | unsigned long timeout; | ||
3152 | 3180 | ||
3153 | if (!valid_lft || (prefered_lft > valid_lft)) | 3181 | if (!valid_lft || (prefered_lft > valid_lft)) |
3154 | return -EINVAL; | 3182 | return -EINVAL; |
3155 | 3183 | ||
3156 | if (valid_lft == INFINITY_LIFE_TIME) { | 3184 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
3157 | ifa_flags |= IFA_F_PERMANENT; | 3185 | if (addrconf_finite_timeout(timeout)) { |
3186 | expires = jiffies_to_clock_t(timeout * HZ); | ||
3187 | valid_lft = timeout; | ||
3188 | flags = RTF_EXPIRES; | ||
3189 | } else { | ||
3190 | expires = 0; | ||
3158 | flags = 0; | 3191 | flags = 0; |
3159 | } else if (valid_lft >= 0x7FFFFFFF/HZ) | 3192 | ifa_flags |= IFA_F_PERMANENT; |
3160 | valid_lft = 0x7FFFFFFF/HZ; | 3193 | } |
3161 | 3194 | ||
3162 | if (prefered_lft == 0) | 3195 | timeout = addrconf_timeout_fixup(prefered_lft, HZ); |
3163 | ifa_flags |= IFA_F_DEPRECATED; | 3196 | if (addrconf_finite_timeout(timeout)) { |
3164 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | 3197 | if (timeout == 0) |
3165 | (prefered_lft != INFINITY_LIFE_TIME)) | 3198 | ifa_flags |= IFA_F_DEPRECATED; |
3166 | prefered_lft = 0x7FFFFFFF/HZ; | 3199 | prefered_lft = timeout; |
3200 | } | ||
3167 | 3201 | ||
3168 | spin_lock_bh(&ifp->lock); | 3202 | spin_lock_bh(&ifp->lock); |
3169 | 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; |
@@ -3176,7 +3210,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
3176 | ipv6_ifa_notify(0, ifp); | 3210 | ipv6_ifa_notify(0, ifp); |
3177 | 3211 | ||
3178 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, | 3212 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, |
3179 | jiffies_to_clock_t(valid_lft * HZ), flags); | 3213 | expires, flags); |
3180 | addrconf_verify(0); | 3214 | addrconf_verify(0); |
3181 | 3215 | ||
3182 | return 0; | 3216 | return 0; |
@@ -4242,7 +4276,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev) | |||
4242 | neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6, | 4276 | neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6, |
4243 | NET_IPV6_NEIGH, "ipv6", | 4277 | NET_IPV6_NEIGH, "ipv6", |
4244 | &ndisc_ifinfo_sysctl_change, | 4278 | &ndisc_ifinfo_sysctl_change, |
4245 | NULL); | 4279 | ndisc_ifinfo_sysctl_strategy); |
4246 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | 4280 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, |
4247 | idev->dev->ifindex, idev, &idev->cnf); | 4281 | idev->dev->ifindex, idev, &idev->cnf); |
4248 | } | 4282 | } |