]> err.no Git - linux-2.6/blobdiff - net/core/dev.c
Pull bugzilla-7880 into release branch
[linux-2.6] / net / core / dev.c
index 96443055324ea9116c35374b7b1e8d6cee54f906..ee4035571c21b55e119bbf4c6c2f6f1a4ee085ab 100644 (file)
@@ -98,6 +98,7 @@
 #include <linux/seq_file.h>
 #include <linux/stat.h>
 #include <linux/if_bridge.h>
+#include <linux/if_macvlan.h>
 #include <net/dst.h>
 #include <net/pkt_sched.h>
 #include <net/checksum.h>
@@ -1813,6 +1814,28 @@ static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
 #define handle_bridge(skb, pt_prev, ret, orig_dev)     (skb)
 #endif
 
+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
+struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *skb) __read_mostly;
+EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook);
+
+static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
+                                            struct packet_type **pt_prev,
+                                            int *ret,
+                                            struct net_device *orig_dev)
+{
+       if (skb->dev->macvlan_port == NULL)
+               return skb;
+
+       if (*pt_prev) {
+               *ret = deliver_skb(skb, *pt_prev, orig_dev);
+               *pt_prev = NULL;
+       }
+       return macvlan_handle_frame_hook(skb);
+}
+#else
+#define handle_macvlan(skb, pt_prev, ret, orig_dev)    (skb)
+#endif
+
 #ifdef CONFIG_NET_CLS_ACT
 /* TODO: Maybe we should just force sch_ingress to be compiled in
  * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
@@ -1918,6 +1941,9 @@ ncls:
 #endif
 
        skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
+       if (!skb)
+               goto out;
+       skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
        if (!skb)
                goto out;
 
@@ -2521,6 +2547,8 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc)
 {
        unsigned short old_flags = dev->flags;
 
+       ASSERT_RTNL();
+
        if ((dev->promiscuity += inc) == 0)
                dev->flags &= ~IFF_PROMISC;
        else
@@ -2535,6 +2563,9 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc)
                        dev->name, (dev->flags & IFF_PROMISC),
                        (old_flags & IFF_PROMISC),
                        audit_get_loginuid(current->audit_context));
+
+               if (dev->change_rx_flags)
+                       dev->change_rx_flags(dev, IFF_PROMISC);
        }
 }
 
@@ -2573,11 +2604,16 @@ void dev_set_allmulti(struct net_device *dev, int inc)
 {
        unsigned short old_flags = dev->flags;
 
+       ASSERT_RTNL();
+
        dev->flags |= IFF_ALLMULTI;
        if ((dev->allmulti += inc) == 0)
                dev->flags &= ~IFF_ALLMULTI;
-       if (dev->flags ^ old_flags)
+       if (dev->flags ^ old_flags) {
+               if (dev->change_rx_flags)
+                       dev->change_rx_flags(dev, IFF_ALLMULTI);
                dev_set_rx_mode(dev);
+       }
 }
 
 /*
@@ -2593,7 +2629,7 @@ void __dev_set_rx_mode(struct net_device *dev)
                return;
 
        if (!netif_device_present(dev))
-               return;
+               return;
 
        if (dev->set_rx_mode)
                dev->set_rx_mode(dev);
@@ -2679,20 +2715,6 @@ int __dev_addr_add(struct dev_addr_list **list, int *count,
        return 0;
 }
 
-void __dev_addr_discard(struct dev_addr_list **list)
-{
-       struct dev_addr_list *tmp;
-
-       while (*list != NULL) {
-               tmp = *list;
-               *list = tmp->next;
-               if (tmp->da_users > tmp->da_gusers)
-                       printk("__dev_addr_discard: address leakage! "
-                              "da_users=%d\n", tmp->da_users);
-               kfree(tmp);
-       }
-}
-
 /**
  *     dev_unicast_delete      - Release secondary unicast address.
  *     @dev: device
@@ -2741,11 +2763,30 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen)
 }
 EXPORT_SYMBOL(dev_unicast_add);
 
-static void dev_unicast_discard(struct net_device *dev)
+static void __dev_addr_discard(struct dev_addr_list **list)
+{
+       struct dev_addr_list *tmp;
+
+       while (*list != NULL) {
+               tmp = *list;
+               *list = tmp->next;
+               if (tmp->da_users > tmp->da_gusers)
+                       printk("__dev_addr_discard: address leakage! "
+                              "da_users=%d\n", tmp->da_users);
+               kfree(tmp);
+       }
+}
+
+static void dev_addr_discard(struct net_device *dev)
 {
        netif_tx_lock_bh(dev);
+
        __dev_addr_discard(&dev->uc_list);
        dev->uc_count = 0;
+
+       __dev_addr_discard(&dev->mc_list);
+       dev->mc_count = 0;
+
        netif_tx_unlock_bh(dev);
 }
 
@@ -2778,6 +2819,8 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
        int ret, changes;
        int old_flags = dev->flags;
 
+       ASSERT_RTNL();
+
        /*
         *      Set the flags on our device.
         */
@@ -2792,6 +2835,9 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
         *      Load in the correct multicast list now the flags have changed.
         */
 
+       if (dev->change_rx_flags && (dev->flags ^ flags) & IFF_MULTICAST)
+               dev->change_rx_flags(dev, IFF_MULTICAST);
+
        dev_set_rx_mode(dev);
 
        /*
@@ -3578,7 +3624,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 
        /* ensure 32-byte alignment of both the device and private area */
        alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST +
-                    (sizeof(struct net_device_subqueue) * queue_count)) &
+                    (sizeof(struct net_device_subqueue) * (queue_count - 1))) &
                     ~NETDEV_ALIGN_CONST;
        alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
 
@@ -3596,7 +3642,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
                dev->priv = ((char *)dev +
                             ((sizeof(struct net_device) +
                               (sizeof(struct net_device_subqueue) *
-                               queue_count) + NETDEV_ALIGN_CONST)
+                               (queue_count - 1)) + NETDEV_ALIGN_CONST)
                              & ~NETDEV_ALIGN_CONST));
        }
 
@@ -3698,8 +3744,7 @@ void unregister_netdevice(struct net_device *dev)
        /*
         *      Flush the unicast and multicast chains
         */
-       dev_unicast_discard(dev);
-       dev_mc_discard(dev);
+       dev_addr_discard(dev);
 
        if (dev->uninit)
                dev->uninit(dev);