tg3: tg3.h cleanups
[safe/jmp/linux-2.6] / drivers / net / veth.c
index 2c86a44..852d0e7 100644 (file)
@@ -8,14 +8,13 @@
  *
  */
 
-#include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
 
 #include <net/dst.h>
 #include <net/xfrm.h>
-#include <net/veth.h>
+#include <linux/veth.h>
 
 #define DRV_NAME       "veth"
 #define DRV_VERSION    "1.0"
@@ -30,14 +29,10 @@ struct veth_net_stats {
 
 struct veth_priv {
        struct net_device *peer;
-       struct net_device *dev;
-       struct list_head list;
        struct veth_net_stats *stats;
        unsigned ip_summed;
 };
 
-static LIST_HEAD(veth_list);
-
 /*
  * ethtool interface
  */
@@ -79,9 +74,14 @@ static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
        }
 }
 
-static int veth_get_stats_count(struct net_device *dev)
+static int veth_get_sset_count(struct net_device *dev, int sset)
 {
-       return ARRAY_SIZE(ethtool_stats_keys);
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(ethtool_stats_keys);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 static void veth_get_ethtool_stats(struct net_device *dev,
@@ -135,7 +135,7 @@ static struct ethtool_ops veth_ethtool_ops = {
        .get_sg                 = ethtool_op_get_sg,
        .set_sg                 = ethtool_op_set_sg,
        .get_strings            = veth_get_strings,
-       .get_stats_count        = veth_get_stats_count,
+       .get_sset_count         = veth_get_sset_count,
        .get_ethtool_stats      = veth_get_ethtool_stats,
 };
 
@@ -239,18 +239,6 @@ static int veth_open(struct net_device *dev)
        return 0;
 }
 
-static int veth_close(struct net_device *dev)
-{
-       struct veth_priv *priv;
-
-       if (netif_carrier_ok(dev)) {
-               priv = netdev_priv(dev);
-               netif_carrier_off(dev);
-               netif_carrier_off(priv->peer);
-       }
-       return 0;
-}
-
 static int veth_dev_init(struct net_device *dev)
 {
        struct veth_net_stats *stats;
@@ -274,20 +262,61 @@ static void veth_dev_free(struct net_device *dev)
        free_netdev(dev);
 }
 
+static const struct net_device_ops veth_netdev_ops = {
+       .ndo_init       = veth_dev_init,
+       .ndo_open       = veth_open,
+       .ndo_start_xmit = veth_xmit,
+       .ndo_get_stats  = veth_get_stats,
+};
+
 static void veth_setup(struct net_device *dev)
 {
        ether_setup(dev);
 
-       dev->hard_start_xmit = veth_xmit;
-       dev->get_stats = veth_get_stats;
-       dev->open = veth_open;
-       dev->stop = veth_close;
+       dev->netdev_ops = &veth_netdev_ops;
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
-       dev->init = veth_dev_init;
        dev->destructor = veth_dev_free;
 }
 
+static void veth_change_state(struct net_device *dev)
+{
+       struct net_device *peer;
+       struct veth_priv *priv;
+
+       priv = netdev_priv(dev);
+       peer = priv->peer;
+
+       if (netif_carrier_ok(peer)) {
+               if (!netif_carrier_ok(dev))
+                       netif_carrier_on(dev);
+       } else {
+               if (netif_carrier_ok(dev))
+                       netif_carrier_off(dev);
+       }
+}
+
+static int veth_device_event(struct notifier_block *unused,
+                            unsigned long event, void *ptr)
+{
+       struct net_device *dev = ptr;
+
+       if (dev->netdev_ops->ndo_open != veth_open)
+               goto out;
+
+       switch (event) {
+       case NETDEV_CHANGE:
+               veth_change_state(dev);
+               break;
+       }
+out:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block veth_notifier_block __read_mostly = {
+       .notifier_call  = veth_device_event,
+};
+
 /*
  * netlink interface
  */
@@ -345,7 +374,7 @@ static int veth_newlink(struct net_device *dev,
        else
                snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d");
 
-       peer = rtnl_create_link(dev->nd_net, ifname, &veth_link_ops, tbp);
+       peer = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp);
        if (IS_ERR(peer))
                return PTR_ERR(peer);
 
@@ -390,14 +419,10 @@ static int veth_newlink(struct net_device *dev,
         */
 
        priv = netdev_priv(dev);
-       priv->dev = dev;
        priv->peer = peer;
-       list_add(&priv->list, &veth_list);
 
        priv = netdev_priv(peer);
-       priv->dev = peer;
        priv->peer = dev;
-       INIT_LIST_HEAD(&priv->list);
        return 0;
 
 err_register_dev:
@@ -419,13 +444,6 @@ static void veth_dellink(struct net_device *dev)
        priv = netdev_priv(dev);
        peer = priv->peer;
 
-       if (!list_empty(&priv->list))
-               list_del(&priv->list);
-
-       priv = netdev_priv(peer);
-       if (!list_empty(&priv->list))
-               list_del(&priv->list);
-
        unregister_netdevice(dev);
        unregister_netdevice(peer);
 }
@@ -449,24 +467,14 @@ static struct rtnl_link_ops veth_link_ops = {
 
 static __init int veth_init(void)
 {
+       register_netdevice_notifier(&veth_notifier_block);
        return rtnl_link_register(&veth_link_ops);
 }
 
 static __exit void veth_exit(void)
 {
-       struct veth_priv *priv, *next;
-
-       rtnl_lock();
-       /*
-        * cannot trust __rtnl_link_unregister() to unregister all
-        * devices, as each ->dellink call will remove two devices
-        * from the list at once.
-        */
-       list_for_each_entry_safe(priv, next, &veth_list, list)
-               veth_dellink(priv->dev);
-
-       __rtnl_link_unregister(&veth_link_ops);
-       rtnl_unlock();
+       rtnl_link_unregister(&veth_link_ops);
+       unregister_netdevice_notifier(&veth_notifier_block);
 }
 
 module_init(veth_init);