net: arp_ioctl() must hold RTNL
[pandora-kernel.git] / net / core / dev.c
index a215269..1e5077d 100644 (file)
@@ -749,7 +749,8 @@ EXPORT_SYMBOL(dev_get_by_index);
  *     @ha: hardware address
  *
  *     Search for an interface by MAC address. Returns NULL if the device
- *     is not found or a pointer to the device. The caller must hold RCU
+ *     is not found or a pointer to the device.
+ *     The caller must hold RCU or RTNL.
  *     The returned device has not had its ref count increased
  *     and the caller must therefore be careful about locking
  *
@@ -1732,33 +1733,6 @@ 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_NO_CSUM) ||
-               ((features & NETIF_F_V4_CSUM) &&
-                protocol == htons(ETH_P_IP)) ||
-               ((features & NETIF_F_V6_CSUM) &&
-                protocol == htons(ETH_P_IPV6)) ||
-               ((features & NETIF_F_FCOE_CRC) &&
-                protocol == htons(ETH_P_FCOE)));
-}
-
-static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
-{
-       __be16 protocol = skb->protocol;
-       int features = dev->features;
-
-       if (vlan_tx_tag_present(skb)) {
-               features &= dev->vlan_features;
-       } else if (protocol == htons(ETH_P_8021Q)) {
-               struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
-               protocol = veh->h_vlan_encapsulated_proto;
-               features &= dev->vlan_features;
-       }
-
-       return can_checksum_protocol(features, protocol);
-}
-
 /**
  * skb_dev_set -- assign a new device to a buffer
  * @skb: buffer for the new device
@@ -1971,16 +1945,14 @@ static void dev_gso_skb_destructor(struct sk_buff *skb)
 /**
  *     dev_gso_segment - Perform emulated hardware segmentation on skb.
  *     @skb: buffer to segment
+ *     @features: device features as applicable to this skb
  *
  *     This function segments the given skb and stores the list of segments
  *     in skb->next.
  */
-static int dev_gso_segment(struct sk_buff *skb)
+static int dev_gso_segment(struct sk_buff *skb, int features)
 {
-       struct net_device *dev = skb->dev;
        struct sk_buff *segs;
-       int features = dev->features & ~(illegal_highdma(dev, skb) ?
-                                        NETIF_F_SG : 0);
 
        segs = skb_gso_segment(skb, features);
 
@@ -2017,22 +1989,52 @@ static inline void skb_orphan_try(struct sk_buff *skb)
        }
 }
 
-int netif_get_vlan_features(struct sk_buff *skb, struct net_device *dev)
+static bool can_checksum_protocol(unsigned long features, __be16 protocol)
+{
+       return ((features & NETIF_F_GEN_CSUM) ||
+               ((features & NETIF_F_V4_CSUM) &&
+                protocol == htons(ETH_P_IP)) ||
+               ((features & NETIF_F_V6_CSUM) &&
+                protocol == htons(ETH_P_IPV6)) ||
+               ((features & NETIF_F_FCOE_CRC) &&
+                protocol == htons(ETH_P_FCOE)));
+}
+
+static int harmonize_features(struct sk_buff *skb, __be16 protocol, int features)
+{
+       if (!can_checksum_protocol(features, protocol)) {
+               features &= ~NETIF_F_ALL_CSUM;
+               features &= ~NETIF_F_SG;
+       } else if (illegal_highdma(skb->dev, skb)) {
+               features &= ~NETIF_F_SG;
+       }
+
+       return features;
+}
+
+int netif_skb_features(struct sk_buff *skb)
 {
        __be16 protocol = skb->protocol;
+       int features = skb->dev->features;
 
        if (protocol == htons(ETH_P_8021Q)) {
                struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
                protocol = veh->h_vlan_encapsulated_proto;
-       } else if (!skb->vlan_tci)
-               return dev->features;
+       } else if (!vlan_tx_tag_present(skb)) {
+               return harmonize_features(skb, protocol, features);
+       }
 
-       if (protocol != htons(ETH_P_8021Q))
-               return dev->features & dev->vlan_features;
-       else
-               return 0;
+       features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_TX);
+
+       if (protocol != htons(ETH_P_8021Q)) {
+               return harmonize_features(skb, protocol, features);
+       } else {
+               features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
+                               NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_TX;
+               return harmonize_features(skb, protocol, features);
+       }
 }
-EXPORT_SYMBOL(netif_get_vlan_features);
+EXPORT_SYMBOL(netif_skb_features);
 
 /*
  * Returns true if either:
@@ -2042,22 +2044,13 @@ EXPORT_SYMBOL(netif_get_vlan_features);
  *        support DMA from it.
  */
 static inline int skb_needs_linearize(struct sk_buff *skb,
-                                     struct net_device *dev)
+                                     int features)
 {
-       if (skb_is_nonlinear(skb)) {
-               int features = dev->features;
-
-               if (vlan_tx_tag_present(skb))
-                       features &= dev->vlan_features;
-
-               return (skb_has_frag_list(skb) &&
-                       !(features & NETIF_F_FRAGLIST)) ||
+       return skb_is_nonlinear(skb) &&
+                       ((skb_has_frag_list(skb) &&
+                               !(features & NETIF_F_FRAGLIST)) ||
                        (skb_shinfo(skb)->nr_frags &&
-                       (!(features & NETIF_F_SG) ||
-                       illegal_highdma(dev, skb)));
-       }
-
-       return 0;
+                               !(features & NETIF_F_SG)));
 }
 
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
@@ -2067,6 +2060,8 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
        int rc = NETDEV_TX_OK;
 
        if (likely(!skb->next)) {
+               int features;
+
                /*
                 * If device doesnt need skb->dst, release it right now while
                 * its hot in this cpu cache
@@ -2079,8 +2074,10 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 
                skb_orphan_try(skb);
 
+               features = netif_skb_features(skb);
+
                if (vlan_tx_tag_present(skb) &&
-                   !(dev->features & NETIF_F_HW_VLAN_TX)) {
+                   !(features & NETIF_F_HW_VLAN_TX)) {
                        skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
                        if (unlikely(!skb))
                                goto out;
@@ -2088,13 +2085,13 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        skb->vlan_tci = 0;
                }
 
-               if (netif_needs_gso(dev, skb)) {
-                       if (unlikely(dev_gso_segment(skb)))
+               if (netif_needs_gso(skb, features)) {
+                       if (unlikely(dev_gso_segment(skb, features)))
                                goto out_kfree_skb;
                        if (skb->next)
                                goto gso;
                } else {
-                       if (skb_needs_linearize(skb, dev) &&
+                       if (skb_needs_linearize(skb, features) &&
                            __skb_linearize(skb))
                                goto out_kfree_skb;
 
@@ -2105,7 +2102,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                                skb_set_transport_header(skb,
                                        skb_checksum_start_offset(skb));
-                               if (!dev_can_checksum(dev, skb) &&
+                               if (!(features & NETIF_F_ALL_CSUM) &&
                                     skb_checksum_help(skb))
                                        goto out_kfree_skb;
                        }
@@ -2301,7 +2298,10 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
                 */
                if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
                        skb_dst_force(skb);
-               __qdisc_update_bstats(q, skb->len);
+
+               qdisc_skb_cb(skb)->pkt_len = skb->len;
+               qdisc_bstats_update(q, skb);
+
                if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
                        if (unlikely(contended)) {
                                spin_unlock(&q->busylock);
@@ -5524,34 +5524,6 @@ void netdev_run_todo(void)
        }
 }
 
-/**
- *     dev_txq_stats_fold - fold tx_queues stats
- *     @dev: device to get statistics from
- *     @stats: struct rtnl_link_stats64 to hold results
- */
-void dev_txq_stats_fold(const struct net_device *dev,
-                       struct rtnl_link_stats64 *stats)
-{
-       u64 tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
-       unsigned int i;
-       struct netdev_queue *txq;
-
-       for (i = 0; i < dev->num_tx_queues; i++) {
-               txq = netdev_get_tx_queue(dev, i);
-               spin_lock_bh(&txq->_xmit_lock);
-               tx_bytes   += txq->tx_bytes;
-               tx_packets += txq->tx_packets;
-               tx_dropped += txq->tx_dropped;
-               spin_unlock_bh(&txq->_xmit_lock);
-       }
-       if (tx_bytes || tx_packets || tx_dropped) {
-               stats->tx_bytes   = tx_bytes;
-               stats->tx_packets = tx_packets;
-               stats->tx_dropped = tx_dropped;
-       }
-}
-EXPORT_SYMBOL(dev_txq_stats_fold);
-
 /* Convert net_device_stats to rtnl_link_stats64.  They have the same
  * fields in the same order, with only the type differing.
  */
@@ -5595,7 +5567,6 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
                netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
        } else {
                netdev_stats_to_stats64(storage, &dev->stats);
-               dev_txq_stats_fold(dev, storage);
        }
        storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
        return storage;
@@ -5621,18 +5592,20 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
 }
 
 /**
- *     alloc_netdev_mq - allocate network device
+ *     alloc_netdev_mqs - allocate network device
  *     @sizeof_priv:   size of private data to allocate space for
  *     @name:          device name format string
  *     @setup:         callback to initialize device
- *     @queue_count:   the number of subqueues to allocate
+ *     @txqs:          the number of TX subqueues to allocate
+ *     @rxqs:          the number of RX subqueues to allocate
  *
  *     Allocates a struct net_device with private data area for driver use
  *     and performs basic initialization.  Also allocates subquue structs
- *     for each queue on the device at the end of the netdevice.
+ *     for each queue on the device.
  */
-struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
-               void (*setup)(struct net_device *), unsigned int queue_count)
+struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
+               void (*setup)(struct net_device *),
+               unsigned int txqs, unsigned int rxqs)
 {
        struct net_device *dev;
        size_t alloc_size;
@@ -5640,12 +5613,20 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 
        BUG_ON(strlen(name) >= sizeof(dev->name));
 
-       if (queue_count < 1) {
+       if (txqs < 1) {
                pr_err("alloc_netdev: Unable to allocate device "
                       "with zero queues.\n");
                return NULL;
        }
 
+#ifdef CONFIG_RPS
+       if (rxqs < 1) {
+               pr_err("alloc_netdev: Unable to allocate device "
+                      "with zero RX queues.\n");
+               return NULL;
+       }
+#endif
+
        alloc_size = sizeof(struct net_device);
        if (sizeof_priv) {
                /* ensure 32-byte alignment of private area */
@@ -5676,14 +5657,14 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 
        dev_net_set(dev, &init_net);
 
-       dev->num_tx_queues = queue_count;
-       dev->real_num_tx_queues = queue_count;
+       dev->num_tx_queues = txqs;
+       dev->real_num_tx_queues = txqs;
        if (netif_alloc_netdev_queues(dev))
                goto free_pcpu;
 
 #ifdef CONFIG_RPS
-       dev->num_rx_queues = queue_count;
-       dev->real_num_rx_queues = queue_count;
+       dev->num_rx_queues = rxqs;
+       dev->real_num_rx_queues = rxqs;
        if (netif_alloc_rx_queues(dev))
                goto free_pcpu;
 #endif
@@ -5711,7 +5692,7 @@ free_p:
        kfree(p);
        return NULL;
 }
-EXPORT_SYMBOL(alloc_netdev_mq);
+EXPORT_SYMBOL(alloc_netdev_mqs);
 
 /**
  *     free_netdev - free network device