ip6: move ipip6_err_gen_icmpv6_unreach()
authorEric Dumazet <edumazet@google.com>
Sun, 19 Jun 2016 04:52:03 +0000 (21:52 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sun, 19 Jun 2016 05:11:39 +0000 (22:11 -0700)
We want to use this helper from GRE as well, so this is
the time to move it in net/ipv6/icmp.c

Also add a @nhs parameter, since SIT and GRE have different
values for the header(s) to skip.

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 432611a297fbc5c8d2359dd15874da6faf7c1cb4..9796481edbdb9a28a3de236f641ecf5417de6e57 100644 (file)
@@ -18,6 +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);
 
 #else
 
index 6c57e6e90301c87a7ade0982954d15d2a0d24111..07bc63c23712a6d12d14cf0c2083dbe00886fc45 100644 (file)
@@ -558,6 +558,45 @@ void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
        kfree_skb(skb);
 }
 
+/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
+ * if sufficient data bytes are available
+ * @nhs is the size of the tunnel header(s) :
+ *  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)
+{
+       struct rt6_info *rt;
+       struct sk_buff *skb2;
+
+       if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8))
+               return 1;
+
+       skb2 = skb_clone(skb, GFP_ATOMIC);
+
+       if (!skb2)
+               return 1;
+
+       skb_dst_drop(skb2);
+       skb_pull(skb2, nhs);
+       skb_reset_network_header(skb2);
+
+       rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0);
+
+       if (rt && rt->dst.dev)
+               skb2->dev = rt->dst.dev;
+
+       icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
+
+       if (rt)
+               ip6_rt_put(rt);
+
+       kfree_skb(skb2);
+
+       return 0;
+}
+EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
+
 static void icmpv6_echo_reply(struct sk_buff *skb)
 {
        struct net *net = dev_net(skb->dev);
index d9f2bd6ef72dbb008f80d2e5fe8ab6f59e0be814..78e84d6793eefaf039501b2795e14529367b6a0b 100644 (file)
@@ -479,42 +479,6 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
        dev_put(dev);
 }
 
-/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
- * if sufficient data bytes are available
- */
-static int ipip6_err_gen_icmpv6_unreach(struct sk_buff *skb)
-{
-       int ihl = ((const struct iphdr *)skb->data)->ihl*4;
-       struct rt6_info *rt;
-       struct sk_buff *skb2;
-
-       if (!pskb_may_pull(skb, ihl + sizeof(struct ipv6hdr) + 8))
-               return 1;
-
-       skb2 = skb_clone(skb, GFP_ATOMIC);
-
-       if (!skb2)
-               return 1;
-
-       skb_dst_drop(skb2);
-       skb_pull(skb2, ihl);
-       skb_reset_network_header(skb2);
-
-       rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0);
-
-       if (rt && rt->dst.dev)
-               skb2->dev = rt->dst.dev;
-
-       icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
-
-       if (rt)
-               ip6_rt_put(rt);
-
-       kfree_skb(skb2);
-
-       return 0;
-}
-
 static int ipip6_err(struct sk_buff *skb, u32 info)
 {
        const struct iphdr *iph = (const struct iphdr *)skb->data;
@@ -575,7 +539,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
                goto out;
 
        err = 0;
-       if (!ipip6_err_gen_icmpv6_unreach(skb))
+       if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4))
                goto out;
 
        if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)