blob: 71c4d60c0e2278814ec25889b949e2c8d0a089c0 [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 Perchesc7e74512012-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>
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +000060#include <net/ping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <net/protocol.h>
62#include <net/raw.h>
63#include <net/rawv6.h>
64#include <net/transp_v6.h>
65#include <net/ip6_route.h>
66#include <net/addrconf.h>
67#include <net/icmp.h>
Herbert Xu8b7817f2007-12-12 10:44:43 -080068#include <net/xfrm.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070069#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Linus Torvalds1da177e2005-04-16 15:20:36 -070073/*
74 * The ICMP socket(s). This is the most convenient way to flow control
75 * our ICMP output as well as maintain a clean interface throughout
76 * all layers. All Socketless IP sends will soon be gone.
77 *
78 * On SMP we have one ICMP socket per-cpu.
79 */
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -080080static inline struct sock *icmpv6_sk(struct net *net)
81{
82 return net->ipv6.icmp_sk[smp_processor_id()];
83}
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +000085static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
86 u8 type, u8 code, int offset, __be32 info)
87{
88 /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
89 struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
90
91 if (!(type & ICMPV6_INFOMSG_MASK))
92 if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
Hannes Frederic Sowac2e538b2016-06-11 20:32:06 +020093 ping_err(skb, offset, ntohl(info));
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +000094}
95
Herbert Xue5bbef22007-10-15 12:50:28 -070096static int icmpv6_rcv(struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Alexey Dobriyan41135cc2009-09-14 12:22:28 +000098static const struct inet6_protocol icmpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 .handler = icmpv6_rcv,
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +0000100 .err_handler = icmpv6_err,
Herbert Xu8b7817f2007-12-12 10:44:43 -0800101 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102};
103
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700104static __inline__ struct sock *icmpv6_xmit_lock(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105{
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700106 struct sock *sk;
107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 local_bh_disable();
109
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700110 sk = icmpv6_sk(net);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800111 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 /* This can happen if the output path (f.e. SIT or
113 * ip6ip6 tunnel) signals dst_link_failure() for an
114 * outgoing ICMP6 packet.
115 */
116 local_bh_enable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700117 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 }
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700119 return sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120}
121
Denis V. Lunev405666d2008-02-29 11:16:46 -0800122static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123{
Denis V. Lunev405666d2008-02-29 11:16:46 -0800124 spin_unlock_bh(&sk->sk_lock.slock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900127/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 * Slightly more convenient version of icmpv6_send.
129 */
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700130void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +0000132 icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 kfree_skb(skb);
134}
135
136/*
137 * Figure out, may we reply to this packet with icmp error.
138 *
139 * We do not reply, if:
140 * - it was icmp error message.
141 * - it is truncated, so that it is known, that protocol is ICMPV6
142 * (i.e. in the middle of some exthdr)
143 *
144 * --ANK (980726)
145 */
146
147static int is_ineligible(struct sk_buff *skb)
148{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700149 int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 int len = skb->len - ptr;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700151 __u8 nexthdr = ipv6_hdr(skb)->nexthdr;
Jesse Gross75f28112011-11-30 17:05:51 -0800152 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
154 if (len < 0)
155 return 1;
156
Jesse Gross75f28112011-11-30 17:05:51 -0800157 ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 if (ptr < 0)
159 return 0;
160 if (nexthdr == IPPROTO_ICMPV6) {
161 u8 _type, *tp;
162 tp = skb_header_pointer(skb,
163 ptr+offsetof(struct icmp6hdr, icmp6_type),
164 sizeof(_type), &_type);
165 if (tp == NULL ||
166 !(*tp & ICMPV6_INFOMSG_MASK))
167 return 1;
168 }
169 return 0;
170}
171
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900172/*
173 * Check the ICMP output rate limit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 */
David S. Miller92d86822011-02-04 15:55:25 -0800175static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
David S. Miller4c9483b2011-03-12 16:22:43 -0500176 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
178 struct dst_entry *dst;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900179 struct net *net = sock_net(sk);
David S. Miller92d86822011-02-04 15:55:25 -0800180 bool res = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 /* Informational messages are not limited. */
183 if (type & ICMPV6_INFOMSG_MASK)
David S. Miller92d86822011-02-04 15:55:25 -0800184 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 /* Do not limit pmtu discovery, it would break it. */
187 if (type == ICMPV6_PKT_TOOBIG)
David S. Miller92d86822011-02-04 15:55:25 -0800188 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900190 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 * Look up the output route.
192 * XXX: perhaps the expire for routing entries cloned by
193 * this lookup should be more aggressive (not longer than timeout).
194 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500195 dst = ip6_route_output(net, sk, fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 if (dst->error) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -0700197 IP6_INC_STATS(net, ip6_dst_idev(dst),
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900198 IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
David S. Miller92d86822011-02-04 15:55:25 -0800200 res = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 } else {
202 struct rt6_info *rt = (struct rt6_info *)dst;
Benjamin Thery9a43b702008-03-05 10:49:18 -0800203 int tmo = net->ipv6.sysctl.icmpv6_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 /* Give more bandwidth to wider prefixes. */
206 if (rt->rt6i_dst.plen < 128)
207 tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
208
David S. Miller92d86822011-02-04 15:55:25 -0800209 if (!rt->rt6i_peer)
210 rt6_bind_peer(rt, 1);
211 res = inet_peer_xrlim_allow(rt->rt6i_peer, tmo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 }
213 dst_release(dst);
214 return res;
215}
216
217/*
218 * an inline helper for the "simple" if statement below
219 * checks if parameter problem report is caused by an
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900220 * unrecognized IPv6 option that has the Option Type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 * highest-order two bits set to 10
222 */
223
224static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset)
225{
226 u8 _optval, *op;
227
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300228 offset += skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
230 if (op == NULL)
231 return 1;
232 return (*op & 0xC0) == 0x80;
233}
234
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +0000235int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
236 struct icmp6hdr *thdr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 struct sk_buff *skb;
239 struct icmp6hdr *icmp6h;
240 int err = 0;
241
242 if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
243 goto out;
244
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300245 icmp6h = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
247 icmp6h->icmp6_cksum = 0;
248
249 if (skb_queue_len(&sk->sk_write_queue) == 1) {
Joe Perches07f07572008-11-19 15:44:53 -0800250 skb->csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 sizeof(struct icmp6hdr), skb->csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500252 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
253 &fl6->daddr,
254 len, fl6->flowi6_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 skb->csum);
256 } else {
Al Viro868c86b2006-11-14 21:35:48 -0800257 __wsum tmp_csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
259 skb_queue_walk(&sk->sk_write_queue, skb) {
260 tmp_csum = csum_add(tmp_csum, skb->csum);
261 }
262
Joe Perches07f07572008-11-19 15:44:53 -0800263 tmp_csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 sizeof(struct icmp6hdr), tmp_csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500265 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
266 &fl6->daddr,
267 len, fl6->flowi6_proto,
Al Viro868c86b2006-11-14 21:35:48 -0800268 tmp_csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 ip6_push_pending_frames(sk);
271out:
272 return err;
273}
274
275struct icmpv6_msg {
276 struct sk_buff *skb;
277 int offset;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800278 uint8_t type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279};
280
281static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
282{
283 struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
284 struct sk_buff *org_skb = msg->skb;
Al Viro5f92a732006-11-14 21:36:54 -0800285 __wsum csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
288 to, len, csum);
289 skb->csum = csum_block_add(skb->csum, csum, odd);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800290 if (!(msg->type & ICMPV6_INFOMSG_MASK))
291 nf_ct_attach(skb, org_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return 0;
293}
294
Masahide NAKAMURA59fbb3a2007-06-26 23:56:32 -0700295#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700296static void mip6_addr_swap(struct sk_buff *skb)
297{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700298 struct ipv6hdr *iph = ipv6_hdr(skb);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700299 struct inet6_skb_parm *opt = IP6CB(skb);
300 struct ipv6_destopt_hao *hao;
301 struct in6_addr tmp;
302 int off;
303
304 if (opt->dsthao) {
305 off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
306 if (likely(off >= 0)) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700307 hao = (struct ipv6_destopt_hao *)
308 (skb_network_header(skb) + off);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000309 tmp = iph->saddr;
310 iph->saddr = hao->addr;
311 hao->addr = tmp;
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700312 }
313 }
314}
315#else
316static inline void mip6_addr_swap(struct sk_buff *skb) {}
317#endif
318
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +0000319struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
320 struct sock *sk, struct flowi6 *fl6)
David S. Millerb42835d2011-03-01 22:06:22 -0800321{
322 struct dst_entry *dst, *dst2;
David S. Miller4c9483b2011-03-12 16:22:43 -0500323 struct flowi6 fl2;
David S. Millerb42835d2011-03-01 22:06:22 -0800324 int err;
325
David S. Miller4c9483b2011-03-12 16:22:43 -0500326 err = ip6_dst_lookup(sk, &dst, fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800327 if (err)
328 return ERR_PTR(err);
329
330 /*
331 * We won't send icmp if the destination is known
332 * anycast.
333 */
334 if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) {
335 LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n");
336 dst_release(dst);
337 return ERR_PTR(-EINVAL);
338 }
339
340 /* No need to clone since we're just using its address. */
341 dst2 = dst;
342
David S. Miller4c9483b2011-03-12 16:22:43 -0500343 dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800344 if (!IS_ERR(dst)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800345 if (dst != dst2)
346 return dst;
David S. Miller452edd52011-03-02 13:27:41 -0800347 } else {
348 if (PTR_ERR(dst) == -EPERM)
349 dst = NULL;
350 else
351 return dst;
David S. Millerb42835d2011-03-01 22:06:22 -0800352 }
353
David S. Miller4c9483b2011-03-12 16:22:43 -0500354 err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6);
David S. Millerb42835d2011-03-01 22:06:22 -0800355 if (err)
356 goto relookup_failed;
357
358 err = ip6_dst_lookup(sk, &dst2, &fl2);
359 if (err)
360 goto relookup_failed;
361
David S. Miller4c9483b2011-03-12 16:22:43 -0500362 dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP);
David S. Miller452edd52011-03-02 13:27:41 -0800363 if (!IS_ERR(dst2)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800364 dst_release(dst);
365 dst = dst2;
David S. Miller452edd52011-03-02 13:27:41 -0800366 } else {
367 err = PTR_ERR(dst2);
368 if (err == -EPERM) {
369 dst_release(dst);
370 return dst2;
371 } else
372 goto relookup_failed;
David S. Millerb42835d2011-03-01 22:06:22 -0800373 }
374
375relookup_failed:
376 if (dst)
377 return dst;
378 return ERR_PTR(err);
379}
380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381/*
382 * Send an ICMP message in response to a packet in error
383 */
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +0000384void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900386 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 struct inet6_dev *idev = NULL;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700388 struct ipv6hdr *hdr = ipv6_hdr(skb);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700389 struct sock *sk;
390 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000391 const struct in6_addr *saddr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 struct dst_entry *dst;
393 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500394 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 struct icmpv6_msg msg;
396 int iif = 0;
397 int addr_type = 0;
398 int len;
Gerrit Renkere651f032009-08-09 08:12:48 +0000399 int hlimit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 int err = 0;
Lorenzo Colitti65900e72014-03-18 20:52:27 +0900401 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700403 if ((u8 *)hdr < skb->head ||
404 (skb->network_header + sizeof(*hdr)) > skb->tail)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 return;
406
407 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900408 * Make sure we respect the rules
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 * i.e. RFC 1885 2.4(e)
410 * Rule (e.1) is enforced by not using icmpv6_send
411 * in any code that processes icmp errors.
412 */
413 addr_type = ipv6_addr_type(&hdr->daddr);
414
Benjamin Thery9a43b702008-03-05 10:49:18 -0800415 if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 saddr = &hdr->daddr;
417
418 /*
419 * Dest addr check
420 */
421
422 if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {
423 if (type != ICMPV6_PKT_TOOBIG &&
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900424 !(type == ICMPV6_PARAMPROB &&
425 code == ICMPV6_UNK_OPTION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 (opt_unrec(skb, info))))
427 return;
428
429 saddr = NULL;
430 }
431
432 addr_type = ipv6_addr_type(&hdr->saddr);
433
434 /*
435 * Source addr check
436 */
437
Hannes Frederic Sowabf56b322013-03-08 02:07:19 +0000438 if (__ipv6_addr_needs_scope_id(addr_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 iif = skb->dev->ifindex;
440
441 /*
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900442 * Must not send error if the source does not uniquely
443 * identify a single node (RFC2463 Section 2.4).
444 * We check unspecified / multicast addresses here,
445 * and anycast addresses will be checked later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 */
447 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700448 LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 return;
450 }
451
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900452 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 * Never answer to a ICMP packet.
454 */
455 if (is_ineligible(skb)) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700456 LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: no reply to icmp error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 return;
458 }
459
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700460 mip6_addr_swap(skb);
461
David S. Miller4c9483b2011-03-12 16:22:43 -0500462 memset(&fl6, 0, sizeof(fl6));
463 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000464 fl6.daddr = hdr->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000466 fl6.saddr = *saddr;
Lorenzo Colitti65900e72014-03-18 20:52:27 +0900467 fl6.flowi6_mark = mark;
David S. Miller4c9483b2011-03-12 16:22:43 -0500468 fl6.flowi6_oif = iif;
David S. Miller1958b852011-03-12 16:36:19 -0500469 fl6.fl6_icmp_type = type;
470 fl6.fl6_icmp_code = code;
Lorenzo Colitti00e03ac2016-11-04 02:23:43 +0900471 fl6.flowi6_uid = sock_net_uid(net, NULL);
David S. Miller4c9483b2011-03-12 16:22:43 -0500472 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700474 sk = icmpv6_xmit_lock(net);
475 if (sk == NULL)
Denis V. Lunev405666d2008-02-29 11:16:46 -0800476 return;
Lorenzo Colitti65900e72014-03-18 20:52:27 +0900477 sk->sk_mark = mark;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700478 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800479
David S. Miller4c9483b2011-03-12 16:22:43 -0500480 if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 goto out;
482
483 tmp_hdr.icmp6_type = type;
484 tmp_hdr.icmp6_code = code;
485 tmp_hdr.icmp6_cksum = 0;
486 tmp_hdr.icmp6_pointer = htonl(info);
487
David S. Miller4c9483b2011-03-12 16:22:43 -0500488 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
489 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000490 else if (!fl6.flowi6_oif)
491 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
David S. Miller4c9483b2011-03-12 16:22:43 -0500493 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800494 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 goto out;
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900496
David S. Miller4c9483b2011-03-12 16:22:43 -0500497 if (ipv6_addr_is_multicast(&fl6.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 hlimit = np->mcast_hops;
499 else
500 hlimit = np->hop_limit;
501 if (hlimit < 0)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -0400502 hlimit = ip6_dst_hoplimit(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 msg.skb = skb;
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300505 msg.offset = skb_network_offset(skb);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800506 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 len = skb->len - msg.offset;
509 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr));
510 if (len < 0) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700511 LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 goto out_dst_release;
513 }
514
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000515 rcu_read_lock();
516 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 err = ip6_append_data(sk, icmpv6_getfrag, &msg,
519 len + sizeof(struct icmp6hdr),
Gerrit Renkere651f032009-08-09 08:12:48 +0000520 sizeof(struct icmp6hdr), hlimit,
David S. Miller4c9483b2011-03-12 16:22:43 -0500521 np->tclass, NULL, &fl6, (struct rt6_info*)dst,
Brian Haley13b52cd2010-04-23 11:26:08 +0000522 MSG_DONTWAIT, np->dontfrag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (err) {
Hannes Frederic Sowae15cf792014-03-31 20:14:10 +0200524 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000526 } else {
527 err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
528 len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000530 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531out_dst_release:
532 dst_release(dst);
533out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800534 icmpv6_xmit_unlock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900536EXPORT_SYMBOL(icmpv6_send);
537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538static void icmpv6_echo_reply(struct sk_buff *skb)
539{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900540 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700541 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700543 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000544 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300545 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500547 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 struct icmpv6_msg msg;
549 struct dst_entry *dst;
550 int err = 0;
551 int hlimit;
Lorenzo Colitti65900e72014-03-18 20:52:27 +0900552 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700554 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 if (!ipv6_unicast_destination(skb))
557 saddr = NULL;
558
559 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
560 tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
561
David S. Miller4c9483b2011-03-12 16:22:43 -0500562 memset(&fl6, 0, sizeof(fl6));
563 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000564 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000566 fl6.saddr = *saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500567 fl6.flowi6_oif = skb->dev->ifindex;
David S. Miller1958b852011-03-12 16:36:19 -0500568 fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
Lorenzo Colitti65900e72014-03-18 20:52:27 +0900569 fl6.flowi6_mark = mark;
Lorenzo Colitti00e03ac2016-11-04 02:23:43 +0900570 fl6.flowi6_uid = sock_net_uid(net, NULL);
David S. Miller4c9483b2011-03-12 16:22:43 -0500571 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700573 sk = icmpv6_xmit_lock(net);
574 if (sk == NULL)
Denis V. Lunev405666d2008-02-29 11:16:46 -0800575 return;
Lorenzo Colitti65900e72014-03-18 20:52:27 +0900576 sk->sk_mark = mark;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700577 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800578
David S. Miller4c9483b2011-03-12 16:22:43 -0500579 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
580 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000581 else if (!fl6.flowi6_oif)
582 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
David S. Miller4c9483b2011-03-12 16:22:43 -0500584 err = ip6_dst_lookup(sk, &dst, &fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 if (err)
586 goto out;
David S. Miller4c9483b2011-03-12 16:22:43 -0500587 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800588 if (IS_ERR(dst))
Patrick McHardye1044112005-09-08 15:11:55 -0700589 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
David S. Miller4c9483b2011-03-12 16:22:43 -0500591 if (ipv6_addr_is_multicast(&fl6.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 hlimit = np->mcast_hops;
593 else
594 hlimit = np->hop_limit;
595 if (hlimit < 0)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -0400596 hlimit = ip6_dst_hoplimit(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000598 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600 msg.skb = skb;
601 msg.offset = 0;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800602 msg.type = ICMPV6_ECHO_REPLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
David S. Miller4c9483b2011-03-12 16:22:43 -0500605 sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl6,
Brian Haley13b52cd2010-04-23 11:26:08 +0000606 (struct rt6_info*)dst, MSG_DONTWAIT,
607 np->dontfrag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
609 if (err) {
Eric Dumazet00d9d6a2010-06-07 22:24:44 +0000610 ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000612 } else {
613 err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
614 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900617out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800618 icmpv6_xmit_unlock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
620
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +0000621void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000623 const struct inet6_protocol *ipprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 int inner_offset;
625 int hash;
626 u8 nexthdr;
Jesse Gross75f28112011-11-30 17:05:51 -0800627 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
630 return;
631
632 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
633 if (ipv6_ext_hdr(nexthdr)) {
634 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800635 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
636 &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 if (inner_offset<0)
638 return;
639 } else {
640 inner_offset = sizeof(struct ipv6hdr);
641 }
642
643 /* Checkin header including 8 bytes of inner protocol header. */
644 if (!pskb_may_pull(skb, inner_offset+8))
645 return;
646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
648 Without this we will not able f.e. to make source routed
649 pmtu discovery.
650 Corresponding argument (opt) to notifiers is already added.
651 --ANK (980726)
652 */
653
654 hash = nexthdr & (MAX_INET_PROTOS - 1);
655
656 rcu_read_lock();
657 ipprot = rcu_dereference(inet6_protos[hash]);
658 if (ipprot && ipprot->err_handler)
659 ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
660 rcu_read_unlock();
661
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800662 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665/*
666 * Handle icmp messages
667 */
668
Herbert Xue5bbef22007-10-15 12:50:28 -0700669static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 struct net_device *dev = skb->dev;
672 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000673 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700675 u8 type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Herbert Xuaebcf822007-12-12 18:54:16 -0800677 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700678 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800679 int nh;
680
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700681 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Herbert Xuaebcf822007-12-12 18:54:16 -0800682 XFRM_STATE_ICMP))
683 goto drop_no_count;
684
David S. Millere2939ea2012-06-15 14:54:11 -0700685 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800686 goto drop_no_count;
687
688 nh = skb_network_offset(skb);
689 skb_set_network_header(skb, sizeof(*hdr));
690
691 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
692 goto drop_no_count;
693
694 skb_set_network_header(skb, nh);
695 }
696
Denis V. Luneve41b5362008-10-08 10:33:26 -0700697 ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700699 saddr = &ipv6_hdr(skb)->saddr;
700 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 /* Perform checksum. */
Herbert Xufb286bb2005-11-10 13:01:24 -0800703 switch (skb->ip_summed) {
Patrick McHardy84fa7932006-08-29 16:44:56 -0700704 case CHECKSUM_COMPLETE:
Herbert Xufb286bb2005-11-10 13:01:24 -0800705 if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
706 skb->csum))
707 break;
708 /* fall through */
709 case CHECKSUM_NONE:
Al Viro868c86b2006-11-14 21:35:48 -0800710 skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len,
711 IPPROTO_ICMPV6, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -0800712 if (__skb_checksum_complete(skb)) {
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +0000713 LIMIT_NETDEBUG(KERN_DEBUG
714 "ICMPv6 checksum failed [%pI6c > %pI6c]\n",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700715 saddr, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 goto discard_it;
717 }
718 }
719
Herbert Xu8cf22942008-02-05 03:15:50 -0800720 if (!pskb_pull(skb, sizeof(*hdr)))
721 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300723 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 type = hdr->icmp6_type;
726
Denis V. Lunev55d43802008-10-08 10:34:54 -0700727 ICMP6MSGIN_INC_STATS_BH(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 switch (type) {
730 case ICMPV6_ECHO_REQUEST:
731 icmpv6_echo_reply(skb);
732 break;
733
734 case ICMPV6_ECHO_REPLY:
Lorenzo Colitti8b17a9a2013-01-16 22:09:49 +0000735 ping_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 break;
737
738 case ICMPV6_PKT_TOOBIG:
739 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
740 standard destination cache. Seems, only "advanced"
741 destination cache will allow to solve this problem
742 --ANK (980726)
743 */
744 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
745 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300746 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 /*
749 * Drop through to notify
750 */
751
752 case ICMPV6_DEST_UNREACH:
753 case ICMPV6_TIME_EXCEED:
754 case ICMPV6_PARAMPROB:
755 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
756 break;
757
758 case NDISC_ROUTER_SOLICITATION:
759 case NDISC_ROUTER_ADVERTISEMENT:
760 case NDISC_NEIGHBOUR_SOLICITATION:
761 case NDISC_NEIGHBOUR_ADVERTISEMENT:
762 case NDISC_REDIRECT:
763 ndisc_rcv(skb);
764 break;
765
766 case ICMPV6_MGM_QUERY:
767 igmp6_event_query(skb);
768 break;
769
770 case ICMPV6_MGM_REPORT:
771 igmp6_event_report(skb);
772 break;
773
774 case ICMPV6_MGM_REDUCTION:
775 case ICMPV6_NI_QUERY:
776 case ICMPV6_NI_REPLY:
777 case ICMPV6_MLD2_REPORT:
778 case ICMPV6_DHAAD_REQUEST:
779 case ICMPV6_DHAAD_REPLY:
780 case ICMPV6_MOBILE_PREFIX_SOL:
781 case ICMPV6_MOBILE_PREFIX_ADV:
782 break;
783
784 default:
Patrick McHardy64ce2072005-08-09 20:50:53 -0700785 LIMIT_NETDEBUG(KERN_DEBUG "icmpv6: msg of unknown type\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 /* informational */
788 if (type & ICMPV6_INFOMSG_MASK)
789 break;
790
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900791 /*
792 * error of unknown type.
793 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 */
795
796 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700797 }
798
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 kfree_skb(skb);
800 return 0;
801
802discard_it:
Denis V. Luneve41b5362008-10-08 10:33:26 -0700803 ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800804drop_no_count:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 kfree_skb(skb);
806 return 0;
807}
808
David S. Miller4c9483b2011-03-12 16:22:43 -0500809void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800810 u8 type,
811 const struct in6_addr *saddr,
812 const struct in6_addr *daddr,
813 int oif)
814{
David S. Miller4c9483b2011-03-12 16:22:43 -0500815 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000816 fl6->saddr = *saddr;
817 fl6->daddr = *daddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500818 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -0500819 fl6->fl6_icmp_type = type;
820 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -0500821 fl6->flowi6_oif = oif;
822 security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800823}
824
Ingo Molnar640c41c2006-08-15 00:06:56 -0700825/*
Denis V. Lunevb7e729c2008-02-29 11:16:08 -0800826 * Special lock-class for __icmpv6_sk:
Ingo Molnar640c41c2006-08-15 00:06:56 -0700827 */
828static struct lock_class_key icmpv6_socket_sk_dst_lock_key;
829
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800830static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
832 struct sock *sk;
833 int err, i, j;
834
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800835 net->ipv6.icmp_sk =
836 kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
837 if (net->ipv6.icmp_sk == NULL)
Denis V. Lunev79c91152008-02-29 11:17:11 -0800838 return -ENOMEM;
839
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700840 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700841 err = inet_ctl_sock_create(&sk, PF_INET6,
842 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 if (err < 0) {
Joe Perchesc7e74512012-05-15 14:11:53 +0000844 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 err);
846 goto fail;
847 }
848
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700849 net->ipv6.icmp_sk[i] = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -0800850
Ingo Molnar640c41c2006-08-15 00:06:56 -0700851 /*
852 * Split off their lock-class, because sk->sk_dst_lock
853 * gets used from softirqs, which is safe for
Denis V. Lunevb7e729c2008-02-29 11:16:08 -0800854 * __icmpv6_sk (because those never get directly used
Ingo Molnar640c41c2006-08-15 00:06:56 -0700855 * via userspace syscalls), but unsafe for normal sockets.
856 */
857 lockdep_set_class(&sk->sk_dst_lock,
858 &icmpv6_socket_sk_dst_lock_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860 /* Enough space for 2 64K ICMP packets, including
861 * sk_buff struct overhead.
862 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +0000863 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 return 0;
866
867 fail:
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -0800868 for (j = 0; j < i; j++)
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700869 inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800870 kfree(net->ipv6.icmp_sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return err;
872}
873
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800874static void __net_exit icmpv6_sk_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 int i;
877
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700878 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700879 inet_ctl_sock_destroy(net->ipv6.icmp_sk[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 }
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800881 kfree(net->ipv6.icmp_sk);
882}
883
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -0800884static struct pernet_operations icmpv6_sk_ops = {
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800885 .init = icmpv6_sk_init,
886 .exit = icmpv6_sk_exit,
887};
888
889int __init icmpv6_init(void)
890{
891 int err;
892
893 err = register_pernet_subsys(&icmpv6_sk_ops);
894 if (err < 0)
895 return err;
896
897 err = -EAGAIN;
898 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
899 goto fail;
900 return 0;
901
902fail:
Joe Perchesc7e74512012-05-15 14:11:53 +0000903 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800904 unregister_pernet_subsys(&icmpv6_sk_ops);
905 return err;
906}
907
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -0800908void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800909{
910 unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
912}
913
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800914
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -0800915static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 int err;
917 int fatal;
918} tab_unreach[] = {
919 { /* NOROUTE */
920 .err = ENETUNREACH,
921 .fatal = 0,
922 },
923 { /* ADM_PROHIBITED */
924 .err = EACCES,
925 .fatal = 1,
926 },
927 { /* Was NOT_NEIGHBOUR, now reserved */
928 .err = EHOSTUNREACH,
929 .fatal = 0,
930 },
931 { /* ADDR_UNREACH */
932 .err = EHOSTUNREACH,
933 .fatal = 0,
934 },
935 { /* PORT_UNREACH */
936 .err = ECONNREFUSED,
937 .fatal = 1,
938 },
Jiri Bohac1a73f022013-08-30 11:18:45 +0200939 { /* POLICY_FAIL */
940 .err = EACCES,
941 .fatal = 1,
942 },
943 { /* REJECT_ROUTE */
944 .err = EACCES,
945 .fatal = 1,
946 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947};
948
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700949int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950{
951 int fatal = 0;
952
953 *err = EPROTO;
954
955 switch (type) {
956 case ICMPV6_DEST_UNREACH:
957 fatal = 1;
Jiri Bohac1a73f022013-08-30 11:18:45 +0200958 if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 *err = tab_unreach[code].err;
960 fatal = tab_unreach[code].fatal;
961 }
962 break;
963
964 case ICMPV6_PKT_TOOBIG:
965 *err = EMSGSIZE;
966 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 case ICMPV6_PARAMPROB:
969 *err = EPROTO;
970 fatal = 1;
971 break;
972
973 case ICMPV6_TIME_EXCEED:
974 *err = EHOSTUNREACH;
975 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 return fatal;
979}
980
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900981EXPORT_SYMBOL(icmpv6_err_convert);
982
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983#ifdef CONFIG_SYSCTL
Daniel Lezcano760f2d02008-01-10 02:53:43 -0800984ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -0800987 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 .maxlen = sizeof(int),
989 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -0800990 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -0800992 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993};
Daniel Lezcano760f2d02008-01-10 02:53:43 -0800994
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +0000995struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -0800996{
997 struct ctl_table *table;
998
999 table = kmemdup(ipv6_icmp_table_template,
1000 sizeof(ipv6_icmp_table_template),
1001 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001002
1003 if (table)
1004 table[0].data = &net->ipv6.sysctl.icmpv6_time;
1005
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001006 return table;
1007}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008#endif
1009