Merge tag 'v3.10.58' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ipv6 / addrconf.c
index 1bbf744c2cc35e7953b9580db08a357f4e829a04..475a16d7b9557fffdd04732353d5e60d740d3d48 100644 (file)
@@ -173,7 +173,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .forwarding             = 0,
        .hop_limit              = IPV6_DEFAULT_HOPLIMIT,
        .mtu6                   = IPV6_MIN_MTU,
-       .accept_ra              = 1,
+       .accept_ra              = 1,    
        .accept_redirects       = 1,
        .autoconf               = 1,
        .force_mld_version      = 0,
@@ -182,7 +182,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .rtr_solicit_interval   = RTR_SOLICITATION_INTERVAL,
        .rtr_solicit_delay      = MAX_RTR_SOLICITATION_DELAY,
 #ifdef CONFIG_IPV6_PRIVACY
-       .use_tempaddr           = 0,
+       .use_tempaddr           = 1,
        .temp_valid_lft         = TEMP_VALID_LIFETIME,
        .temp_prefered_lft      = TEMP_PREFERRED_LIFETIME,
        .regen_max_retry        = REGEN_MAX_RETRY,
@@ -191,6 +191,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .max_addresses          = IPV6_MAX_ADDRESSES,
        .accept_ra_defrtr       = 1,
        .accept_ra_pinfo        = 1,
+#ifdef CONFIG_MTK_DHCPV6C_WIFI 
+       .ra_info_flag           = 0,
+#endif         
 #ifdef CONFIG_IPV6_ROUTER_PREF
        .accept_ra_rtr_pref     = 1,
        .rtr_probe_interval     = 60 * HZ,
@@ -198,6 +201,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .accept_ra_rt_info_max_plen = 0,
 #endif
 #endif
+       .accept_ra_rt_table     = 0,
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
        .disable_ipv6           = 0,
@@ -216,7 +220,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .rtr_solicit_interval   = RTR_SOLICITATION_INTERVAL,
        .rtr_solicit_delay      = MAX_RTR_SOLICITATION_DELAY,
 #ifdef CONFIG_IPV6_PRIVACY
-       .use_tempaddr           = 0,
+       .use_tempaddr           = 1,
        .temp_valid_lft         = TEMP_VALID_LIFETIME,
        .temp_prefered_lft      = TEMP_PREFERRED_LIFETIME,
        .regen_max_retry        = REGEN_MAX_RETRY,
@@ -225,6 +229,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .max_addresses          = IPV6_MAX_ADDRESSES,
        .accept_ra_defrtr       = 1,
        .accept_ra_pinfo        = 1,
+#ifdef CONFIG_MTK_DHCPV6C_WIFI 
+       .ra_info_flag           = 0,
+#endif 
 #ifdef CONFIG_IPV6_ROUTER_PREF
        .accept_ra_rtr_pref     = 1,
        .rtr_probe_interval     = 60 * HZ,
@@ -232,6 +239,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .accept_ra_rt_info_max_plen = 0,
 #endif
 #endif
+       .accept_ra_rt_table     = 0,
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
        .disable_ipv6           = 0,
@@ -758,9 +766,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)
        } else if ((!newf) ^ (!old))
                dev_forward_change((struct inet6_dev *)table->extra1);
        rtnl_unlock();
-
+       
        if (newf)
                rt6_purge_dflt_routers(net);
+
        return 1;
 }
 #endif
@@ -1111,8 +1120,11 @@ retry:
         * Lifetime is greater than REGEN_ADVANCE time units.  In particular,
         * an implementation must not create a temporary address with a zero
         * Preferred Lifetime.
+        * Use age calculation as in addrconf_verify to avoid unnecessary
+        * temporary addresses being generated.
         */
-       if (tmp_prefered_lft <= regen_advance) {
+       age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
+       if (tmp_prefered_lft <= regen_advance + age) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
                ret = -1;
@@ -1124,12 +1136,10 @@ retry:
        if (ifp->flags & IFA_F_OPTIMISTIC)
                addr_flags |= IFA_F_OPTIMISTIC;
 
-       ift = !max_addresses ||
-             ipv6_count_addresses(idev) < max_addresses ?
-               ipv6_add_addr(idev, &addr, tmp_plen,
-                             ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK,
-                             addr_flags) : NULL;
-       if (IS_ERR_OR_NULL(ift)) {
+       ift = ipv6_add_addr(idev, &addr, tmp_plen,
+                           ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK,
+                           addr_flags);
+       if (IS_ERR(ift)) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
                pr_info("%s: retry temporary address regeneration\n", __func__);
@@ -1448,6 +1458,23 @@ try_nextdev:
 }
 EXPORT_SYMBOL(ipv6_dev_get_saddr);
 
+int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
+                     unsigned char banned_flags)
+{
+       struct inet6_ifaddr *ifp;
+       int err = -EADDRNOTAVAIL;
+
+       list_for_each_entry(ifp, &idev->addr_list, if_list) {
+               if (ifp->scope == IFA_LINK &&
+                   !(ifp->flags & banned_flags)) {
+                       *addr = ifp->addr;
+                       err = 0;
+                       break;
+               }
+       }
+       return err;
+}
+
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
                    unsigned char banned_flags)
 {
@@ -1457,17 +1484,8 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
        rcu_read_lock();
        idev = __in6_dev_get(dev);
        if (idev) {
-               struct inet6_ifaddr *ifp;
-
                read_lock_bh(&idev->lock);
-               list_for_each_entry(ifp, &idev->addr_list, if_list) {
-                       if (ifp->scope == IFA_LINK &&
-                           !(ifp->flags & banned_flags)) {
-                               *addr = ifp->addr;
-                               err = 0;
-                               break;
-                       }
-               }
+               err = __ipv6_get_lladdr(idev, addr, banned_flags);
                read_unlock_bh(&idev->lock);
        }
        rcu_read_unlock();
@@ -1527,6 +1545,33 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
        return false;
 }
 
+/* Compares an address/prefix_len with addresses on device @dev.
+ * If one is found it returns true.
+ */
+bool ipv6_chk_custom_prefix(const struct in6_addr *addr,
+       const unsigned int prefix_len, struct net_device *dev)
+{
+       struct inet6_dev *idev;
+       struct inet6_ifaddr *ifa;
+       bool ret = false;
+
+       rcu_read_lock();
+       idev = __in6_dev_get(dev);
+       if (idev) {
+               read_lock_bh(&idev->lock);
+               list_for_each_entry(ifa, &idev->addr_list, if_list) {
+                       ret = ipv6_prefix_equal(addr, &ifa->addr, prefix_len);
+                       if (ret)
+                               break;
+               }
+               read_unlock_bh(&idev->lock);
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+EXPORT_SYMBOL(ipv6_chk_custom_prefix);
+
 int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev)
 {
        struct inet6_dev *idev;
@@ -1803,6 +1848,10 @@ static int addrconf_ifid_gre(u8 *eui, struct net_device *dev)
 
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
 {
+    /* MTK_NET_CHANGES */
+    if (strncmp(dev->name, "ccmni", 2) == 0)
+        return -1;
+               
        switch (dev->type) {
        case ARPHRD_ETHER:
        case ARPHRD_FDDI:
@@ -1910,6 +1959,31 @@ static void  __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmp
 }
 #endif
 
+u32 addrconf_rt_table(const struct net_device *dev, u32 default_table) {
+       /* Determines into what table to put autoconf PIO/RIO/default routes
+        * learned on this device.
+        *
+        * - If 0, use the same table for every device. This puts routes into
+        *   one of RT_TABLE_{PREFIX,INFO,DFLT} depending on the type of route
+        *   (but note that these three are currently all equal to
+        *   RT6_TABLE_MAIN).
+        * - If > 0, use the specified table.
+        * - If < 0, put routes into table dev->ifindex + (-rt_table).
+        */
+       struct inet6_dev *idev = in6_dev_get(dev);
+       u32 table;
+       int sysctl = idev->cnf.accept_ra_rt_table;
+       if (sysctl == 0) {
+               table = default_table;
+       } else if (sysctl > 0) {
+               table = (u32) sysctl;
+       } else {
+               table = (unsigned) dev->ifindex + (-sysctl);
+       }
+       in6_dev_put(idev);
+       return table;
+}
+
 /*
  *     Add prefix route.
  */
@@ -1919,7 +1993,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
                      unsigned long expires, u32 flags)
 {
        struct fib6_config cfg = {
-               .fc_table = RT6_TABLE_PREFIX,
+               .fc_table = addrconf_rt_table(dev, RT6_TABLE_PREFIX),
                .fc_metric = IP6_RT_PRIO_ADDRCONF,
                .fc_ifindex = dev->ifindex,
                .fc_expires = expires,
@@ -1953,7 +2027,8 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
        struct rt6_info *rt = NULL;
        struct fib6_table *table;
 
-       table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX);
+       table = fib6_get_table(dev_net(dev),
+                              addrconf_rt_table(dev, RT6_TABLE_PREFIX));
        if (table == NULL)
                return NULL;
 
@@ -2655,6 +2730,19 @@ static void init_loopback(struct net_device *dev)
                        if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))
                                continue;
 
+                       if (sp_ifa->rt) {
+                               /* This dst has been added to garbage list when
+                                * lo device down, release this obsolete dst and
+                                * reallocate a new router for ifa.
+                                */
+                               if (sp_ifa->rt->dst.obsolete > 0) {
+                                       ip6_rt_put(sp_ifa->rt);
+                                       sp_ifa->rt = NULL;
+                               } else {
+                                       continue;
+                               }
+                       }
+
                        sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0);
 
                        /* Failure cases are ignored */
@@ -4156,6 +4244,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
 #endif
 #endif
+       array[DEVCONF_ACCEPT_RA_RT_TABLE] = cnf->accept_ra_rt_table;
        array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
        array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
@@ -4168,6 +4257,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
        array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
        array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify;
+#ifdef CONFIG_MTK_DHCPV6C_WIFI 
+       array[DEVCONF_RA_INFO_FLAG] = cnf->ra_info_flag;
+#endif 
 }
 
 static inline size_t inet6_ifla6_size(void)
@@ -4303,6 +4395,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
        struct inet6_ifaddr *ifp;
        struct net_device *dev = idev->dev;
        bool update_rs = false;
+       struct in6_addr ll_addr;
 
        if (token == NULL)
                return -EINVAL;
@@ -4322,11 +4415,9 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
 
        write_unlock_bh(&idev->lock);
 
-       if (!idev->dead && (idev->if_flags & IF_READY)) {
-               struct in6_addr ll_addr;
-
-               ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE |
-                               IFA_F_OPTIMISTIC);
+       if (!idev->dead && (idev->if_flags & IF_READY) &&
+           !ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE |
+                            IFA_F_OPTIMISTIC)) {
 
                /* If we're not ready, then normal ifup will take care
                 * of this. Otherwise, we need to request our rs here.
@@ -4865,6 +4956,13 @@ static struct addrconf_sysctl_table
                },
 #endif
 #endif
+               {
+                       .procname       = "accept_ra_rt_table",
+                       .data           = &ipv6_devconf.accept_ra_rt_table,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
+               },
                {
                        .procname       = "proxy_ndp",
                        .data           = &ipv6_devconf.proxy_ndp,
@@ -4926,6 +5024,15 @@ static struct addrconf_sysctl_table
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec
                },
+#ifdef CONFIG_MTK_DHCPV6C_WIFI 
+               {
+                       .procname               = "ra_info_flag",
+                       .data                   = &ipv6_devconf.ra_info_flag,
+                       .maxlen                 = sizeof(int),
+                       .mode                   = 0644,
+                       .proc_handler   = proc_dointvec
+               },
+#endif
                {
                        /* sentinel */
                }