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>
Linus Torvalds's avatar
Linus Torvalds committed
71
72
73
74
75
76
77
78
79
80

#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.
 */
81
82
83
84
static inline struct sock *icmpv6_sk(struct net *net)
{
	return net->ipv6.icmp_sk[smp_processor_id()];
}
Linus Torvalds's avatar
Linus Torvalds committed
85

86
87
88
static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
		       u8 type, u8 code, int offset, __be32 info)
{
89
90
	/* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
	struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
91
92
93
94
95
	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)
96
		ip6_redirect(skb, net, skb->dev->ifindex, 0);
97
98
99
100

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

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

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

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

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

117
	sk = icmpv6_sk(net);
118
	if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
Linus Torvalds's avatar
Linus Torvalds committed
119
120
121
122
123
		/* 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();
124
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
125
	}
126
	return sk;
Linus Torvalds's avatar
Linus Torvalds committed
127
128
}

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

/*
 * 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)
 */

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

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

155
	ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
Linus Torvalds's avatar
Linus Torvalds committed
156
	if (ptr < 0)
157
		return false;
Linus Torvalds's avatar
Linus Torvalds committed
158
159
160
161
162
163
164
	if (nexthdr == IPPROTO_ICMPV6) {
		u8 _type, *tp;
		tp = skb_header_pointer(skb,
			ptr+offsetof(struct icmp6hdr, icmp6_type),
			sizeof(_type), &_type);
		if (tp == NULL ||
		    !(*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
211
212
213
214
215
		if (icmp_global_allow()) {
			struct inet_peer *peer;

			peer = inet_getpeer_v6(net->ipv6.peers,
					       &rt->rt6i_dst.addr, 1);
			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
234
	op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
	if (op == NULL)
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
247
	skb = skb_peek(&sk->sk_write_queue);
	if (skb == NULL)
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(sk, &dst, fl6);
334
335
336
337
338
339
340
341
	if (err)
		return ERR_PTR(err);

	/*
	 * We won't send icmp if the destination is known
	 * anycast.
	 */
	if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) {
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
365
366
367
368
	if (err)
		goto relookup_failed;

	err = ip6_dst_lookup(sk, &dst2, &fl2);
	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
403
404
405
	struct icmpv6_msg msg;
	int iif = 0;
	int addr_type = 0;
	int len;
406
	int hlimit;
Linus Torvalds's avatar
Linus Torvalds committed
407
	int err = 0;
408
	u32 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds's avatar
Linus Torvalds committed
409

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

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

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

	/*
	 *	Dest addr check
	 */

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

		saddr = NULL;
	}

	addr_type = ipv6_addr_type(&hdr->saddr);

	/*
	 *	Source addr check
	 */

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

	/*
450
451
452
453
	 *	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
454
455
	 */
	if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
456
		net_dbg_ratelimited("icmp6_send: addr_any/mcast source\n");
Linus Torvalds's avatar
Linus Torvalds committed
457
458
459
		return;
	}

460
	/*
Linus Torvalds's avatar
Linus Torvalds committed
461
462
463
	 *	Never answer to a ICMP packet.
	 */
	if (is_ineligible(skb)) {
464
		net_dbg_ratelimited("icmp6_send: no reply to icmp error\n");
Linus Torvalds's avatar
Linus Torvalds committed
465
466
467
		return;
	}

468
469
	mip6_addr_swap(skb);

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

481
482
	sk = icmpv6_xmit_lock(net);
	if (sk == NULL)
483
		return;
484
	sk->sk_mark = mark;
485
	np = inet6_sk(sk);
486

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

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

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

500
	dst = icmpv6_route_lookup(net, skb, sk, &fl6);
501
	if (IS_ERR(dst))
Linus Torvalds's avatar
Linus Torvalds committed
502
		goto out;
503

504
	hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
Linus Torvalds's avatar
Linus Torvalds committed
505
506

	msg.skb = skb;
507
	msg.offset = skb_network_offset(skb);
508
	msg.type = type;
Linus Torvalds's avatar
Linus Torvalds committed
509
510

	len = skb->len - msg.offset;
511
	len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
Linus Torvalds's avatar
Linus Torvalds committed
512
	if (len < 0) {
513
		net_dbg_ratelimited("icmp: len problem\n");
Linus Torvalds's avatar
Linus Torvalds committed
514
515
516
		goto out_dst_release;
	}

Eric Dumazet's avatar
Eric Dumazet committed
517
518
	rcu_read_lock();
	idev = __in6_dev_get(skb->dev);
Linus Torvalds's avatar
Linus Torvalds committed
519
520
521

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

/* 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);
}
546

Linus Torvalds's avatar
Linus Torvalds committed
547
548
static void icmpv6_echo_reply(struct sk_buff *skb)
{
549
	struct net *net = dev_net(skb->dev);
550
	struct sock *sk;
Linus Torvalds's avatar
Linus Torvalds committed
551
	struct inet6_dev *idev;
552
	struct ipv6_pinfo *np;
553
	const struct in6_addr *saddr = NULL;
554
	struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
555
	struct icmp6hdr tmp_hdr;
556
	struct flowi6 fl6;
Linus Torvalds's avatar
Linus Torvalds committed
557
558
559
560
	struct icmpv6_msg msg;
	struct dst_entry *dst;
	int err = 0;
	int hlimit;
561
	u8 tclass;
562
	u32 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds's avatar
Linus Torvalds committed
563

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

566
	if (!ipv6_unicast_destination(skb) &&
567
	    !(net->ipv6.sysctl.anycast_src_echo_reply &&
568
	      ipv6_anycast_destination(skb)))
Linus Torvalds's avatar
Linus Torvalds committed
569
570
571
572
573
		saddr = NULL;

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

574
575
	memset(&fl6, 0, sizeof(fl6));
	fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan's avatar
Alexey Dobriyan committed
576
	fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds's avatar
Linus Torvalds committed
577
	if (saddr)
Alexey Dobriyan's avatar
Alexey Dobriyan committed
578
		fl6.saddr = *saddr;
579
	fl6.flowi6_oif = skb->dev->ifindex;
580
	fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
581
	fl6.flowi6_mark = mark;
582
	security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds's avatar
Linus Torvalds committed
583

584
585
	sk = icmpv6_xmit_lock(net);
	if (sk == NULL)
586
		return;
587
	sk->sk_mark = mark;
588
	np = inet6_sk(sk);
589

590
591
	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
		fl6.flowi6_oif = np->mcast_oif;
592
593
	else if (!fl6.flowi6_oif)
		fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds's avatar
Linus Torvalds committed
594

595
	err = ip6_dst_lookup(sk, &dst, &fl6);
Linus Torvalds's avatar
Linus Torvalds committed
596
597
	if (err)
		goto out;
598
	dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
599
	if (IS_ERR(dst))
600
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
601

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

Eric Dumazet's avatar
Eric Dumazet committed
604
	idev = __in6_dev_get(skb->dev);
Linus Torvalds's avatar
Linus Torvalds committed
605
606
607

	msg.skb = skb;
	msg.offset = 0;
608
	msg.type = ICMPV6_ECHO_REPLY;
Linus Torvalds's avatar
Linus Torvalds committed
609

610
	tclass = ipv6_get_dsfield(ipv6_hdr(skb));
Linus Torvalds's avatar
Linus Torvalds committed
611
	err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
612
				sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl6,
613
				(struct rt6_info *)dst, MSG_DONTWAIT,
614
				np->dontfrag);
Linus Torvalds's avatar
Linus Torvalds committed
615
616

	if (err) {
Eric Dumazet's avatar
Eric Dumazet committed
617
		ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds's avatar
Linus Torvalds committed
618
		ip6_flush_pending_frames(sk);
Eric Dumazet's avatar
Eric Dumazet committed
619
620
621
	} else {
		err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
						 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds's avatar
Linus Torvalds committed
622
623
	}
	dst_release(dst);
624
out:
625
	icmpv6_xmit_unlock(sk);
Linus Torvalds's avatar
Linus Torvalds committed
626
627
}

628
void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds's avatar
Linus Torvalds committed
629
{
630
	const struct inet6_protocol *ipprot;
Linus Torvalds's avatar
Linus Torvalds committed
631
	int inner_offset;
632
	__be16 frag_off;
633
	u8 nexthdr;
634
	struct net *net = dev_net(skb->dev);
Linus Torvalds's avatar
Linus Torvalds committed
635
636

	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
637
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
638
639
640
641

	nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
	if (ipv6_ext_hdr(nexthdr)) {
		/* now skip over extension headers */
642
643
		inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
						&nexthdr, &frag_off);
644
		if (inner_offset < 0)
645
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
646
647
648
649
650
651
	} else {
		inner_offset = sizeof(struct ipv6hdr);
	}

	/* Checkin header including 8 bytes of inner protocol header. */
	if (!pskb_may_pull(skb, inner_offset+8))
652
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
653
654
655
656
657
658
659
660

	/* 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)
	 */

661
	ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds's avatar
Linus Torvalds committed
662
663
664
	if (ipprot && ipprot->err_handler)
		ipprot->err_handler(skb, NULL, type, code, inner_offset, info);

665
	raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
666
667
668
669
	return;

out:
	ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
Linus Torvalds's avatar
Linus Torvalds committed
670
}
671

Linus Torvalds's avatar
Linus Torvalds committed
672
673
674
675
/*
 *	Handle icmp messages
 */

676
static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
677
678
679
{
	struct net_device *dev = skb->dev;
	struct inet6_dev *idev = __in6_dev_get(dev);
680
	const struct in6_addr *saddr, *daddr;
Linus Torvalds's avatar
Linus Torvalds committed
681
	struct icmp6hdr *hdr;
682
	u8 type;
683
	bool success = false;
Linus Torvalds's avatar
Linus Torvalds committed
684

685
	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
686
		struct sec_path *sp = skb_sec_path(skb);
687
688
		int nh;

689
		if (!(sp && sp->xvec[sp->len - 1]->props.flags &
690
691
692
				 XFRM_STATE_ICMP))
			goto drop_no_count;

693
		if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
694
695
696
697
698
699
700
701
702
703
704
			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);
	}

705
	ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds's avatar
Linus Torvalds committed
706

707
708
	saddr = &ipv6_hdr(skb)->saddr;
	daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds's avatar
Linus Torvalds committed
709

710
	if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
711
712
		net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
				    saddr, daddr);
713
		goto csum_error;
Linus Torvalds's avatar
Linus Torvalds committed
714
715
	}

716
717
	if (!pskb_pull(skb, sizeof(*hdr)))
		goto discard_it;
Linus Torvalds's avatar
Linus Torvalds committed
718

719
	hdr = icmp6_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
720
721
722

	type = hdr->icmp6_type;

723
	ICMP6MSGIN_INC_STATS_BH(dev_net(dev), idev, type);
Linus Torvalds's avatar
Linus Torvalds committed
724
725
726
727
728
729
730

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

	case ICMPV6_ECHO_REPLY:
731
		success = ping_rcv(skb);
Linus Torvalds's avatar
Linus Torvalds committed
732
733
734
735
736
737
738
739
740
741
		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;
742
		hdr = icmp6_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
743
744
745
746
747
748
749
750
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

		/*
		 *	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;

785
		net_dbg_ratelimited("icmpv6: msg of unknown type\n");
786

787
788
789
		/*
		 * error of unknown type.
		 * must pass to upper level
Linus Torvalds's avatar
Linus Torvalds committed
790
791
792
		 */

		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
793
794
	}

795
796
797
798
799
800
801
802
	/* 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
803
804
	return 0;

805
806
csum_error:
	ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds's avatar
Linus Torvalds committed
807
discard_it:
808
	ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INERRORS);
809
drop_no_count:
Linus Torvalds's avatar
Linus Torvalds committed
810
811
812
813
	kfree_skb(skb);
	return 0;
}

814
void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
815
816
817
818
819
		      u8 type,
		      const struct in6_addr *saddr,
		      const struct in6_addr *daddr,
		      int oif)
{
820
	memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan's avatar
Alexey Dobriyan committed
821
822
	fl6->saddr = *saddr;
	fl6->daddr = *daddr;
823
	fl6->flowi6_proto	= IPPROTO_ICMPV6;
824
825
	fl6->fl6_icmp_type	= type;
	fl6->fl6_icmp_code	= 0;
826
827
	fl6->flowi6_oif		= oif;
	security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
828
829
}

830
/*
831
 * Special lock-class for __icmpv6_sk:
832
833
834
 */
static struct lock_class_key icmpv6_socket_sk_dst_lock_key;

835
static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds's avatar
Linus Torvalds committed
836
837
838
839
{
	struct sock *sk;
	int err, i, j;

840
841
842
	net->ipv6.icmp_sk =
		kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
	if (net->ipv6.icmp_sk == NULL)
843
844
		return -ENOMEM;

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

854
		net->ipv6.icmp_sk[i] = sk;
855

856
857
858
		/*
		 * Split off their lock-class, because sk->sk_dst_lock
		 * gets used from softirqs, which is safe for
859
		 * __icmpv6_sk (because those never get directly used
860
861
862
863
		 * via userspace syscalls), but unsafe for normal sockets.
		 */
		lockdep_set_class(&sk->sk_dst_lock,
				  &icmpv6_socket_sk_dst_lock_key);
Linus Torvalds's avatar
Linus Torvalds committed
864
865
866
867

		/* Enough space for 2 64K ICMP packets, including
		 * sk_buff struct overhead.
		 */
Eric Dumazet's avatar
Eric Dumazet committed
868
		sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds's avatar
Linus Torvalds committed
869
870
871
872
	}
	return 0;

 fail:
873
	for (j = 0; j < i; j++)
874
		inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]);
875
	kfree(net->ipv6.icmp_sk);
Linus Torvalds's avatar
Linus Torvalds committed
876
877
878
	return err;
}

879
static void __net_exit icmpv6_sk_exit(struct net *net)
Linus Torvalds's avatar
Linus Torvalds committed
880
881
882
{
	int i;

883
	for_each_possible_cpu(i) {
884
		inet_ctl_sock_destroy(net->ipv6.icmp_sk[i]);
Linus Torvalds's avatar
Linus Torvalds committed
885
	}
886
887
888
	kfree(net->ipv6.icmp_sk);
}

889
static struct pernet_operations icmpv6_sk_ops = {
890
891
	.init = icmpv6_sk_init,
	.exit = icmpv6_sk_exit,
892
893
894
895
896
897
898
899
900
901
902
903
904
};

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;
905
906
907
908

	err = inet6_register_icmp_sender(icmp6_send);
	if (err)
		goto sender_reg_err;
909
910
	return 0;

911
912
sender_reg_err:
	inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
913
fail:
914
	pr_err("Failed to register ICMP6 protocol\n");
915
916
917
918
	unregister_pernet_subsys(&icmpv6_sk_ops);
	return err;
}

919
void icmpv6_cleanup(void)
920
{
921
	inet6_unregister_icmp_sender(icmp6_send);
922
	unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds's avatar
Linus Torvalds committed
923
924
925
	inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
}

926

927
static const struct icmp6_err {
Linus Torvalds's avatar
Linus Torvalds committed
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
	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,
	},
951
952
953
954
955
956
957
958
	{	/* POLICY_FAIL */
		.err	= EACCES,
		.fatal	= 1,
	},
	{	/* REJECT_ROUTE	*/
		.err	= EACCES,
		.fatal	= 1,
	},
Linus Torvalds's avatar
Linus Torvalds committed
959
960
};

961
int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds's avatar
Linus Torvalds committed
962
963
964
965
966
967
968
969
{
	int fatal = 0;

	*err = EPROTO;

	switch (type) {
	case ICMPV6_DEST_UNREACH:
		fatal = 1;
970
		if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds's avatar
Linus Torvalds committed
971
972
973
974
975
976
977
978
			*err  = tab_unreach[code].err;
			fatal = tab_unreach[code].fatal;
		}
		break;

	case ICMPV6_PKT_TOOBIG:
		*err = EMSGSIZE;
		break;
979

Linus Torvalds's avatar
Linus Torvalds committed
980
981
982
983
984
985
986
987
	case ICMPV6_PARAMPROB:
		*err = EPROTO;
		fatal = 1;
		break;

	case ICMPV6_TIME_EXCEED:
		*err = EHOSTUNREACH;
		break;
988
	}
Linus Torvalds's avatar
Linus Torvalds committed
989
990
991

	return fatal;
}
992
993
EXPORT_SYMBOL(icmpv6_err_convert);

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

1006
struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
1007
1008
1009
1010
1011
1012
{
	struct ctl_table *table;

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

1014
	if (table)
1015
1016
		table[0].data = &net->ipv6.sysctl.icmpv6_time;

1017
1018
	return table;
}
Linus Torvalds's avatar
Linus Torvalds committed
1019
#endif