]> git.ipfire.org Git - people/ms/linux.git/commitdiff
[IPV4/IPV6]: Fix inet{,6} device initialization order.
authorDavid L Stevens <dlstevens@us.ibm.com>
Sat, 6 Jan 2007 00:06:28 +0000 (01:06 +0100)
committerAdrian Bunk <bunk@stusta.de>
Tue, 9 Jan 2007 02:23:31 +0000 (03:23 +0100)
It is important that we only assign dev->ip{,6}_ptr
only after all portions of the inet{,6} are setup.

Otherwise we can receive packets before the multicast
spinlocks et al. are initialized.

Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
net/ipv4/devinet.c
net/ipv6/addrconf.c

index 3ffa60dadc0c6b7360ce91c2b58404785d6d1be3..73a62007e36e9add5868a5c19b9f6105a9135ba7 100644 (file)
@@ -158,9 +158,8 @@ struct in_device *inetdev_init(struct net_device *dev)
                              NET_IPV4_NEIGH, "ipv4", NULL, NULL);
 #endif
 
-       /* Account for reference dev->ip_ptr */
+       /* Account for reference dev->ip_ptr (below) */
        in_dev_hold(in_dev);
-       rcu_assign_pointer(dev->ip_ptr, in_dev);
 
 #ifdef CONFIG_SYSCTL
        devinet_sysctl_register(in_dev, &in_dev->cnf);
@@ -169,6 +168,8 @@ struct in_device *inetdev_init(struct net_device *dev)
        if (dev->flags & IFF_UP)
                ip_mc_up(in_dev);
 out:
+       /* we can receive as soon as ip_ptr is set -- do this last */
+       rcu_assign_pointer(dev->ip_ptr, in_dev);
        return in_dev;
 out_kfree:
        kfree(in_dev);
index 77da3a81cc034d59c84379ff9adff251623f2a39..c5005b23ec051578ee50647a2df96009517245ba 100644 (file)
@@ -393,10 +393,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
                if (netif_carrier_ok(dev))
                        ndev->if_flags |= IF_READY;
 
-               write_lock_bh(&addrconf_lock);
-               dev->ip6_ptr = ndev;
-               write_unlock_bh(&addrconf_lock);
-
                ipv6_mc_init_dev(ndev);
                ndev->tstamp = jiffies;
 #ifdef CONFIG_SYSCTL
@@ -406,6 +402,10 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
                                      NULL);
                addrconf_sysctl_register(ndev, &ndev->cnf);
 #endif
+               write_lock_bh(&addrconf_lock);
+               dev->ip6_ptr = ndev;
+               write_unlock_bh(&addrconf_lock);
+
        }
        return ndev;
 }