icmp.c 23 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
 *	Internet Control Message Protocol (ICMPv6)
 *	Linux INET6 implementation
 *
 *	Authors:
 *	Pedro Roque		<roque@di.fc.ul.pt>
 *
 *	Based on net/ipv4/icmp.c
 *
 *	RFC 1885
 *
 *	This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */

/*
 *	Changes:
 *
 *	Andi Kleen		:	exception handling
 *	Andi Kleen			add rate limits. never reply to a icmp.
 *					add more length checks and other fixes.
 *	yoshfuji		:	ensure to sent parameter problem for
 *					fragments.
 *	YOSHIFUJI Hideaki @USAGI:	added sysctl for icmp rate limit.
 *	Randy Dunlap and
 *	YOSHIFUJI Hideaki @USAGI:	Per-interface statistics support
 *	Kazunori MIYAZAWA @USAGI:       change output process to use ip6_append_data
 */

32
33
#define pr_fmt(fmt) "IPv6: " fmt

Linus Torvalds's avatar
Linus Torvalds committed
34
35
36
37
38
39
40
41
42
43
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/init.h>
44
#include <linux/netfilter.h>
45
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59

#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/icmpv6.h>

#include <net/ip.h>
#include <net/sock.h>

#include <net/ipv6.h>
#include <net/ip6_checksum.h>
60
#include <net/ping.h>
Linus Torvalds's avatar
Linus Torvalds committed
61
62
63
64
65
66
67
#include <net/protocol.h>
#include <net/raw.h>
#include <net/rawv6.h>
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/icmp.h>
68
#include <net/xfrm.h>
69
#include <net/inet_common.h>
70
#include <net/dsfield.h>
71
#include <net/l3mdev.h>
Linus Torvalds's avatar
Linus Torvalds committed
72
73
74
75
76
77
78
79
80
81

#include <asm/uaccess.h>

/*
 *	The ICMP socket(s). This is the most convenient way to flow control
 *	our ICMP output as well as maintain a clean interface throughout
 *	all layers. All Socketless IP sends will soon be gone.
 *
 *	On SMP we have one ICMP socket per-cpu.
 */
82
83
84
85
static inline struct sock *icmpv6_sk(struct net *net)
{
	return net->ipv6.icmp_sk[smp_processor_id()];
}
Linus Torvalds's avatar
Linus Torvalds committed
86

87
88
89
static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
		       u8 type, u8 code, int offset, __be32 info)
{
90
91
	/* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
	struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
92
93
94
95
96
	struct net *net = dev_net(skb->dev);

	if (type == ICMPV6_PKT_TOOBIG)
		ip6_update_pmtu(skb, net, info, 0, 0);
	else if (type == NDISC_REDIRECT)
97
		ip6_redirect(skb, net, skb->dev->ifindex, 0);
98
99
100
101

	if (!(type & ICMPV6_INFOMSG_MASK))
		if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
			ping_err(skb, offset, info);
102
103
}

104
static int icmpv6_rcv(struct sk_buff *skb);
Linus Torvalds's avatar
Linus Torvalds committed
105

106
static const struct inet6_protocol icmpv6_protocol = {
Linus Torvalds's avatar
Linus Torvalds committed
107
	.handler	=	icmpv6_rcv,
108
	.err_handler	=	icmpv6_err,
109
	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
Linus Torvalds's avatar
Linus Torvalds committed
110
111
};

112
static __inline__ struct sock *icmpv6_xmit_lock(struct net *net)
Linus Torvalds's avatar
Linus Torvalds committed
113
{
114
115
	struct sock *sk;

Linus Torvalds's avatar
Linus Torvalds committed
116
117
	local_bh_disable();

118
	sk = icmpv6_sk(net);
119
	if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
Linus Torvalds's avatar
Linus Torvalds committed
120
121
122
123
124
		/* This can happen if the output path (f.e. SIT or
		 * ip6ip6 tunnel) signals dst_link_failure() for an
		 * outgoing ICMP6 packet.
		 */
		local_bh_enable();
125
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
126
	}
127
	return sk;
Linus Torvalds's avatar
Linus Torvalds committed
128
129
}

130
static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
Linus Torvalds's avatar
Linus Torvalds committed
131
{
132
	spin_unlock_bh(&sk->sk_lock.slock);
Linus Torvalds's avatar
Linus Torvalds committed
133
134
135
136
137
138
139
140
141
142
143
144
145
}

/*
 * Figure out, may we reply to this packet with icmp error.
 *
 * We do not reply, if:
 *	- it was icmp error message.
 *	- it is truncated, so that it is known, that protocol is ICMPV6
 *	  (i.e. in the middle of some exthdr)
 *
 *	--ANK (980726)
 */

146
static bool is_ineligible(const struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
147
{
148
	int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
Linus Torvalds's avatar
Linus Torvalds committed
149
	int len = skb->len - ptr;
150
	__u8 nexthdr = ipv6_hdr(skb)->nexthdr;
151
	__be16 frag_off;
Linus Torvalds's avatar
Linus Torvalds committed
152
153

	if (len < 0)
154
		return true;
Linus Torvalds's avatar
Linus Torvalds committed
155

156
	ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
Linus Torvalds's avatar
Linus Torvalds committed
157
	if (ptr < 0)
158
		return false;
Linus Torvalds's avatar
Linus Torvalds committed
159
160
161
162
163
	if (nexthdr == IPPROTO_ICMPV6) {
		u8 _type, *tp;
		tp = skb_header_pointer(skb,
			ptr+offsetof(struct icmp6hdr, icmp6_type),
			sizeof(_type), &_type);
164
		if (!tp || !(*tp & ICMPV6_INFOMSG_MASK))
165
			return true;
Linus Torvalds's avatar
Linus Torvalds committed
166
	}
167
	return false;
Linus Torvalds's avatar
Linus Torvalds committed
168
169
}

170
171
/*
 * Check the ICMP output rate limit
Linus Torvalds's avatar
Linus Torvalds committed
172
 */
173
174
static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
			       struct flowi6 *fl6)
Linus Torvalds's avatar
Linus Torvalds committed
175
{
176
	struct net *net = sock_net(sk);
177
	struct dst_entry *dst;
178
	bool res = false;
Linus Torvalds's avatar
Linus Torvalds committed
179
180
181

	/* Informational messages are not limited. */
	if (type & ICMPV6_INFOMSG_MASK)
182
		return true;
Linus Torvalds's avatar
Linus Torvalds committed
183
184
185

	/* Do not limit pmtu discovery, it would break it. */
	if (type == ICMPV6_PKT_TOOBIG)
186
		return true;
Linus Torvalds's avatar
Linus Torvalds committed
187

188
	/*
Linus Torvalds's avatar
Linus Torvalds committed
189
190
191
192
	 * Look up the output route.
	 * XXX: perhaps the expire for routing entries cloned by
	 * this lookup should be more aggressive (not longer than timeout).
	 */
193
	dst = ip6_route_output(net, sk, fl6);
Linus Torvalds's avatar
Linus Torvalds committed
194
	if (dst->error) {
195
		IP6_INC_STATS(net, ip6_dst_idev(dst),
196
			      IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds's avatar
Linus Torvalds committed
197
	} else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
198
		res = true;
Linus Torvalds's avatar
Linus Torvalds committed
199
200
	} else {
		struct rt6_info *rt = (struct rt6_info *)dst;
201
		int tmo = net->ipv6.sysctl.icmpv6_time;
Linus Torvalds's avatar
Linus Torvalds committed
202
203
204
205
206

		/* Give more bandwidth to wider prefixes. */
		if (rt->rt6i_dst.plen < 128)
			tmo >>= ((128 - rt->rt6i_dst.plen)>>5);

207
208
209
210
		if (icmp_global_allow()) {
			struct inet_peer *peer;

			peer = inet_getpeer_v6(net->ipv6.peers,
211
					       &fl6->daddr, 1);
212
213
214
215
			res = inet_peer_xrlim_allow(peer, tmo);
			if (peer)
				inet_putpeer(peer);
		}
Linus Torvalds's avatar
Linus Torvalds committed
216
217
218
219
220
221
222
223
	}
	dst_release(dst);
	return res;
}

/*
 *	an inline helper for the "simple" if statement below
 *	checks if parameter problem report is caused by an
224
 *	unrecognized IPv6 option that has the Option Type
Linus Torvalds's avatar
Linus Torvalds committed
225
226
227
 *	highest-order two bits set to 10
 */

228
static bool opt_unrec(struct sk_buff *skb, __u32 offset)
Linus Torvalds's avatar
Linus Torvalds committed
229
230
231
{
	u8 _optval, *op;

232
	offset += skb_network_offset(skb);
Linus Torvalds's avatar
Linus Torvalds committed
233
	op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
234
	if (!op)
235
		return true;
Linus Torvalds's avatar
Linus Torvalds committed
236
237
238
	return (*op & 0xC0) == 0x80;
}

239
240
int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
			       struct icmp6hdr *thdr, int len)
Linus Torvalds's avatar
Linus Torvalds committed
241
242
243
244
245
{
	struct sk_buff *skb;
	struct icmp6hdr *icmp6h;
	int err = 0;

246
	skb = skb_peek(&sk->sk_write_queue);
247
	if (!skb)
Linus Torvalds's avatar
Linus Torvalds committed
248
249
		goto out;

250
	icmp6h = icmp6_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
251
252
253
254
	memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
	icmp6h->icmp6_cksum = 0;

	if (skb_queue_len(&sk->sk_write_queue) == 1) {
255
		skb->csum = csum_partial(icmp6h,
Linus Torvalds's avatar
Linus Torvalds committed
256
					sizeof(struct icmp6hdr), skb->csum);
257
258
259
		icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
						      &fl6->daddr,
						      len, fl6->flowi6_proto,
Linus Torvalds's avatar
Linus Torvalds committed
260
261
						      skb->csum);
	} else {
262
		__wsum tmp_csum = 0;
Linus Torvalds's avatar
Linus Torvalds committed
263
264
265
266
267

		skb_queue_walk(&sk->sk_write_queue, skb) {
			tmp_csum = csum_add(tmp_csum, skb->csum);
		}

268
		tmp_csum = csum_partial(icmp6h,
Linus Torvalds's avatar
Linus Torvalds committed
269
					sizeof(struct icmp6hdr), tmp_csum);
270
271
272
		icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
						      &fl6->daddr,
						      len, fl6->flowi6_proto,
273
						      tmp_csum);
Linus Torvalds's avatar
Linus Torvalds committed
274
275
276
277
278
279
280
281
282
	}
	ip6_push_pending_frames(sk);
out:
	return err;
}

struct icmpv6_msg {
	struct sk_buff	*skb;
	int		offset;
283
	uint8_t		type;
Linus Torvalds's avatar
Linus Torvalds committed
284
285
286
287
288
289
};

static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
{
	struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
	struct sk_buff *org_skb = msg->skb;
290
	__wsum csum = 0;
Linus Torvalds's avatar
Linus Torvalds committed
291
292
293
294

	csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
				      to, len, csum);
	skb->csum = csum_block_add(skb->csum, csum, odd);
295
296
	if (!(msg->type & ICMPV6_INFOMSG_MASK))
		nf_ct_attach(skb, org_skb);
Linus Torvalds's avatar
Linus Torvalds committed
297
298
299
	return 0;
}

Amerigo Wang's avatar
Amerigo Wang committed
300
#if IS_ENABLED(CONFIG_IPV6_MIP6)
301
302
static void mip6_addr_swap(struct sk_buff *skb)
{
303
	struct ipv6hdr *iph = ipv6_hdr(skb);
304
305
306
307
308
309
310
311
	struct inet6_skb_parm *opt = IP6CB(skb);
	struct ipv6_destopt_hao *hao;
	struct in6_addr tmp;
	int off;

	if (opt->dsthao) {
		off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
		if (likely(off >= 0)) {
312
313
			hao = (struct ipv6_destopt_hao *)
					(skb_network_header(skb) + off);
Alexey Dobriyan's avatar
Alexey Dobriyan committed
314
315
316
			tmp = iph->saddr;
			iph->saddr = hao->addr;
			hao->addr = tmp;
317
318
319
320
321
322
323
		}
	}
}
#else
static inline void mip6_addr_swap(struct sk_buff *skb) {}
#endif

stephen hemminger's avatar
stephen hemminger committed
324
325
326
327
static struct dst_entry *icmpv6_route_lookup(struct net *net,
					     struct sk_buff *skb,
					     struct sock *sk,
					     struct flowi6 *fl6)
328
329
{
	struct dst_entry *dst, *dst2;
330
	struct flowi6 fl2;
331
332
	int err;

333
	err = ip6_dst_lookup(net, sk, &dst, fl6);
334
335
336
337
338
339
340
	if (err)
		return ERR_PTR(err);

	/*
	 * We won't send icmp if the destination is known
	 * anycast.
	 */
341
	if (ipv6_anycast_destination(dst, &fl6->daddr)) {
342
		net_dbg_ratelimited("icmp6_send: acast source\n");
343
344
345
346
347
348
349
		dst_release(dst);
		return ERR_PTR(-EINVAL);
	}

	/* No need to clone since we're just using its address. */
	dst2 = dst;

350
	dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0);
351
	if (!IS_ERR(dst)) {
352
353
		if (dst != dst2)
			return dst;
354
355
356
357
358
	} else {
		if (PTR_ERR(dst) == -EPERM)
			dst = NULL;
		else
			return dst;
359
360
	}

361
	err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6);
362
363
364
	if (err)
		goto relookup_failed;

365
	err = ip6_dst_lookup(net, sk, &dst2, &fl2);
366
367
368
	if (err)
		goto relookup_failed;

369
	dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP);
370
	if (!IS_ERR(dst2)) {
371
372
		dst_release(dst);
		dst = dst2;
373
374
375
376
377
378
379
	} else {
		err = PTR_ERR(dst2);
		if (err == -EPERM) {
			dst_release(dst);
			return dst2;
		} else
			goto relookup_failed;
380
381
382
383
384
385
386
387
	}

relookup_failed:
	if (dst)
		return dst;
	return ERR_PTR(err);
}

Linus Torvalds's avatar
Linus Torvalds committed
388
389
390
/*
 *	Send an ICMP message in response to a packet in error
 */
391
static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
Linus Torvalds's avatar
Linus Torvalds committed
392
{
393
	struct net *net = dev_net(skb->dev);
Linus Torvalds's avatar
Linus Torvalds committed
394
	struct inet6_dev *idev = NULL;
395
	struct ipv6hdr *hdr = ipv6_hdr(skb);
396
397
	struct sock *sk;
	struct ipv6_pinfo *np;
398
	const struct in6_addr *saddr = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
399
400
	struct dst_entry *dst;
	struct icmp6hdr tmp_hdr;
401
	struct flowi6 fl6;
Linus Torvalds's avatar
Linus Torvalds committed
402
	struct icmpv6_msg msg;
403
	struct sockcm_cookie sockc_unused = {0};
Linus Torvalds's avatar
Linus Torvalds committed
404
405
406
	int iif = 0;
	int addr_type = 0;
	int len;
407
	int hlimit;
Linus Torvalds's avatar
Linus Torvalds committed
408
	int err = 0;
409
	u32 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds's avatar
Linus Torvalds committed
410

411
	if ((u8 *)hdr < skb->head ||
412
	    (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb))
Linus Torvalds's avatar
Linus Torvalds committed
413
414
415
		return;

	/*
416
	 *	Make sure we respect the rules
Linus Torvalds's avatar
Linus Torvalds committed
417
	 *	i.e. RFC 1885 2.4(e)
418
	 *	Rule (e.1) is enforced by not using icmp6_send
Linus Torvalds's avatar
Linus Torvalds committed
419
420
421
422
	 *	in any code that processes icmp errors.
	 */
	addr_type = ipv6_addr_type(&hdr->daddr);

423
	if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) ||
424
	    ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr))
Linus Torvalds's avatar
Linus Torvalds committed
425
426
427
428
429
430
		saddr = &hdr->daddr;

	/*
	 *	Dest addr check
	 */

zhuyj's avatar
zhuyj committed
431
	if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) {
Linus Torvalds's avatar
Linus Torvalds committed
432
		if (type != ICMPV6_PKT_TOOBIG &&
433
434
		    !(type == ICMPV6_PARAMPROB &&
		      code == ICMPV6_UNK_OPTION &&
Linus Torvalds's avatar
Linus Torvalds committed
435
436
437
438
439
440
441
442
443
444
445
446
		      (opt_unrec(skb, info))))
			return;

		saddr = NULL;
	}

	addr_type = ipv6_addr_type(&hdr->saddr);

	/*
	 *	Source addr check
	 */

447
	if (__ipv6_addr_needs_scope_id(addr_type))
Linus Torvalds's avatar
Linus Torvalds committed
448
449
450
		iif = skb->dev->ifindex;

	/*
451
452
453
454
	 *	Must not send error if the source does not uniquely
	 *	identify a single node (RFC2463 Section 2.4).
	 *	We check unspecified / multicast addresses here,
	 *	and anycast addresses will be checked later.
Linus Torvalds's avatar
Linus Torvalds committed
455
456
	 */
	if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
457
458
		net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n",
				    &hdr->saddr, &hdr->daddr);
Linus Torvalds's avatar
Linus Torvalds committed
459
460
461
		return;
	}

462
	/*
Linus Torvalds's avatar
Linus Torvalds committed
463
464
465
	 *	Never answer to a ICMP packet.
	 */
	if (is_ineligible(skb)) {
466
467
		net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n",
				    &hdr->saddr, &hdr->daddr);
Linus Torvalds's avatar
Linus Torvalds committed
468
469
470
		return;
	}

471
472
	mip6_addr_swap(skb);

473
474
	memset(&fl6, 0, sizeof(fl6));
	fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan's avatar
Alexey Dobriyan committed
475
	fl6.daddr = hdr->saddr;
Linus Torvalds's avatar
Linus Torvalds committed
476
	if (saddr)
Alexey Dobriyan's avatar
Alexey Dobriyan committed
477
		fl6.saddr = *saddr;
478
	fl6.flowi6_mark = mark;
479
	fl6.flowi6_oif = iif;
480
481
	fl6.fl6_icmp_type = type;
	fl6.fl6_icmp_code = code;
482
	security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds's avatar
Linus Torvalds committed
483

484
	sk = icmpv6_xmit_lock(net);
485
	if (!sk)
486
		return;
487
	sk->sk_mark = mark;
488
	np = inet6_sk(sk);
489

490
	if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds's avatar
Linus Torvalds committed
491
492
493
494
495
496
497
		goto out;

	tmp_hdr.icmp6_type = type;
	tmp_hdr.icmp6_code = code;
	tmp_hdr.icmp6_cksum = 0;
	tmp_hdr.icmp6_pointer = htonl(info);

498
499
	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
		fl6.flowi6_oif = np->mcast_oif;
500
501
	else if (!fl6.flowi6_oif)
		fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds's avatar
Linus Torvalds committed
502

503
504
505
	if (!fl6.flowi6_oif)
		fl6.flowi6_oif = l3mdev_master_ifindex(skb->dev);

506
	dst = icmpv6_route_lookup(net, skb, sk, &fl6);
507
	if (IS_ERR(dst))
Linus Torvalds's avatar
Linus Torvalds committed
508
		goto out;
509

510
	hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
Linus Torvalds's avatar
Linus Torvalds committed
511
512

	msg.skb = skb;
513
	msg.offset = skb_network_offset(skb);
514
	msg.type = type;
Linus Torvalds's avatar
Linus Torvalds committed
515
516

	len = skb->len - msg.offset;
517
	len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
Linus Torvalds's avatar
Linus Torvalds committed
518
	if (len < 0) {
519
520
		net_dbg_ratelimited("icmp: len problem [%pI6c > %pI6c]\n",
				    &hdr->saddr, &hdr->daddr);
Linus Torvalds's avatar
Linus Torvalds committed
521
522
523
		goto out_dst_release;
	}

Eric Dumazet's avatar
Eric Dumazet committed
524
525
	rcu_read_lock();
	idev = __in6_dev_get(skb->dev);
Linus Torvalds's avatar
Linus Torvalds committed
526
527
528

	err = ip6_append_data(sk, icmpv6_getfrag, &msg,
			      len + sizeof(struct icmp6hdr),
529
			      sizeof(struct icmp6hdr), hlimit,
530
			      np->tclass, NULL, &fl6, (struct rt6_info *)dst,
531
			      MSG_DONTWAIT, np->dontfrag, &sockc_unused);
Linus Torvalds's avatar
Linus Torvalds committed
532
	if (err) {
533
		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds's avatar
Linus Torvalds committed
534
		ip6_flush_pending_frames(sk);
Eric Dumazet's avatar
Eric Dumazet committed
535
536
537
	} else {
		err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
						 len + sizeof(struct icmp6hdr));
Linus Torvalds's avatar
Linus Torvalds committed
538
	}
Eric Dumazet's avatar
Eric Dumazet committed
539
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
540
541
542
out_dst_release:
	dst_release(dst);
out:
543
	icmpv6_xmit_unlock(sk);
Linus Torvalds's avatar
Linus Torvalds committed
544
}
545
546
547
548
549
550
551
552

/* Slightly more convenient version of icmp6_send.
 */
void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
{
	icmp6_send(skb, ICMPV6_PARAMPROB, code, pos);
	kfree_skb(skb);
}
553

Linus Torvalds's avatar
Linus Torvalds committed
554
555
static void icmpv6_echo_reply(struct sk_buff *skb)
{
556
	struct net *net = dev_net(skb->dev);
557
	struct sock *sk;
Linus Torvalds's avatar
Linus Torvalds committed
558
	struct inet6_dev *idev;
559
	struct ipv6_pinfo *np;
560
	const struct in6_addr *saddr = NULL;
561
	struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
562
	struct icmp6hdr tmp_hdr;
563
	struct flowi6 fl6;
Linus Torvalds's avatar
Linus Torvalds committed
564
565
566
567
	struct icmpv6_msg msg;
	struct dst_entry *dst;
	int err = 0;
	int hlimit;
568
	u8 tclass;
569
	u32 mark = IP6_REPLY_MARK(net, skb->mark);
570
	struct sockcm_cookie sockc_unused = {0};
Linus Torvalds's avatar
Linus Torvalds committed
571

572
	saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds's avatar
Linus Torvalds committed
573

574
	if (!ipv6_unicast_destination(skb) &&
575
	    !(net->ipv6.sysctl.anycast_src_echo_reply &&
576
	      ipv6_anycast_destination(skb_dst(skb), saddr)))
Linus Torvalds's avatar
Linus Torvalds committed
577
578
579
580
581
		saddr = NULL;

	memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
	tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;

582
583
	memset(&fl6, 0, sizeof(fl6));
	fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan's avatar
Alexey Dobriyan committed
584
	fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds's avatar
Linus Torvalds committed
585
	if (saddr)
Alexey Dobriyan's avatar
Alexey Dobriyan committed
586
		fl6.saddr = *saddr;
587
	fl6.flowi6_oif = l3mdev_fib_oif(skb->dev);
588
	fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
589
	fl6.flowi6_mark = mark;
590
	security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds's avatar
Linus Torvalds committed
591

592
	sk = icmpv6_xmit_lock(net);
593
	if (!sk)
594
		return;
595
	sk->sk_mark = mark;
596
	np = inet6_sk(sk);
597

598
599
	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
		fl6.flowi6_oif = np->mcast_oif;
600
601
	else if (!fl6.flowi6_oif)
		fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds's avatar
Linus Torvalds committed
602

603
	err = ip6_dst_lookup(net, sk, &dst, &fl6);
Linus Torvalds's avatar
Linus Torvalds committed
604
605
	if (err)
		goto out;
606
	dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
607
	if (IS_ERR(dst))
608
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
609

610
	hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
Linus Torvalds's avatar
Linus Torvalds committed
611

Eric Dumazet's avatar
Eric Dumazet committed
612
	idev = __in6_dev_get(skb->dev);
Linus Torvalds's avatar
Linus Torvalds committed
613
614
615

	msg.skb = skb;
	msg.offset = 0;
616
	msg.type = ICMPV6_ECHO_REPLY;
Linus Torvalds's avatar
Linus Torvalds committed
617

618
	tclass = ipv6_get_dsfield(ipv6_hdr(skb));
Linus Torvalds's avatar
Linus Torvalds committed
619
	err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
620
				sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl6,
621
				(struct rt6_info *)dst, MSG_DONTWAIT,
622
				np->dontfrag, &sockc_unused);
Linus Torvalds's avatar
Linus Torvalds committed
623
624

	if (err) {
625
		__ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds's avatar
Linus Torvalds committed
626
		ip6_flush_pending_frames(sk);
Eric Dumazet's avatar
Eric Dumazet committed
627
628
629
	} else {
		err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
						 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds's avatar
Linus Torvalds committed
630
631
	}
	dst_release(dst);
632
out:
633
	icmpv6_xmit_unlock(sk);
Linus Torvalds's avatar
Linus Torvalds committed
634
635
}

636
void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds's avatar
Linus Torvalds committed
637
{
638
	const struct inet6_protocol *ipprot;
Linus Torvalds's avatar
Linus Torvalds committed
639
	int inner_offset;
640
	__be16 frag_off;
641
	u8 nexthdr;
642
	struct net *net = dev_net(skb->dev);
Linus Torvalds's avatar
Linus Torvalds committed
643
644

	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
645
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
646
647
648
649

	nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
	if (ipv6_ext_hdr(nexthdr)) {
		/* now skip over extension headers */
650
651
		inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
						&nexthdr, &frag_off);
652
		if (inner_offset < 0)
653
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
654
655
656
657
658
659
	} else {
		inner_offset = sizeof(struct ipv6hdr);
	}

	/* Checkin header including 8 bytes of inner protocol header. */
	if (!pskb_may_pull(skb, inner_offset+8))
660
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
661
662
663
664
665
666
667
668

	/* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
	   Without this we will not able f.e. to make source routed
	   pmtu discovery.
	   Corresponding argument (opt) to notifiers is already added.
	   --ANK (980726)
	 */

669
	ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds's avatar
Linus Torvalds committed
670
671
672
	if (ipprot && ipprot->err_handler)
		ipprot->err_handler(skb, NULL, type, code, inner_offset, info);

673
	raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
674
675
676
	return;

out:
677
	__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
Linus Torvalds's avatar
Linus Torvalds committed
678
}
679

Linus Torvalds's avatar
Linus Torvalds committed
680
681
682
683
/*
 *	Handle icmp messages
 */

684
static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
685
686
687
{
	struct net_device *dev = skb->dev;
	struct inet6_dev *idev = __in6_dev_get(dev);
688
	const struct in6_addr *saddr, *daddr;
Linus Torvalds's avatar
Linus Torvalds committed
689
	struct icmp6hdr *hdr;
690
	u8 type;
691
	bool success = false;
Linus Torvalds's avatar
Linus Torvalds committed
692

693
	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
694
		struct sec_path *sp = skb_sec_path(skb);
695
696
		int nh;

697
		if (!(sp && sp->xvec[sp->len - 1]->props.flags &
698
699
700
				 XFRM_STATE_ICMP))
			goto drop_no_count;

701
		if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
702
703
704
705
706
707
708
709
710
711
712
			goto drop_no_count;

		nh = skb_network_offset(skb);
		skb_set_network_header(skb, sizeof(*hdr));

		if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
			goto drop_no_count;

		skb_set_network_header(skb, nh);
	}

713
	__ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds's avatar
Linus Torvalds committed
714

715
716
	saddr = &ipv6_hdr(skb)->saddr;
	daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds's avatar
Linus Torvalds committed
717

718
	if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
719
720
		net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
				    saddr, daddr);
721
		goto csum_error;
Linus Torvalds's avatar
Linus Torvalds committed
722
723
	}

724
725
	if (!pskb_pull(skb, sizeof(*hdr)))
		goto discard_it;
Linus Torvalds's avatar
Linus Torvalds committed
726

727
	hdr = icmp6_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
728
729
730

	type = hdr->icmp6_type;

731
	ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type);
Linus Torvalds's avatar
Linus Torvalds committed
732
733
734
735
736
737
738

	switch (type) {
	case ICMPV6_ECHO_REQUEST:
		icmpv6_echo_reply(skb);
		break;

	case ICMPV6_ECHO_REPLY:
739
		success = ping_rcv(skb);
Linus Torvalds's avatar
Linus Torvalds committed
740
741
742
743
744
745
746
747
748
749
		break;

	case ICMPV6_PKT_TOOBIG:
		/* BUGGG_FUTURE: if packet contains rthdr, we cannot update
		   standard destination cache. Seems, only "advanced"
		   destination cache will allow to solve this problem
		   --ANK (980726)
		 */
		if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
			goto discard_it;
750
		hdr = icmp6_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792

		/*
		 *	Drop through to notify
		 */

	case ICMPV6_DEST_UNREACH:
	case ICMPV6_TIME_EXCEED:
	case ICMPV6_PARAMPROB:
		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
		break;

	case NDISC_ROUTER_SOLICITATION:
	case NDISC_ROUTER_ADVERTISEMENT:
	case NDISC_NEIGHBOUR_SOLICITATION:
	case NDISC_NEIGHBOUR_ADVERTISEMENT:
	case NDISC_REDIRECT:
		ndisc_rcv(skb);
		break;

	case ICMPV6_MGM_QUERY:
		igmp6_event_query(skb);
		break;

	case ICMPV6_MGM_REPORT:
		igmp6_event_report(skb);
		break;

	case ICMPV6_MGM_REDUCTION:
	case ICMPV6_NI_QUERY:
	case ICMPV6_NI_REPLY:
	case ICMPV6_MLD2_REPORT:
	case ICMPV6_DHAAD_REQUEST:
	case ICMPV6_DHAAD_REPLY:
	case ICMPV6_MOBILE_PREFIX_SOL:
	case ICMPV6_MOBILE_PREFIX_ADV:
		break;

	default:
		/* informational */
		if (type & ICMPV6_INFOMSG_MASK)
			break;

793
794
		net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
				    saddr, daddr);
795

796
797
798
		/*
		 * error of unknown type.
		 * must pass to upper level
Linus Torvalds's avatar
Linus Torvalds committed
799
800
801
		 */

		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
802
803
	}

804
805
806
807
808
809
810
811
	/* until the v6 path can be better sorted assume failure and
	 * preserve the status quo behaviour for the rest of the paths to here
	 */
	if (success)
		consume_skb(skb);
	else
		kfree_skb(skb);

Linus Torvalds's avatar
Linus Torvalds committed
812
813
	return 0;

814
csum_error:
815
	__ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds's avatar
Linus Torvalds committed
816
discard_it:
817
	__ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS);
818
drop_no_count:
Linus Torvalds's avatar
Linus Torvalds committed
819
820
821
822
	kfree_skb(skb);
	return 0;
}

823
void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
824
825
826
827
828
		      u8 type,
		      const struct in6_addr *saddr,
		      const struct in6_addr *daddr,
		      int oif)
{
829
	memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan's avatar
Alexey Dobriyan committed
830
831
	fl6->saddr = *saddr;
	fl6->daddr = *daddr;
832
	fl6->flowi6_proto	= IPPROTO_ICMPV6;
833
834
	fl6->fl6_icmp_type	= type;
	fl6->fl6_icmp_code	= 0;
835
836
	fl6->flowi6_oif		= oif;
	security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
837
838
}

839
static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds's avatar
Linus Torvalds committed
840
841
842
843
{
	struct sock *sk;
	int err, i, j;

844
845
	net->ipv6.icmp_sk =
		kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
846
	if (!net->ipv6.icmp_sk)
847
848
		return -ENOMEM;

849
	for_each_possible_cpu(i) {
850
851
		err = inet_ctl_sock_create(&sk, PF_INET6,
					   SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds's avatar
Linus Torvalds committed
852
		if (err < 0) {
853
			pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds's avatar
Linus Torvalds committed
854
855
856
857
			       err);
			goto fail;
		}

858
		net->ipv6.icmp_sk[i] = sk;
859

Linus Torvalds's avatar
Linus Torvalds committed
860
861
862
		/* Enough space for 2 64K ICMP packets, including
		 * sk_buff struct overhead.
		 */
Eric Dumazet's avatar
Eric Dumazet committed
863
		sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds's avatar
Linus Torvalds committed
864
865
866
867
	}
	return 0;

 fail:
868
	for (j = 0; j < i; j++)
869
		inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]);
870
	kfree(net->ipv6.icmp_sk);
Linus Torvalds's avatar
Linus Torvalds committed
871
872
873
	return err;
}

874
static void __net_exit icmpv6_sk_exit(struct net *net)
Linus Torvalds's avatar
Linus Torvalds committed
875
876
877
{
	int i;

878
	for_each_possible_cpu(i) {
879
		inet_ctl_sock_destroy(net->ipv6.icmp_sk[i]);
Linus Torvalds's avatar
Linus Torvalds committed
880
	}
881
882
883
	kfree(net->ipv6.icmp_sk);
}

884
static struct pernet_operations icmpv6_sk_ops = {
885
886
	.init = icmpv6_sk_init,
	.exit = icmpv6_sk_exit,
887
888
889
890
891
892
893
894
895
896
897
898
899
};

int __init icmpv6_init(void)
{
	int err;

	err = register_pernet_subsys(&icmpv6_sk_ops);
	if (err < 0)
		return err;

	err = -EAGAIN;
	if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
		goto fail;
900
901
902
903

	err = inet6_register_icmp_sender(icmp6_send);
	if (err)
		goto sender_reg_err;
904
905
	return 0;

906
907
sender_reg_err:
	inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
908
fail:
909
	pr_err("Failed to register ICMP6 protocol\n");
910
911
912
913
	unregister_pernet_subsys(&icmpv6_sk_ops);
	return err;
}

914
void icmpv6_cleanup(void)
915
{
916
	inet6_unregister_icmp_sender(icmp6_send);
917
	unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds's avatar
Linus Torvalds committed
918
919
920
	inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
}

921

922
static const struct icmp6_err {
Linus Torvalds's avatar
Linus Torvalds committed
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
	int err;
	int fatal;
} tab_unreach[] = {
	{	/* NOROUTE */
		.err	= ENETUNREACH,
		.fatal	= 0,
	},
	{	/* ADM_PROHIBITED */
		.err	= EACCES,
		.fatal	= 1,
	},
	{	/* Was NOT_NEIGHBOUR, now reserved */
		.err	= EHOSTUNREACH,
		.fatal	= 0,
	},
	{	/* ADDR_UNREACH	*/
		.err	= EHOSTUNREACH,
		.fatal	= 0,
	},
	{	/* PORT_UNREACH	*/
		.err	= ECONNREFUSED,
		.fatal	= 1,
	},
946
947
948
949
950
951
952
953
	{	/* POLICY_FAIL */
		.err	= EACCES,
		.fatal	= 1,
	},
	{	/* REJECT_ROUTE	*/
		.err	= EACCES,
		.fatal	= 1,
	},
Linus Torvalds's avatar
Linus Torvalds committed
954
955
};

956
int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds's avatar
Linus Torvalds committed
957
958
959
960
961
962
963
964
{
	int fatal = 0;

	*err = EPROTO;

	switch (type) {
	case ICMPV6_DEST_UNREACH:
		fatal = 1;
965
		if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds's avatar
Linus Torvalds committed
966
967
968
969
970
971
972
973
			*err  = tab_unreach[code].err;
			fatal = tab_unreach[code].fatal;
		}
		break;

	case ICMPV6_PKT_TOOBIG:
		*err = EMSGSIZE;
		break;
974

Linus Torvalds's avatar
Linus Torvalds committed
975
976
977
978
979
980
981
982
	case ICMPV6_PARAMPROB:
		*err = EPROTO;
		fatal = 1;
		break;

	case ICMPV6_TIME_EXCEED:
		*err = EHOSTUNREACH;
		break;
983
	}
Linus Torvalds's avatar
Linus Torvalds committed
984
985
986

	return fatal;
}
987
988
EXPORT_SYMBOL(icmpv6_err_convert);

Linus Torvalds's avatar
Linus Torvalds committed
989
#ifdef CONFIG_SYSCTL
stephen hemminger's avatar
stephen hemminger committed
990
static struct ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds's avatar
Linus Torvalds committed
991
992
	{
		.procname	= "ratelimit",
993
		.data		= &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds's avatar
Linus Torvalds committed
994
995
		.maxlen		= sizeof(int),
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
996
		.proc_handler	= proc_dointvec_ms_jiffies,
Linus Torvalds's avatar
Linus Torvalds committed
997
	},
998
	{ },
Linus Torvalds's avatar
Linus Torvalds committed
999
};
1000

1001
struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
1002
1003
1004
1005
1006
1007
{
	struct ctl_table *table;

	table = kmemdup(ipv6_icmp_table_template,
			sizeof(ipv6_icmp_table_template),
			GFP_KERNEL);
1008

1009
	if (table)
1010
1011
		table[0].data = &net->ipv6.sysctl.icmpv6_time;

1012
1013
	return table;
}
Linus Torvalds's avatar
Linus Torvalds committed
1014
#endif