blob: b4ff0a42b8c70248faf1b7298c1bec2cc79368ee [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Internet Control Message Protocol (ICMPv6)
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Based on net/ipv4/icmp.c
9 *
10 * RFC 1885
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18/*
19 * Changes:
20 *
21 * Andi Kleen : exception handling
22 * Andi Kleen add rate limits. never reply to a icmp.
23 * add more length checks and other fixes.
24 * yoshfuji : ensure to sent parameter problem for
25 * fragments.
26 * YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit.
27 * Randy Dunlap and
28 * YOSHIFUJI Hideaki @USAGI: Per-interface statistics support
29 * Kazunori MIYAZAWA @USAGI: change output process to use ip6_append_data
30 */
31
Joe Perchesf3213832012-05-15 14:11:53 +000032#define pr_fmt(fmt) "IPv6: " fmt
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
35#include <linux/errno.h>
36#include <linux/types.h>
37#include <linux/socket.h>
38#include <linux/in.h>
39#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/sockios.h>
41#include <linux/net.h>
42#include <linux/skbuff.h>
43#include <linux/init.h>
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -080044#include <linux/netfilter.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090045#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_SYSCTL
48#include <linux/sysctl.h>
49#endif
50
51#include <linux/inet.h>
52#include <linux/netdevice.h>
53#include <linux/icmpv6.h>
54
55#include <net/ip.h>
56#include <net/sock.h>
57
58#include <net/ipv6.h>
59#include <net/ip6_checksum.h>
60#include <net/protocol.h>
61#include <net/raw.h>
62#include <net/rawv6.h>
63#include <net/transp_v6.h>
64#include <net/ip6_route.h>
65#include <net/addrconf.h>
66#include <net/icmp.h>
Herbert Xu8b7817f2007-12-12 10:44:43 -080067#include <net/xfrm.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070068#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Linus Torvalds1da177e2005-04-16 15:20:36 -070072/*
73 * The ICMP socket(s). This is the most convenient way to flow control
74 * our ICMP output as well as maintain a clean interface throughout
75 * all layers. All Socketless IP sends will soon be gone.
76 *
77 * On SMP we have one ICMP socket per-cpu.
78 */
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -080079static inline struct sock *icmpv6_sk(struct net *net)
80{
81 return net->ipv6.icmp_sk[smp_processor_id()];
82}
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Steffen Klassert6f809da2013-01-16 22:09:49 +000084static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
85 u8 type, u8 code, int offset, __be32 info)
86{
87 struct net *net = dev_net(skb->dev);
88
89 if (type == ICMPV6_PKT_TOOBIG)
90 ip6_update_pmtu(skb, net, info, 0, 0);
91 else if (type == NDISC_REDIRECT)
92 ip6_redirect(skb, net, 0, 0);
93}
94
Herbert Xue5bbef22007-10-15 12:50:28 -070095static int icmpv6_rcv(struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Alexey Dobriyan41135cc2009-09-14 12:22:28 +000097static const struct inet6_protocol icmpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 .handler = icmpv6_rcv,
Steffen Klassert6f809da2013-01-16 22:09:49 +000099 .err_handler = icmpv6_err,
Herbert Xu8b7817f2007-12-12 10:44:43 -0800100 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101};
102
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700103static __inline__ struct sock *icmpv6_xmit_lock(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700105 struct sock *sk;
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 local_bh_disable();
108
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700109 sk = icmpv6_sk(net);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800110 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 /* This can happen if the output path (f.e. SIT or
112 * ip6ip6 tunnel) signals dst_link_failure() for an
113 * outgoing ICMP6 packet.
114 */
115 local_bh_enable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700116 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 }
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700118 return sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119}
120
Denis V. Lunev405666d2008-02-29 11:16:46 -0800121static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
Denis V. Lunev405666d2008-02-29 11:16:46 -0800123 spin_unlock_bh(&sk->sk_lock.slock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124}
125
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900126/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 * Figure out, may we reply to this packet with icmp error.
128 *
129 * We do not reply, if:
130 * - it was icmp error message.
131 * - it is truncated, so that it is known, that protocol is ICMPV6
132 * (i.e. in the middle of some exthdr)
133 *
134 * --ANK (980726)
135 */
136
Eric Dumazeta50feda2012-05-18 18:57:34 +0000137static bool is_ineligible(const struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700139 int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 int len = skb->len - ptr;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700141 __u8 nexthdr = ipv6_hdr(skb)->nexthdr;
Jesse Gross75f28112011-11-30 17:05:51 -0800142 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 if (len < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000145 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Jesse Gross75f28112011-11-30 17:05:51 -0800147 ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 if (ptr < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000149 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 if (nexthdr == IPPROTO_ICMPV6) {
151 u8 _type, *tp;
152 tp = skb_header_pointer(skb,
153 ptr+offsetof(struct icmp6hdr, icmp6_type),
154 sizeof(_type), &_type);
155 if (tp == NULL ||
156 !(*tp & ICMPV6_INFOMSG_MASK))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000157 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000159 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160}
161
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900162/*
163 * Check the ICMP output rate limit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 */
David S. Miller92d86822011-02-04 15:55:25 -0800165static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
David S. Miller4c9483b2011-03-12 16:22:43 -0500166 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
168 struct dst_entry *dst;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900169 struct net *net = sock_net(sk);
David S. Miller92d86822011-02-04 15:55:25 -0800170 bool res = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172 /* Informational messages are not limited. */
173 if (type & ICMPV6_INFOMSG_MASK)
David S. Miller92d86822011-02-04 15:55:25 -0800174 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
176 /* Do not limit pmtu discovery, it would break it. */
177 if (type == ICMPV6_PKT_TOOBIG)
David S. Miller92d86822011-02-04 15:55:25 -0800178 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900180 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 * Look up the output route.
182 * XXX: perhaps the expire for routing entries cloned by
183 * this lookup should be more aggressive (not longer than timeout).
184 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500185 dst = ip6_route_output(net, sk, fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 if (dst->error) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -0700187 IP6_INC_STATS(net, ip6_dst_idev(dst),
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900188 IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
David S. Miller92d86822011-02-04 15:55:25 -0800190 res = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 } else {
192 struct rt6_info *rt = (struct rt6_info *)dst;
Benjamin Thery9a43b702008-03-05 10:49:18 -0800193 int tmo = net->ipv6.sysctl.icmpv6_time;
David S. Millerfbfe95a2012-06-08 23:24:18 -0700194 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196 /* Give more bandwidth to wider prefixes. */
197 if (rt->rt6i_dst.plen < 128)
198 tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
199
David S. Miller1d861aa2012-07-10 03:58:16 -0700200 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
David S. Millerfbfe95a2012-06-08 23:24:18 -0700201 res = inet_peer_xrlim_allow(peer, tmo);
David S. Miller1d861aa2012-07-10 03:58:16 -0700202 if (peer)
203 inet_putpeer(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 }
205 dst_release(dst);
206 return res;
207}
208
209/*
210 * an inline helper for the "simple" if statement below
211 * checks if parameter problem report is caused by an
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900212 * unrecognized IPv6 option that has the Option Type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 * highest-order two bits set to 10
214 */
215
Eric Dumazeta50feda2012-05-18 18:57:34 +0000216static bool opt_unrec(struct sk_buff *skb, __u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217{
218 u8 _optval, *op;
219
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300220 offset += skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
222 if (op == NULL)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000223 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return (*op & 0xC0) == 0x80;
225}
226
David S. Miller4c9483b2011-03-12 16:22:43 -0500227static int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, struct icmp6hdr *thdr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 struct sk_buff *skb;
230 struct icmp6hdr *icmp6h;
231 int err = 0;
232
233 if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
234 goto out;
235
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300236 icmp6h = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
238 icmp6h->icmp6_cksum = 0;
239
240 if (skb_queue_len(&sk->sk_write_queue) == 1) {
Joe Perches07f07572008-11-19 15:44:53 -0800241 skb->csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 sizeof(struct icmp6hdr), skb->csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500243 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
244 &fl6->daddr,
245 len, fl6->flowi6_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 skb->csum);
247 } else {
Al Viro868c86b2006-11-14 21:35:48 -0800248 __wsum tmp_csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 skb_queue_walk(&sk->sk_write_queue, skb) {
251 tmp_csum = csum_add(tmp_csum, skb->csum);
252 }
253
Joe Perches07f07572008-11-19 15:44:53 -0800254 tmp_csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 sizeof(struct icmp6hdr), tmp_csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500256 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
257 &fl6->daddr,
258 len, fl6->flowi6_proto,
Al Viro868c86b2006-11-14 21:35:48 -0800259 tmp_csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 ip6_push_pending_frames(sk);
262out:
263 return err;
264}
265
266struct icmpv6_msg {
267 struct sk_buff *skb;
268 int offset;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800269 uint8_t type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270};
271
272static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
273{
274 struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
275 struct sk_buff *org_skb = msg->skb;
Al Viro5f92a732006-11-14 21:36:54 -0800276 __wsum csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
278 csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
279 to, len, csum);
280 skb->csum = csum_block_add(skb->csum, csum, odd);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800281 if (!(msg->type & ICMPV6_INFOMSG_MASK))
282 nf_ct_attach(skb, org_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 return 0;
284}
285
Amerigo Wang07a93622012-10-29 16:23:10 +0000286#if IS_ENABLED(CONFIG_IPV6_MIP6)
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700287static void mip6_addr_swap(struct sk_buff *skb)
288{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700289 struct ipv6hdr *iph = ipv6_hdr(skb);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700290 struct inet6_skb_parm *opt = IP6CB(skb);
291 struct ipv6_destopt_hao *hao;
292 struct in6_addr tmp;
293 int off;
294
295 if (opt->dsthao) {
296 off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
297 if (likely(off >= 0)) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700298 hao = (struct ipv6_destopt_hao *)
299 (skb_network_header(skb) + off);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000300 tmp = iph->saddr;
301 iph->saddr = hao->addr;
302 hao->addr = tmp;
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700303 }
304 }
305}
306#else
307static inline void mip6_addr_swap(struct sk_buff *skb) {}
308#endif
309
David S. Millerb42835d2011-03-01 22:06:22 -0800310static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
David S. Miller4c9483b2011-03-12 16:22:43 -0500311 struct sock *sk, struct flowi6 *fl6)
David S. Millerb42835d2011-03-01 22:06:22 -0800312{
313 struct dst_entry *dst, *dst2;
David S. Miller4c9483b2011-03-12 16:22:43 -0500314 struct flowi6 fl2;
David S. Millerb42835d2011-03-01 22:06:22 -0800315 int err;
316
David S. Miller4c9483b2011-03-12 16:22:43 -0500317 err = ip6_dst_lookup(sk, &dst, fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800318 if (err)
319 return ERR_PTR(err);
320
321 /*
322 * We won't send icmp if the destination is known
323 * anycast.
324 */
325 if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) {
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000326 LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: acast source\n");
David S. Millerb42835d2011-03-01 22:06:22 -0800327 dst_release(dst);
328 return ERR_PTR(-EINVAL);
329 }
330
331 /* No need to clone since we're just using its address. */
332 dst2 = dst;
333
David S. Miller4c9483b2011-03-12 16:22:43 -0500334 dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800335 if (!IS_ERR(dst)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800336 if (dst != dst2)
337 return dst;
David S. Miller452edd52011-03-02 13:27:41 -0800338 } else {
339 if (PTR_ERR(dst) == -EPERM)
340 dst = NULL;
341 else
342 return dst;
David S. Millerb42835d2011-03-01 22:06:22 -0800343 }
344
David S. Miller4c9483b2011-03-12 16:22:43 -0500345 err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6);
David S. Millerb42835d2011-03-01 22:06:22 -0800346 if (err)
347 goto relookup_failed;
348
349 err = ip6_dst_lookup(sk, &dst2, &fl2);
350 if (err)
351 goto relookup_failed;
352
David S. Miller4c9483b2011-03-12 16:22:43 -0500353 dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP);
David S. Miller452edd52011-03-02 13:27:41 -0800354 if (!IS_ERR(dst2)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800355 dst_release(dst);
356 dst = dst2;
David S. Miller452edd52011-03-02 13:27:41 -0800357 } else {
358 err = PTR_ERR(dst2);
359 if (err == -EPERM) {
360 dst_release(dst);
361 return dst2;
362 } else
363 goto relookup_failed;
David S. Millerb42835d2011-03-01 22:06:22 -0800364 }
365
366relookup_failed:
367 if (dst)
368 return dst;
369 return ERR_PTR(err);
370}
371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372/*
373 * Send an ICMP message in response to a packet in error
374 */
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000375static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900377 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 struct inet6_dev *idev = NULL;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700379 struct ipv6hdr *hdr = ipv6_hdr(skb);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700380 struct sock *sk;
381 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000382 const struct in6_addr *saddr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 struct dst_entry *dst;
384 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500385 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 struct icmpv6_msg msg;
387 int iif = 0;
388 int addr_type = 0;
389 int len;
Gerrit Renkere651f032009-08-09 08:12:48 +0000390 int hlimit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 int err = 0;
392
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700393 if ((u8 *)hdr < skb->head ||
394 (skb->network_header + sizeof(*hdr)) > skb->tail)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return;
396
397 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900398 * Make sure we respect the rules
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 * i.e. RFC 1885 2.4(e)
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000400 * Rule (e.1) is enforced by not using icmp6_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 * in any code that processes icmp errors.
402 */
403 addr_type = ipv6_addr_type(&hdr->daddr);
404
Benjamin Thery9a43b702008-03-05 10:49:18 -0800405 if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 saddr = &hdr->daddr;
407
408 /*
409 * Dest addr check
410 */
411
412 if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {
413 if (type != ICMPV6_PKT_TOOBIG &&
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900414 !(type == ICMPV6_PARAMPROB &&
415 code == ICMPV6_UNK_OPTION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 (opt_unrec(skb, info))))
417 return;
418
419 saddr = NULL;
420 }
421
422 addr_type = ipv6_addr_type(&hdr->saddr);
423
424 /*
425 * Source addr check
426 */
427
Hannes Frederic Sowa842df072013-03-08 02:07:19 +0000428 if (__ipv6_addr_needs_scope_id(addr_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 iif = skb->dev->ifindex;
430
431 /*
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900432 * Must not send error if the source does not uniquely
433 * identify a single node (RFC2463 Section 2.4).
434 * We check unspecified / multicast addresses here,
435 * and anycast addresses will be checked later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 */
437 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000438 LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: addr_any/mcast source\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 return;
440 }
441
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900442 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 * Never answer to a ICMP packet.
444 */
445 if (is_ineligible(skb)) {
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000446 LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: no reply to icmp error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 return;
448 }
449
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700450 mip6_addr_swap(skb);
451
David S. Miller4c9483b2011-03-12 16:22:43 -0500452 memset(&fl6, 0, sizeof(fl6));
453 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000454 fl6.daddr = hdr->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000456 fl6.saddr = *saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500457 fl6.flowi6_oif = iif;
David S. Miller1958b852011-03-12 16:36:19 -0500458 fl6.fl6_icmp_type = type;
459 fl6.fl6_icmp_code = code;
David S. Miller4c9483b2011-03-12 16:22:43 -0500460 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700462 sk = icmpv6_xmit_lock(net);
463 if (sk == NULL)
Denis V. Lunev405666d2008-02-29 11:16:46 -0800464 return;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700465 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800466
David S. Miller4c9483b2011-03-12 16:22:43 -0500467 if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 goto out;
469
470 tmp_hdr.icmp6_type = type;
471 tmp_hdr.icmp6_code = code;
472 tmp_hdr.icmp6_cksum = 0;
473 tmp_hdr.icmp6_pointer = htonl(info);
474
David S. Miller4c9483b2011-03-12 16:22:43 -0500475 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
476 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000477 else if (!fl6.flowi6_oif)
478 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
David S. Miller4c9483b2011-03-12 16:22:43 -0500480 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800481 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 goto out;
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900483
David S. Miller4c9483b2011-03-12 16:22:43 -0500484 if (ipv6_addr_is_multicast(&fl6.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 hlimit = np->mcast_hops;
486 else
487 hlimit = np->hop_limit;
488 if (hlimit < 0)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -0400489 hlimit = ip6_dst_hoplimit(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 msg.skb = skb;
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300492 msg.offset = skb_network_offset(skb);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800493 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 len = skb->len - msg.offset;
496 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr));
497 if (len < 0) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700498 LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 goto out_dst_release;
500 }
501
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000502 rcu_read_lock();
503 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 err = ip6_append_data(sk, icmpv6_getfrag, &msg,
506 len + sizeof(struct icmp6hdr),
Gerrit Renkere651f032009-08-09 08:12:48 +0000507 sizeof(struct icmp6hdr), hlimit,
Eldad Zacka2d91a02012-04-01 07:49:07 +0000508 np->tclass, NULL, &fl6, (struct rt6_info *)dst,
Brian Haley13b52cd2010-04-23 11:26:08 +0000509 MSG_DONTWAIT, np->dontfrag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 if (err) {
Eric Dumazet00d9d6a2010-06-07 22:24:44 +0000511 ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000513 } else {
514 err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
515 len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 }
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000517 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518out_dst_release:
519 dst_release(dst);
520out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800521 icmpv6_xmit_unlock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522}
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000523
524/* Slightly more convenient version of icmp6_send.
525 */
526void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
527{
528 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos);
529 kfree_skb(skb);
530}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532static void icmpv6_echo_reply(struct sk_buff *skb)
533{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900534 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700535 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700537 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000538 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300539 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500541 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 struct icmpv6_msg msg;
543 struct dst_entry *dst;
544 int err = 0;
545 int hlimit;
546
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700547 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 if (!ipv6_unicast_destination(skb))
550 saddr = NULL;
551
552 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
553 tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
554
David S. Miller4c9483b2011-03-12 16:22:43 -0500555 memset(&fl6, 0, sizeof(fl6));
556 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000557 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000559 fl6.saddr = *saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500560 fl6.flowi6_oif = skb->dev->ifindex;
David S. Miller1958b852011-03-12 16:36:19 -0500561 fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
David S. Miller4c9483b2011-03-12 16:22:43 -0500562 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700564 sk = icmpv6_xmit_lock(net);
565 if (sk == NULL)
Denis V. Lunev405666d2008-02-29 11:16:46 -0800566 return;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700567 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800568
David S. Miller4c9483b2011-03-12 16:22:43 -0500569 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
570 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000571 else if (!fl6.flowi6_oif)
572 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
David S. Miller4c9483b2011-03-12 16:22:43 -0500574 err = ip6_dst_lookup(sk, &dst, &fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 if (err)
576 goto out;
David S. Miller4c9483b2011-03-12 16:22:43 -0500577 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800578 if (IS_ERR(dst))
Patrick McHardye104411b2005-09-08 15:11:55 -0700579 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
David S. Miller4c9483b2011-03-12 16:22:43 -0500581 if (ipv6_addr_is_multicast(&fl6.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 hlimit = np->mcast_hops;
583 else
584 hlimit = np->hop_limit;
585 if (hlimit < 0)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -0400586 hlimit = ip6_dst_hoplimit(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000588 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590 msg.skb = skb;
591 msg.offset = 0;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800592 msg.type = ICMPV6_ECHO_REPLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
David S. Miller4c9483b2011-03-12 16:22:43 -0500595 sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl6,
Eldad Zacka2d91a02012-04-01 07:49:07 +0000596 (struct rt6_info *)dst, MSG_DONTWAIT,
Brian Haley13b52cd2010-04-23 11:26:08 +0000597 np->dontfrag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 if (err) {
Eric Dumazet00d9d6a2010-06-07 22:24:44 +0000600 ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000602 } else {
603 err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
604 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900607out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800608 icmpv6_xmit_unlock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609}
610
David S. Millerb94f1c02012-07-12 00:33:37 -0700611void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000613 const struct inet6_protocol *ipprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 int inner_offset;
Jesse Gross75f28112011-11-30 17:05:51 -0800615 __be16 frag_off;
David S. Millerf9242b62012-06-19 18:56:21 -0700616 u8 nexthdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
619 return;
620
621 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
622 if (ipv6_ext_hdr(nexthdr)) {
623 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800624 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
625 &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 if (inner_offset<0)
627 return;
628 } else {
629 inner_offset = sizeof(struct ipv6hdr);
630 }
631
632 /* Checkin header including 8 bytes of inner protocol header. */
633 if (!pskb_may_pull(skb, inner_offset+8))
634 return;
635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
637 Without this we will not able f.e. to make source routed
638 pmtu discovery.
639 Corresponding argument (opt) to notifiers is already added.
640 --ANK (980726)
641 */
642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 rcu_read_lock();
David S. Millerf9242b62012-06-19 18:56:21 -0700644 ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (ipprot && ipprot->err_handler)
646 ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
647 rcu_read_unlock();
648
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800649 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652/*
653 * Handle icmp messages
654 */
655
Herbert Xue5bbef22007-10-15 12:50:28 -0700656static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 struct net_device *dev = skb->dev;
659 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000660 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700662 u8 type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Herbert Xuaebcf822007-12-12 18:54:16 -0800664 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700665 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800666 int nh;
667
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700668 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Herbert Xuaebcf822007-12-12 18:54:16 -0800669 XFRM_STATE_ICMP))
670 goto drop_no_count;
671
David S. Miller81aded22012-06-15 14:54:11 -0700672 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800673 goto drop_no_count;
674
675 nh = skb_network_offset(skb);
676 skb_set_network_header(skb, sizeof(*hdr));
677
678 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
679 goto drop_no_count;
680
681 skb_set_network_header(skb, nh);
682 }
683
Denis V. Luneve41b5362008-10-08 10:33:26 -0700684 ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700686 saddr = &ipv6_hdr(skb)->saddr;
687 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 /* Perform checksum. */
Herbert Xufb286bb2005-11-10 13:01:24 -0800690 switch (skb->ip_summed) {
Patrick McHardy84fa7932006-08-29 16:44:56 -0700691 case CHECKSUM_COMPLETE:
Herbert Xufb286bb2005-11-10 13:01:24 -0800692 if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
693 skb->csum))
694 break;
695 /* fall through */
696 case CHECKSUM_NONE:
Al Viro868c86b2006-11-14 21:35:48 -0800697 skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len,
698 IPPROTO_ICMPV6, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -0800699 if (__skb_checksum_complete(skb)) {
Harvey Harrison5b095d9892008-10-29 12:52:50 -0700700 LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%pI6 > %pI6]\n",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700701 saddr, daddr);
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +0000702 goto csum_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 }
704 }
705
Herbert Xu8cf22942008-02-05 03:15:50 -0800706 if (!pskb_pull(skb, sizeof(*hdr)))
707 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300709 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 type = hdr->icmp6_type;
712
Denis V. Lunev55d43802008-10-08 10:34:54 -0700713 ICMP6MSGIN_INC_STATS_BH(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715 switch (type) {
716 case ICMPV6_ECHO_REQUEST:
717 icmpv6_echo_reply(skb);
718 break;
719
720 case ICMPV6_ECHO_REPLY:
721 /* we couldn't care less */
722 break;
723
724 case ICMPV6_PKT_TOOBIG:
725 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
726 standard destination cache. Seems, only "advanced"
727 destination cache will allow to solve this problem
728 --ANK (980726)
729 */
730 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
731 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300732 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 /*
735 * Drop through to notify
736 */
737
738 case ICMPV6_DEST_UNREACH:
739 case ICMPV6_TIME_EXCEED:
740 case ICMPV6_PARAMPROB:
741 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
742 break;
743
744 case NDISC_ROUTER_SOLICITATION:
745 case NDISC_ROUTER_ADVERTISEMENT:
746 case NDISC_NEIGHBOUR_SOLICITATION:
747 case NDISC_NEIGHBOUR_ADVERTISEMENT:
748 case NDISC_REDIRECT:
749 ndisc_rcv(skb);
750 break;
751
752 case ICMPV6_MGM_QUERY:
753 igmp6_event_query(skb);
754 break;
755
756 case ICMPV6_MGM_REPORT:
757 igmp6_event_report(skb);
758 break;
759
760 case ICMPV6_MGM_REDUCTION:
761 case ICMPV6_NI_QUERY:
762 case ICMPV6_NI_REPLY:
763 case ICMPV6_MLD2_REPORT:
764 case ICMPV6_DHAAD_REQUEST:
765 case ICMPV6_DHAAD_REPLY:
766 case ICMPV6_MOBILE_PREFIX_SOL:
767 case ICMPV6_MOBILE_PREFIX_ADV:
768 break;
769
770 default:
Patrick McHardy64ce2072005-08-09 20:50:53 -0700771 LIMIT_NETDEBUG(KERN_DEBUG "icmpv6: msg of unknown type\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
773 /* informational */
774 if (type & ICMPV6_INFOMSG_MASK)
775 break;
776
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900777 /*
778 * error of unknown type.
779 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 */
781
782 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700783 }
784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 kfree_skb(skb);
786 return 0;
787
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +0000788csum_error:
789 ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790discard_it:
Denis V. Luneve41b5362008-10-08 10:33:26 -0700791 ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800792drop_no_count:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 kfree_skb(skb);
794 return 0;
795}
796
David S. Miller4c9483b2011-03-12 16:22:43 -0500797void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800798 u8 type,
799 const struct in6_addr *saddr,
800 const struct in6_addr *daddr,
801 int oif)
802{
David S. Miller4c9483b2011-03-12 16:22:43 -0500803 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000804 fl6->saddr = *saddr;
805 fl6->daddr = *daddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500806 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -0500807 fl6->fl6_icmp_type = type;
808 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -0500809 fl6->flowi6_oif = oif;
810 security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800811}
812
Ingo Molnar640c41c2006-08-15 00:06:56 -0700813/*
Denis V. Lunevb7e729c2008-02-29 11:16:08 -0800814 * Special lock-class for __icmpv6_sk:
Ingo Molnar640c41c2006-08-15 00:06:56 -0700815 */
816static struct lock_class_key icmpv6_socket_sk_dst_lock_key;
817
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800818static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819{
820 struct sock *sk;
821 int err, i, j;
822
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800823 net->ipv6.icmp_sk =
824 kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
825 if (net->ipv6.icmp_sk == NULL)
Denis V. Lunev79c91152008-02-29 11:17:11 -0800826 return -ENOMEM;
827
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700828 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700829 err = inet_ctl_sock_create(&sk, PF_INET6,
830 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (err < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +0000832 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 err);
834 goto fail;
835 }
836
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700837 net->ipv6.icmp_sk[i] = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -0800838
Ingo Molnar640c41c2006-08-15 00:06:56 -0700839 /*
840 * Split off their lock-class, because sk->sk_dst_lock
841 * gets used from softirqs, which is safe for
Denis V. Lunevb7e729c2008-02-29 11:16:08 -0800842 * __icmpv6_sk (because those never get directly used
Ingo Molnar640c41c2006-08-15 00:06:56 -0700843 * via userspace syscalls), but unsafe for normal sockets.
844 */
845 lockdep_set_class(&sk->sk_dst_lock,
846 &icmpv6_socket_sk_dst_lock_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 /* Enough space for 2 64K ICMP packets, including
849 * sk_buff struct overhead.
850 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +0000851 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 return 0;
854
855 fail:
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -0800856 for (j = 0; j < i; j++)
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700857 inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800858 kfree(net->ipv6.icmp_sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 return err;
860}
861
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800862static void __net_exit icmpv6_sk_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
864 int i;
865
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700866 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700867 inet_ctl_sock_destroy(net->ipv6.icmp_sk[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 }
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800869 kfree(net->ipv6.icmp_sk);
870}
871
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -0800872static struct pernet_operations icmpv6_sk_ops = {
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800873 .init = icmpv6_sk_init,
874 .exit = icmpv6_sk_exit,
875};
876
877int __init icmpv6_init(void)
878{
879 int err;
880
881 err = register_pernet_subsys(&icmpv6_sk_ops);
882 if (err < 0)
883 return err;
884
885 err = -EAGAIN;
886 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
887 goto fail;
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000888
889 err = inet6_register_icmp_sender(icmp6_send);
890 if (err)
891 goto sender_reg_err;
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800892 return 0;
893
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000894sender_reg_err:
895 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800896fail:
Joe Perchesf3213832012-05-15 14:11:53 +0000897 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800898 unregister_pernet_subsys(&icmpv6_sk_ops);
899 return err;
900}
901
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -0800902void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800903{
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000904 inet6_unregister_icmp_sender(icmp6_send);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800905 unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
907}
908
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800909
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -0800910static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 int err;
912 int fatal;
913} tab_unreach[] = {
914 { /* NOROUTE */
915 .err = ENETUNREACH,
916 .fatal = 0,
917 },
918 { /* ADM_PROHIBITED */
919 .err = EACCES,
920 .fatal = 1,
921 },
922 { /* Was NOT_NEIGHBOUR, now reserved */
923 .err = EHOSTUNREACH,
924 .fatal = 0,
925 },
926 { /* ADDR_UNREACH */
927 .err = EHOSTUNREACH,
928 .fatal = 0,
929 },
930 { /* PORT_UNREACH */
931 .err = ECONNREFUSED,
932 .fatal = 1,
933 },
934};
935
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700936int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 int fatal = 0;
939
940 *err = EPROTO;
941
942 switch (type) {
943 case ICMPV6_DEST_UNREACH:
944 fatal = 1;
945 if (code <= ICMPV6_PORT_UNREACH) {
946 *err = tab_unreach[code].err;
947 fatal = tab_unreach[code].fatal;
948 }
949 break;
950
951 case ICMPV6_PKT_TOOBIG:
952 *err = EMSGSIZE;
953 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 case ICMPV6_PARAMPROB:
956 *err = EPROTO;
957 fatal = 1;
958 break;
959
960 case ICMPV6_TIME_EXCEED:
961 *err = EHOSTUNREACH;
962 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 return fatal;
966}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900967EXPORT_SYMBOL(icmpv6_err_convert);
968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969#ifdef CONFIG_SYSCTL
Daniel Lezcano760f2d02008-01-10 02:53:43 -0800970ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -0800973 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 .maxlen = sizeof(int),
975 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -0800976 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -0800978 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979};
Daniel Lezcano760f2d02008-01-10 02:53:43 -0800980
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +0000981struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -0800982{
983 struct ctl_table *table;
984
985 table = kmemdup(ipv6_icmp_table_template,
986 sizeof(ipv6_icmp_table_template),
987 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +0900988
Eric W. Biedermanc027aab2012-11-16 03:03:10 +0000989 if (table)
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +0900990 table[0].data = &net->ipv6.sysctl.icmpv6_time;
991
Daniel Lezcano760f2d02008-01-10 02:53:43 -0800992 return table;
993}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994#endif
995