diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
| -rw-r--r-- | net/ipv6/ip6_output.c | 20 | 
1 files changed, 15 insertions, 5 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ef02b26ccf81..16f91a2e7888 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -342,6 +342,20 @@ static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)  	return mtu;  } +static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) +{ +	if (skb->len <= mtu || skb->local_df) +		return false; + +	if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu) +		return true; + +	if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) +		return false; + +	return true; +} +  int ip6_forward(struct sk_buff *skb)  {  	struct dst_entry *dst = skb_dst(skb); @@ -466,8 +480,7 @@ int ip6_forward(struct sk_buff *skb)  	if (mtu < IPV6_MIN_MTU)  		mtu = IPV6_MIN_MTU; -	if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) || -	    (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) { +	if (ip6_pkt_too_big(skb, mtu)) {  		/* Again, force OUTPUT device used as source address */  		skb->dev = dst->dev;  		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); @@ -517,9 +530,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)  	to->tc_index = from->tc_index;  #endif  	nf_copy(to, from); -#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) -	to->nf_trace = from->nf_trace; -#endif  	skb_copy_secmark(to, from);  }  |