ipv6: translate ICMP_TIME_EXCEEDED to ICMPV6_TIME_EXCEED
authorEric Dumazet <edumazet@google.com>
Sun, 19 Jun 2016 04:52:04 +0000 (21:52 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sun, 19 Jun 2016 05:11:39 +0000 (22:11 -0700)
For better traceroute/mtr support for SIT and GRE tunnels,
we translate IPV4 ICMP ICMP_TIME_EXCEEDED to ICMPV6_TIME_EXCEED

We also have to translate the IPv4 source IP address of ICMP
message to IPv6 v4mapped.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/icmpv6.h
net/ipv6/icmp.c
net/ipv6/sit.c

index 9796481..97ae980 100644 (file)
@@ -18,7 +18,7 @@ typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info,
                             const struct in6_addr *force_saddr);
 extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn);
 extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn);
-int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs);
+int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type);
 
 #else
 
index 07bc63c..867aebc 100644 (file)
@@ -564,8 +564,9 @@ void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
  *  Either an IPv4 header for SIT encap
  *         an IPv4 header + GRE header for GRE encap
  */
-int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs)
+int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type)
 {
+       struct in6_addr temp_saddr;
        struct rt6_info *rt;
        struct sk_buff *skb2;
 
@@ -586,8 +587,13 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs)
        if (rt && rt->dst.dev)
                skb2->dev = rt->dst.dev;
 
-       icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
-
+       ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr);
+       if (type == ICMP_TIME_EXCEEDED)
+               icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
+                          0, &temp_saddr);
+       else
+               icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH,
+                          0, &temp_saddr);
        if (rt)
                ip6_rt_put(rt);
 
index 78e84d6..d7a3611 100644 (file)
@@ -535,11 +535,11 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
                goto out;
        }
 
-       if (t->parms.iph.daddr == 0)
+       err = 0;
+       if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type))
                goto out;
 
-       err = 0;
-       if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4))
+       if (t->parms.iph.daddr == 0)
                goto out;
 
        if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)