diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1743dcd02d5b..8fbe3a5d8169 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -5500,7 +5500,14 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev, netdev_features_t passthru_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features); -netdev_features_t netif_skb_features(struct sk_buff *skb); +netdev_features_t __netif_skb_features(struct sk_buff *skb, + bool check_gso_limits); + +static inline netdev_features_t netif_skb_features(struct sk_buff *skb) +{ + return __netif_skb_features(skb, true); +} + void skb_warn_bad_offload(const struct sk_buff *skb); static inline bool net_gso_ok(netdev_features_t features, int gso_type) diff --git a/net/core/dev.c b/net/core/dev.c index df7ec4faaa81..4ea6ea4b111e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3897,16 +3897,24 @@ netif_get_gso_max_size(const struct net_device *dev, const struct sk_buff *skb) READ_ONCE(dev->gso_ipv4_max_size); } -static netdev_features_t gso_features_check(const struct sk_buff *skb, - struct net_device *dev, - netdev_features_t features) +static bool +gso_within_dev_limits(const struct sk_buff *skb, const struct net_device *dev) { - u16 gso_segs = skb_shinfo(skb)->gso_segs; - - if (gso_segs > READ_ONCE(dev->gso_max_segs)) - return features & ~NETIF_F_GSO_MASK; + if (skb_shinfo(skb)->gso_segs > READ_ONCE(dev->gso_max_segs)) + return false; if (unlikely(skb->len >= netif_get_gso_max_size(dev, skb))) + return false; + + return true; +} + +static netdev_features_t gso_features_check(const struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features, + bool check_limits) +{ + if (check_limits && !gso_within_dev_limits(skb, dev)) return features & ~NETIF_F_GSO_MASK; if (!skb_shinfo(skb)->gso_type) { @@ -3955,13 +3963,15 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb, return features; } -netdev_features_t netif_skb_features(struct sk_buff *skb) +netdev_features_t +__netif_skb_features(struct sk_buff *skb, bool check_gso_limits) { struct net_device *dev = skb->dev; netdev_features_t features = dev->features; if (skb_is_gso(skb)) - features = gso_features_check(skb, dev, features); + features = gso_features_check(skb, dev, features, + check_gso_limits); /* If encapsulation offload request, verify we are testing * hardware encapsulation features instead of standard @@ -3984,7 +3994,7 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) return harmonize_features(skb, features); } -EXPORT_SYMBOL(netif_skb_features); +EXPORT_SYMBOL(__netif_skb_features); static int xmit_one(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, bool more)