aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/addrconf.c46
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 */
1872static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) 1872static 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 */