net: Kill link between CSUM and SG features.
[pandora-kernel.git] / net / core / dev.c
index 9610389..bb99993 100644 (file)
@@ -2208,16 +2208,8 @@ out:
 }
 EXPORT_SYMBOL(skb_checksum_help);
 
 }
 EXPORT_SYMBOL(skb_checksum_help);
 
-/**
- *     skb_mac_gso_segment - mac layer segmentation handler.
- *     @skb: buffer to segment
- *     @features: features for the output path (see dev->features)
- */
-struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
-                                   netdev_features_t features)
+__be16 skb_network_protocol(struct sk_buff *skb)
 {
 {
-       struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
-       struct packet_offload *ptype;
        __be16 type = skb->protocol;
 
        while (type == htons(ETH_P_8021Q)) {
        __be16 type = skb->protocol;
 
        while (type == htons(ETH_P_8021Q)) {
@@ -2225,13 +2217,31 @@ struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
                struct vlan_hdr *vh;
 
                if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
                struct vlan_hdr *vh;
 
                if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
-                       return ERR_PTR(-EINVAL);
+                       return 0;
 
                vh = (struct vlan_hdr *)(skb->data + vlan_depth);
                type = vh->h_vlan_encapsulated_proto;
                vlan_depth += VLAN_HLEN;
        }
 
 
                vh = (struct vlan_hdr *)(skb->data + vlan_depth);
                type = vh->h_vlan_encapsulated_proto;
                vlan_depth += VLAN_HLEN;
        }
 
+       return type;
+}
+
+/**
+ *     skb_mac_gso_segment - mac layer segmentation handler.
+ *     @skb: buffer to segment
+ *     @features: features for the output path (see dev->features)
+ */
+struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
+                                   netdev_features_t features)
+{
+       struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
+       struct packet_offload *ptype;
+       __be16 type = skb_network_protocol(skb);
+
+       if (unlikely(!type))
+               return ERR_PTR(-EINVAL);
+
        __skb_pull(skb, skb->mac_len);
 
        rcu_read_lock();
        __skb_pull(skb, skb->mac_len);
 
        rcu_read_lock();
@@ -2398,24 +2408,12 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
        return 0;
 }
 
        return 0;
 }
 
-static bool can_checksum_protocol(netdev_features_t 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 netdev_features_t harmonize_features(struct sk_buff *skb,
        __be16 protocol, netdev_features_t features)
 {
        if (skb->ip_summed != CHECKSUM_NONE &&
            !can_checksum_protocol(features, protocol)) {
                features &= ~NETIF_F_ALL_CSUM;
 static netdev_features_t harmonize_features(struct sk_buff *skb,
        __be16 protocol, netdev_features_t features)
 {
        if (skb->ip_summed != CHECKSUM_NONE &&
            !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;
        }
        } else if (illegal_highdma(skb->dev, skb)) {
                features &= ~NETIF_F_SG;
        }
@@ -4921,20 +4919,25 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,
                features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
        }
 
                features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
        }
 
-       /* Fix illegal SG+CSUM combinations. */
-       if ((features & NETIF_F_SG) &&
-           !(features & NETIF_F_ALL_CSUM)) {
-               netdev_dbg(dev,
-                       "Dropping NETIF_F_SG since no checksum feature.\n");
-               features &= ~NETIF_F_SG;
-       }
-
        /* TSO requires that SG is present as well. */
        if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) {
                netdev_dbg(dev, "Dropping TSO features since no SG feature.\n");
                features &= ~NETIF_F_ALL_TSO;
        }
 
        /* TSO requires that SG is present as well. */
        if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) {
                netdev_dbg(dev, "Dropping TSO features since no SG feature.\n");
                features &= ~NETIF_F_ALL_TSO;
        }
 
+       if ((features & NETIF_F_TSO) && !(features & NETIF_F_HW_CSUM) &&
+                                       !(features & NETIF_F_IP_CSUM)) {
+               netdev_dbg(dev, "Dropping TSO features since no CSUM feature.\n");
+               features &= ~NETIF_F_TSO;
+               features &= ~NETIF_F_TSO_ECN;
+       }
+
+       if ((features & NETIF_F_TSO6) && !(features & NETIF_F_HW_CSUM) &&
+                                        !(features & NETIF_F_IPV6_CSUM)) {
+               netdev_dbg(dev, "Dropping TSO6 features since no CSUM feature.\n");
+               features &= ~NETIF_F_TSO6;
+       }
+
        /* TSO ECN requires that TSO is present as well. */
        if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN)
                features &= ~NETIF_F_TSO_ECN;
        /* TSO ECN requires that TSO is present as well. */
        if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN)
                features &= ~NETIF_F_TSO_ECN;