diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 73 |
1 files changed, 49 insertions, 24 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 8dd9155502b5..3a835578fd1c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -1764,14 +1764,16 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1764 | * 2) Configure prefixes with the auto flag set | 1764 | * 2) Configure prefixes with the auto flag set |
1765 | */ | 1765 | */ |
1766 | 1766 | ||
1767 | /* Avoid arithmetic overflow. Really, we could | 1767 | if (valid_lft == INFINITY_LIFE_TIME) |
1768 | save rt_expires in seconds, likely valid_lft, | 1768 | rt_expires = ~0UL; |
1769 | but it would require division in fib gc, that it | 1769 | else if (valid_lft >= 0x7FFFFFFF/HZ) { |
1770 | not good. | 1770 | /* Avoid arithmetic overflow. Really, we could |
1771 | */ | 1771 | * save rt_expires in seconds, likely valid_lft, |
1772 | if (valid_lft >= 0x7FFFFFFF/HZ) | 1772 | * but it would require division in fib gc, that it |
1773 | * not good. | ||
1774 | */ | ||
1773 | rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ); | 1775 | rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ); |
1774 | else | 1776 | } else |
1775 | rt_expires = valid_lft * HZ; | 1777 | rt_expires = valid_lft * HZ; |
1776 | 1778 | ||
1777 | /* | 1779 | /* |
@@ -1779,7 +1781,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1779 | * Avoid arithmetic overflow there as well. | 1781 | * Avoid arithmetic overflow there as well. |
1780 | * Overflow can happen only if HZ < USER_HZ. | 1782 | * Overflow can happen only if HZ < USER_HZ. |
1781 | */ | 1783 | */ |
1782 | if (HZ < USER_HZ && rt_expires > 0x7FFFFFFF / USER_HZ) | 1784 | if (HZ < USER_HZ && ~rt_expires && rt_expires > 0x7FFFFFFF / USER_HZ) |
1783 | rt_expires = 0x7FFFFFFF / USER_HZ; | 1785 | rt_expires = 0x7FFFFFFF / USER_HZ; |
1784 | 1786 | ||
1785 | if (pinfo->onlink) { | 1787 | if (pinfo->onlink) { |
@@ -1788,17 +1790,28 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1788 | dev->ifindex, 1); | 1790 | dev->ifindex, 1); |
1789 | 1791 | ||
1790 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { | 1792 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { |
1791 | if (rt->rt6i_flags&RTF_EXPIRES) { | 1793 | /* Autoconf prefix route */ |
1792 | if (valid_lft == 0) { | 1794 | if (valid_lft == 0) { |
1793 | ip6_del_rt(rt); | 1795 | ip6_del_rt(rt); |
1794 | rt = NULL; | 1796 | rt = NULL; |
1795 | } else { | 1797 | } else if (~rt_expires) { |
1796 | rt->rt6i_expires = jiffies + rt_expires; | 1798 | /* not infinity */ |
1797 | } | 1799 | rt->rt6i_expires = jiffies + rt_expires; |
1800 | rt->rt6i_flags |= RTF_EXPIRES; | ||
1801 | } else { | ||
1802 | rt->rt6i_flags &= ~RTF_EXPIRES; | ||
1803 | rt->rt6i_expires = 0; | ||
1798 | } | 1804 | } |
1799 | } else if (valid_lft) { | 1805 | } else if (valid_lft) { |
1806 | int flags = RTF_ADDRCONF | RTF_PREFIX_RT; | ||
1807 | clock_t expires = 0; | ||
1808 | if (~rt_expires) { | ||
1809 | /* not infinity */ | ||
1810 | flags |= RTF_EXPIRES; | ||
1811 | expires = jiffies_to_clock_t(rt_expires); | ||
1812 | } | ||
1800 | addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, | 1813 | addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, |
1801 | dev, jiffies_to_clock_t(rt_expires), RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT); | 1814 | dev, expires, flags); |
1802 | } | 1815 | } |
1803 | if (rt) | 1816 | if (rt) |
1804 | dst_release(&rt->u.dst); | 1817 | dst_release(&rt->u.dst); |
@@ -2021,7 +2034,8 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2021 | struct inet6_dev *idev; | 2034 | struct inet6_dev *idev; |
2022 | struct net_device *dev; | 2035 | struct net_device *dev; |
2023 | int scope; | 2036 | int scope; |
2024 | u32 flags = RTF_EXPIRES; | 2037 | u32 flags; |
2038 | clock_t expires; | ||
2025 | 2039 | ||
2026 | ASSERT_RTNL(); | 2040 | ASSERT_RTNL(); |
2027 | 2041 | ||
@@ -2041,8 +2055,13 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2041 | if (valid_lft == INFINITY_LIFE_TIME) { | 2055 | if (valid_lft == INFINITY_LIFE_TIME) { |
2042 | ifa_flags |= IFA_F_PERMANENT; | 2056 | ifa_flags |= IFA_F_PERMANENT; |
2043 | flags = 0; | 2057 | flags = 0; |
2044 | } else if (valid_lft >= 0x7FFFFFFF/HZ) | 2058 | expires = 0; |
2045 | valid_lft = 0x7FFFFFFF/HZ; | 2059 | } else { |
2060 | if (valid_lft >= 0x7FFFFFFF/HZ) | ||
2061 | valid_lft = 0x7FFFFFFF/HZ; | ||
2062 | flags = RTF_EXPIRES; | ||
2063 | expires = jiffies_to_clock_t(valid_lft * HZ); | ||
2064 | } | ||
2046 | 2065 | ||
2047 | if (prefered_lft == 0) | 2066 | if (prefered_lft == 0) |
2048 | ifa_flags |= IFA_F_DEPRECATED; | 2067 | ifa_flags |= IFA_F_DEPRECATED; |
@@ -2060,7 +2079,7 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2060 | spin_unlock_bh(&ifp->lock); | 2079 | spin_unlock_bh(&ifp->lock); |
2061 | 2080 | ||
2062 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, | 2081 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, |
2063 | jiffies_to_clock_t(valid_lft * HZ), flags); | 2082 | expires, flags); |
2064 | /* | 2083 | /* |
2065 | * Note that section 3.1 of RFC 4429 indicates | 2084 | * Note that section 3.1 of RFC 4429 indicates |
2066 | * that the Optimistic flag should not be set for | 2085 | * that the Optimistic flag should not be set for |
@@ -3148,7 +3167,8 @@ 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, | 3167 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, |
3149 | u32 prefered_lft, u32 valid_lft) | 3168 | u32 prefered_lft, u32 valid_lft) |
3150 | { | 3169 | { |
3151 | u32 flags = RTF_EXPIRES; | 3170 | u32 flags; |
3171 | clock_t expires; | ||
3152 | 3172 | ||
3153 | if (!valid_lft || (prefered_lft > valid_lft)) | 3173 | if (!valid_lft || (prefered_lft > valid_lft)) |
3154 | return -EINVAL; | 3174 | return -EINVAL; |
@@ -3156,8 +3176,13 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
3156 | if (valid_lft == INFINITY_LIFE_TIME) { | 3176 | if (valid_lft == INFINITY_LIFE_TIME) { |
3157 | ifa_flags |= IFA_F_PERMANENT; | 3177 | ifa_flags |= IFA_F_PERMANENT; |
3158 | flags = 0; | 3178 | flags = 0; |
3159 | } else if (valid_lft >= 0x7FFFFFFF/HZ) | 3179 | expires = 0; |
3160 | valid_lft = 0x7FFFFFFF/HZ; | 3180 | } else { |
3181 | if (valid_lft >= 0x7FFFFFFF/HZ) | ||
3182 | valid_lft = 0x7FFFFFFF/HZ; | ||
3183 | flags = RTF_EXPIRES; | ||
3184 | expires = jiffies_to_clock_t(valid_lft * HZ); | ||
3185 | } | ||
3161 | 3186 | ||
3162 | if (prefered_lft == 0) | 3187 | if (prefered_lft == 0) |
3163 | ifa_flags |= IFA_F_DEPRECATED; | 3188 | ifa_flags |= IFA_F_DEPRECATED; |
@@ -3176,7 +3201,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
3176 | ipv6_ifa_notify(0, ifp); | 3201 | ipv6_ifa_notify(0, ifp); |
3177 | 3202 | ||
3178 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, | 3203 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, |
3179 | jiffies_to_clock_t(valid_lft * HZ), flags); | 3204 | expires, flags); |
3180 | addrconf_verify(0); | 3205 | addrconf_verify(0); |
3181 | 3206 | ||
3182 | return 0; | 3207 | return 0; |