blob: 9a809a4b3d862444ff858f92a4d87ad6662e3d15 [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>
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +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
Steffen Klassert6f809da2013-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{
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000088 /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
89 struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
Steffen Klassert6f809da2013-01-16 22:09:49 +000090 struct net *net = dev_net(skb->dev);
91
92 if (type == ICMPV6_PKT_TOOBIG)
93 ip6_update_pmtu(skb, net, info, 0, 0);
94 else if (type == NDISC_REDIRECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +080095 ip6_redirect(skb, net, skb->dev->ifindex, 0);
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000096
97 if (!(type & ICMPV6_INFOMSG_MASK))
98 if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
99 ping_err(skb, offset, info);
Steffen Klassert6f809da2013-01-16 22:09:49 +0000100}
101
Herbert Xue5bbef22007-10-15 12:50:28 -0700102static int icmpv6_rcv(struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000104static const struct inet6_protocol icmpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 .handler = icmpv6_rcv,
Steffen Klassert6f809da2013-01-16 22:09:49 +0000106 .err_handler = icmpv6_err,
Herbert Xu8b7817f2007-12-12 10:44:43 -0800107 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700110static __inline__ struct sock *icmpv6_xmit_lock(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700112 struct sock *sk;
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 local_bh_disable();
115
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700116 sk = icmpv6_sk(net);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800117 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 /* This can happen if the output path (f.e. SIT or
119 * ip6ip6 tunnel) signals dst_link_failure() for an
120 * outgoing ICMP6 packet.
121 */
122 local_bh_enable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700123 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 }
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700125 return sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126}
127
Denis V. Lunev405666d2008-02-29 11:16:46 -0800128static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
Denis V. Lunev405666d2008-02-29 11:16:46 -0800130 spin_unlock_bh(&sk->sk_lock.slock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900133/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 * Figure out, may we reply to this packet with icmp error.
135 *
136 * We do not reply, if:
137 * - it was icmp error message.
138 * - it is truncated, so that it is known, that protocol is ICMPV6
139 * (i.e. in the middle of some exthdr)
140 *
141 * --ANK (980726)
142 */
143
Eric Dumazeta50feda2012-05-18 18:57:34 +0000144static bool is_ineligible(const struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700146 int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 int len = skb->len - ptr;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700148 __u8 nexthdr = ipv6_hdr(skb)->nexthdr;
Jesse Gross75f28112011-11-30 17:05:51 -0800149 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 if (len < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000152 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Jesse Gross75f28112011-11-30 17:05:51 -0800154 ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 if (ptr < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000156 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if (nexthdr == IPPROTO_ICMPV6) {
158 u8 _type, *tp;
159 tp = skb_header_pointer(skb,
160 ptr+offsetof(struct icmp6hdr, icmp6_type),
161 sizeof(_type), &_type);
162 if (tp == NULL ||
163 !(*tp & ICMPV6_INFOMSG_MASK))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000164 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000166 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167}
168
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900169/*
170 * Check the ICMP output rate limit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 */
David S. Miller92d86822011-02-04 15:55:25 -0800172static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
David S. Miller4c9483b2011-03-12 16:22:43 -0500173 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
175 struct dst_entry *dst;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900176 struct net *net = sock_net(sk);
David S. Miller92d86822011-02-04 15:55:25 -0800177 bool res = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179 /* Informational messages are not limited. */
180 if (type & ICMPV6_INFOMSG_MASK)
David S. Miller92d86822011-02-04 15:55:25 -0800181 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 /* Do not limit pmtu discovery, it would break it. */
184 if (type == ICMPV6_PKT_TOOBIG)
David S. Miller92d86822011-02-04 15:55:25 -0800185 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900187 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 * Look up the output route.
189 * XXX: perhaps the expire for routing entries cloned by
190 * this lookup should be more aggressive (not longer than timeout).
191 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500192 dst = ip6_route_output(net, sk, fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 if (dst->error) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -0700194 IP6_INC_STATS(net, ip6_dst_idev(dst),
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900195 IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
David S. Miller92d86822011-02-04 15:55:25 -0800197 res = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 } else {
199 struct rt6_info *rt = (struct rt6_info *)dst;
Benjamin Thery9a43b702008-03-05 10:49:18 -0800200 int tmo = net->ipv6.sysctl.icmpv6_time;
David S. Millerfbfe95a2012-06-08 23:24:18 -0700201 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 /* Give more bandwidth to wider prefixes. */
204 if (rt->rt6i_dst.plen < 128)
205 tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
206
David S. Miller1d861aa2012-07-10 03:58:16 -0700207 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
David S. Millerfbfe95a2012-06-08 23:24:18 -0700208 res = inet_peer_xrlim_allow(peer, tmo);
David S. Miller1d861aa2012-07-10 03:58:16 -0700209 if (peer)
210 inet_putpeer(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
212 dst_release(dst);
213 return res;
214}
215
216/*
217 * an inline helper for the "simple" if statement below
218 * checks if parameter problem report is caused by an
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900219 * unrecognized IPv6 option that has the Option Type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 * highest-order two bits set to 10
221 */
222
Eric Dumazeta50feda2012-05-18 18:57:34 +0000223static bool opt_unrec(struct sk_buff *skb, __u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 u8 _optval, *op;
226
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300227 offset += skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
229 if (op == NULL)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000230 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 return (*op & 0xC0) == 0x80;
232}
233
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +0000234int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
235 struct icmp6hdr *thdr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
237 struct sk_buff *skb;
238 struct icmp6hdr *icmp6h;
239 int err = 0;
240
241 if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
242 goto out;
243
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300244 icmp6h = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
246 icmp6h->icmp6_cksum = 0;
247
248 if (skb_queue_len(&sk->sk_write_queue) == 1) {
Joe Perches07f07572008-11-19 15:44:53 -0800249 skb->csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 sizeof(struct icmp6hdr), skb->csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500251 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
252 &fl6->daddr,
253 len, fl6->flowi6_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 skb->csum);
255 } else {
Al Viro868c86b2006-11-14 21:35:48 -0800256 __wsum tmp_csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 skb_queue_walk(&sk->sk_write_queue, skb) {
259 tmp_csum = csum_add(tmp_csum, skb->csum);
260 }
261
Joe Perches07f07572008-11-19 15:44:53 -0800262 tmp_csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 sizeof(struct icmp6hdr), tmp_csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500264 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
265 &fl6->daddr,
266 len, fl6->flowi6_proto,
Al Viro868c86b2006-11-14 21:35:48 -0800267 tmp_csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 ip6_push_pending_frames(sk);
270out:
271 return err;
272}
273
274struct icmpv6_msg {
275 struct sk_buff *skb;
276 int offset;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800277 uint8_t type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278};
279
280static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
281{
282 struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
283 struct sk_buff *org_skb = msg->skb;
Al Viro5f92a732006-11-14 21:36:54 -0800284 __wsum csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
287 to, len, csum);
288 skb->csum = csum_block_add(skb->csum, csum, odd);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800289 if (!(msg->type & ICMPV6_INFOMSG_MASK))
290 nf_ct_attach(skb, org_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 return 0;
292}
293
Amerigo Wang07a93622012-10-29 16:23:10 +0000294#if IS_ENABLED(CONFIG_IPV6_MIP6)
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700295static void mip6_addr_swap(struct sk_buff *skb)
296{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700297 struct ipv6hdr *iph = ipv6_hdr(skb);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700298 struct inet6_skb_parm *opt = IP6CB(skb);
299 struct ipv6_destopt_hao *hao;
300 struct in6_addr tmp;
301 int off;
302
303 if (opt->dsthao) {
304 off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
305 if (likely(off >= 0)) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700306 hao = (struct ipv6_destopt_hao *)
307 (skb_network_header(skb) + off);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000308 tmp = iph->saddr;
309 iph->saddr = hao->addr;
310 hao->addr = tmp;
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700311 }
312 }
313}
314#else
315static inline void mip6_addr_swap(struct sk_buff *skb) {}
316#endif
317
stephen hemmingere8243532013-12-29 14:03:31 -0800318static struct dst_entry *icmpv6_route_lookup(struct net *net,
319 struct sk_buff *skb,
320 struct sock *sk,
321 struct flowi6 *fl6)
David S. Millerb42835d2011-03-01 22:06:22 -0800322{
323 struct dst_entry *dst, *dst2;
David S. Miller4c9483b2011-03-12 16:22:43 -0500324 struct flowi6 fl2;
David S. Millerb42835d2011-03-01 22:06:22 -0800325 int err;
326
David S. Miller4c9483b2011-03-12 16:22:43 -0500327 err = ip6_dst_lookup(sk, &dst, fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800328 if (err)
329 return ERR_PTR(err);
330
331 /*
332 * We won't send icmp if the destination is known
333 * anycast.
334 */
335 if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) {
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000336 LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: acast source\n");
David S. Millerb42835d2011-03-01 22:06:22 -0800337 dst_release(dst);
338 return ERR_PTR(-EINVAL);
339 }
340
341 /* No need to clone since we're just using its address. */
342 dst2 = dst;
343
David S. Miller4c9483b2011-03-12 16:22:43 -0500344 dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800345 if (!IS_ERR(dst)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800346 if (dst != dst2)
347 return dst;
David S. Miller452edd52011-03-02 13:27:41 -0800348 } else {
349 if (PTR_ERR(dst) == -EPERM)
350 dst = NULL;
351 else
352 return dst;
David S. Millerb42835d2011-03-01 22:06:22 -0800353 }
354
David S. Miller4c9483b2011-03-12 16:22:43 -0500355 err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6);
David S. Millerb42835d2011-03-01 22:06:22 -0800356 if (err)
357 goto relookup_failed;
358
359 err = ip6_dst_lookup(sk, &dst2, &fl2);
360 if (err)
361 goto relookup_failed;
362
David S. Miller4c9483b2011-03-12 16:22:43 -0500363 dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP);
David S. Miller452edd52011-03-02 13:27:41 -0800364 if (!IS_ERR(dst2)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800365 dst_release(dst);
366 dst = dst2;
David S. Miller452edd52011-03-02 13:27:41 -0800367 } else {
368 err = PTR_ERR(dst2);
369 if (err == -EPERM) {
370 dst_release(dst);
371 return dst2;
372 } else
373 goto relookup_failed;
David S. Millerb42835d2011-03-01 22:06:22 -0800374 }
375
376relookup_failed:
377 if (dst)
378 return dst;
379 return ERR_PTR(err);
380}
381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382/*
383 * Send an ICMP message in response to a packet in error
384 */
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000385static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900387 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 struct inet6_dev *idev = NULL;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700389 struct ipv6hdr *hdr = ipv6_hdr(skb);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700390 struct sock *sk;
391 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000392 const struct in6_addr *saddr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 struct dst_entry *dst;
394 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500395 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 struct icmpv6_msg msg;
397 int iif = 0;
398 int addr_type = 0;
399 int len;
Gerrit Renkere651f032009-08-09 08:12:48 +0000400 int hlimit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 int err = 0;
402
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700403 if ((u8 *)hdr < skb->head ||
Simon Horman29a3cad2013-05-28 20:34:26 +0000404 (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb))
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)
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000410 * Rule (e.1) is enforced by not using icmp6_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 * 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 Sowa842df072013-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)) {
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000448 LIMIT_NETDEBUG(KERN_DEBUG "icmp6_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)) {
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000456 LIMIT_NETDEBUG(KERN_DEBUG "icmp6_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;
David S. Miller4c9483b2011-03-12 16:22:43 -0500467 fl6.flowi6_oif = iif;
David S. Miller1958b852011-03-12 16:36:19 -0500468 fl6.fl6_icmp_type = type;
469 fl6.fl6_icmp_code = code;
David S. Miller4c9483b2011-03-12 16:22:43 -0500470 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700472 sk = icmpv6_xmit_lock(net);
473 if (sk == NULL)
Denis V. Lunev405666d2008-02-29 11:16:46 -0800474 return;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700475 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800476
David S. Miller4c9483b2011-03-12 16:22:43 -0500477 if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 goto out;
479
480 tmp_hdr.icmp6_type = type;
481 tmp_hdr.icmp6_code = code;
482 tmp_hdr.icmp6_cksum = 0;
483 tmp_hdr.icmp6_pointer = htonl(info);
484
David S. Miller4c9483b2011-03-12 16:22:43 -0500485 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
486 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000487 else if (!fl6.flowi6_oif)
488 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
David S. Miller4c9483b2011-03-12 16:22:43 -0500490 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800491 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 goto out;
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900493
David S. Miller4c9483b2011-03-12 16:22:43 -0500494 if (ipv6_addr_is_multicast(&fl6.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 hlimit = np->mcast_hops;
496 else
497 hlimit = np->hop_limit;
498 if (hlimit < 0)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -0400499 hlimit = ip6_dst_hoplimit(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
501 msg.skb = skb;
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300502 msg.offset = skb_network_offset(skb);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800503 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 len = skb->len - msg.offset;
506 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr));
507 if (len < 0) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700508 LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 goto out_dst_release;
510 }
511
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000512 rcu_read_lock();
513 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515 err = ip6_append_data(sk, icmpv6_getfrag, &msg,
516 len + sizeof(struct icmp6hdr),
Gerrit Renkere651f032009-08-09 08:12:48 +0000517 sizeof(struct icmp6hdr), hlimit,
Eldad Zacka2d91a02012-04-01 07:49:07 +0000518 np->tclass, NULL, &fl6, (struct rt6_info *)dst,
Brian Haley13b52cd2010-04-23 11:26:08 +0000519 MSG_DONTWAIT, np->dontfrag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 if (err) {
Eric Dumazet00d9d6a2010-06-07 22:24:44 +0000521 ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000523 } else {
524 err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
525 len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000527 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528out_dst_release:
529 dst_release(dst);
530out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800531 icmpv6_xmit_unlock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532}
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000533
534/* Slightly more convenient version of icmp6_send.
535 */
536void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
537{
538 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos);
539 kfree_skb(skb);
540}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542static void icmpv6_echo_reply(struct sk_buff *skb)
543{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900544 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700545 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700547 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000548 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300549 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500551 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 struct icmpv6_msg msg;
553 struct dst_entry *dst;
554 int err = 0;
555 int hlimit;
556
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700557 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
FX Le Bail509aba32014-01-07 14:57:27 +0100559 if (!ipv6_unicast_destination(skb) &&
560 !(net->ipv6.anycast_src_echo_reply &&
561 ipv6_anycast_destination(skb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 saddr = NULL;
563
564 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
565 tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
566
David S. Miller4c9483b2011-03-12 16:22:43 -0500567 memset(&fl6, 0, sizeof(fl6));
568 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000569 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000571 fl6.saddr = *saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500572 fl6.flowi6_oif = skb->dev->ifindex;
David S. Miller1958b852011-03-12 16:36:19 -0500573 fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
David S. Miller4c9483b2011-03-12 16:22:43 -0500574 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700576 sk = icmpv6_xmit_lock(net);
577 if (sk == NULL)
Denis V. Lunev405666d2008-02-29 11:16:46 -0800578 return;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700579 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800580
David S. Miller4c9483b2011-03-12 16:22:43 -0500581 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
582 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000583 else if (!fl6.flowi6_oif)
584 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
David S. Miller4c9483b2011-03-12 16:22:43 -0500586 err = ip6_dst_lookup(sk, &dst, &fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 if (err)
588 goto out;
David S. Miller4c9483b2011-03-12 16:22:43 -0500589 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800590 if (IS_ERR(dst))
Patrick McHardye104411b2005-09-08 15:11:55 -0700591 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
David S. Miller4c9483b2011-03-12 16:22:43 -0500593 if (ipv6_addr_is_multicast(&fl6.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 hlimit = np->mcast_hops;
595 else
596 hlimit = np->hop_limit;
597 if (hlimit < 0)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -0400598 hlimit = ip6_dst_hoplimit(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000600 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602 msg.skb = skb;
603 msg.offset = 0;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800604 msg.type = ICMPV6_ECHO_REPLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
606 err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
David S. Miller4c9483b2011-03-12 16:22:43 -0500607 sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl6,
Eldad Zacka2d91a02012-04-01 07:49:07 +0000608 (struct rt6_info *)dst, MSG_DONTWAIT,
Brian Haley13b52cd2010-04-23 11:26:08 +0000609 np->dontfrag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 if (err) {
Eric Dumazet00d9d6a2010-06-07 22:24:44 +0000612 ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000614 } else {
615 err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
616 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900619out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800620 icmpv6_xmit_unlock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
David S. Millerb94f1c02012-07-12 00:33:37 -0700623void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000625 const struct inet6_protocol *ipprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 int inner_offset;
Jesse Gross75f28112011-11-30 17:05:51 -0800627 __be16 frag_off;
David S. Millerf9242b62012-06-19 18:56:21 -0700628 u8 nexthdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
631 return;
632
633 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
634 if (ipv6_ext_hdr(nexthdr)) {
635 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800636 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
637 &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (inner_offset<0)
639 return;
640 } else {
641 inner_offset = sizeof(struct ipv6hdr);
642 }
643
644 /* Checkin header including 8 bytes of inner protocol header. */
645 if (!pskb_may_pull(skb, inner_offset+8))
646 return;
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
649 Without this we will not able f.e. to make source routed
650 pmtu discovery.
651 Corresponding argument (opt) to notifiers is already added.
652 --ANK (980726)
653 */
654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 rcu_read_lock();
David S. Millerf9242b62012-06-19 18:56:21 -0700656 ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (ipprot && ipprot->err_handler)
658 ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
659 rcu_read_unlock();
660
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800661 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900663
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664/*
665 * Handle icmp messages
666 */
667
Herbert Xue5bbef22007-10-15 12:50:28 -0700668static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 struct net_device *dev = skb->dev;
671 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000672 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700674 u8 type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Herbert Xuaebcf822007-12-12 18:54:16 -0800676 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700677 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800678 int nh;
679
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700680 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Herbert Xuaebcf822007-12-12 18:54:16 -0800681 XFRM_STATE_ICMP))
682 goto drop_no_count;
683
David S. Miller81aded22012-06-15 14:54:11 -0700684 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800685 goto drop_no_count;
686
687 nh = skb_network_offset(skb);
688 skb_set_network_header(skb, sizeof(*hdr));
689
690 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
691 goto drop_no_count;
692
693 skb_set_network_header(skb, nh);
694 }
695
Denis V. Luneve41b5362008-10-08 10:33:26 -0700696 ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700698 saddr = &ipv6_hdr(skb)->saddr;
699 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701 /* Perform checksum. */
Herbert Xufb286bb2005-11-10 13:01:24 -0800702 switch (skb->ip_summed) {
Patrick McHardy84fa7932006-08-29 16:44:56 -0700703 case CHECKSUM_COMPLETE:
Herbert Xufb286bb2005-11-10 13:01:24 -0800704 if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
705 skb->csum))
706 break;
707 /* fall through */
708 case CHECKSUM_NONE:
Al Viro868c86b2006-11-14 21:35:48 -0800709 skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len,
710 IPPROTO_ICMPV6, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -0800711 if (__skb_checksum_complete(skb)) {
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +0000712 LIMIT_NETDEBUG(KERN_DEBUG
713 "ICMPv6 checksum failed [%pI6c > %pI6c]\n",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700714 saddr, daddr);
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +0000715 goto csum_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 }
717 }
718
Herbert Xu8cf22942008-02-05 03:15:50 -0800719 if (!pskb_pull(skb, sizeof(*hdr)))
720 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300722 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 type = hdr->icmp6_type;
725
Denis V. Lunev55d43802008-10-08 10:34:54 -0700726 ICMP6MSGIN_INC_STATS_BH(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
728 switch (type) {
729 case ICMPV6_ECHO_REQUEST:
730 icmpv6_echo_reply(skb);
731 break;
732
733 case ICMPV6_ECHO_REPLY:
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +0000734 ping_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 break;
736
737 case ICMPV6_PKT_TOOBIG:
738 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
739 standard destination cache. Seems, only "advanced"
740 destination cache will allow to solve this problem
741 --ANK (980726)
742 */
743 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
744 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300745 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 /*
748 * Drop through to notify
749 */
750
751 case ICMPV6_DEST_UNREACH:
752 case ICMPV6_TIME_EXCEED:
753 case ICMPV6_PARAMPROB:
754 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
755 break;
756
757 case NDISC_ROUTER_SOLICITATION:
758 case NDISC_ROUTER_ADVERTISEMENT:
759 case NDISC_NEIGHBOUR_SOLICITATION:
760 case NDISC_NEIGHBOUR_ADVERTISEMENT:
761 case NDISC_REDIRECT:
762 ndisc_rcv(skb);
763 break;
764
765 case ICMPV6_MGM_QUERY:
766 igmp6_event_query(skb);
767 break;
768
769 case ICMPV6_MGM_REPORT:
770 igmp6_event_report(skb);
771 break;
772
773 case ICMPV6_MGM_REDUCTION:
774 case ICMPV6_NI_QUERY:
775 case ICMPV6_NI_REPLY:
776 case ICMPV6_MLD2_REPORT:
777 case ICMPV6_DHAAD_REQUEST:
778 case ICMPV6_DHAAD_REPLY:
779 case ICMPV6_MOBILE_PREFIX_SOL:
780 case ICMPV6_MOBILE_PREFIX_ADV:
781 break;
782
783 default:
Patrick McHardy64ce2072005-08-09 20:50:53 -0700784 LIMIT_NETDEBUG(KERN_DEBUG "icmpv6: msg of unknown type\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
786 /* informational */
787 if (type & ICMPV6_INFOMSG_MASK)
788 break;
789
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900790 /*
791 * error of unknown type.
792 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 */
794
795 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700796 }
797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 kfree_skb(skb);
799 return 0;
800
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +0000801csum_error:
802 ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803discard_it:
Denis V. Luneve41b5362008-10-08 10:33:26 -0700804 ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800805drop_no_count:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 kfree_skb(skb);
807 return 0;
808}
809
David S. Miller4c9483b2011-03-12 16:22:43 -0500810void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800811 u8 type,
812 const struct in6_addr *saddr,
813 const struct in6_addr *daddr,
814 int oif)
815{
David S. Miller4c9483b2011-03-12 16:22:43 -0500816 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000817 fl6->saddr = *saddr;
818 fl6->daddr = *daddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500819 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -0500820 fl6->fl6_icmp_type = type;
821 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -0500822 fl6->flowi6_oif = oif;
823 security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800824}
825
Ingo Molnar640c41c2006-08-15 00:06:56 -0700826/*
Denis V. Lunevb7e729c2008-02-29 11:16:08 -0800827 * Special lock-class for __icmpv6_sk:
Ingo Molnar640c41c2006-08-15 00:06:56 -0700828 */
829static struct lock_class_key icmpv6_socket_sk_dst_lock_key;
830
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800831static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
833 struct sock *sk;
834 int err, i, j;
835
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800836 net->ipv6.icmp_sk =
837 kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
838 if (net->ipv6.icmp_sk == NULL)
Denis V. Lunev79c91152008-02-29 11:17:11 -0800839 return -ENOMEM;
840
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700841 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700842 err = inet_ctl_sock_create(&sk, PF_INET6,
843 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 if (err < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +0000845 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 err);
847 goto fail;
848 }
849
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700850 net->ipv6.icmp_sk[i] = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -0800851
Ingo Molnar640c41c2006-08-15 00:06:56 -0700852 /*
853 * Split off their lock-class, because sk->sk_dst_lock
854 * gets used from softirqs, which is safe for
Denis V. Lunevb7e729c2008-02-29 11:16:08 -0800855 * __icmpv6_sk (because those never get directly used
Ingo Molnar640c41c2006-08-15 00:06:56 -0700856 * via userspace syscalls), but unsafe for normal sockets.
857 */
858 lockdep_set_class(&sk->sk_dst_lock,
859 &icmpv6_socket_sk_dst_lock_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
861 /* Enough space for 2 64K ICMP packets, including
862 * sk_buff struct overhead.
863 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +0000864 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 return 0;
867
868 fail:
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -0800869 for (j = 0; j < i; j++)
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700870 inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800871 kfree(net->ipv6.icmp_sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return err;
873}
874
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800875static void __net_exit icmpv6_sk_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
877 int i;
878
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700879 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700880 inet_ctl_sock_destroy(net->ipv6.icmp_sk[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800882 kfree(net->ipv6.icmp_sk);
883}
884
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -0800885static struct pernet_operations icmpv6_sk_ops = {
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800886 .init = icmpv6_sk_init,
887 .exit = icmpv6_sk_exit,
888};
889
890int __init icmpv6_init(void)
891{
892 int err;
893
894 err = register_pernet_subsys(&icmpv6_sk_ops);
895 if (err < 0)
896 return err;
897
898 err = -EAGAIN;
899 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
900 goto fail;
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000901
902 err = inet6_register_icmp_sender(icmp6_send);
903 if (err)
904 goto sender_reg_err;
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800905 return 0;
906
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000907sender_reg_err:
908 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800909fail:
Joe Perchesf3213832012-05-15 14:11:53 +0000910 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800911 unregister_pernet_subsys(&icmpv6_sk_ops);
912 return err;
913}
914
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -0800915void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800916{
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000917 inet6_unregister_icmp_sender(icmp6_send);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800918 unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
920}
921
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800922
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -0800923static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 int err;
925 int fatal;
926} tab_unreach[] = {
927 { /* NOROUTE */
928 .err = ENETUNREACH,
929 .fatal = 0,
930 },
931 { /* ADM_PROHIBITED */
932 .err = EACCES,
933 .fatal = 1,
934 },
935 { /* Was NOT_NEIGHBOUR, now reserved */
936 .err = EHOSTUNREACH,
937 .fatal = 0,
938 },
939 { /* ADDR_UNREACH */
940 .err = EHOSTUNREACH,
941 .fatal = 0,
942 },
943 { /* PORT_UNREACH */
944 .err = ECONNREFUSED,
945 .fatal = 1,
946 },
Jiri Bohac61e76b12013-08-30 11:18:45 +0200947 { /* POLICY_FAIL */
948 .err = EACCES,
949 .fatal = 1,
950 },
951 { /* REJECT_ROUTE */
952 .err = EACCES,
953 .fatal = 1,
954 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955};
956
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700957int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
959 int fatal = 0;
960
961 *err = EPROTO;
962
963 switch (type) {
964 case ICMPV6_DEST_UNREACH:
965 fatal = 1;
Jiri Bohac61e76b12013-08-30 11:18:45 +0200966 if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 *err = tab_unreach[code].err;
968 fatal = tab_unreach[code].fatal;
969 }
970 break;
971
972 case ICMPV6_PKT_TOOBIG:
973 *err = EMSGSIZE;
974 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 case ICMPV6_PARAMPROB:
977 *err = EPROTO;
978 fatal = 1;
979 break;
980
981 case ICMPV6_TIME_EXCEED:
982 *err = EHOSTUNREACH;
983 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 return fatal;
987}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900988EXPORT_SYMBOL(icmpv6_err_convert);
989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990#ifdef CONFIG_SYSCTL
stephen hemmingere8243532013-12-29 14:03:31 -0800991static struct ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -0800994 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 .maxlen = sizeof(int),
996 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -0800997 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -0800999 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000};
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001001
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001002struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001003{
1004 struct ctl_table *table;
1005
1006 table = kmemdup(ipv6_icmp_table_template,
1007 sizeof(ipv6_icmp_table_template),
1008 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001009
Eric W. Biedermanc027aab2012-11-16 03:03:10 +00001010 if (table)
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001011 table[0].data = &net->ipv6.sysctl.icmpv6_time;
1012
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001013 return table;
1014}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015#endif
1016