aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--net/core/dev.c35
2 files changed, 29 insertions, 10 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0f6b1c965815..d4dac09a5ad2 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2303,7 +2303,7 @@ unsigned long netdev_fix_features(unsigned long features, const char *name);
2303void netif_stacked_transfer_operstate(const struct net_device *rootdev, 2303void netif_stacked_transfer_operstate(const struct net_device *rootdev,
2304 struct net_device *dev); 2304 struct net_device *dev);
2305 2305
2306int netif_get_vlan_features(struct sk_buff *skb, struct net_device *dev); 2306int netif_skb_features(struct sk_buff *skb);
2307 2307
2308static inline int net_gso_ok(int features, int gso_type) 2308static inline int net_gso_ok(int features, int gso_type)
2309{ 2309{
@@ -2320,7 +2320,7 @@ static inline int skb_gso_ok(struct sk_buff *skb, int features)
2320static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) 2320static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
2321{ 2321{
2322 if (skb_is_gso(skb)) { 2322 if (skb_is_gso(skb)) {
2323 int features = netif_get_vlan_features(skb, dev); 2323 int features = netif_skb_features(skb);
2324 2324
2325 return (!skb_gso_ok(skb, features) || 2325 return (!skb_gso_ok(skb, features) ||
2326 unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); 2326 unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
diff --git a/net/core/dev.c b/net/core/dev.c
index d8befd06da04..a51dfd7b56fb 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2017,22 +2017,41 @@ static inline void skb_orphan_try(struct sk_buff *skb)
2017 } 2017 }
2018} 2018}
2019 2019
2020int netif_get_vlan_features(struct sk_buff *skb, struct net_device *dev) 2020static int harmonize_features(struct sk_buff *skb, __be16 protocol, int features)
2021{
2022 if (!can_checksum_protocol(protocol, features)) {
2023 features &= ~NETIF_F_ALL_CSUM;
2024 features &= ~NETIF_F_SG;
2025 } else if (illegal_highdma(skb->dev, skb)) {
2026 features &= ~NETIF_F_SG;
2027 }
2028
2029 return features;
2030}
2031
2032int netif_skb_features(struct sk_buff *skb)
2021{ 2033{
2022 __be16 protocol = skb->protocol; 2034 __be16 protocol = skb->protocol;
2035 int features = skb->dev->features;
2023 2036
2024 if (protocol == htons(ETH_P_8021Q)) { 2037 if (protocol == htons(ETH_P_8021Q)) {
2025 struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; 2038 struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
2026 protocol = veh->h_vlan_encapsulated_proto; 2039 protocol = veh->h_vlan_encapsulated_proto;
2027 } else if (!skb->vlan_tci) 2040 } else if (!vlan_tx_tag_present(skb)) {
2028 return dev->features; 2041 return harmonize_features(skb, protocol, features);
2042 }
2029 2043
2030 if (protocol != htons(ETH_P_8021Q)) 2044 features &= skb->dev->vlan_features;
2031 return dev->features & dev->vlan_features; 2045
2032 else 2046 if (protocol != htons(ETH_P_8021Q)) {
2033 return 0; 2047 return harmonize_features(skb, protocol, features);
2048 } else {
2049 features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
2050 NETIF_F_GEN_CSUM;
2051 return harmonize_features(skb, protocol, features);
2052 }
2034} 2053}
2035EXPORT_SYMBOL(netif_get_vlan_features); 2054EXPORT_SYMBOL(netif_skb_features);
2036 2055
2037/* 2056/*
2038 * Returns true if either: 2057 * Returns true if either: