diff options
-rw-r--r-- | net/ipv6/addrconf.c | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 81702b9ba5be..c0641887bdeb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -1869,15 +1869,21 @@ err_exit: | |||
1869 | /* | 1869 | /* |
1870 | * Manual configuration of address on an interface | 1870 | * Manual configuration of address on an interface |
1871 | */ | 1871 | */ |
1872 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) | 1872 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, |
1873 | __u32 prefered_lft, __u32 valid_lft) | ||
1873 | { | 1874 | { |
1874 | struct inet6_ifaddr *ifp; | 1875 | struct inet6_ifaddr *ifp; |
1875 | struct inet6_dev *idev; | 1876 | struct inet6_dev *idev; |
1876 | struct net_device *dev; | 1877 | struct net_device *dev; |
1878 | __u8 ifa_flags = 0; | ||
1877 | int scope; | 1879 | int scope; |
1878 | 1880 | ||
1879 | ASSERT_RTNL(); | 1881 | ASSERT_RTNL(); |
1880 | 1882 | ||
1883 | /* check the lifetime */ | ||
1884 | if (!valid_lft || prefered_lft > valid_lft) | ||
1885 | return -EINVAL; | ||
1886 | |||
1881 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | 1887 | if ((dev = __dev_get_by_index(ifindex)) == NULL) |
1882 | return -ENODEV; | 1888 | return -ENODEV; |
1883 | 1889 | ||
@@ -1889,10 +1895,29 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) | |||
1889 | 1895 | ||
1890 | scope = ipv6_addr_scope(pfx); | 1896 | scope = ipv6_addr_scope(pfx); |
1891 | 1897 | ||
1892 | ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT); | 1898 | if (valid_lft == INFINITY_LIFE_TIME) |
1899 | ifa_flags |= IFA_F_PERMANENT; | ||
1900 | else if (valid_lft >= 0x7FFFFFFF/HZ) | ||
1901 | valid_lft = 0x7FFFFFFF/HZ; | ||
1902 | |||
1903 | if (prefered_lft == 0) | ||
1904 | ifa_flags |= IFA_F_DEPRECATED; | ||
1905 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | ||
1906 | (prefered_lft != INFINITY_LIFE_TIME)) | ||
1907 | prefered_lft = 0x7FFFFFFF/HZ; | ||
1908 | |||
1909 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); | ||
1910 | |||
1893 | if (!IS_ERR(ifp)) { | 1911 | if (!IS_ERR(ifp)) { |
1912 | spin_lock(&ifp->lock); | ||
1913 | ifp->valid_lft = valid_lft; | ||
1914 | ifp->prefered_lft = prefered_lft; | ||
1915 | ifp->tstamp = jiffies; | ||
1916 | spin_unlock(&ifp->lock); | ||
1917 | |||
1894 | addrconf_dad_start(ifp, 0); | 1918 | addrconf_dad_start(ifp, 0); |
1895 | in6_ifa_put(ifp); | 1919 | in6_ifa_put(ifp); |
1920 | addrconf_verify(0); | ||
1896 | return 0; | 1921 | return 0; |
1897 | } | 1922 | } |
1898 | 1923 | ||
@@ -1945,7 +1970,8 @@ int addrconf_add_ifaddr(void __user *arg) | |||
1945 | return -EFAULT; | 1970 | return -EFAULT; |
1946 | 1971 | ||
1947 | rtnl_lock(); | 1972 | rtnl_lock(); |
1948 | err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen); | 1973 | err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, |
1974 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); | ||
1949 | rtnl_unlock(); | 1975 | rtnl_unlock(); |
1950 | return err; | 1976 | return err; |
1951 | } | 1977 | } |
@@ -2870,6 +2896,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2870 | struct rtattr **rta = arg; | 2896 | struct rtattr **rta = arg; |
2871 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 2897 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); |
2872 | struct in6_addr *pfx; | 2898 | struct in6_addr *pfx; |
2899 | __u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME; | ||
2873 | 2900 | ||
2874 | pfx = NULL; | 2901 | pfx = NULL; |
2875 | if (rta[IFA_ADDRESS-1]) { | 2902 | if (rta[IFA_ADDRESS-1]) { |
@@ -2886,7 +2913,18 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2886 | if (pfx == NULL) | 2913 | if (pfx == NULL) |
2887 | return -EINVAL; | 2914 | return -EINVAL; |
2888 | 2915 | ||
2889 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 2916 | if (rta[IFA_CACHEINFO-1]) { |
2917 | struct ifa_cacheinfo *ci; | ||
2918 | if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci)) | ||
2919 | return -EINVAL; | ||
2920 | ci = RTA_DATA(rta[IFA_CACHEINFO-1]); | ||
2921 | valid_lft = ci->ifa_valid; | ||
2922 | prefered_lft = ci->ifa_prefered; | ||
2923 | } | ||
2924 | |||
2925 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | ||
2926 | prefered_lft, valid_lft); | ||
2927 | |||
2890 | } | 2928 | } |
2891 | 2929 | ||
2892 | /* Maximum length of ifa_cacheinfo attributes */ | 2930 | /* Maximum length of ifa_cacheinfo attributes */ |