NFS: Don't use GFP_KERNEL in rpcsec_gss downcalls
[safe/jmp/linux-2.6] / net / ipv6 / addrconf.c
index 8c1e86a..413054f 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/route.h>
 #include <linux/inetdevice.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 #endif
@@ -137,6 +138,8 @@ static DEFINE_SPINLOCK(addrconf_verify_lock);
 static void addrconf_join_anycast(struct inet6_ifaddr *ifp);
 static void addrconf_leave_anycast(struct inet6_ifaddr *ifp);
 
+static void addrconf_bonding_change(struct net_device *dev,
+                                   unsigned long event);
 static int addrconf_ifdown(struct net_device *dev, int how);
 
 static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags);
@@ -276,31 +279,31 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
 
 static int snmp6_alloc_dev(struct inet6_dev *idev)
 {
-       if (snmp_mib_init((void **)idev->stats.ipv6,
+       if (snmp_mib_init((void __percpu **)idev->stats.ipv6,
                          sizeof(struct ipstats_mib)) < 0)
                goto err_ip;
-       if (snmp_mib_init((void **)idev->stats.icmpv6,
+       if (snmp_mib_init((void __percpu **)idev->stats.icmpv6,
                          sizeof(struct icmpv6_mib)) < 0)
                goto err_icmp;
-       if (snmp_mib_init((void **)idev->stats.icmpv6msg,
+       if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg,
                          sizeof(struct icmpv6msg_mib)) < 0)
                goto err_icmpmsg;
 
        return 0;
 
 err_icmpmsg:
-       snmp_mib_free((void **)idev->stats.icmpv6);
+       snmp_mib_free((void __percpu **)idev->stats.icmpv6);
 err_icmp:
-       snmp_mib_free((void **)idev->stats.ipv6);
+       snmp_mib_free((void __percpu **)idev->stats.ipv6);
 err_ip:
        return -ENOMEM;
 }
 
 static void snmp6_free_dev(struct inet6_dev *idev)
 {
-       snmp_mib_free((void **)idev->stats.icmpv6msg);
-       snmp_mib_free((void **)idev->stats.icmpv6);
-       snmp_mib_free((void **)idev->stats.ipv6);
+       snmp_mib_free((void __percpu **)idev->stats.icmpv6msg);
+       snmp_mib_free((void __percpu **)idev->stats.icmpv6);
+       snmp_mib_free((void __percpu **)idev->stats.ipv6);
 }
 
 /* Nobody refers to this device, we may destroy it. */
@@ -479,9 +482,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
        struct net_device *dev;
        struct inet6_dev *idev;
 
-       read_lock(&dev_base_lock);
-       for_each_netdev(net, dev) {
-               rcu_read_lock();
+       rcu_read_lock();
+       for_each_netdev_rcu(net, dev) {
                idev = __in6_dev_get(dev);
                if (idev) {
                        int changed = (!idev->cnf.forwarding) ^ (!newf);
@@ -489,9 +491,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
                        if (changed)
                                dev_forward_change(idev);
                }
-               rcu_read_unlock();
        }
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 }
 
 static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
@@ -502,8 +503,11 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
        if (p == &net->ipv6.devconf_dflt->forwarding)
                return 0;
 
-       if (!rtnl_trylock())
+       if (!rtnl_trylock()) {
+               /* Restore the original values before restarting */
+               *p = old;
                return restart_syscall();
+       }
 
        if (p == &net->ipv6.devconf_all->forwarding) {
                __s32 newf = net->ipv6.devconf_all->forwarding;
@@ -989,8 +993,7 @@ struct ipv6_saddr_dst {
 
 static inline int ipv6_saddr_preferred(int type)
 {
-       if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|
-                   IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED))
+       if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|IPV6_ADDR_LOOPBACK))
                return 1;
        return 0;
 }
@@ -1135,10 +1138,9 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
        hiscore->rule = -1;
        hiscore->ifa = NULL;
 
-       read_lock(&dev_base_lock);
        rcu_read_lock();
 
-       for_each_netdev(net, dev) {
+       for_each_netdev_rcu(net, dev) {
                struct inet6_dev *idev;
 
                /* Candidate Source Address (section 4)
@@ -1233,7 +1235,6 @@ try_nextdev:
                read_unlock_bh(&idev->lock);
        }
        rcu_read_unlock();
-       read_unlock(&dev_base_lock);
 
        if (!hiscore->ifa)
                return -EADDRNOTAVAIL;
@@ -1371,13 +1372,17 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add
 
 /* Gets referenced address, destroys ifaddr */
 
-static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
+static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
 {
        if (ifp->flags&IFA_F_PERMANENT) {
                spin_lock_bh(&ifp->lock);
                addrconf_del_timer(ifp);
                ifp->flags |= IFA_F_TENTATIVE;
+               if (dad_failed)
+                       ifp->flags |= IFA_F_DADFAILED;
                spin_unlock_bh(&ifp->lock);
+               if (dad_failed)
+                       ipv6_ifa_notify(0, ifp);
                in6_ifa_put(ifp);
 #ifdef CONFIG_IPV6_PRIVACY
        } else if (ifp->flags&IFA_F_TEMPORARY) {
@@ -1403,8 +1408,8 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
        struct inet6_dev *idev = ifp->idev;
 
        if (net_ratelimit())
-               printk(KERN_INFO "%s: IPv6 duplicate address detected!\n",
-                       ifp->idev->dev->name);
+               printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n",
+                       ifp->idev->dev->name, &ifp->addr);
 
        if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
                struct in6_addr addr;
@@ -1422,7 +1427,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
                }
        }
 
-       addrconf_dad_stop(ifp);
+       addrconf_dad_stop(ifp, 1);
 }
 
 /* Join to solicited addr multicast group. */
@@ -1916,8 +1921,32 @@ ok:
                                        update_lft = 1;
                                else if (stored_lft <= MIN_VALID_LIFETIME) {
                                        /* valid_lft <= stored_lft is always true */
-                                       /* XXX: IPsec */
-                                       update_lft = 0;
+                                       /*
+                                        * RFC 4862 Section 5.5.3e:
+                                        * "Note that the preferred lifetime of
+                                        *  the corresponding address is always
+                                        *  reset to the Preferred Lifetime in
+                                        *  the received Prefix Information
+                                        *  option, regardless of whether the
+                                        *  valid lifetime is also reset or
+                                        *  ignored."
+                                        *
+                                        *  So if the preferred lifetime in
+                                        *  this advertisement is different
+                                        *  than what we have stored, but the
+                                        *  valid lifetime is invalid, just
+                                        *  reset prefered_lft.
+                                        *
+                                        *  We must set the valid lifetime
+                                        *  to the stored lifetime since we'll
+                                        *  be updating the timestamp below,
+                                        *  else we'll set it back to the
+                                        *  minumum.
+                                        */
+                                       if (prefered_lft != ifp->prefered_lft) {
+                                               valid_lft = stored_lft;
+                                               update_lft = 1;
+                                       }
                                } else {
                                        valid_lft = MIN_VALID_LIFETIME;
                                        if (valid_lft < prefered_lft)
@@ -2556,6 +2585,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                                return notifier_from_errno(err);
                }
                break;
+       case NETDEV_BONDING_OLDTYPE:
+       case NETDEV_BONDING_NEWTYPE:
+               addrconf_bonding_change(dev, event);
+               break;
        }
 
        return NOTIFY_OK;
@@ -2569,10 +2602,23 @@ static struct notifier_block ipv6_dev_notf = {
        .priority = 0
 };
 
+static void addrconf_bonding_change(struct net_device *dev, unsigned long event)
+{
+       struct inet6_dev *idev;
+       ASSERT_RTNL();
+
+       idev = __in6_dev_get(dev);
+
+       if (event == NETDEV_BONDING_NEWTYPE)
+               ipv6_mc_remap(idev);
+       else if (event == NETDEV_BONDING_OLDTYPE)
+               ipv6_mc_unmap(idev);
+}
+
 static int addrconf_ifdown(struct net_device *dev, int how)
 {
        struct inet6_dev *idev;
-       struct inet6_ifaddr *ifa, **bifa;
+       struct inet6_ifaddr *ifa, *keep_list, **bifa;
        struct net *net = dev_net(dev);
        int i;
 
@@ -2605,11 +2651,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
                write_lock_bh(&addrconf_hash_lock);
                while ((ifa = *bifa) != NULL) {
-                       if (ifa->idev == idev) {
+                       if (ifa->idev == idev &&
+                           (how || !(ifa->flags&IFA_F_PERMANENT) ||
+                            ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
                                *bifa = ifa->lst_next;
                                ifa->lst_next = NULL;
-                               addrconf_del_timer(ifa);
-                               in6_ifa_put(ifa);
+                               __in6_ifa_put(ifa);
                                continue;
                        }
                        bifa = &ifa->lst_next;
@@ -2645,11 +2692,40 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                write_lock_bh(&idev->lock);
        }
 #endif
+       keep_list = NULL;
+       bifa = &keep_list;
        while ((ifa = idev->addr_list) != NULL) {
                idev->addr_list = ifa->if_next;
                ifa->if_next = NULL;
-               ifa->dead = 1;
+
                addrconf_del_timer(ifa);
+
+               /* If just doing link down, and address is permanent
+                  and not link-local, then retain it. */
+               if (how == 0 &&
+                   (ifa->flags&IFA_F_PERMANENT) &&
+                   !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
+
+                       /* Move to holding list */
+                       *bifa = ifa;
+                       bifa = &ifa->if_next;
+
+                       /* If not doing DAD on this address, just keep it. */
+                       if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
+                           idev->cnf.accept_dad <= 0 ||
+                           (ifa->flags & IFA_F_NODAD))
+                               continue;
+
+                       /* If it was tentative already, no need to notify */
+                       if (ifa->flags & IFA_F_TENTATIVE)
+                               continue;
+
+                       /* Flag it for later restoration when link comes up */
+                       ifa->flags |= IFA_F_TENTATIVE;
+                       in6_ifa_hold(ifa);
+               } else {
+                       ifa->dead = 1;
+               }
                write_unlock_bh(&idev->lock);
 
                __ipv6_ifa_notify(RTM_DELADDR, ifa);
@@ -2658,6 +2734,9 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
                write_lock_bh(&idev->lock);
        }
+
+       idev->addr_list = keep_list;
+
        write_unlock_bh(&idev->lock);
 
        /* Step 5: Discard multicast list */
@@ -2683,28 +2762,29 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 static void addrconf_rs_timer(unsigned long data)
 {
        struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;
+       struct inet6_dev *idev = ifp->idev;
 
-       if (ifp->idev->cnf.forwarding)
+       read_lock(&idev->lock);
+       if (idev->dead || !(idev->if_flags & IF_READY))
                goto out;
 
-       if (ifp->idev->if_flags & IF_RA_RCVD) {
-               /*
-                *      Announcement received after solicitation
-                *      was sent
-                */
+       if (idev->cnf.forwarding)
+               goto out;
+
+       /* Announcement received after solicitation was sent */
+       if (idev->if_flags & IF_RA_RCVD)
                goto out;
-       }
 
        spin_lock(&ifp->lock);
-       if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) {
+       if (ifp->probes++ < idev->cnf.rtr_solicits) {
                /* The wait after the last probe can be shorter */
                addrconf_mod_timer(ifp, AC_RS,
-                                  (ifp->probes == ifp->idev->cnf.rtr_solicits) ?
-                                  ifp->idev->cnf.rtr_solicit_delay :
-                                  ifp->idev->cnf.rtr_solicit_interval);
+                                  (ifp->probes == idev->cnf.rtr_solicits) ?
+                                  idev->cnf.rtr_solicit_delay :
+                                  idev->cnf.rtr_solicit_interval);
                spin_unlock(&ifp->lock);
 
-               ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters);
+               ndisc_send_rs(idev->dev, &ifp->addr, &in6addr_linklocal_allrouters);
        } else {
                spin_unlock(&ifp->lock);
                /*
@@ -2712,10 +2792,11 @@ static void addrconf_rs_timer(unsigned long data)
                 * assumption any longer.
                 */
                printk(KERN_DEBUG "%s: no IPv6 routers present\n",
-                      ifp->idev->dev->name);
+                      idev->dev->name);
        }
 
 out:
+       read_unlock(&idev->lock);
        in6_ifa_put(ifp);
 }
 
@@ -2748,14 +2829,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
        read_lock_bh(&idev->lock);
        if (ifp->dead)
                goto out;
-       spin_lock_bh(&ifp->lock);
 
+       spin_lock(&ifp->lock);
        if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
            idev->cnf.accept_dad < 1 ||
            !(ifp->flags&IFA_F_TENTATIVE) ||
            ifp->flags & IFA_F_NODAD) {
-               ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
-               spin_unlock_bh(&ifp->lock);
+               ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
+               spin_unlock(&ifp->lock);
                read_unlock_bh(&idev->lock);
 
                addrconf_dad_completed(ifp);
@@ -2763,7 +2844,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
        }
 
        if (!(idev->if_flags & IF_READY)) {
-               spin_unlock_bh(&ifp->lock);
+               spin_unlock(&ifp->lock);
                read_unlock_bh(&idev->lock);
                /*
                 * If the device is not ready:
@@ -2771,7 +2852,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
                 * - otherwise, kill it.
                 */
                in6_ifa_hold(ifp);
-               addrconf_dad_stop(ifp);
+               addrconf_dad_stop(ifp, 0);
                return;
        }
 
@@ -2783,7 +2864,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
                ip6_ins_rt(ifp->rt);
 
        addrconf_dad_kick(ifp);
-       spin_unlock_bh(&ifp->lock);
+       spin_unlock(&ifp->lock);
 out:
        read_unlock_bh(&idev->lock);
 }
@@ -2794,20 +2875,21 @@ static void addrconf_dad_timer(unsigned long data)
        struct inet6_dev *idev = ifp->idev;
        struct in6_addr mcaddr;
 
-       read_lock_bh(&idev->lock);
-       if (idev->dead) {
-               read_unlock_bh(&idev->lock);
+       read_lock(&idev->lock);
+       if (idev->dead || !(idev->if_flags & IF_READY)) {
+               read_unlock(&idev->lock);
                goto out;
        }
-       spin_lock_bh(&ifp->lock);
+
+       spin_lock(&ifp->lock);
        if (ifp->probes == 0) {
                /*
                 * DAD was successful
                 */
 
-               ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
-               spin_unlock_bh(&ifp->lock);
-               read_unlock_bh(&idev->lock);
+               ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
+               spin_unlock(&ifp->lock);
+               read_unlock(&idev->lock);
 
                addrconf_dad_completed(ifp);
 
@@ -2816,8 +2898,8 @@ static void addrconf_dad_timer(unsigned long data)
 
        ifp->probes--;
        addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time);
-       spin_unlock_bh(&ifp->lock);
-       read_unlock_bh(&idev->lock);
+       spin_unlock(&ifp->lock);
+       read_unlock(&idev->lock);
 
        /* send a neighbour solicitation for our addr */
        addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
@@ -2864,12 +2946,12 @@ static void addrconf_dad_run(struct inet6_dev *idev) {
 
        read_lock_bh(&idev->lock);
        for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) {
-               spin_lock_bh(&ifp->lock);
+               spin_lock(&ifp->lock);
                if (!(ifp->flags & IFA_F_TENTATIVE)) {
-                       spin_unlock_bh(&ifp->lock);
+                       spin_unlock(&ifp->lock);
                        continue;
                }
-               spin_unlock_bh(&ifp->lock);
+               spin_unlock(&ifp->lock);
                addrconf_dad_kick(ifp);
        }
        read_unlock_bh(&idev->lock);
@@ -2986,14 +3068,14 @@ static const struct file_operations if6_fops = {
        .release        = seq_release_net,
 };
 
-static int if6_proc_net_init(struct net *net)
+static int __net_init if6_proc_net_init(struct net *net)
 {
        if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops))
                return -ENOMEM;
        return 0;
 }
 
-static void if6_proc_net_exit(struct net *net)
+static void __net_exit if6_proc_net_exit(struct net *net)
 {
        proc_net_remove(net, "if_inet6");
 }
@@ -3085,7 +3167,7 @@ restart:
                                spin_unlock(&ifp->lock);
                                continue;
                        } else if (age >= ifp->prefered_lft) {
-                               /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
+                               /* jiffies - ifp->tstamp > age >= ifp->prefered_lft */
                                int deprecate = 0;
 
                                if (!(ifp->flags&IFA_F_DEPRECATED)) {
@@ -3362,7 +3444,10 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
                valid = ifa->valid_lft;
                if (preferred != INFINITY_LIFE_TIME) {
                        long tval = (jiffies - ifa->tstamp)/HZ;
-                       preferred -= tval;
+                       if (preferred > tval)
+                               preferred -= tval;
+                       else
+                               preferred = 0;
                        if (valid != INFINITY_LIFE_TIME)
                                valid -= tval;
                }
@@ -3437,85 +3522,114 @@ enum addr_type_t
        ANYCAST_ADDR,
 };
 
+/* called with rcu_read_lock() */
+static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
+                         struct netlink_callback *cb, enum addr_type_t type,
+                         int s_ip_idx, int *p_ip_idx)
+{
+       struct inet6_ifaddr *ifa;
+       struct ifmcaddr6 *ifmca;
+       struct ifacaddr6 *ifaca;
+       int err = 1;
+       int ip_idx = *p_ip_idx;
+
+       read_lock_bh(&idev->lock);
+       switch (type) {
+       case UNICAST_ADDR:
+               /* unicast address incl. temp addr */
+               for (ifa = idev->addr_list; ifa;
+                    ifa = ifa->if_next, ip_idx++) {
+                       if (ip_idx < s_ip_idx)
+                               continue;
+                       err = inet6_fill_ifaddr(skb, ifa,
+                                               NETLINK_CB(cb->skb).pid,
+                                               cb->nlh->nlmsg_seq,
+                                               RTM_NEWADDR,
+                                               NLM_F_MULTI);
+                       if (err <= 0)
+                               break;
+               }
+               break;
+       case MULTICAST_ADDR:
+               /* multicast address */
+               for (ifmca = idev->mc_list; ifmca;
+                    ifmca = ifmca->next, ip_idx++) {
+                       if (ip_idx < s_ip_idx)
+                               continue;
+                       err = inet6_fill_ifmcaddr(skb, ifmca,
+                                                 NETLINK_CB(cb->skb).pid,
+                                                 cb->nlh->nlmsg_seq,
+                                                 RTM_GETMULTICAST,
+                                                 NLM_F_MULTI);
+                       if (err <= 0)
+                               break;
+               }
+               break;
+       case ANYCAST_ADDR:
+               /* anycast address */
+               for (ifaca = idev->ac_list; ifaca;
+                    ifaca = ifaca->aca_next, ip_idx++) {
+                       if (ip_idx < s_ip_idx)
+                               continue;
+                       err = inet6_fill_ifacaddr(skb, ifaca,
+                                                 NETLINK_CB(cb->skb).pid,
+                                                 cb->nlh->nlmsg_seq,
+                                                 RTM_GETANYCAST,
+                                                 NLM_F_MULTI);
+                       if (err <= 0)
+                               break;
+               }
+               break;
+       default:
+               break;
+       }
+       read_unlock_bh(&idev->lock);
+       *p_ip_idx = ip_idx;
+       return err;
+}
+
 static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                           enum addr_type_t type)
 {
+       struct net *net = sock_net(skb->sk);
+       int h, s_h;
        int idx, ip_idx;
        int s_idx, s_ip_idx;
-       int err = 1;
        struct net_device *dev;
-       struct inet6_dev *idev = NULL;
-       struct inet6_ifaddr *ifa;
-       struct ifmcaddr6 *ifmca;
-       struct ifacaddr6 *ifaca;
-       struct net *net = sock_net(skb->sk);
-
-       s_idx = cb->args[0];
-       s_ip_idx = ip_idx = cb->args[1];
+       struct inet6_dev *idev;
+       struct hlist_head *head;
+       struct hlist_node *node;
 
-       idx = 0;
-       for_each_netdev(net, dev) {
-               if (idx < s_idx)
-                       goto cont;
-               if (idx > s_idx)
-                       s_ip_idx = 0;
-               ip_idx = 0;
-               if ((idev = in6_dev_get(dev)) == NULL)
-                       goto cont;
-               read_lock_bh(&idev->lock);
-               switch (type) {
-               case UNICAST_ADDR:
-                       /* unicast address incl. temp addr */
-                       for (ifa = idev->addr_list; ifa;
-                            ifa = ifa->if_next, ip_idx++) {
-                               if (ip_idx < s_ip_idx)
-                                       continue;
-                               err = inet6_fill_ifaddr(skb, ifa,
-                                                       NETLINK_CB(cb->skb).pid,
-                                                       cb->nlh->nlmsg_seq,
-                                                       RTM_NEWADDR,
-                                                       NLM_F_MULTI);
-                       }
-                       break;
-               case MULTICAST_ADDR:
-                       /* multicast address */
-                       for (ifmca = idev->mc_list; ifmca;
-                            ifmca = ifmca->next, ip_idx++) {
-                               if (ip_idx < s_ip_idx)
-                                       continue;
-                               err = inet6_fill_ifmcaddr(skb, ifmca,
-                                                         NETLINK_CB(cb->skb).pid,
-                                                         cb->nlh->nlmsg_seq,
-                                                         RTM_GETMULTICAST,
-                                                         NLM_F_MULTI);
-                       }
-                       break;
-               case ANYCAST_ADDR:
-                       /* anycast address */
-                       for (ifaca = idev->ac_list; ifaca;
-                            ifaca = ifaca->aca_next, ip_idx++) {
-                               if (ip_idx < s_ip_idx)
-                                       continue;
-                               err = inet6_fill_ifacaddr(skb, ifaca,
-                                                         NETLINK_CB(cb->skb).pid,
-                                                         cb->nlh->nlmsg_seq,
-                                                         RTM_GETANYCAST,
-                                                         NLM_F_MULTI);
-                       }
-                       break;
-               default:
-                       break;
-               }
-               read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
+       s_h = cb->args[0];
+       s_idx = idx = cb->args[1];
+       s_ip_idx = ip_idx = cb->args[2];
 
-               if (err <= 0)
-                       break;
+       rcu_read_lock();
+       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+               idx = 0;
+               head = &net->dev_index_head[h];
+               hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
+                       if (idx < s_idx)
+                               goto cont;
+                       if (h > s_h || idx > s_idx)
+                               s_ip_idx = 0;
+                       ip_idx = 0;
+                       if ((idev = __in6_dev_get(dev)) == NULL)
+                               goto cont;
+
+                       if (in6_dump_addrs(idev, skb, cb, type,
+                                          s_ip_idx, &ip_idx) <= 0)
+                               goto done;
 cont:
-               idx++;
+                       idx++;
+               }
        }
-       cb->args[0] = idx;
-       cb->args[1] = ip_idx;
+done:
+       rcu_read_unlock();
+       cb->args[0] = h;
+       cb->args[1] = idx;
+       cb->args[2] = ip_idx;
+
        return skb->len;
 }
 
@@ -3660,6 +3774,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 #endif
        array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
        array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
+       array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
 }
 
 static inline size_t inet6_if_nlmsg_size(void)
@@ -3678,8 +3793,8 @@ static inline size_t inet6_if_nlmsg_size(void)
                 );
 }
 
-static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items,
-                                     int bytes)
+static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
+                                     int items, int bytes)
 {
        int i;
        int pad = bytes - sizeof(u64) * items;
@@ -3698,10 +3813,10 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
 {
        switch(attrtype) {
        case IFLA_INET6_STATS:
-               __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
+               __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
                break;
        case IFLA_INET6_ICMP6STATS:
-               __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
+               __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
                break;
        }
 }
@@ -3778,28 +3893,39 @@ nla_put_failure:
 static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct net *net = sock_net(skb->sk);
-       int idx, err;
-       int s_idx = cb->args[0];
+       int h, s_h;
+       int idx = 0, s_idx;
        struct net_device *dev;
        struct inet6_dev *idev;
+       struct hlist_head *head;
+       struct hlist_node *node;
 
-       read_lock(&dev_base_lock);
-       idx = 0;
-       for_each_netdev(net, dev) {
-               if (idx < s_idx)
-                       goto cont;
-               if ((idev = in6_dev_get(dev)) == NULL)
-                       goto cont;
-               err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid,
-                               cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
-               in6_dev_put(idev);
-               if (err <= 0)
-                       break;
+       s_h = cb->args[0];
+       s_idx = cb->args[1];
+
+       rcu_read_lock();
+       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+               idx = 0;
+               head = &net->dev_index_head[h];
+               hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
+                       if (idx < s_idx)
+                               goto cont;
+                       idev = __in6_dev_get(dev);
+                       if (!idev)
+                               goto cont;
+                       if (inet6_fill_ifinfo(skb, idev,
+                                             NETLINK_CB(cb->skb).pid,
+                                             cb->nlh->nlmsg_seq,
+                                             RTM_NEWLINK, NLM_F_MULTI) <= 0)
+                               goto out;
 cont:
-               idx++;
+                       idx++;
+               }
        }
-       read_unlock(&dev_base_lock);
-       cb->args[0] = idx;
+out:
+       rcu_read_unlock();
+       cb->args[1] = idx;
+       cb->args[0] = h;
 
        return skb->len;
 }
@@ -3938,55 +4064,23 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
 #ifdef CONFIG_SYSCTL
 
 static
-int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
+int addrconf_sysctl_forward(ctl_table *ctl, int write,
                           void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int *valp = ctl->data;
        int val = *valp;
+       loff_t pos = *ppos;
        int ret;
 
-       ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+       ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
 
        if (write)
                ret = addrconf_fixup_forwarding(ctl, valp, val);
+       if (ret)
+               *ppos = pos;
        return ret;
 }
 
-static int addrconf_sysctl_forward_strategy(ctl_table *table,
-                                           void __user *oldval,
-                                           size_t __user *oldlenp,
-                                           void __user *newval, size_t newlen)
-{
-       int *valp = table->data;
-       int val = *valp;
-       int new;
-
-       if (!newval || !newlen)
-               return 0;
-       if (newlen != sizeof(int))
-               return -EINVAL;
-       if (get_user(new, (int __user *)newval))
-               return -EFAULT;
-       if (new == *valp)
-               return 0;
-       if (oldval && oldlenp) {
-               size_t len;
-               if (get_user(len, oldlenp))
-                       return -EFAULT;
-               if (len) {
-                       if (len > table->maxlen)
-                               len = table->maxlen;
-                       if (copy_to_user(oldval, valp, len))
-                               return -EFAULT;
-                       if (put_user(len, oldlenp))
-                               return -EFAULT;
-               }
-       }
-
-       *valp = new;
-       return addrconf_fixup_forwarding(table, valp, val);
-}
-
 static void dev_disable_change(struct inet6_dev *idev)
 {
        if (!idev || !idev->dev)
@@ -4003,9 +4097,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf)
        struct net_device *dev;
        struct inet6_dev *idev;
 
-       read_lock(&dev_base_lock);
-       for_each_netdev(net, dev) {
-               rcu_read_lock();
+       rcu_read_lock();
+       for_each_netdev_rcu(net, dev) {
                idev = __in6_dev_get(dev);
                if (idev) {
                        int changed = (!idev->cnf.disable_ipv6) ^ (!newf);
@@ -4013,9 +4106,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf)
                        if (changed)
                                dev_disable_change(idev);
                }
-               rcu_read_unlock();
        }
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 }
 
 static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
@@ -4027,8 +4119,11 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
        if (p == &net->ipv6.devconf_dflt->disable_ipv6)
                return 0;
 
-       if (!rtnl_trylock())
+       if (!rtnl_trylock()) {
+               /* Restore the original values before restarting */
+               *p = old;
                return restart_syscall();
+       }
 
        if (p == &net->ipv6.devconf_all->disable_ipv6) {
                __s32 newf = net->ipv6.devconf_all->disable_ipv6;
@@ -4042,17 +4137,20 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
 }
 
 static
-int addrconf_sysctl_disable(ctl_table *ctl, int write, struct file * filp,
+int addrconf_sysctl_disable(ctl_table *ctl, int write,
                            void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int *valp = ctl->data;
        int val = *valp;
+       loff_t pos = *ppos;
        int ret;
 
-       ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+       ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
 
        if (write)
                ret = addrconf_disable_ipv6(ctl, valp, val);
+       if (ret)
+               *ppos = pos;
        return ret;
 }
 
@@ -4065,16 +4163,13 @@ static struct addrconf_sysctl_table
        .sysctl_header = NULL,
        .addrconf_vars = {
                {
-                       .ctl_name       =       NET_IPV6_FORWARDING,
                        .procname       =       "forwarding",
                        .data           =       &ipv6_devconf.forwarding,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       addrconf_sysctl_forward,
-                       .strategy       =       addrconf_sysctl_forward_strategy,
                },
                {
-                       .ctl_name       =       NET_IPV6_HOP_LIMIT,
                        .procname       =       "hop_limit",
                        .data           =       &ipv6_devconf.hop_limit,
                        .maxlen         =       sizeof(int),
@@ -4082,7 +4177,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_MTU,
                        .procname       =       "mtu",
                        .data           =       &ipv6_devconf.mtu6,
                        .maxlen         =       sizeof(int),
@@ -4090,7 +4184,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA,
                        .procname       =       "accept_ra",
                        .data           =       &ipv6_devconf.accept_ra,
                        .maxlen         =       sizeof(int),
@@ -4098,7 +4191,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_REDIRECTS,
                        .procname       =       "accept_redirects",
                        .data           =       &ipv6_devconf.accept_redirects,
                        .maxlen         =       sizeof(int),
@@ -4106,7 +4198,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_AUTOCONF,
                        .procname       =       "autoconf",
                        .data           =       &ipv6_devconf.autoconf,
                        .maxlen         =       sizeof(int),
@@ -4114,7 +4205,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_DAD_TRANSMITS,
                        .procname       =       "dad_transmits",
                        .data           =       &ipv6_devconf.dad_transmits,
                        .maxlen         =       sizeof(int),
@@ -4122,7 +4212,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_RTR_SOLICITS,
                        .procname       =       "router_solicitations",
                        .data           =       &ipv6_devconf.rtr_solicits,
                        .maxlen         =       sizeof(int),
@@ -4130,25 +4219,20 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_RTR_SOLICIT_INTERVAL,
                        .procname       =       "router_solicitation_interval",
                        .data           =       &ipv6_devconf.rtr_solicit_interval,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       proc_dointvec_jiffies,
-                       .strategy       =       sysctl_jiffies,
                },
                {
-                       .ctl_name       =       NET_IPV6_RTR_SOLICIT_DELAY,
                        .procname       =       "router_solicitation_delay",
                        .data           =       &ipv6_devconf.rtr_solicit_delay,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       proc_dointvec_jiffies,
-                       .strategy       =       sysctl_jiffies,
                },
                {
-                       .ctl_name       =       NET_IPV6_FORCE_MLD_VERSION,
                        .procname       =       "force_mld_version",
                        .data           =       &ipv6_devconf.force_mld_version,
                        .maxlen         =       sizeof(int),
@@ -4157,7 +4241,6 @@ static struct addrconf_sysctl_table
                },
 #ifdef CONFIG_IPV6_PRIVACY
                {
-                       .ctl_name       =       NET_IPV6_USE_TEMPADDR,
                        .procname       =       "use_tempaddr",
                        .data           =       &ipv6_devconf.use_tempaddr,
                        .maxlen         =       sizeof(int),
@@ -4165,7 +4248,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_TEMP_VALID_LFT,
                        .procname       =       "temp_valid_lft",
                        .data           =       &ipv6_devconf.temp_valid_lft,
                        .maxlen         =       sizeof(int),
@@ -4173,7 +4255,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_TEMP_PREFERED_LFT,
                        .procname       =       "temp_prefered_lft",
                        .data           =       &ipv6_devconf.temp_prefered_lft,
                        .maxlen         =       sizeof(int),
@@ -4181,7 +4262,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_REGEN_MAX_RETRY,
                        .procname       =       "regen_max_retry",
                        .data           =       &ipv6_devconf.regen_max_retry,
                        .maxlen         =       sizeof(int),
@@ -4189,7 +4269,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_MAX_DESYNC_FACTOR,
                        .procname       =       "max_desync_factor",
                        .data           =       &ipv6_devconf.max_desync_factor,
                        .maxlen         =       sizeof(int),
@@ -4198,7 +4277,6 @@ static struct addrconf_sysctl_table
                },
 #endif
                {
-                       .ctl_name       =       NET_IPV6_MAX_ADDRESSES,
                        .procname       =       "max_addresses",
                        .data           =       &ipv6_devconf.max_addresses,
                        .maxlen         =       sizeof(int),
@@ -4206,7 +4284,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_DEFRTR,
                        .procname       =       "accept_ra_defrtr",
                        .data           =       &ipv6_devconf.accept_ra_defrtr,
                        .maxlen         =       sizeof(int),
@@ -4214,7 +4291,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_PINFO,
                        .procname       =       "accept_ra_pinfo",
                        .data           =       &ipv6_devconf.accept_ra_pinfo,
                        .maxlen         =       sizeof(int),
@@ -4223,7 +4299,6 @@ static struct addrconf_sysctl_table
                },
 #ifdef CONFIG_IPV6_ROUTER_PREF
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_RTR_PREF,
                        .procname       =       "accept_ra_rtr_pref",
                        .data           =       &ipv6_devconf.accept_ra_rtr_pref,
                        .maxlen         =       sizeof(int),
@@ -4231,17 +4306,14 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_RTR_PROBE_INTERVAL,
                        .procname       =       "router_probe_interval",
                        .data           =       &ipv6_devconf.rtr_probe_interval,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       proc_dointvec_jiffies,
-                       .strategy       =       sysctl_jiffies,
                },
 #ifdef CONFIG_IPV6_ROUTE_INFO
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,
                        .procname       =       "accept_ra_rt_info_max_plen",
                        .data           =       &ipv6_devconf.accept_ra_rt_info_max_plen,
                        .maxlen         =       sizeof(int),
@@ -4251,7 +4323,6 @@ static struct addrconf_sysctl_table
 #endif
 #endif
                {
-                       .ctl_name       =       NET_IPV6_PROXY_NDP,
                        .procname       =       "proxy_ndp",
                        .data           =       &ipv6_devconf.proxy_ndp,
                        .maxlen         =       sizeof(int),
@@ -4259,7 +4330,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_SOURCE_ROUTE,
                        .procname       =       "accept_source_route",
                        .data           =       &ipv6_devconf.accept_source_route,
                        .maxlen         =       sizeof(int),
@@ -4268,7 +4338,6 @@ static struct addrconf_sysctl_table
                },
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
                {
-                       .ctl_name       =       CTL_UNNUMBERED,
                        .procname       =       "optimistic_dad",
                        .data           =       &ipv6_devconf.optimistic_dad,
                        .maxlen         =       sizeof(int),
@@ -4279,7 +4348,6 @@ static struct addrconf_sysctl_table
 #endif
 #ifdef CONFIG_IPV6_MROUTE
                {
-                       .ctl_name       =       CTL_UNNUMBERED,
                        .procname       =       "mc_forwarding",
                        .data           =       &ipv6_devconf.mc_forwarding,
                        .maxlen         =       sizeof(int),
@@ -4288,16 +4356,13 @@ static struct addrconf_sysctl_table
                },
 #endif
                {
-                       .ctl_name       =       CTL_UNNUMBERED,
                        .procname       =       "disable_ipv6",
                        .data           =       &ipv6_devconf.disable_ipv6,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       addrconf_sysctl_disable,
-                       .strategy       =       sysctl_intvec,
                },
                {
-                       .ctl_name       =       CTL_UNNUMBERED,
                        .procname       =       "accept_dad",
                        .data           =       &ipv6_devconf.accept_dad,
                        .maxlen         =       sizeof(int),
@@ -4305,13 +4370,20 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       0,      /* sentinel */
+                       .procname       = "force_tllao",
+                       .data           = &ipv6_devconf.force_tllao,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec
+               },
+               {
+                       /* sentinel */
                }
        },
 };
 
 static int __addrconf_sysctl_register(struct net *net, char *dev_name,
-               int ctl_name, struct inet6_dev *idev, struct ipv6_devconf *p)
+               struct inet6_dev *idev, struct ipv6_devconf *p)
 {
        int i;
        struct addrconf_sysctl_table *t;
@@ -4319,9 +4391,9 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
 #define ADDRCONF_CTL_PATH_DEV  3
 
        struct ctl_path addrconf_ctl_path[] = {
-               { .procname = "net", .ctl_name = CTL_NET, },
-               { .procname = "ipv6", .ctl_name = NET_IPV6, },
-               { .procname = "conf", .ctl_name = NET_IPV6_CONF, },
+               { .procname = "net", },
+               { .procname = "ipv6", },
+               { .procname = "conf", },
                { /* to be set */ },
                { },
        };
@@ -4347,7 +4419,6 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
                goto free;
 
        addrconf_ctl_path[ADDRCONF_CTL_PATH_DEV].procname = t->dev_name;
-       addrconf_ctl_path[ADDRCONF_CTL_PATH_DEV].ctl_name = ctl_name;
 
        t->sysctl_header = register_net_sysctl_table(net, addrconf_ctl_path,
                        t->addrconf_vars);
@@ -4381,12 +4452,10 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
 
 static void addrconf_sysctl_register(struct inet6_dev *idev)
 {
-       neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6,
-                             NET_IPV6_NEIGH, "ipv6",
-                             &ndisc_ifinfo_sysctl_change,
-                             ndisc_ifinfo_sysctl_strategy);
+       neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6",
+                             &ndisc_ifinfo_sysctl_change);
        __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
-                       idev->dev->ifindex, idev, &idev->cnf);
+                                       idev, &idev->cnf);
 }
 
 static void addrconf_sysctl_unregister(struct inet6_dev *idev)
@@ -4398,7 +4467,7 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev)
 
 #endif
 
-static int addrconf_init_net(struct net *net)
+static int __net_init addrconf_init_net(struct net *net)
 {
        int err;
        struct ipv6_devconf *all, *dflt;
@@ -4407,7 +4476,7 @@ static int addrconf_init_net(struct net *net)
        all = &ipv6_devconf;
        dflt = &ipv6_devconf_dflt;
 
-       if (net != &init_net) {
+       if (!net_eq(net, &init_net)) {
                all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL);
                if (all == NULL)
                        goto err_alloc_all;
@@ -4425,13 +4494,11 @@ static int addrconf_init_net(struct net *net)
        net->ipv6.devconf_dflt = dflt;
 
 #ifdef CONFIG_SYSCTL
-       err = __addrconf_sysctl_register(net, "all", NET_PROTO_CONF_ALL,
-                       NULL, all);
+       err = __addrconf_sysctl_register(net, "all", NULL, all);
        if (err < 0)
                goto err_reg_all;
 
-       err = __addrconf_sysctl_register(net, "default", NET_PROTO_CONF_DEFAULT,
-                       NULL, dflt);
+       err = __addrconf_sysctl_register(net, "default", NULL, dflt);
        if (err < 0)
                goto err_reg_dflt;
 #endif
@@ -4449,13 +4516,13 @@ err_alloc_all:
        return err;
 }
 
-static void addrconf_exit_net(struct net *net)
+static void __net_exit addrconf_exit_net(struct net *net)
 {
 #ifdef CONFIG_SYSCTL
        __addrconf_sysctl_unregister(net->ipv6.devconf_dflt);
        __addrconf_sysctl_unregister(net->ipv6.devconf_all);
 #endif
-       if (net != &init_net) {
+       if (!net_eq(net, &init_net)) {
                kfree(net->ipv6.devconf_dflt);
                kfree(net->ipv6.devconf_all);
        }