Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5fbba8ac authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

ip6: move ipip6_err_gen_icmpv6_unreach()



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: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b1cadc1a
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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);
			     const struct in6_addr *force_saddr);
extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn);
extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn);
extern int inet6_unregister_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
#else


+39 −0
Original line number Original line Diff line number Diff line
@@ -558,6 +558,45 @@ void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
	kfree_skb(skb);
	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)
static void icmpv6_echo_reply(struct sk_buff *skb)
{
{
	struct net *net = dev_net(skb->dev);
	struct net *net = dev_net(skb->dev);
+1 −37
Original line number Original line Diff line number Diff line
@@ -479,42 +479,6 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
	dev_put(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)
static int ipip6_err(struct sk_buff *skb, u32 info)
{
{
	const struct iphdr *iph = (const struct iphdr *)skb->data;
	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;
		goto out;


	err = 0;
	err = 0;
	if (!ipip6_err_gen_icmpv6_unreach(skb))
	if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4))
		goto out;
		goto out;


	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)