mac80211: remove trivial rx_data->fc users
[safe/jmp/linux-2.6] / net / core / dev.c
index 9516105..7593393 100644 (file)
@@ -90,6 +90,7 @@
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 #include <linux/notifier.h>
 #include <linux/skbuff.h>
 #include <net/net_namespace.h>
 #include <linux/err.h>
 #include <linux/ctype.h>
 #include <linux/if_arp.h>
+#include <linux/if_vlan.h>
 
 #include "net-sysfs.h"
 
@@ -162,7 +164,7 @@ struct net_dma {
        struct dma_client client;
        spinlock_t lock;
        cpumask_t channel_mask;
-       struct dma_chan *channels[NR_CPUS];
+       struct dma_chan **channels;
 };
 
 static enum dma_state_client
@@ -216,7 +218,7 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
 /* Device list insertion */
 static int list_netdevice(struct net_device *dev)
 {
-       struct net *net = dev->nd_net;
+       struct net *net = dev_net(dev);
 
        ASSERT_RTNL();
 
@@ -453,7 +455,7 @@ static int netdev_boot_setup_add(char *name, struct ifmap *map)
        for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) {
                if (s[i].name[0] == '\0' || s[i].name[0] == ' ') {
                        memset(s[i].name, 0, sizeof(s[i].name));
-                       strcpy(s[i].name, name);
+                       strlcpy(s[i].name, name, IFNAMSIZ);
                        memcpy(&s[i].map, map, sizeof(s[i].map));
                        break;
                }
@@ -478,7 +480,7 @@ int netdev_boot_setup_check(struct net_device *dev)
 
        for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) {
                if (s[i].name[0] != '\0' && s[i].name[0] != ' ' &&
-                   !strncmp(dev->name, s[i].name, strlen(s[i].name))) {
+                   !strcmp(dev->name, s[i].name)) {
                        dev->irq        = s[i].map.irq;
                        dev->base_addr  = s[i].map.base_addr;
                        dev->mem_start  = s[i].map.mem_start;
@@ -852,8 +854,8 @@ int dev_alloc_name(struct net_device *dev, const char *name)
        struct net *net;
        int ret;
 
-       BUG_ON(!dev->nd_net);
-       net = dev->nd_net;
+       BUG_ON(!dev_net(dev));
+       net = dev_net(dev);
        ret = __dev_alloc_name(net, name, buf);
        if (ret >= 0)
                strlcpy(dev->name, buf, IFNAMSIZ);
@@ -877,9 +879,9 @@ int dev_change_name(struct net_device *dev, char *newname)
        struct net *net;
 
        ASSERT_RTNL();
-       BUG_ON(!dev->nd_net);
+       BUG_ON(!dev_net(dev));
 
-       net = dev->nd_net;
+       net = dev_net(dev);
        if (dev->flags & IFF_UP)
                return -EBUSY;
 
@@ -903,7 +905,11 @@ int dev_change_name(struct net_device *dev, char *newname)
                strlcpy(dev->name, newname, IFNAMSIZ);
 
 rollback:
-       device_rename(&dev->dev, dev->name);
+       err = device_rename(&dev->dev, dev->name);
+       if (err) {
+               memcpy(dev->name, oldname, IFNAMSIZ);
+               return err;
+       }
 
        write_lock_bh(&dev_base_lock);
        hlist_del(&dev->name_hlist);
@@ -956,6 +962,12 @@ void netdev_state_change(struct net_device *dev)
        }
 }
 
+void netdev_bonding_change(struct net_device *dev)
+{
+       call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, dev);
+}
+EXPORT_SYMBOL(netdev_bonding_change);
+
 /**
  *     dev_load        - load a network module
  *     @net: the applicable net namespace
@@ -994,6 +1006,8 @@ int dev_open(struct net_device *dev)
 {
        int ret = 0;
 
+       ASSERT_RTNL();
+
        /*
         *      Is it already up?
         */
@@ -1060,6 +1074,8 @@ int dev_open(struct net_device *dev)
  */
 int dev_close(struct net_device *dev)
 {
+       ASSERT_RTNL();
+
        might_sleep();
 
        if (!(dev->flags & IFF_UP))
@@ -1108,6 +1124,29 @@ int dev_close(struct net_device *dev)
 }
 
 
+/**
+ *     dev_disable_lro - disable Large Receive Offload on a device
+ *     @dev: device
+ *
+ *     Disable Large Receive Offload (LRO) on a net device.  Must be
+ *     called under RTNL.  This is needed if received packets may be
+ *     forwarded to another interface.
+ */
+void dev_disable_lro(struct net_device *dev)
+{
+       if (dev->ethtool_ops && dev->ethtool_ops->get_flags &&
+           dev->ethtool_ops->set_flags) {
+               u32 flags = dev->ethtool_ops->get_flags(dev);
+               if (flags & ETH_FLAG_LRO) {
+                       flags &= ~ETH_FLAG_LRO;
+                       dev->ethtool_ops->set_flags(dev, flags);
+               }
+       }
+       WARN_ON(dev->features & NETIF_F_LRO);
+}
+EXPORT_SYMBOL(dev_disable_lro);
+
+
 static int dev_boot_phase = 1;
 
 /*
@@ -1354,6 +1393,29 @@ void netif_device_attach(struct net_device *dev)
 }
 EXPORT_SYMBOL(netif_device_attach);
 
+static bool can_checksum_protocol(unsigned long features, __be16 protocol)
+{
+       return ((features & NETIF_F_GEN_CSUM) ||
+               ((features & NETIF_F_IP_CSUM) &&
+                protocol == htons(ETH_P_IP)) ||
+               ((features & NETIF_F_IPV6_CSUM) &&
+                protocol == htons(ETH_P_IPV6)));
+}
+
+static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
+{
+       if (can_checksum_protocol(dev->features, skb->protocol))
+               return true;
+
+       if (skb->protocol == htons(ETH_P_8021Q)) {
+               struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
+               if (can_checksum_protocol(dev->features & dev->vlan_features,
+                                         veh->h_vlan_encapsulated_proto))
+                       return true;
+       }
+
+       return false;
+}
 
 /*
  * Invalidate hardware checksum when packet is to be mangled, and
@@ -1524,7 +1586,7 @@ static int dev_gso_segment(struct sk_buff *skb)
        if (!segs)
                return 0;
 
-       if (unlikely(IS_ERR(segs)))
+       if (IS_ERR(segs))
                return PTR_ERR(segs);
 
        skb->next = segs;
@@ -1632,14 +1694,8 @@ int dev_queue_xmit(struct sk_buff *skb)
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                skb_set_transport_header(skb, skb->csum_start -
                                              skb_headroom(skb));
-
-               if (!(dev->features & NETIF_F_GEN_CSUM) &&
-                   !((dev->features & NETIF_F_IP_CSUM) &&
-                     skb->protocol == htons(ETH_P_IP)) &&
-                   !((dev->features & NETIF_F_IPV6_CSUM) &&
-                     skb->protocol == htons(ETH_P_IPV6)))
-                       if (skb_checksum_help(skb))
-                               goto out_kfree_skb;
+               if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb))
+                       goto out_kfree_skb;
        }
 
 gso:
@@ -2051,6 +2107,10 @@ int netif_receive_skb(struct sk_buff *skb)
 
        rcu_read_lock();
 
+       /* Don't receive packets in an exiting network namespace */
+       if (!net_alive(dev_net(skb->dev)))
+               goto out;
+
 #ifdef CONFIG_NET_CLS_ACT
        if (skb->tc_verd & TC_NCLS) {
                skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
@@ -2143,7 +2203,7 @@ static int process_backlog(struct napi_struct *napi, int quota)
  *
  * The entry's receive function will be scheduled to run
  */
-void fastcall __napi_schedule(struct napi_struct *n)
+void __napi_schedule(struct napi_struct *n)
 {
        unsigned long flags;
 
@@ -2444,7 +2504,7 @@ static struct netif_rx_stats *softnet_get_online(loff_t *pos)
 {
        struct netif_rx_stats *rc = NULL;
 
-       while (*pos < NR_CPUS)
+       while (*pos < nr_cpu_ids)
                if (cpu_online(*pos)) {
                        rc = &per_cpu(netdev_rx_stat, *pos);
                        break;
@@ -2615,7 +2675,7 @@ static int ptype_seq_show(struct seq_file *seq, void *v)
 
        if (v == SEQ_START_TOKEN)
                seq_puts(seq, "Type Device      Function\n");
-       else {
+       else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
                if (pt->type == htons(ETH_P_ALL))
                        seq_puts(seq, "ALL ");
                else
@@ -2639,7 +2699,8 @@ static const struct seq_operations ptype_seq_ops = {
 
 static int ptype_seq_open(struct inode *inode, struct file *file)
 {
-       return seq_open(file, &ptype_seq_ops);
+       return seq_open_net(inode, file, &ptype_seq_ops,
+                       sizeof(struct seq_net_private));
 }
 
 static const struct file_operations ptype_seq_fops = {
@@ -2647,7 +2708,7 @@ static const struct file_operations ptype_seq_fops = {
        .open    = ptype_seq_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
-       .release = seq_release,
+       .release = seq_release_net,
 };
 
 
@@ -2738,16 +2799,29 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
        return 0;
 }
 
-static void __dev_set_promiscuity(struct net_device *dev, int inc)
+static int __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
-               dev->flags |= IFF_PROMISC;
+       dev->flags |= IFF_PROMISC;
+       dev->promiscuity += inc;
+       if (dev->promiscuity == 0) {
+               /*
+                * Avoid overflow.
+                * If inc causes overflow, untouch promisc and return error.
+                */
+               if (inc < 0)
+                       dev->flags &= ~IFF_PROMISC;
+               else {
+                       dev->promiscuity -= inc;
+                       printk(KERN_WARNING "%s: promiscuity touches roof, "
+                               "set promiscuity failed, promiscuity feature "
+                               "of device might be broken.\n", dev->name);
+                       return -EOVERFLOW;
+               }
+       }
        if (dev->flags != old_flags) {
                printk(KERN_INFO "device %s %s promiscuous mode\n",
                       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
@@ -2765,6 +2839,7 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc)
                if (dev->change_rx_flags)
                        dev->change_rx_flags(dev, IFF_PROMISC);
        }
+       return 0;
 }
 
 /**
@@ -2776,14 +2851,19 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc)
  *     remains above zero the interface remains promiscuous. Once it hits zero
  *     the device reverts back to normal filtering operation. A negative inc
  *     value is used to drop promiscuity on the device.
+ *     Return 0 if successful or a negative errno code on error.
  */
-void dev_set_promiscuity(struct net_device *dev, int inc)
+int dev_set_promiscuity(struct net_device *dev, int inc)
 {
        unsigned short old_flags = dev->flags;
+       int err;
 
-       __dev_set_promiscuity(dev, inc);
+       err = __dev_set_promiscuity(dev, inc);
+       if (err < 0)
+               return err;
        if (dev->flags != old_flags)
                dev_set_rx_mode(dev);
+       return err;
 }
 
 /**
@@ -2796,22 +2876,38 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
  *     to all interfaces. Once it hits zero the device reverts back to normal
  *     filtering operation. A negative @inc value is used to drop the counter
  *     when releasing a resource needing all multicasts.
+ *     Return 0 if successful or a negative errno code on error.
  */
 
-void dev_set_allmulti(struct net_device *dev, int inc)
+int 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;
+       dev->allmulti += inc;
+       if (dev->allmulti == 0) {
+               /*
+                * Avoid overflow.
+                * If inc causes overflow, untouch allmulti and return error.
+                */
+               if (inc < 0)
+                       dev->flags &= ~IFF_ALLMULTI;
+               else {
+                       dev->allmulti -= inc;
+                       printk(KERN_WARNING "%s: allmulti touches roof, "
+                               "set allmulti failed, allmulti feature of "
+                               "device might be broken.\n", dev->name);
+                       return -EOVERFLOW;
+               }
+       }
        if (dev->flags ^ old_flags) {
                if (dev->change_rx_flags)
                        dev->change_rx_flags(dev, IFF_ALLMULTI);
                dev_set_rx_mode(dev);
        }
+       return 0;
 }
 
 /*
@@ -2942,7 +3038,7 @@ EXPORT_SYMBOL(dev_unicast_delete);
 /**
  *     dev_unicast_add         - add a secondary unicast address
  *     @dev: device
- *     @addr: address to delete
+ *     @addr: address to add
  *     @alen: length of @addr
  *
  *     Add a secondary unicast address to the device or increase
@@ -3038,8 +3134,7 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from)
 EXPORT_SYMBOL(dev_unicast_sync);
 
 /**
- *     dev_unicast_unsync - Remove synchronized addresses from the destination
- *                          device
+ *     dev_unicast_unsync - Remove synchronized addresses from the destination device
  *     @to: destination device
  *     @from: source device
  *
@@ -3133,7 +3228,7 @@ 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)
+       if (dev->change_rx_flags && (old_flags ^ flags) & IFF_MULTICAST)
                dev->change_rx_flags(dev, IFF_MULTICAST);
 
        dev_set_rx_mode(dev);
@@ -3330,7 +3425,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        return -EOPNOTSUPP;
 
                case SIOCADDMULTI:
-                       if (!dev->set_multicast_list ||
+                       if ((!dev->set_multicast_list && !dev->set_rx_mode) ||
                            ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
                                return -EINVAL;
                        if (!netif_device_present(dev))
@@ -3339,7 +3434,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                                          dev->addr_len, 1);
 
                case SIOCDELMULTI:
-                       if (!dev->set_multicast_list ||
+                       if ((!dev->set_multicast_list && !dev->set_rx_mode) ||
                            ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
                                return -EINVAL;
                        if (!netif_device_present(dev))
@@ -3689,8 +3784,8 @@ int register_netdevice(struct net_device *dev)
 
        /* When net_device's are persistent, this will be fatal. */
        BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
-       BUG_ON(!dev->nd_net);
-       net = dev->nd_net;
+       BUG_ON(!dev_net(dev));
+       net = dev_net(dev);
 
        spin_lock_init(&dev->queue_lock);
        spin_lock_init(&dev->_xmit_lock);
@@ -3776,6 +3871,7 @@ int register_netdevice(struct net_device *dev)
                }
        }
 
+       netdev_initialize_kobject(dev);
        ret = netdev_register_kobject(dev);
        if (ret)
                goto err_uninit;
@@ -3996,11 +4092,15 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 
        BUG_ON(strlen(name) >= sizeof(dev->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 - 1))) &
-                    ~NETDEV_ALIGN_CONST;
-       alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
+       alloc_size = sizeof(struct net_device) +
+                    sizeof(struct net_device_subqueue) * (queue_count - 1);
+       if (sizeof_priv) {
+               /* ensure 32-byte alignment of private area */
+               alloc_size = (alloc_size + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
+               alloc_size += sizeof_priv;
+       }
+       /* ensure 32-byte alignment of whole construct */
+       alloc_size += NETDEV_ALIGN_CONST;
 
        p = kzalloc(alloc_size, GFP_KERNEL);
        if (!p) {
@@ -4011,7 +4111,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        dev = (struct net_device *)
                (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
        dev->padded = (char *)dev - (char *)p;
-       dev->nd_net = &init_net;
+       dev_net_set(dev, &init_net);
 
        if (sizeof_priv) {
                dev->priv = ((char *)dev +
@@ -4022,6 +4122,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        }
 
        dev->egress_subqueue_count = queue_count;
+       dev->gso_max_size = GSO_MAX_SIZE;
 
        dev->get_stats = internal_stats;
        netpoll_netdev_init(dev);
@@ -4041,6 +4142,8 @@ EXPORT_SYMBOL(alloc_netdev_mq);
  */
 void free_netdev(struct net_device *dev)
 {
+       release_net(dev_net(dev));
+
        /*  Compatibility with error handling in drivers */
        if (dev->reg_state == NETREG_UNINITIALIZED) {
                kfree((char *)dev - dev->padded);
@@ -4135,7 +4238,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 
        /* Get out if there is nothing todo */
        err = 0;
-       if (dev->nd_net == net)
+       if (net_eq(dev_net(dev), net))
                goto out;
 
        /* Pick the destination device name, and ensure
@@ -4186,7 +4289,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
        dev_addr_discard(dev);
 
        /* Actually switch the network namespace */
-       dev->nd_net = net;
+       dev_net_set(dev, net);
 
        /* Assign the new device name */
        if (destname != dev->name)
@@ -4201,7 +4304,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
        }
 
        /* Fixup kobjects */
-       err = device_rename(&dev->dev, dev->name);
+       netdev_unregister_kobject(dev);
+       err = netdev_register_kobject(dev);
        WARN_ON(err);
 
        /* Add the device back in the hashes */
@@ -4317,7 +4421,7 @@ netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
        spin_lock(&net_dma->lock);
        switch (state) {
        case DMA_RESOURCE_AVAILABLE:
-               for (i = 0; i < NR_CPUS; i++)
+               for (i = 0; i < nr_cpu_ids; i++)
                        if (net_dma->channels[i] == chan) {
                                found = 1;
                                break;
@@ -4332,7 +4436,7 @@ netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
                }
                break;
        case DMA_RESOURCE_REMOVED:
-               for (i = 0; i < NR_CPUS; i++)
+               for (i = 0; i < nr_cpu_ids; i++)
                        if (net_dma->channels[i] == chan) {
                                found = 1;
                                pos = i;
@@ -4359,6 +4463,13 @@ netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
  */
 static int __init netdev_dma_register(void)
 {
+       net_dma.channels = kzalloc(nr_cpu_ids * sizeof(struct net_dma),
+                                                               GFP_KERNEL);
+       if (unlikely(!net_dma.channels)) {
+               printk(KERN_NOTICE
+                               "netdev_dma: no memory for net_dma.channels\n");
+               return -ENOMEM;
+       }
        spin_lock_init(&net_dma.lock);
        dma_cap_set(DMA_MEMCPY, net_dma.client.cap_mask);
        dma_async_client_register(&net_dma.client);
@@ -4464,17 +4575,19 @@ static void __net_exit default_device_exit(struct net *net)
        rtnl_lock();
        for_each_netdev_safe(net, dev, next) {
                int err;
+               char fb_name[IFNAMSIZ];
 
                /* Ignore unmoveable devices (i.e. loopback) */
                if (dev->features & NETIF_F_NETNS_LOCAL)
                        continue;
 
                /* Push remaing network devices to init_net */
-               err = dev_change_net_namespace(dev, &init_net, "dev%d");
+               snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex);
+               err = dev_change_net_namespace(dev, &init_net, fb_name);
                if (err) {
-                       printk(KERN_WARNING "%s: failed to move %s to init_net: %d\n",
+                       printk(KERN_EMERG "%s: failed to move %s to init_net: %d\n",
                                __func__, dev->name, err);
-                       unregister_netdevice(dev);
+                       BUG();
                }
        }
        rtnl_unlock();