net: Call netdev_features_change() from netdev_update_features()
[pandora-kernel.git] / net / core / dev.c
index 563ddc2..02f5637 100644 (file)
@@ -1454,6 +1454,27 @@ static inline void net_timestamp_check(struct sk_buff *skb)
                __net_timestamp(skb);
 }
 
+static inline bool is_skb_forwardable(struct net_device *dev,
+                                     struct sk_buff *skb)
+{
+       unsigned int len;
+
+       if (!(dev->flags & IFF_UP))
+               return false;
+
+       len = dev->mtu + dev->hard_header_len + VLAN_HLEN;
+       if (skb->len <= len)
+               return true;
+
+       /* if TSO is enabled, we don't care about the length as the packet
+        * could be forwarded without being segmented before
+        */
+       if (skb_is_gso(skb))
+               return true;
+
+       return false;
+}
+
 /**
  * dev_forward_skb - loopback an skb to another netif
  *
@@ -1477,8 +1498,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
        skb_orphan(skb);
        nf_reset(skb);
 
-       if (unlikely(!(dev->flags & IFF_UP) ||
-                    (skb->len > (dev->mtu + dev->hard_header_len + VLAN_HLEN)))) {
+       if (unlikely(!is_skb_forwardable(dev, skb))) {
                atomic_long_inc(&dev->rx_dropped);
                kfree_skb(skb);
                return NET_RX_DROP;
@@ -5216,7 +5236,7 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
 }
 EXPORT_SYMBOL(netdev_fix_features);
 
-void netdev_update_features(struct net_device *dev)
+int __netdev_update_features(struct net_device *dev)
 {
        u32 features;
        int err = 0;
@@ -5230,7 +5250,7 @@ void netdev_update_features(struct net_device *dev)
        features = netdev_fix_features(dev, features);
 
        if (dev->features == features)
-               return;
+               return 0;
 
        netdev_info(dev, "Features changed: 0x%08x -> 0x%08x\n",
                dev->features, features);
@@ -5238,12 +5258,23 @@ void netdev_update_features(struct net_device *dev)
        if (dev->netdev_ops->ndo_set_features)
                err = dev->netdev_ops->ndo_set_features(dev, features);
 
-       if (!err)
-               dev->features = features;
-       else if (err < 0)
+       if (unlikely(err < 0)) {
                netdev_err(dev,
                        "set_features() failed (%d); wanted 0x%08x, left 0x%08x\n",
                        err, features, dev->features);
+               return -1;
+       }
+
+       if (!err)
+               dev->features = features;
+
+       return 1;
+}
+
+void netdev_update_features(struct net_device *dev)
+{
+       if (__netdev_update_features(dev))
+               netdev_features_change(dev);
 }
 EXPORT_SYMBOL(netdev_update_features);
 
@@ -5410,7 +5441,7 @@ int register_netdevice(struct net_device *dev)
                goto err_uninit;
        dev->reg_state = NETREG_REGISTERED;
 
-       netdev_update_features(dev);
+       __netdev_update_features(dev);
 
        /*
         *      Default initial state at registry is that the