diff options
-rw-r--r-- | include/net/route.h | 5 | ||||
-rw-r--r-- | net/ipv4/ah4.c | 1 | ||||
-rw-r--r-- | net/ipv4/esp4.c | 1 | ||||
-rw-r--r-- | net/ipv4/ip_gre.c | 14 | ||||
-rw-r--r-- | net/ipv4/ipcomp.c | 1 | ||||
-rw-r--r-- | net/ipv4/ipip.c | 15 | ||||
-rw-r--r-- | net/ipv4/ping.c | 1 | ||||
-rw-r--r-- | net/ipv4/raw.c | 3 | ||||
-rw-r--r-- | net/ipv4/route.c | 28 | ||||
-rw-r--r-- | net/ipv4/udp.c | 1 | ||||
-rw-r--r-- | net/ipv6/sit.c | 15 |
11 files changed, 72 insertions, 13 deletions
diff --git a/include/net/route.h b/include/net/route.h index a36ae429ed5d..47eb25ac1f7f 100644 --- a/include/net/route.h +++ b/include/net/route.h | |||
@@ -215,7 +215,10 @@ static inline int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 s | |||
215 | return ip_route_input_common(skb, dst, src, tos, devin, true); | 215 | return ip_route_input_common(skb, dst, src, tos, devin, true); |
216 | } | 216 | } |
217 | 217 | ||
218 | extern void ip_rt_send_redirect(struct sk_buff *skb); | 218 | extern void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, |
219 | int oif, u32 mark, u8 protocol, int flow_flags); | ||
220 | extern void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu); | ||
221 | extern void ip_rt_send_redirect(struct sk_buff *skb); | ||
219 | 222 | ||
220 | extern unsigned int inet_addr_type(struct net *net, __be32 addr); | 223 | extern unsigned int inet_addr_type(struct net *net, __be32 addr); |
221 | extern unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr); | 224 | extern unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr); |
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index e8f2617ecd47..916d5ecaf6c6 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c | |||
@@ -408,6 +408,7 @@ static void ah4_err(struct sk_buff *skb, u32 info) | |||
408 | return; | 408 | return; |
409 | pr_debug("pmtu discovery on SA AH/%08x/%08x\n", | 409 | pr_debug("pmtu discovery on SA AH/%08x/%08x\n", |
410 | ntohl(ah->spi), ntohl(iph->daddr)); | 410 | ntohl(ah->spi), ntohl(iph->daddr)); |
411 | ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0); | ||
411 | xfrm_state_put(x); | 412 | xfrm_state_put(x); |
412 | } | 413 | } |
413 | 414 | ||
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index cb982a61536f..7b95b49a36ce 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -494,6 +494,7 @@ static void esp4_err(struct sk_buff *skb, u32 info) | |||
494 | return; | 494 | return; |
495 | NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n", | 495 | NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n", |
496 | ntohl(esph->spi), ntohl(iph->daddr)); | 496 | ntohl(esph->spi), ntohl(iph->daddr)); |
497 | ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0); | ||
497 | xfrm_state_put(x); | 498 | xfrm_state_put(x); |
498 | } | 499 | } |
499 | 500 | ||
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f49047b79609..594cec35ac4d 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -516,9 +516,6 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
516 | case ICMP_PORT_UNREACH: | 516 | case ICMP_PORT_UNREACH: |
517 | /* Impossible event. */ | 517 | /* Impossible event. */ |
518 | return; | 518 | return; |
519 | case ICMP_FRAG_NEEDED: | ||
520 | /* Soft state for pmtu is maintained by IP core. */ | ||
521 | return; | ||
522 | default: | 519 | default: |
523 | /* All others are translated to HOST_UNREACH. | 520 | /* All others are translated to HOST_UNREACH. |
524 | rfc2003 contains "deep thoughts" about NET_UNREACH, | 521 | rfc2003 contains "deep thoughts" about NET_UNREACH, |
@@ -538,7 +535,16 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
538 | flags & GRE_KEY ? | 535 | flags & GRE_KEY ? |
539 | *(((__be32 *)p) + (grehlen / 4) - 1) : 0, | 536 | *(((__be32 *)p) + (grehlen / 4) - 1) : 0, |
540 | p[1]); | 537 | p[1]); |
541 | if (t == NULL || t->parms.iph.daddr == 0 || | 538 | if (t == NULL) |
539 | goto out; | ||
540 | |||
541 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | ||
542 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, | ||
543 | t->parms.link, 0, IPPROTO_GRE, 0); | ||
544 | goto out; | ||
545 | } | ||
546 | |||
547 | if (t->parms.iph.daddr == 0 || | ||
542 | ipv4_is_multicast(t->parms.iph.daddr)) | 548 | ipv4_is_multicast(t->parms.iph.daddr)) |
543 | goto out; | 549 | goto out; |
544 | 550 | ||
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 63b64c45a826..b91375482d84 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c | |||
@@ -42,6 +42,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) | |||
42 | return; | 42 | return; |
43 | NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n", | 43 | NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n", |
44 | spi, &iph->daddr); | 44 | spi, &iph->daddr); |
45 | ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0); | ||
45 | xfrm_state_put(x); | 46 | xfrm_state_put(x); |
46 | } | 47 | } |
47 | 48 | ||
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 2d0f99bf61b3..715338a1b205 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -348,9 +348,6 @@ static int ipip_err(struct sk_buff *skb, u32 info) | |||
348 | case ICMP_PORT_UNREACH: | 348 | case ICMP_PORT_UNREACH: |
349 | /* Impossible event. */ | 349 | /* Impossible event. */ |
350 | return 0; | 350 | return 0; |
351 | case ICMP_FRAG_NEEDED: | ||
352 | /* Soft state for pmtu is maintained by IP core. */ | ||
353 | return 0; | ||
354 | default: | 351 | default: |
355 | /* All others are translated to HOST_UNREACH. | 352 | /* All others are translated to HOST_UNREACH. |
356 | rfc2003 contains "deep thoughts" about NET_UNREACH, | 353 | rfc2003 contains "deep thoughts" about NET_UNREACH, |
@@ -369,7 +366,17 @@ static int ipip_err(struct sk_buff *skb, u32 info) | |||
369 | 366 | ||
370 | rcu_read_lock(); | 367 | rcu_read_lock(); |
371 | t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); | 368 | t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); |
372 | if (t == NULL || t->parms.iph.daddr == 0) | 369 | if (t == NULL) |
370 | goto out; | ||
371 | |||
372 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | ||
373 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, | ||
374 | t->dev->ifindex, 0, IPPROTO_IPIP, 0); | ||
375 | err = 0; | ||
376 | goto out; | ||
377 | } | ||
378 | |||
379 | if (t->parms.iph.daddr == 0) | ||
373 | goto out; | 380 | goto out; |
374 | 381 | ||
375 | err = 0; | 382 | err = 0; |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 2c00e8bf684d..340fcf29a966 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -371,6 +371,7 @@ void ping_err(struct sk_buff *skb, u32 info) | |||
371 | break; | 371 | break; |
372 | case ICMP_DEST_UNREACH: | 372 | case ICMP_DEST_UNREACH: |
373 | if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ | 373 | if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ |
374 | ipv4_sk_update_pmtu(skb, sk, info); | ||
374 | if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) { | 375 | if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) { |
375 | err = EMSGSIZE; | 376 | err = EMSGSIZE; |
376 | harderr = 1; | 377 | harderr = 1; |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 4032b818f3e4..659ddfb10947 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -216,6 +216,9 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) | |||
216 | int err = 0; | 216 | int err = 0; |
217 | int harderr = 0; | 217 | int harderr = 0; |
218 | 218 | ||
219 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) | ||
220 | ipv4_sk_update_pmtu(skb, sk, info); | ||
221 | |||
219 | /* Report error on raw socket, if: | 222 | /* Report error on raw socket, if: |
220 | 1. User requested ip_recverr. | 223 | 1. User requested ip_recverr. |
221 | 2. Socket is connected (otherwise the error indication | 224 | 2. Socket is connected (otherwise the error indication |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 655506af47ca..41df5297a412 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1711,6 +1711,34 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
1711 | } | 1711 | } |
1712 | } | 1712 | } |
1713 | 1713 | ||
1714 | void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, | ||
1715 | int oif, u32 mark, u8 protocol, int flow_flags) | ||
1716 | { | ||
1717 | const struct iphdr *iph = (const struct iphdr *)skb->data; | ||
1718 | struct flowi4 fl4; | ||
1719 | struct rtable *rt; | ||
1720 | |||
1721 | flowi4_init_output(&fl4, oif, mark, RT_TOS(iph->tos), RT_SCOPE_UNIVERSE, | ||
1722 | protocol, flow_flags | FLOWI_FLAG_PRECOW_METRICS, | ||
1723 | iph->daddr, iph->saddr, 0, 0); | ||
1724 | rt = __ip_route_output_key(net, &fl4); | ||
1725 | if (!IS_ERR(rt)) { | ||
1726 | ip_rt_update_pmtu(&rt->dst, mtu); | ||
1727 | ip_rt_put(rt); | ||
1728 | } | ||
1729 | } | ||
1730 | EXPORT_SYMBOL_GPL(ipv4_update_pmtu); | ||
1731 | |||
1732 | void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) | ||
1733 | { | ||
1734 | const struct inet_sock *inet = inet_sk(sk); | ||
1735 | |||
1736 | return ipv4_update_pmtu(skb, sock_net(sk), mtu, | ||
1737 | sk->sk_bound_dev_if, sk->sk_mark, | ||
1738 | inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, | ||
1739 | inet_sk_flowi_flags(sk)); | ||
1740 | } | ||
1741 | EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu); | ||
1714 | 1742 | ||
1715 | static void ipv4_validate_peer(struct rtable *rt) | 1743 | static void ipv4_validate_peer(struct rtable *rt) |
1716 | { | 1744 | { |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index eaca73644e79..db017efb76ea 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -615,6 +615,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) | |||
615 | break; | 615 | break; |
616 | case ICMP_DEST_UNREACH: | 616 | case ICMP_DEST_UNREACH: |
617 | if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ | 617 | if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ |
618 | ipv4_sk_update_pmtu(skb, sk, info); | ||
618 | if (inet->pmtudisc != IP_PMTUDISC_DONT) { | 619 | if (inet->pmtudisc != IP_PMTUDISC_DONT) { |
619 | err = EMSGSIZE; | 620 | err = EMSGSIZE; |
620 | harderr = 1; | 621 | harderr = 1; |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 60415711563f..49aea94c9be3 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -527,9 +527,6 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
527 | case ICMP_PORT_UNREACH: | 527 | case ICMP_PORT_UNREACH: |
528 | /* Impossible event. */ | 528 | /* Impossible event. */ |
529 | return 0; | 529 | return 0; |
530 | case ICMP_FRAG_NEEDED: | ||
531 | /* Soft state for pmtu is maintained by IP core. */ | ||
532 | return 0; | ||
533 | default: | 530 | default: |
534 | /* All others are translated to HOST_UNREACH. | 531 | /* All others are translated to HOST_UNREACH. |
535 | rfc2003 contains "deep thoughts" about NET_UNREACH, | 532 | rfc2003 contains "deep thoughts" about NET_UNREACH, |
@@ -551,7 +548,17 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
551 | skb->dev, | 548 | skb->dev, |
552 | iph->daddr, | 549 | iph->daddr, |
553 | iph->saddr); | 550 | iph->saddr); |
554 | if (t == NULL || t->parms.iph.daddr == 0) | 551 | if (t == NULL) |
552 | goto out; | ||
553 | |||
554 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | ||
555 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, | ||
556 | t->dev->ifindex, 0, IPPROTO_IPV6, 0); | ||
557 | err = 0; | ||
558 | goto out; | ||
559 | } | ||
560 | |||
561 | if (t->parms.iph.daddr == 0) | ||
555 | goto out; | 562 | goto out; |
556 | 563 | ||
557 | err = 0; | 564 | err = 0; |