|
@@ -2208,16 +2208,8 @@ out:
|
|
|
}
|
|
|
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)) {
|
|
@@ -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)))
|
|
|
- return ERR_PTR(-EINVAL);
|
|
|
+ return 0;
|
|
|
|
|
|
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();
|
|
@@ -2398,24 +2408,12 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
|
|
|
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;
|
|
|
- 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);
|
|
|
}
|
|
|
|
|
|
- /* 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;
|
|
|
}
|
|
|
|
|
|
+ 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;
|