aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c34
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
345static 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
345int ip6_forward(struct sk_buff *skb) 359int 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