Linux 3.2.102
[pandora-kernel.git] / net / bridge / br_if.c
index e738154..56693c3 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/netpoll.h>
 #include <linux/ethtool.h>
 #include <linux/if_arp.h>
  */
 static int port_cost(struct net_device *dev)
 {
-       if (dev->ethtool_ops && dev->ethtool_ops->get_settings) {
-               struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, };
-
-               if (!dev_ethtool_get_settings(dev, &ecmd)) {
-                       switch (ethtool_cmd_speed(&ecmd)) {
-                       case SPEED_10000:
-                               return 2;
-                       case SPEED_1000:
-                               return 4;
-                       case SPEED_100:
-                               return 19;
-                       case SPEED_10:
-                               return 100;
-                       }
+       struct ethtool_cmd ecmd;
+
+       if (!__ethtool_get_settings(dev, &ecmd)) {
+               switch (ethtool_cmd_speed(&ecmd)) {
+               case SPEED_10000:
+                       return 2;
+               case SPEED_1000:
+                       return 4;
+               case SPEED_100:
+                       return 19;
+               case SPEED_10:
+                       return 100;
                }
        }
 
@@ -161,15 +160,18 @@ static void del_nbp(struct net_bridge_port *p)
        call_rcu(&p->rcu, destroy_nbp_rcu);
 }
 
-/* called with RTNL */
-static void del_br(struct net_bridge *br, struct list_head *head)
+/* Delete bridge device */
+void br_dev_delete(struct net_device *dev, struct list_head *head)
 {
+       struct net_bridge *br = netdev_priv(dev);
        struct net_bridge_port *p, *n;
 
        list_for_each_entry_safe(p, n, &br->port_list, list) {
                del_nbp(p);
        }
 
+       br_fdb_delete_by_port(br, NULL, 1);
+
        del_timer_sync(&br->gc_timer);
 
        br_sysfs_delbr(br->dev);
@@ -240,6 +242,7 @@ int br_add_bridge(struct net *net, const char *name)
                return -ENOMEM;
 
        dev_net_set(dev, net);
+       dev->rtnl_link_ops = &br_link_ops;
 
        res = register_netdev(dev);
        if (res)
@@ -268,7 +271,7 @@ int br_del_bridge(struct net *net, const char *name)
        }
 
        else
-               del_br(netdev_priv(dev), NULL);
+               br_dev_delete(dev, NULL);
 
        rtnl_unlock();
        return ret;
@@ -324,7 +327,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
        /* Don't allow bridging non-ethernet like devices */
        if ((dev->flags & IFF_LOOPBACK) ||
-           dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN)
+           dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN ||
+           !is_valid_ether_addr(dev->dev_addr))
                return -EINVAL;
 
        /* No bridging of bridges */
@@ -351,10 +355,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
        err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
                                   SYSFS_BRIDGE_PORT_ATTR);
-       if (err)
-               goto err0;
-
-       err = br_fdb_insert(br, p, dev->dev_addr);
        if (err)
                goto err1;
 
@@ -396,6 +396,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
        dev_set_mtu(br->dev, br_min_mtu(br));
 
+       if (br_fdb_insert(br, p, dev->dev_addr))
+               netdev_err(dev, "failed insert local address bridge forwarding table\n");
+
        kobject_uevent(&p->kobj, KOBJ_ADD);
 
        return 0;
@@ -405,11 +408,9 @@ err4:
 err3:
        sysfs_remove_link(br->ifobj, p->dev->name);
 err2:
-       br_fdb_delete_by_port(br, p, 1);
-err1:
        kobject_put(&p->kobj);
        p = NULL; /* kobject_put frees */
-err0:
+err1:
        dev_set_promiscuity(dev, -1);
 put_back:
        dev_put(dev);
@@ -449,7 +450,7 @@ void __net_exit br_net_exit(struct net *net)
        rtnl_lock();
        for_each_netdev(net, dev)
                if (dev->priv_flags & IFF_EBRIDGE)
-                       del_br(netdev_priv(dev), &list);
+                       br_dev_delete(dev, &list);
 
        unregister_netdevice_many(&list);
        rtnl_unlock();