net: prevent sign extension in dev_get_stats()
[pandora-kernel.git] / net / core / dev.c
index 42895aa..bb7a0cc 100644 (file)
@@ -1918,7 +1918,7 @@ int skb_checksum_help(struct sk_buff *skb)
                        goto out;
        }
 
-       *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+       *(__sum16 *)(skb->data + offset) = csum_fold(csum) ?: CSUM_MANGLED_0;
 out_set_summed:
        skb->ip_summed = CHECKSUM_NONE;
 out:
@@ -3261,8 +3261,6 @@ static int __netif_receive_skb(struct sk_buff *skb)
 
        pt_prev = NULL;
 
-       rcu_read_lock();
-
 another_round:
 
        __this_cpu_inc(softnet_data.processed);
@@ -3357,7 +3355,6 @@ ncls:
        }
 
 out:
-       rcu_read_unlock();
        return ret;
 }
 
@@ -3378,34 +3375,31 @@ out:
  */
 int netif_receive_skb(struct sk_buff *skb)
 {
+       int ret;
+
        if (netdev_tstamp_prequeue)
                net_timestamp_check(skb);
 
        if (skb_defer_rx_timestamp(skb))
                return NET_RX_SUCCESS;
 
+       rcu_read_lock();
+
 #ifdef CONFIG_RPS
        {
                struct rps_dev_flow voidflow, *rflow = &voidflow;
-               int cpu, ret;
-
-               rcu_read_lock();
-
-               cpu = get_rps_cpu(skb->dev, skb, &rflow);
+               int cpu = get_rps_cpu(skb->dev, skb, &rflow);
 
                if (cpu >= 0) {
                        ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
                        rcu_read_unlock();
-               } else {
-                       rcu_read_unlock();
-                       ret = __netif_receive_skb(skb);
+                       return ret;
                }
-
-               return ret;
        }
-#else
-       return __netif_receive_skb(skb);
 #endif
+       ret = __netif_receive_skb(skb);
+       rcu_read_unlock();
+       return ret;
 }
 EXPORT_SYMBOL(netif_receive_skb);
 
@@ -3633,7 +3627,9 @@ void skb_gro_reset_offset(struct sk_buff *skb)
            !PageHighMem(skb_frag_page(&skb_shinfo(skb)->frags[0]))) {
                NAPI_GRO_CB(skb)->frag0 =
                        skb_frag_address(&skb_shinfo(skb)->frags[0]);
-               NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(&skb_shinfo(skb)->frags[0]);
+               NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int,
+                                                   skb_frag_size(&skb_shinfo(skb)->frags[0]),
+                                                   skb->end - skb->tail);
        }
 }
 EXPORT_SYMBOL(skb_gro_reset_offset);
@@ -3796,8 +3792,10 @@ static int process_backlog(struct napi_struct *napi, int quota)
                unsigned int qlen;
 
                while ((skb = __skb_dequeue(&sd->process_queue))) {
+                       rcu_read_lock();
                        local_irq_enable();
                        __netif_receive_skb(skb);
+                       rcu_read_unlock();
                        local_irq_disable();
                        input_queue_head_incr(sd);
                        if (++work >= quota) {
@@ -5450,6 +5448,9 @@ int __netdev_update_features(struct net_device *dev)
                netdev_err(dev,
                        "set_features() failed (%d); wanted 0x%08x, left 0x%08x\n",
                        err, features, dev->features);
+               /* return non-0 since some features might have changed and
+                * it's better to fire a spurious notification than miss it
+                */
                return -1;
        }
 
@@ -5941,7 +5942,7 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
        } else {
                netdev_stats_to_stats64(storage, &dev->stats);
        }
-       storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
+       storage->rx_dropped += (unsigned long)atomic_long_read(&dev->rx_dropped);
        return storage;
 }
 EXPORT_SYMBOL(dev_get_stats);