diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ef02b26ccf81..070a2fae2375 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) | |||
342 | return mtu; | 342 | return mtu; |
343 | } | 343 | } |
344 | 344 | ||
345 | static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) | ||
346 | { | ||
347 | if (skb->len <= mtu || skb->local_df) | ||
348 | return false; | ||
349 | |||
350 | if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu) | ||
351 | return true; | ||
352 | |||
353 | if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) | ||
354 | return false; | ||
355 | |||
356 | return true; | ||
357 | } | ||
358 | |||
345 | int ip6_forward(struct sk_buff *skb) | 359 | int ip6_forward(struct sk_buff *skb) |
346 | { | 360 | { |
347 | struct dst_entry *dst = skb_dst(skb); | 361 | struct dst_entry *dst = skb_dst(skb); |
@@ -466,8 +480,7 @@ int ip6_forward(struct sk_buff *skb) | |||
466 | if (mtu < IPV6_MIN_MTU) | 480 | if (mtu < IPV6_MIN_MTU) |
467 | mtu = IPV6_MIN_MTU; | 481 | mtu = IPV6_MIN_MTU; |
468 | 482 | ||
469 | if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) || | 483 | if (ip6_pkt_too_big(skb, mtu)) { |
470 | (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) { | ||
471 | /* Again, force OUTPUT device used as source address */ | 484 | /* Again, force OUTPUT device used as source address */ |
472 | skb->dev = dst->dev; | 485 | skb->dev = dst->dev; |
473 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 486 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |