]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/macvlan.c
Merge branch 'slub-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/christoph/vm
[linux-2.6-omap-h63xx.git] / drivers / net / macvlan.c
index b7c81c874f7a0a15e4bd65281aa9ceeb1e83b0cf..f651a816b280bfcb04d1d6fdda8d12e2819b4ce5 100644 (file)
@@ -73,8 +73,6 @@ static void macvlan_broadcast(struct sk_buff *skb,
        for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
                hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
                        dev = vlan->dev;
-                       if (unlikely(!(dev->flags & IFF_UP)))
-                               continue;
 
                        nskb = skb_clone(skb, GFP_ATOMIC);
                        if (nskb == NULL) {
@@ -178,7 +176,6 @@ static const struct header_ops macvlan_hard_header_ops = {
        .create         = macvlan_hard_header,
        .rebuild        = eth_rebuild_header,
        .parse          = eth_header_parse,
-       .rebuild        = eth_rebuild_header,
        .cache          = eth_header_cache,
        .cache_update   = eth_header_cache_update,
 };
@@ -216,6 +213,29 @@ static int macvlan_stop(struct net_device *dev)
        return 0;
 }
 
+static int macvlan_set_mac_address(struct net_device *dev, void *p)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       struct sockaddr *addr = p;
+       int err;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       if (!(dev->flags & IFF_UP))
+               goto out;
+
+       err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN);
+       if (err < 0)
+               return err;
+       dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+
+out:
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+       return 0;
+}
+
 static void macvlan_change_rx_flags(struct net_device *dev, int change)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
@@ -303,6 +323,7 @@ static void macvlan_setup(struct net_device *dev)
        dev->stop               = macvlan_stop;
        dev->change_mtu         = macvlan_change_mtu;
        dev->change_rx_flags    = macvlan_change_rx_flags;
+       dev->set_mac_address    = macvlan_set_mac_address;
        dev->set_multicast_list = macvlan_set_multicast_list;
        dev->hard_start_xmit    = macvlan_hard_start_xmit;
        dev->destructor         = free_netdev;
@@ -354,7 +375,7 @@ static void macvlan_transfer_operstate(struct net_device *dev)
                if (!netif_carrier_ok(dev))
                        netif_carrier_on(dev);
        } else {
-               if (netif_carrier_ok(lowerdev))
+               if (netif_carrier_ok(dev))
                        netif_carrier_off(dev);
        }
 }
@@ -385,6 +406,13 @@ static int macvlan_newlink(struct net_device *dev,
        if (lowerdev == NULL)
                return -ENODEV;
 
+       /* Don't allow macvlans on top of other macvlans - its not really
+        * wrong, but lockdep can't handle it and its not useful for anything
+        * you couldn't do directly on top of the real device.
+        */
+       if (lowerdev->rtnl_link_ops == dev->rtnl_link_ops)
+               return -ENODEV;
+
        if (!tb[IFLA_MTU])
                dev->mtu = lowerdev->mtu;
        else if (dev->mtu > lowerdev->mtu)
@@ -480,7 +508,7 @@ static int __init macvlan_init_module(void)
                goto err1;
        return 0;
 err1:
-       macvlan_handle_frame_hook = macvlan_handle_frame;
+       macvlan_handle_frame_hook = NULL;
        unregister_netdevice_notifier(&macvlan_notifier_block);
        return err;
 }