diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ef02b26ccf81..64d6073731d3 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); |
@@ -517,9 +530,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) | |||
517 | to->tc_index = from->tc_index; | 530 | to->tc_index = from->tc_index; |
518 | #endif | 531 | #endif |
519 | nf_copy(to, from); | 532 | nf_copy(to, from); |
520 | #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) | ||
521 | to->nf_trace = from->nf_trace; | ||
522 | #endif | ||
523 | skb_copy_secmark(to, from); | 533 | skb_copy_secmark(to, from); |
524 | } | 534 | } |
525 | 535 | ||
@@ -1091,21 +1101,19 @@ static void ip6_append_data_mtu(unsigned int *mtu, | |||
1091 | unsigned int fragheaderlen, | 1101 | unsigned int fragheaderlen, |
1092 | struct sk_buff *skb, | 1102 | struct sk_buff *skb, |
1093 | struct rt6_info *rt, | 1103 | struct rt6_info *rt, |
1094 | bool pmtuprobe) | 1104 | unsigned int orig_mtu) |
1095 | { | 1105 | { |
1096 | if (!(rt->dst.flags & DST_XFRM_TUNNEL)) { | 1106 | if (!(rt->dst.flags & DST_XFRM_TUNNEL)) { |
1097 | if (skb == NULL) { | 1107 | if (skb == NULL) { |
1098 | /* first fragment, reserve header_len */ | 1108 | /* first fragment, reserve header_len */ |
1099 | *mtu = *mtu - rt->dst.header_len; | 1109 | *mtu = orig_mtu - rt->dst.header_len; |
1100 | 1110 | ||
1101 | } else { | 1111 | } else { |
1102 | /* | 1112 | /* |
1103 | * this fragment is not first, the headers | 1113 | * this fragment is not first, the headers |
1104 | * space is regarded as data space. | 1114 | * space is regarded as data space. |
1105 | */ | 1115 | */ |
1106 | *mtu = min(*mtu, pmtuprobe ? | 1116 | *mtu = orig_mtu; |
1107 | rt->dst.dev->mtu : | ||
1108 | dst_mtu(rt->dst.path)); | ||
1109 | } | 1117 | } |
1110 | *maxfraglen = ((*mtu - fragheaderlen) & ~7) | 1118 | *maxfraglen = ((*mtu - fragheaderlen) & ~7) |
1111 | + fragheaderlen - sizeof(struct frag_hdr); | 1119 | + fragheaderlen - sizeof(struct frag_hdr); |
@@ -1122,7 +1130,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1122 | struct ipv6_pinfo *np = inet6_sk(sk); | 1130 | struct ipv6_pinfo *np = inet6_sk(sk); |
1123 | struct inet_cork *cork; | 1131 | struct inet_cork *cork; |
1124 | struct sk_buff *skb, *skb_prev = NULL; | 1132 | struct sk_buff *skb, *skb_prev = NULL; |
1125 | unsigned int maxfraglen, fragheaderlen, mtu; | 1133 | unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; |
1126 | int exthdrlen; | 1134 | int exthdrlen; |
1127 | int dst_exthdrlen; | 1135 | int dst_exthdrlen; |
1128 | int hh_len; | 1136 | int hh_len; |
@@ -1204,6 +1212,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1204 | dst_exthdrlen = 0; | 1212 | dst_exthdrlen = 0; |
1205 | mtu = cork->fragsize; | 1213 | mtu = cork->fragsize; |
1206 | } | 1214 | } |
1215 | orig_mtu = mtu; | ||
1207 | 1216 | ||
1208 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); | 1217 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
1209 | 1218 | ||
@@ -1301,8 +1310,7 @@ alloc_new_skb: | |||
1301 | if (skb == NULL || skb_prev == NULL) | 1310 | if (skb == NULL || skb_prev == NULL) |
1302 | ip6_append_data_mtu(&mtu, &maxfraglen, | 1311 | ip6_append_data_mtu(&mtu, &maxfraglen, |
1303 | fragheaderlen, skb, rt, | 1312 | fragheaderlen, skb, rt, |
1304 | np->pmtudisc >= | 1313 | orig_mtu); |
1305 | IPV6_PMTUDISC_PROBE); | ||
1306 | 1314 | ||
1307 | skb_prev = skb; | 1315 | skb_prev = skb; |
1308 | 1316 | ||