blob: cbab41d557b20596c8f38fc01362bc77051b014e [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * Internet Control Message Protocol (ICMPv6)
4 * Linux INET6 implementation
5 *
6 * Authors:
7 * Pedro Roque <roque@di.fc.ul.pt>
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Based on net/ipv4/icmp.c
10 *
11 * RFC 1885
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
13
14/*
15 * Changes:
16 *
17 * Andi Kleen : exception handling
18 * Andi Kleen add rate limits. never reply to a icmp.
19 * add more length checks and other fixes.
20 * yoshfuji : ensure to sent parameter problem for
21 * fragments.
22 * YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit.
23 * Randy Dunlap and
24 * YOSHIFUJI Hideaki @USAGI: Per-interface statistics support
25 * Kazunori MIYAZAWA @USAGI: change output process to use ip6_append_data
26 */
27
Joe Perchesf3213832012-05-15 14:11:53 +000028#define pr_fmt(fmt) "IPv6: " fmt
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31#include <linux/errno.h>
32#include <linux/types.h>
33#include <linux/socket.h>
34#include <linux/in.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sockios.h>
37#include <linux/net.h>
38#include <linux/skbuff.h>
39#include <linux/init.h>
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -080040#include <linux/netfilter.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090041#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#ifdef CONFIG_SYSCTL
44#include <linux/sysctl.h>
45#endif
46
47#include <linux/inet.h>
48#include <linux/netdevice.h>
49#include <linux/icmpv6.h>
50
51#include <net/ip.h>
52#include <net/sock.h>
53
54#include <net/ipv6.h>
55#include <net/ip6_checksum.h>
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000056#include <net/ping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <net/protocol.h>
58#include <net/raw.h>
59#include <net/rawv6.h>
60#include <net/transp_v6.h>
61#include <net/ip6_route.h>
62#include <net/addrconf.h>
63#include <net/icmp.h>
Herbert Xu8b7817f2007-12-12 10:44:43 -080064#include <net/xfrm.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070065#include <net/inet_common.h>
Hannes Frederic Sowa825edac2014-01-11 11:55:46 +010066#include <net/dsfield.h>
David Ahernca254492015-10-12 11:47:10 -070067#include <net/l3mdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080069#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/*
72 * The ICMP socket(s). This is the most convenient way to flow control
73 * our ICMP output as well as maintain a clean interface throughout
74 * all layers. All Socketless IP sends will soon be gone.
75 *
76 * On SMP we have one ICMP socket per-cpu.
77 */
Eric Dumazet2789c142019-05-31 15:27:00 -070078static struct sock *icmpv6_sk(struct net *net)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -080079{
Eric Dumazet2789c142019-05-31 15:27:00 -070080 return this_cpu_read(*net->ipv6.icmp_sk);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -080081}
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Stefano Brivio32bbd872018-11-08 12:19:21 +010083static int icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Steffen Klassert6f809da2013-01-16 22:09:49 +000084 u8 type, u8 code, int offset, __be32 info)
85{
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000086 /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
87 struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
Steffen Klassert6f809da2013-01-16 22:09:49 +000088 struct net *net = dev_net(skb->dev);
89
90 if (type == ICMPV6_PKT_TOOBIG)
Georg Kohmann5f379ef2018-08-02 13:56:58 +020091 ip6_update_pmtu(skb, net, info, skb->dev->ifindex, 0, sock_net_uid(net, NULL));
Steffen Klassert6f809da2013-01-16 22:09:49 +000092 else if (type == NDISC_REDIRECT)
Lorenzo Colittie2d118a2016-11-04 02:23:43 +090093 ip6_redirect(skb, net, skb->dev->ifindex, 0,
94 sock_net_uid(net, NULL));
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000095
96 if (!(type & ICMPV6_INFOMSG_MASK))
97 if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
Hannes Frederic Sowadcb94b82016-06-11 20:32:06 +020098 ping_err(skb, offset, ntohl(info));
Stefano Brivio32bbd872018-11-08 12:19:21 +010099
100 return 0;
Steffen Klassert6f809da2013-01-16 22:09:49 +0000101}
102
Herbert Xue5bbef22007-10-15 12:50:28 -0700103static int icmpv6_rcv(struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000105static const struct inet6_protocol icmpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 .handler = icmpv6_rcv,
Steffen Klassert6f809da2013-01-16 22:09:49 +0000107 .err_handler = icmpv6_err,
Herbert Xu8b7817f2007-12-12 10:44:43 -0800108 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109};
110
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100111/* Called with BH disabled */
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700112static __inline__ struct sock *icmpv6_xmit_lock(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700114 struct sock *sk;
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 */
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700122 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 }
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700124 return sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Denis V. Lunev405666d2008-02-29 11:16:46 -0800127static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100129 spin_unlock(&sk->sk_lock.slock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130}
131
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900132/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 * Figure out, may we reply to this packet with icmp error.
134 *
135 * We do not reply, if:
136 * - it was icmp error message.
137 * - it is truncated, so that it is known, that protocol is ICMPV6
138 * (i.e. in the middle of some exthdr)
139 *
140 * --ANK (980726)
141 */
142
Eric Dumazeta50feda2012-05-18 18:57:34 +0000143static bool is_ineligible(const struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700145 int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 int len = skb->len - ptr;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700147 __u8 nexthdr = ipv6_hdr(skb)->nexthdr;
Jesse Gross75f28112011-11-30 17:05:51 -0800148 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 if (len < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000151 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Jesse Gross75f28112011-11-30 17:05:51 -0800153 ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 if (ptr < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000155 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 if (nexthdr == IPPROTO_ICMPV6) {
157 u8 _type, *tp;
158 tp = skb_header_pointer(skb,
159 ptr+offsetof(struct icmp6hdr, icmp6_type),
160 sizeof(_type), &_type);
Hangbin Liu2efdaaa2020-10-27 20:33:13 +0800161
162 /* Based on RFC 8200, Section 4.5 Fragment Header, return
163 * false if this is a fragment packet with no icmp header info.
164 */
165 if (!tp && frag_off != 0)
166 return false;
167 else if (!tp || !(*tp & ICMPV6_INFOMSG_MASK))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000168 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000170 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400173static bool icmpv6_mask_allow(struct net *net, int type)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100174{
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400175 if (type > ICMPV6_MSG_MAX)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100176 return true;
177
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400178 /* Limit if icmp type is set in ratemask. */
179 if (!test_bit(type, net->ipv6.sysctl.icmpv6_ratemask))
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100180 return true;
181
182 return false;
183}
184
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400185static bool icmpv6_global_allow(struct net *net, int type)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100186{
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400187 if (icmpv6_mask_allow(net, type))
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100188 return true;
189
190 if (icmp_global_allow())
191 return true;
192
193 return false;
194}
195
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900196/*
197 * Check the ICMP output rate limit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 */
Eric Dumazet4cdf5072014-09-19 07:38:40 -0700199static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
200 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900202 struct net *net = sock_net(sk);
Eric Dumazet4cdf5072014-09-19 07:38:40 -0700203 struct dst_entry *dst;
David S. Miller92d86822011-02-04 15:55:25 -0800204 bool res = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400206 if (icmpv6_mask_allow(net, type))
David S. Miller92d86822011-02-04 15:55:25 -0800207 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900209 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 * Look up the output route.
211 * XXX: perhaps the expire for routing entries cloned by
212 * this lookup should be more aggressive (not longer than timeout).
213 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500214 dst = ip6_route_output(net, sk, fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 if (dst->error) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -0700216 IP6_INC_STATS(net, ip6_dst_idev(dst),
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900217 IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
David S. Miller92d86822011-02-04 15:55:25 -0800219 res = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 } else {
221 struct rt6_info *rt = (struct rt6_info *)dst;
Benjamin Thery9a43b702008-03-05 10:49:18 -0800222 int tmo = net->ipv6.sysctl.icmpv6_time;
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100223 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225 /* Give more bandwidth to wider prefixes. */
226 if (rt->rt6i_dst.plen < 128)
227 tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
228
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100229 peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr, 1);
230 res = inet_peer_xrlim_allow(peer, tmo);
231 if (peer)
232 inet_putpeer(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 }
234 dst_release(dst);
235 return res;
236}
237
Tim Stallardb93cfb92020-04-03 21:22:57 +0100238static bool icmpv6_rt_has_prefsrc(struct sock *sk, u8 type,
239 struct flowi6 *fl6)
240{
241 struct net *net = sock_net(sk);
242 struct dst_entry *dst;
243 bool res = false;
244
245 dst = ip6_route_output(net, sk, fl6);
246 if (!dst->error) {
247 struct rt6_info *rt = (struct rt6_info *)dst;
248 struct in6_addr prefsrc;
249
250 rt6_get_prefsrc(rt, &prefsrc);
251 res = !ipv6_addr_any(&prefsrc);
252 }
253 dst_release(dst);
254 return res;
255}
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257/*
258 * an inline helper for the "simple" if statement below
259 * checks if parameter problem report is caused by an
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900260 * unrecognized IPv6 option that has the Option Type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 * highest-order two bits set to 10
262 */
263
Eric Dumazeta50feda2012-05-18 18:57:34 +0000264static bool opt_unrec(struct sk_buff *skb, __u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 u8 _optval, *op;
267
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300268 offset += skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
Ian Morris63159f22015-03-29 14:00:04 +0100270 if (!op)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000271 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 return (*op & 0xC0) == 0x80;
273}
274
Joe Perches4e64b1e2017-10-05 23:46:14 -0700275void icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
276 struct icmp6hdr *thdr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
278 struct sk_buff *skb;
279 struct icmp6hdr *icmp6h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Ian Morrise5d08d72014-11-23 21:28:43 +0000281 skb = skb_peek(&sk->sk_write_queue);
Ian Morris63159f22015-03-29 14:00:04 +0100282 if (!skb)
Joe Perches4e64b1e2017-10-05 23:46:14 -0700283 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300285 icmp6h = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
287 icmp6h->icmp6_cksum = 0;
288
289 if (skb_queue_len(&sk->sk_write_queue) == 1) {
Joe Perches07f07572008-11-19 15:44:53 -0800290 skb->csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 sizeof(struct icmp6hdr), skb->csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500292 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
293 &fl6->daddr,
294 len, fl6->flowi6_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 skb->csum);
296 } else {
Al Viro868c86b2006-11-14 21:35:48 -0800297 __wsum tmp_csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 skb_queue_walk(&sk->sk_write_queue, skb) {
300 tmp_csum = csum_add(tmp_csum, skb->csum);
301 }
302
Joe Perches07f07572008-11-19 15:44:53 -0800303 tmp_csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 sizeof(struct icmp6hdr), tmp_csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500305 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
306 &fl6->daddr,
307 len, fl6->flowi6_proto,
Al Viro868c86b2006-11-14 21:35:48 -0800308 tmp_csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 ip6_push_pending_frames(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
312
313struct icmpv6_msg {
314 struct sk_buff *skb;
315 int offset;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800316 uint8_t type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317};
318
319static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
320{
321 struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
322 struct sk_buff *org_skb = msg->skb;
Al Viro8d5930d2020-07-10 20:07:10 -0400323 __wsum csum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
Al Viro8d5930d2020-07-10 20:07:10 -0400326 to, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 skb->csum = csum_block_add(skb->csum, csum, odd);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800328 if (!(msg->type & ICMPV6_INFOMSG_MASK))
329 nf_ct_attach(skb, org_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 return 0;
331}
332
Amerigo Wang07a93622012-10-29 16:23:10 +0000333#if IS_ENABLED(CONFIG_IPV6_MIP6)
Jason A. Donenfeldce4feb02021-02-23 14:18:58 +0100334static void mip6_addr_swap(struct sk_buff *skb, const struct inet6_skb_parm *opt)
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700335{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700336 struct ipv6hdr *iph = ipv6_hdr(skb);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700337 struct ipv6_destopt_hao *hao;
338 struct in6_addr tmp;
339 int off;
340
341 if (opt->dsthao) {
342 off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
343 if (likely(off >= 0)) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700344 hao = (struct ipv6_destopt_hao *)
345 (skb_network_header(skb) + off);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000346 tmp = iph->saddr;
347 iph->saddr = hao->addr;
348 hao->addr = tmp;
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700349 }
350 }
351}
352#else
Jason A. Donenfeldce4feb02021-02-23 14:18:58 +0100353static inline void mip6_addr_swap(struct sk_buff *skb, const struct inet6_skb_parm *opt) {}
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700354#endif
355
stephen hemmingere8243532013-12-29 14:03:31 -0800356static struct dst_entry *icmpv6_route_lookup(struct net *net,
357 struct sk_buff *skb,
358 struct sock *sk,
359 struct flowi6 *fl6)
David S. Millerb42835d2011-03-01 22:06:22 -0800360{
361 struct dst_entry *dst, *dst2;
David S. Miller4c9483b2011-03-12 16:22:43 -0500362 struct flowi6 fl2;
David S. Millerb42835d2011-03-01 22:06:22 -0800363 int err;
364
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700365 err = ip6_dst_lookup(net, sk, &dst, fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800366 if (err)
367 return ERR_PTR(err);
368
369 /*
370 * We won't send icmp if the destination is known
371 * anycast.
372 */
Martin KaFai Lau2647a9b2015-05-22 20:55:58 -0700373 if (ipv6_anycast_destination(dst, &fl6->daddr)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800374 net_dbg_ratelimited("icmp6_send: acast source\n");
David S. Millerb42835d2011-03-01 22:06:22 -0800375 dst_release(dst);
376 return ERR_PTR(-EINVAL);
377 }
378
379 /* No need to clone since we're just using its address. */
380 dst2 = dst;
381
David S. Miller4c9483b2011-03-12 16:22:43 -0500382 dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800383 if (!IS_ERR(dst)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800384 if (dst != dst2)
385 return dst;
David S. Miller452edd52011-03-02 13:27:41 -0800386 } else {
387 if (PTR_ERR(dst) == -EPERM)
388 dst = NULL;
389 else
390 return dst;
David S. Millerb42835d2011-03-01 22:06:22 -0800391 }
392
David S. Miller4c9483b2011-03-12 16:22:43 -0500393 err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6);
David S. Millerb42835d2011-03-01 22:06:22 -0800394 if (err)
395 goto relookup_failed;
396
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700397 err = ip6_dst_lookup(net, sk, &dst2, &fl2);
David S. Millerb42835d2011-03-01 22:06:22 -0800398 if (err)
399 goto relookup_failed;
400
David S. Miller4c9483b2011-03-12 16:22:43 -0500401 dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP);
David S. Miller452edd52011-03-02 13:27:41 -0800402 if (!IS_ERR(dst2)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800403 dst_release(dst);
404 dst = dst2;
David S. Miller452edd52011-03-02 13:27:41 -0800405 } else {
406 err = PTR_ERR(dst2);
407 if (err == -EPERM) {
408 dst_release(dst);
409 return dst2;
410 } else
411 goto relookup_failed;
David S. Millerb42835d2011-03-01 22:06:22 -0800412 }
413
414relookup_failed:
415 if (dst)
416 return dst;
417 return ERR_PTR(err);
418}
419
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400420static struct net_device *icmp6_dev(const struct sk_buff *skb)
David Ahern1b70d7922017-08-28 13:53:34 -0700421{
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400422 struct net_device *dev = skb->dev;
David Ahern1b70d7922017-08-28 13:53:34 -0700423
424 /* for local traffic to local address, skb dev is the loopback
425 * device. Check if there is a dst attached to the skb and if so
David Ahern24b711e2018-07-19 12:41:18 -0700426 * get the real device index. Same is needed for replies to a link
427 * local address on a device enslaved to an L3 master device
David Ahern1b70d7922017-08-28 13:53:34 -0700428 */
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400429 if (unlikely(dev->ifindex == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) {
David Ahern1b70d7922017-08-28 13:53:34 -0700430 const struct rt6_info *rt6 = skb_rt6_info(skb);
431
432 if (rt6)
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400433 dev = rt6->rt6i_idev->dev;
David Ahern1b70d7922017-08-28 13:53:34 -0700434 }
435
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400436 return dev;
437}
438
439static int icmp6_iif(const struct sk_buff *skb)
440{
441 return icmp6_dev(skb)->ifindex;
David Ahern1b70d7922017-08-28 13:53:34 -0700442}
443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444/*
445 * Send an ICMP message in response to a packet in error
446 */
Eric Dumazetcc7a21b2020-06-19 12:02:59 -0700447void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
Jason A. Donenfeldce4feb02021-02-23 14:18:58 +0100448 const struct in6_addr *force_saddr,
449 const struct inet6_skb_parm *parm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
451 struct inet6_dev *idev = NULL;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700452 struct ipv6hdr *hdr = ipv6_hdr(skb);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700453 struct sock *sk;
Eric Dumazet8d933672019-01-04 11:00:00 -0800454 struct net *net;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700455 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000456 const struct in6_addr *saddr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 struct dst_entry *dst;
458 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500459 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 struct icmpv6_msg msg;
Wei Wang26879da2016-05-02 21:40:07 -0700461 struct ipcm6_cookie ipc6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 int iif = 0;
463 int addr_type = 0;
464 int len;
Eric Dumazet8d933672019-01-04 11:00:00 -0800465 u32 mark;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700467 if ((u8 *)hdr < skb->head ||
Simon Horman29a3cad2013-05-28 20:34:26 +0000468 (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 return;
470
Eric Dumazet8d933672019-01-04 11:00:00 -0800471 if (!skb->dev)
472 return;
473 net = dev_net(skb->dev);
474 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900476 * Make sure we respect the rules
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 * i.e. RFC 1885 2.4(e)
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000478 * Rule (e.1) is enforced by not using icmp6_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 * in any code that processes icmp errors.
480 */
481 addr_type = ipv6_addr_type(&hdr->daddr);
482
FX Le Bail446fab52014-01-19 17:00:36 +0100483 if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) ||
FX Le Baild94c1f92014-02-07 11:22:37 +0100484 ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 saddr = &hdr->daddr;
486
487 /*
488 * Dest addr check
489 */
490
zhuyj9a6b4b32015-01-14 17:23:59 +0800491 if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 if (type != ICMPV6_PKT_TOOBIG &&
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900493 !(type == ICMPV6_PARAMPROB &&
494 code == ICMPV6_UNK_OPTION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 (opt_unrec(skb, info))))
496 return;
497
498 saddr = NULL;
499 }
500
501 addr_type = ipv6_addr_type(&hdr->saddr);
502
503 /*
504 * Source addr check
505 */
506
David Ahern4832c302017-08-17 12:17:20 -0700507 if (__ipv6_addr_needs_scope_id(addr_type)) {
David Ahern1b70d7922017-08-28 13:53:34 -0700508 iif = icmp6_iif(skb);
David Ahern4832c302017-08-17 12:17:20 -0700509 } else {
Mathieu Desnoyers272928d2020-10-12 10:50:15 -0400510 /*
511 * The source device is used for looking up which routing table
512 * to use for sending an ICMP error.
513 */
514 iif = l3mdev_master_ifindex(skb->dev);
David Ahern79dc7e32016-11-27 18:52:53 -0800515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517 /*
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900518 * Must not send error if the source does not uniquely
519 * identify a single node (RFC2463 Section 2.4).
520 * We check unspecified / multicast addresses here,
521 * and anycast addresses will be checked later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 */
523 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200524 net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n",
525 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 return;
527 }
528
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900529 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 * Never answer to a ICMP packet.
531 */
532 if (is_ineligible(skb)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200533 net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n",
534 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return;
536 }
537
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100538 /* Needed by both icmp_global_allow and icmpv6_xmit_lock */
539 local_bh_disable();
540
541 /* Check global sysctl_icmp_msgs_per_sec ratelimit */
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400542 if (!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, type))
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100543 goto out_bh_enable;
544
Jason A. Donenfeldce4feb02021-02-23 14:18:58 +0100545 mip6_addr_swap(skb, parm);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700546
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700547 sk = icmpv6_xmit_lock(net);
548 if (!sk)
549 goto out_bh_enable;
550
David S. Miller4c9483b2011-03-12 16:22:43 -0500551 memset(&fl6, 0, sizeof(fl6));
552 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000553 fl6.daddr = hdr->saddr;
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700554 if (force_saddr)
555 saddr = force_saddr;
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700556 if (saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000557 fl6.saddr = *saddr;
Tim Stallardb93cfb92020-04-03 21:22:57 +0100558 } else if (!icmpv6_rt_has_prefsrc(sk, type, &fl6)) {
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700559 /* select a more meaningful saddr from input if */
560 struct net_device *in_netdev;
561
Jason A. Donenfeldce4feb02021-02-23 14:18:58 +0100562 in_netdev = dev_get_by_index(net, parm->iif);
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700563 if (in_netdev) {
564 ipv6_dev_get_saddr(net, in_netdev, &fl6.daddr,
565 inet6_sk(sk)->srcprefs,
566 &fl6.saddr);
567 dev_put(in_netdev);
568 }
569 }
Lorenzo Colittie1108612014-05-13 10:17:33 -0700570 fl6.flowi6_mark = mark;
David S. Miller4c9483b2011-03-12 16:22:43 -0500571 fl6.flowi6_oif = iif;
David S. Miller1958b852011-03-12 16:36:19 -0500572 fl6.fl6_icmp_type = type;
573 fl6.fl6_icmp_code = code;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900574 fl6.flowi6_uid = sock_net_uid(net, NULL);
David Ahernb4bac172018-03-02 08:32:18 -0800575 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, NULL);
David S. Miller4c9483b2011-03-12 16:22:43 -0500576 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700578 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800579
David S. Miller4c9483b2011-03-12 16:22:43 -0500580 if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 goto out;
582
583 tmp_hdr.icmp6_type = type;
584 tmp_hdr.icmp6_code = code;
585 tmp_hdr.icmp6_cksum = 0;
586 tmp_hdr.icmp6_pointer = htonl(info);
587
David S. Miller4c9483b2011-03-12 16:22:43 -0500588 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
589 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000590 else if (!fl6.flowi6_oif)
591 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Willem de Bruijnb515430a2018-07-06 10:12:55 -0400593 ipcm6_init_sk(&ipc6, np);
Willem de Bruijn0da75362020-07-01 16:00:06 -0400594 ipc6.sockc.mark = mark;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +0200595 fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
596
David S. Miller4c9483b2011-03-12 16:22:43 -0500597 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800598 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 goto out;
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900600
Wei Wang26879da2016-05-02 21:40:07 -0700601 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 msg.skb = skb;
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300604 msg.offset = skb_network_offset(skb);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800605 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 len = skb->len - msg.offset;
Ian Morris67ba4152014-08-24 21:53:10 +0100608 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 if (len < 0) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200610 net_dbg_ratelimited("icmp: len problem [%pI6c > %pI6c]\n",
611 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_dst_release;
613 }
614
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000615 rcu_read_lock();
616 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Joe Perches4e64b1e2017-10-05 23:46:14 -0700618 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
619 len + sizeof(struct icmp6hdr),
620 sizeof(struct icmp6hdr),
621 &ipc6, &fl6, (struct rt6_info *)dst,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400622 MSG_DONTWAIT)) {
Hannes Frederic Sowa43a43b62014-03-31 20:14:10 +0200623 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000625 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700626 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
627 len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000629 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630out_dst_release:
631 dst_release(dst);
632out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800633 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100634out_bh_enable:
635 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636}
Eric Dumazetcc7a21b2020-06-19 12:02:59 -0700637EXPORT_SYMBOL(icmp6_send);
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000638
639/* Slightly more convenient version of icmp6_send.
640 */
641void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
642{
Jason A. Donenfeldce4feb02021-02-23 14:18:58 +0100643 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL, IP6CB(skb));
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000644 kfree_skb(skb);
645}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900646
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700647/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
648 * if sufficient data bytes are available
649 * @nhs is the size of the tunnel header(s) :
650 * Either an IPv4 header for SIT encap
651 * an IPv4 header + GRE header for GRE encap
652 */
Eric Dumazet20e19542016-06-18 21:52:06 -0700653int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
654 unsigned int data_len)
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700655{
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700656 struct in6_addr temp_saddr;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700657 struct rt6_info *rt;
658 struct sk_buff *skb2;
Eric Dumazet20e19542016-06-18 21:52:06 -0700659 u32 info = 0;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700660
661 if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8))
662 return 1;
663
Eric Dumazet20e19542016-06-18 21:52:06 -0700664 /* RFC 4884 (partial) support for ICMP extensions */
665 if (data_len < 128 || (data_len & 7) || skb->len < data_len)
666 data_len = 0;
667
668 skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700669
670 if (!skb2)
671 return 1;
672
673 skb_dst_drop(skb2);
674 skb_pull(skb2, nhs);
675 skb_reset_network_header(skb2);
676
David Ahernb75cc8f2018-03-02 08:32:17 -0800677 rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0,
678 skb, 0);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700679
680 if (rt && rt->dst.dev)
681 skb2->dev = rt->dst.dev;
682
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700683 ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr);
Eric Dumazet20e19542016-06-18 21:52:06 -0700684
685 if (data_len) {
686 /* RFC 4884 (partial) support :
687 * insert 0 padding at the end, before the extensions
688 */
689 __skb_push(skb2, nhs);
690 skb_reset_network_header(skb2);
691 memmove(skb2->data, skb2->data + nhs, data_len - nhs);
692 memset(skb2->data + data_len - nhs, 0, nhs);
693 /* RFC 4884 4.5 : Length is measured in 64-bit words,
694 * and stored in reserved[0]
695 */
696 info = (data_len/8) << 24;
697 }
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700698 if (type == ICMP_TIME_EXCEEDED)
699 icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
Jason A. Donenfeldce4feb02021-02-23 14:18:58 +0100700 info, &temp_saddr, IP6CB(skb2));
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700701 else
702 icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH,
Jason A. Donenfeldce4feb02021-02-23 14:18:58 +0100703 info, &temp_saddr, IP6CB(skb2));
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700704 if (rt)
705 ip6_rt_put(rt);
706
707 kfree_skb(skb2);
708
709 return 0;
710}
711EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713static void icmpv6_echo_reply(struct sk_buff *skb)
714{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900715 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700716 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700718 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000719 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300720 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500722 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 struct icmpv6_msg msg;
724 struct dst_entry *dst;
Wei Wang26879da2016-05-02 21:40:07 -0700725 struct ipcm6_cookie ipc6;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700726 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400727 bool acast;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -0400729 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) &&
730 net->ipv6.sysctl.icmpv6_echo_ignore_multicast)
731 return;
732
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700733 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400735 acast = ipv6_anycast_destination(skb_dst(skb), saddr);
736 if (acast && net->ipv6.sysctl.icmpv6_echo_ignore_anycast)
737 return;
738
FX Le Bail509aba32014-01-07 14:57:27 +0100739 if (!ipv6_unicast_destination(skb) &&
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400740 !(net->ipv6.sysctl.anycast_src_echo_reply && acast))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 saddr = NULL;
742
743 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
744 tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
745
David S. Miller4c9483b2011-03-12 16:22:43 -0500746 memset(&fl6, 0, sizeof(fl6));
Eric Dumazeta346abe2019-07-01 06:39:36 -0700747 if (net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES)
748 fl6.flowlabel = ip6_flowlabel(ipv6_hdr(skb));
749
David S. Miller4c9483b2011-03-12 16:22:43 -0500750 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000751 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000753 fl6.saddr = *saddr;
David Ahern1b70d7922017-08-28 13:53:34 -0700754 fl6.flowi6_oif = icmp6_iif(skb);
David S. Miller1958b852011-03-12 16:36:19 -0500755 fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700756 fl6.flowi6_mark = mark;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900757 fl6.flowi6_uid = sock_net_uid(net, NULL);
David S. Miller4c9483b2011-03-12 16:22:43 -0500758 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100760 local_bh_disable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700761 sk = icmpv6_xmit_lock(net);
Ian Morris63159f22015-03-29 14:00:04 +0100762 if (!sk)
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100763 goto out_bh_enable;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700764 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800765
David S. Miller4c9483b2011-03-12 16:22:43 -0500766 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
767 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000768 else if (!fl6.flowi6_oif)
769 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Joe Perches4e64b1e2017-10-05 23:46:14 -0700771 if (ip6_dst_lookup(net, sk, &dst, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 goto out;
David S. Miller4c9483b2011-03-12 16:22:43 -0500773 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800774 if (IS_ERR(dst))
Patrick McHardye104411b2005-09-08 15:11:55 -0700775 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400777 /* Check the ratelimit */
778 if ((!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, ICMPV6_ECHO_REPLY)) ||
779 !icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6))
780 goto out_dst_release;
781
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000782 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 msg.skb = skb;
785 msg.offset = 0;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800786 msg.type = ICMPV6_ECHO_REPLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Willem de Bruijnb515430a2018-07-06 10:12:55 -0400788 ipcm6_init_sk(&ipc6, np);
Wei Wang26879da2016-05-02 21:40:07 -0700789 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
790 ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
Willem de Bruijn0da75362020-07-01 16:00:06 -0400791 ipc6.sockc.mark = mark;
Wei Wang26879da2016-05-02 21:40:07 -0700792
Joe Perches4e64b1e2017-10-05 23:46:14 -0700793 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
794 skb->len + sizeof(struct icmp6hdr),
795 sizeof(struct icmp6hdr), &ipc6, &fl6,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400796 (struct rt6_info *)dst, MSG_DONTWAIT)) {
Eric Dumazeta16292a2016-04-27 16:44:36 -0700797 __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000799 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700800 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
801 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 }
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400803out_dst_release:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900805out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800806 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100807out_bh_enable:
808 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
David S. Millerb94f1c02012-07-12 00:33:37 -0700811void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000813 const struct inet6_protocol *ipprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 int inner_offset;
Jesse Gross75f28112011-11-30 17:05:51 -0800815 __be16 frag_off;
David S. Millerf9242b62012-06-19 18:56:21 -0700816 u8 nexthdr;
Duan Jiong7304fe42014-07-31 17:54:32 +0800817 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
Duan Jiong7304fe42014-07-31 17:54:32 +0800820 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
823 if (ipv6_ext_hdr(nexthdr)) {
824 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800825 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
826 &nexthdr, &frag_off);
Ian Morris67ba4152014-08-24 21:53:10 +0100827 if (inner_offset < 0)
Duan Jiong7304fe42014-07-31 17:54:32 +0800828 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 } else {
830 inner_offset = sizeof(struct ipv6hdr);
831 }
832
833 /* Checkin header including 8 bytes of inner protocol header. */
834 if (!pskb_may_pull(skb, inner_offset+8))
Duan Jiong7304fe42014-07-31 17:54:32 +0800835 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
838 Without this we will not able f.e. to make source routed
839 pmtu discovery.
840 Corresponding argument (opt) to notifiers is already added.
841 --ANK (980726)
842 */
843
David S. Millerf9242b62012-06-19 18:56:21 -0700844 ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (ipprot && ipprot->err_handler)
846 ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800848 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Duan Jiong7304fe42014-07-31 17:54:32 +0800849 return;
850
851out:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700852 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855/*
856 * Handle icmp messages
857 */
858
Herbert Xue5bbef22007-10-15 12:50:28 -0700859static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200861 struct net *net = dev_net(skb->dev);
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400862 struct net_device *dev = icmp6_dev(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000864 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700866 u8 type;
Rick Jonese3e32172014-11-17 14:04:29 -0800867 bool success = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
Herbert Xuaebcf822007-12-12 18:54:16 -0800869 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700870 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800871 int nh;
872
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700873 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Herbert Xuaebcf822007-12-12 18:54:16 -0800874 XFRM_STATE_ICMP))
875 goto drop_no_count;
876
David S. Miller81aded22012-06-15 14:54:11 -0700877 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800878 goto drop_no_count;
879
880 nh = skb_network_offset(skb);
881 skb_set_network_header(skb, sizeof(*hdr));
882
883 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
884 goto drop_no_count;
885
886 skb_set_network_header(skb, nh);
887 }
888
Eric Dumazeta16292a2016-04-27 16:44:36 -0700889 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700891 saddr = &ipv6_hdr(skb)->saddr;
892 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Tom Herbert39471ac2014-05-07 16:52:29 -0700894 if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800895 net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
896 saddr, daddr);
Tom Herbert39471ac2014-05-07 16:52:29 -0700897 goto csum_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
899
Herbert Xu8cf22942008-02-05 03:15:50 -0800900 if (!pskb_pull(skb, sizeof(*hdr)))
901 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300903 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
905 type = hdr->icmp6_type;
906
Eric Dumazetf3832ed2016-04-27 16:44:42 -0700907 ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
909 switch (type) {
910 case ICMPV6_ECHO_REQUEST:
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200911 if (!net->ipv6.sysctl.icmpv6_echo_ignore_all)
912 icmpv6_echo_reply(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 break;
914
915 case ICMPV6_ECHO_REPLY:
Rick Jonese3e32172014-11-17 14:04:29 -0800916 success = ping_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 break;
918
919 case ICMPV6_PKT_TOOBIG:
920 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
921 standard destination cache. Seems, only "advanced"
922 destination cache will allow to solve this problem
923 --ANK (980726)
924 */
925 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
926 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300927 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -0500929 /* to notify */
Joe Perchesa8eceea2020-03-12 15:50:22 -0700930 fallthrough;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 case ICMPV6_DEST_UNREACH:
932 case ICMPV6_TIME_EXCEED:
933 case ICMPV6_PARAMPROB:
934 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
935 break;
936
937 case NDISC_ROUTER_SOLICITATION:
938 case NDISC_ROUTER_ADVERTISEMENT:
939 case NDISC_NEIGHBOUR_SOLICITATION:
940 case NDISC_NEIGHBOUR_ADVERTISEMENT:
941 case NDISC_REDIRECT:
942 ndisc_rcv(skb);
943 break;
944
945 case ICMPV6_MGM_QUERY:
946 igmp6_event_query(skb);
947 break;
948
949 case ICMPV6_MGM_REPORT:
950 igmp6_event_report(skb);
951 break;
952
953 case ICMPV6_MGM_REDUCTION:
954 case ICMPV6_NI_QUERY:
955 case ICMPV6_NI_REPLY:
956 case ICMPV6_MLD2_REPORT:
957 case ICMPV6_DHAAD_REQUEST:
958 case ICMPV6_DHAAD_REPLY:
959 case ICMPV6_MOBILE_PREFIX_SOL:
960 case ICMPV6_MOBILE_PREFIX_ADV:
961 break;
962
963 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 /* informational */
965 if (type & ICMPV6_INFOMSG_MASK)
966 break;
967
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200968 net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
969 saddr, daddr);
David S. Millerea85a0a2014-10-07 16:33:53 -0400970
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900971 /*
972 * error of unknown type.
973 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 */
975
976 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700977 }
978
Rick Jonese3e32172014-11-17 14:04:29 -0800979 /* until the v6 path can be better sorted assume failure and
980 * preserve the status quo behaviour for the rest of the paths to here
981 */
982 if (success)
983 consume_skb(skb);
984 else
985 kfree_skb(skb);
986
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 return 0;
988
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +0000989csum_error:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700990 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991discard_it:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700992 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800993drop_no_count:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 kfree_skb(skb);
995 return 0;
996}
997
David S. Miller4c9483b2011-03-12 16:22:43 -0500998void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800999 u8 type,
1000 const struct in6_addr *saddr,
1001 const struct in6_addr *daddr,
1002 int oif)
1003{
David S. Miller4c9483b2011-03-12 16:22:43 -05001004 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001005 fl6->saddr = *saddr;
1006 fl6->daddr = *daddr;
Ian Morris67ba4152014-08-24 21:53:10 +01001007 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -05001008 fl6->fl6_icmp_type = type;
1009 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -05001010 fl6->flowi6_oif = oif;
1011 security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001012}
1013
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001014static void __net_exit icmpv6_sk_exit(struct net *net)
1015{
1016 int i;
1017
1018 for_each_possible_cpu(i)
Kefeng Wang75efc252019-02-23 15:28:28 +08001019 inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv6.icmp_sk, i));
1020 free_percpu(net->ipv6.icmp_sk);
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001021}
1022
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001023static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 struct sock *sk;
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001026 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Kefeng Wang75efc252019-02-23 15:28:28 +08001028 net->ipv6.icmp_sk = alloc_percpu(struct sock *);
Ian Morris63159f22015-03-29 14:00:04 +01001029 if (!net->ipv6.icmp_sk)
Denis V. Lunev79c91152008-02-29 11:17:11 -08001030 return -ENOMEM;
1031
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001032 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001033 err = inet_ctl_sock_create(&sk, PF_INET6,
1034 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 if (err < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001036 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 err);
1038 goto fail;
1039 }
1040
Kefeng Wang75efc252019-02-23 15:28:28 +08001041 *per_cpu_ptr(net->ipv6.icmp_sk, i) = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -08001042
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 /* Enough space for 2 64K ICMP packets, including
1044 * sk_buff struct overhead.
1045 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +00001046 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 return 0;
1049
1050 fail:
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001051 icmpv6_sk_exit(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 return err;
1053}
1054
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001055static struct pernet_operations icmpv6_sk_ops = {
Ian Morris67ba4152014-08-24 21:53:10 +01001056 .init = icmpv6_sk_init,
1057 .exit = icmpv6_sk_exit,
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001058};
1059
1060int __init icmpv6_init(void)
1061{
1062 int err;
1063
1064 err = register_pernet_subsys(&icmpv6_sk_ops);
1065 if (err < 0)
1066 return err;
1067
1068 err = -EAGAIN;
1069 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
1070 goto fail;
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001071
1072 err = inet6_register_icmp_sender(icmp6_send);
1073 if (err)
1074 goto sender_reg_err;
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001075 return 0;
1076
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001077sender_reg_err:
1078 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001079fail:
Joe Perchesf3213832012-05-15 14:11:53 +00001080 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001081 unregister_pernet_subsys(&icmpv6_sk_ops);
1082 return err;
1083}
1084
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001085void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001086{
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001087 inet6_unregister_icmp_sender(icmp6_send);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001088 unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
1090}
1091
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001092
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -08001093static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 int err;
1095 int fatal;
1096} tab_unreach[] = {
1097 { /* NOROUTE */
1098 .err = ENETUNREACH,
1099 .fatal = 0,
1100 },
1101 { /* ADM_PROHIBITED */
1102 .err = EACCES,
1103 .fatal = 1,
1104 },
1105 { /* Was NOT_NEIGHBOUR, now reserved */
1106 .err = EHOSTUNREACH,
1107 .fatal = 0,
1108 },
1109 { /* ADDR_UNREACH */
1110 .err = EHOSTUNREACH,
1111 .fatal = 0,
1112 },
1113 { /* PORT_UNREACH */
1114 .err = ECONNREFUSED,
1115 .fatal = 1,
1116 },
Jiri Bohac61e76b12013-08-30 11:18:45 +02001117 { /* POLICY_FAIL */
1118 .err = EACCES,
1119 .fatal = 1,
1120 },
1121 { /* REJECT_ROUTE */
1122 .err = EACCES,
1123 .fatal = 1,
1124 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125};
1126
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07001127int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
1129 int fatal = 0;
1130
1131 *err = EPROTO;
1132
1133 switch (type) {
1134 case ICMPV6_DEST_UNREACH:
1135 fatal = 1;
Jiri Bohac61e76b12013-08-30 11:18:45 +02001136 if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 *err = tab_unreach[code].err;
1138 fatal = tab_unreach[code].fatal;
1139 }
1140 break;
1141
1142 case ICMPV6_PKT_TOOBIG:
1143 *err = EMSGSIZE;
1144 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001145
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 case ICMPV6_PARAMPROB:
1147 *err = EPROTO;
1148 fatal = 1;
1149 break;
1150
1151 case ICMPV6_TIME_EXCEED:
1152 *err = EHOSTUNREACH;
1153 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
1156 return fatal;
1157}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001158EXPORT_SYMBOL(icmpv6_err_convert);
1159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160#ifdef CONFIG_SYSCTL
stephen hemmingere8243532013-12-29 14:03:31 -08001161static struct ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -08001164 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 .maxlen = sizeof(int),
1166 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08001167 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 },
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001169 {
1170 .procname = "echo_ignore_all",
1171 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_all,
1172 .maxlen = sizeof(int),
1173 .mode = 0644,
1174 .proc_handler = proc_dointvec,
1175 },
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001176 {
1177 .procname = "echo_ignore_multicast",
1178 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_multicast,
1179 .maxlen = sizeof(int),
1180 .mode = 0644,
1181 .proc_handler = proc_dointvec,
1182 },
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001183 {
1184 .procname = "echo_ignore_anycast",
1185 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_anycast,
1186 .maxlen = sizeof(int),
1187 .mode = 0644,
1188 .proc_handler = proc_dointvec,
1189 },
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001190 {
1191 .procname = "ratemask",
1192 .data = &init_net.ipv6.sysctl.icmpv6_ratemask_ptr,
1193 .maxlen = ICMPV6_MSG_MAX + 1,
1194 .mode = 0644,
1195 .proc_handler = proc_do_large_bitmap,
1196 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001197 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198};
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001199
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001200struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001201{
1202 struct ctl_table *table;
1203
1204 table = kmemdup(ipv6_icmp_table_template,
1205 sizeof(ipv6_icmp_table_template),
1206 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001207
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001208 if (table) {
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001209 table[0].data = &net->ipv6.sysctl.icmpv6_time;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001210 table[1].data = &net->ipv6.sysctl.icmpv6_echo_ignore_all;
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001211 table[2].data = &net->ipv6.sysctl.icmpv6_echo_ignore_multicast;
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001212 table[3].data = &net->ipv6.sysctl.icmpv6_echo_ignore_anycast;
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001213 table[4].data = &net->ipv6.sysctl.icmpv6_ratemask_ptr;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001214 }
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001215 return table;
1216}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217#endif