blob: 96c5cc0f30cebb02280a8384e34234701989f0d6 [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>
Andrew Lunne4129442022-01-03 18:11:31 +010060#include <net/seg6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <net/transp_v6.h>
62#include <net/ip6_route.h>
63#include <net/addrconf.h>
64#include <net/icmp.h>
Herbert Xu8b7817f2007-12-12 10:44:43 -080065#include <net/xfrm.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070066#include <net/inet_common.h>
Hannes Frederic Sowa825edac2014-01-11 11:55:46 +010067#include <net/dsfield.h>
David Ahernca254492015-10-12 11:47:10 -070068#include <net/l3mdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080070#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Linus Torvalds1da177e2005-04-16 15:20:36 -070072/*
73 * The ICMP socket(s). This is the most convenient way to flow control
74 * our ICMP output as well as maintain a clean interface throughout
75 * all layers. All Socketless IP sends will soon be gone.
76 *
77 * On SMP we have one ICMP socket per-cpu.
78 */
Eric Dumazet2789c142019-05-31 15:27:00 -070079static struct sock *icmpv6_sk(struct net *net)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -080080{
Eric Dumazet2789c142019-05-31 15:27:00 -070081 return this_cpu_read(*net->ipv6.icmp_sk);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -080082}
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Stefano Brivio32bbd872018-11-08 12:19:21 +010084static int icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Steffen Klassert6f809da2013-01-16 22:09:49 +000085 u8 type, u8 code, int offset, __be32 info)
86{
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000087 /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
88 struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
Steffen Klassert6f809da2013-01-16 22:09:49 +000089 struct net *net = dev_net(skb->dev);
90
91 if (type == ICMPV6_PKT_TOOBIG)
Georg Kohmann5f379ef2018-08-02 13:56:58 +020092 ip6_update_pmtu(skb, net, info, skb->dev->ifindex, 0, sock_net_uid(net, NULL));
Steffen Klassert6f809da2013-01-16 22:09:49 +000093 else if (type == NDISC_REDIRECT)
Lorenzo Colittie2d118a2016-11-04 02:23:43 +090094 ip6_redirect(skb, net, skb->dev->ifindex, 0,
95 sock_net_uid(net, NULL));
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000096
97 if (!(type & ICMPV6_INFOMSG_MASK))
98 if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
Hannes Frederic Sowadcb94b82016-06-11 20:32:06 +020099 ping_err(skb, offset, ntohl(info));
Stefano Brivio32bbd872018-11-08 12:19:21 +0100100
101 return 0;
Steffen Klassert6f809da2013-01-16 22:09:49 +0000102}
103
Herbert Xue5bbef22007-10-15 12:50:28 -0700104static int icmpv6_rcv(struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000106static const struct inet6_protocol icmpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 .handler = icmpv6_rcv,
Steffen Klassert6f809da2013-01-16 22:09:49 +0000108 .err_handler = icmpv6_err,
Herbert Xu8b7817f2007-12-12 10:44:43 -0800109 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110};
111
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100112/* Called with BH disabled */
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700113static __inline__ struct sock *icmpv6_xmit_lock(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700115 struct sock *sk;
116
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700117 sk = icmpv6_sk(net);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800118 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 /* This can happen if the output path (f.e. SIT or
120 * ip6ip6 tunnel) signals dst_link_failure() for an
121 * outgoing ICMP6 packet.
122 */
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{
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100130 spin_unlock(&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);
Hangbin Liu2efdaaa2020-10-27 20:33:13 +0800162
163 /* Based on RFC 8200, Section 4.5 Fragment Header, return
164 * false if this is a fragment packet with no icmp header info.
165 */
166 if (!tp && frag_off != 0)
167 return false;
168 else if (!tp || !(*tp & ICMPV6_INFOMSG_MASK))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000169 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000171 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172}
173
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400174static bool icmpv6_mask_allow(struct net *net, int type)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100175{
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400176 if (type > ICMPV6_MSG_MAX)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100177 return true;
178
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400179 /* Limit if icmp type is set in ratemask. */
180 if (!test_bit(type, net->ipv6.sysctl.icmpv6_ratemask))
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100181 return true;
182
183 return false;
184}
185
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400186static bool icmpv6_global_allow(struct net *net, int type)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100187{
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400188 if (icmpv6_mask_allow(net, type))
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100189 return true;
190
191 if (icmp_global_allow())
192 return true;
193
194 return false;
195}
196
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900197/*
198 * Check the ICMP output rate limit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 */
Eric Dumazet4cdf5072014-09-19 07:38:40 -0700200static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
201 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900203 struct net *net = sock_net(sk);
Eric Dumazet4cdf5072014-09-19 07:38:40 -0700204 struct dst_entry *dst;
David S. Miller92d86822011-02-04 15:55:25 -0800205 bool res = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400207 if (icmpv6_mask_allow(net, type))
David S. Miller92d86822011-02-04 15:55:25 -0800208 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900210 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 * Look up the output route.
212 * XXX: perhaps the expire for routing entries cloned by
213 * this lookup should be more aggressive (not longer than timeout).
214 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500215 dst = ip6_route_output(net, sk, fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 if (dst->error) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -0700217 IP6_INC_STATS(net, ip6_dst_idev(dst),
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900218 IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
David S. Miller92d86822011-02-04 15:55:25 -0800220 res = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 } else {
222 struct rt6_info *rt = (struct rt6_info *)dst;
Benjamin Thery9a43b702008-03-05 10:49:18 -0800223 int tmo = net->ipv6.sysctl.icmpv6_time;
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100224 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226 /* Give more bandwidth to wider prefixes. */
227 if (rt->rt6i_dst.plen < 128)
228 tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
229
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100230 peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr, 1);
231 res = inet_peer_xrlim_allow(peer, tmo);
232 if (peer)
233 inet_putpeer(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 }
235 dst_release(dst);
236 return res;
237}
238
Tim Stallardb93cfb92020-04-03 21:22:57 +0100239static bool icmpv6_rt_has_prefsrc(struct sock *sk, u8 type,
240 struct flowi6 *fl6)
241{
242 struct net *net = sock_net(sk);
243 struct dst_entry *dst;
244 bool res = false;
245
246 dst = ip6_route_output(net, sk, fl6);
247 if (!dst->error) {
248 struct rt6_info *rt = (struct rt6_info *)dst;
249 struct in6_addr prefsrc;
250
251 rt6_get_prefsrc(rt, &prefsrc);
252 res = !ipv6_addr_any(&prefsrc);
253 }
254 dst_release(dst);
255 return res;
256}
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258/*
259 * an inline helper for the "simple" if statement below
260 * checks if parameter problem report is caused by an
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900261 * unrecognized IPv6 option that has the Option Type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 * highest-order two bits set to 10
263 */
264
Eric Dumazeta50feda2012-05-18 18:57:34 +0000265static bool opt_unrec(struct sk_buff *skb, __u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
267 u8 _optval, *op;
268
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300269 offset += skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
Ian Morris63159f22015-03-29 14:00:04 +0100271 if (!op)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000272 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return (*op & 0xC0) == 0x80;
274}
275
Joe Perches4e64b1e2017-10-05 23:46:14 -0700276void icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
277 struct icmp6hdr *thdr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278{
279 struct sk_buff *skb;
280 struct icmp6hdr *icmp6h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Ian Morrise5d08d72014-11-23 21:28:43 +0000282 skb = skb_peek(&sk->sk_write_queue);
Ian Morris63159f22015-03-29 14:00:04 +0100283 if (!skb)
Joe Perches4e64b1e2017-10-05 23:46:14 -0700284 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300286 icmp6h = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
288 icmp6h->icmp6_cksum = 0;
289
290 if (skb_queue_len(&sk->sk_write_queue) == 1) {
Joe Perches07f07572008-11-19 15:44:53 -0800291 skb->csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 sizeof(struct icmp6hdr), skb->csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500293 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
294 &fl6->daddr,
295 len, fl6->flowi6_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 skb->csum);
297 } else {
Al Viro868c86b2006-11-14 21:35:48 -0800298 __wsum tmp_csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 skb_queue_walk(&sk->sk_write_queue, skb) {
301 tmp_csum = csum_add(tmp_csum, skb->csum);
302 }
303
Joe Perches07f07572008-11-19 15:44:53 -0800304 tmp_csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 sizeof(struct icmp6hdr), tmp_csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500306 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
307 &fl6->daddr,
308 len, fl6->flowi6_proto,
Al Viro868c86b2006-11-14 21:35:48 -0800309 tmp_csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 ip6_push_pending_frames(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
314struct icmpv6_msg {
315 struct sk_buff *skb;
316 int offset;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800317 uint8_t type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318};
319
320static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
321{
322 struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
323 struct sk_buff *org_skb = msg->skb;
Al Viro8d5930d2020-07-10 20:07:10 -0400324 __wsum csum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
Al Viro8d5930d2020-07-10 20:07:10 -0400327 to, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 skb->csum = csum_block_add(skb->csum, csum, odd);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800329 if (!(msg->type & ICMPV6_INFOMSG_MASK))
330 nf_ct_attach(skb, org_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 return 0;
332}
333
Amerigo Wang07a93622012-10-29 16:23:10 +0000334#if IS_ENABLED(CONFIG_IPV6_MIP6)
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100335static void mip6_addr_swap(struct sk_buff *skb, const struct inet6_skb_parm *opt)
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700336{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700337 struct ipv6hdr *iph = ipv6_hdr(skb);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700338 struct ipv6_destopt_hao *hao;
339 struct in6_addr tmp;
340 int off;
341
342 if (opt->dsthao) {
343 off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
344 if (likely(off >= 0)) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700345 hao = (struct ipv6_destopt_hao *)
346 (skb_network_header(skb) + off);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000347 tmp = iph->saddr;
348 iph->saddr = hao->addr;
349 hao->addr = tmp;
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700350 }
351 }
352}
353#else
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100354static inline void mip6_addr_swap(struct sk_buff *skb, const struct inet6_skb_parm *opt) {}
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700355#endif
356
stephen hemmingere8243532013-12-29 14:03:31 -0800357static struct dst_entry *icmpv6_route_lookup(struct net *net,
358 struct sk_buff *skb,
359 struct sock *sk,
360 struct flowi6 *fl6)
David S. Millerb42835d2011-03-01 22:06:22 -0800361{
362 struct dst_entry *dst, *dst2;
David S. Miller4c9483b2011-03-12 16:22:43 -0500363 struct flowi6 fl2;
David S. Millerb42835d2011-03-01 22:06:22 -0800364 int err;
365
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700366 err = ip6_dst_lookup(net, sk, &dst, fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800367 if (err)
368 return ERR_PTR(err);
369
370 /*
371 * We won't send icmp if the destination is known
372 * anycast.
373 */
Martin KaFai Lau2647a9b2015-05-22 20:55:58 -0700374 if (ipv6_anycast_destination(dst, &fl6->daddr)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800375 net_dbg_ratelimited("icmp6_send: acast source\n");
David S. Millerb42835d2011-03-01 22:06:22 -0800376 dst_release(dst);
377 return ERR_PTR(-EINVAL);
378 }
379
380 /* No need to clone since we're just using its address. */
381 dst2 = dst;
382
David S. Miller4c9483b2011-03-12 16:22:43 -0500383 dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800384 if (!IS_ERR(dst)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800385 if (dst != dst2)
386 return dst;
David S. Miller452edd52011-03-02 13:27:41 -0800387 } else {
388 if (PTR_ERR(dst) == -EPERM)
389 dst = NULL;
390 else
391 return dst;
David S. Millerb42835d2011-03-01 22:06:22 -0800392 }
393
David S. Miller4c9483b2011-03-12 16:22:43 -0500394 err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6);
David S. Millerb42835d2011-03-01 22:06:22 -0800395 if (err)
396 goto relookup_failed;
397
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700398 err = ip6_dst_lookup(net, sk, &dst2, &fl2);
David S. Millerb42835d2011-03-01 22:06:22 -0800399 if (err)
400 goto relookup_failed;
401
David S. Miller4c9483b2011-03-12 16:22:43 -0500402 dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP);
David S. Miller452edd52011-03-02 13:27:41 -0800403 if (!IS_ERR(dst2)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800404 dst_release(dst);
405 dst = dst2;
David S. Miller452edd52011-03-02 13:27:41 -0800406 } else {
407 err = PTR_ERR(dst2);
408 if (err == -EPERM) {
409 dst_release(dst);
410 return dst2;
411 } else
412 goto relookup_failed;
David S. Millerb42835d2011-03-01 22:06:22 -0800413 }
414
415relookup_failed:
416 if (dst)
417 return dst;
418 return ERR_PTR(err);
419}
420
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400421static struct net_device *icmp6_dev(const struct sk_buff *skb)
David Ahern1b70d7922017-08-28 13:53:34 -0700422{
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400423 struct net_device *dev = skb->dev;
David Ahern1b70d7922017-08-28 13:53:34 -0700424
425 /* for local traffic to local address, skb dev is the loopback
426 * device. Check if there is a dst attached to the skb and if so
David Ahern24b711e2018-07-19 12:41:18 -0700427 * get the real device index. Same is needed for replies to a link
428 * local address on a device enslaved to an L3 master device
David Ahern1b70d7922017-08-28 13:53:34 -0700429 */
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400430 if (unlikely(dev->ifindex == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) {
David Ahern1b70d7922017-08-28 13:53:34 -0700431 const struct rt6_info *rt6 = skb_rt6_info(skb);
432
433 if (rt6)
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400434 dev = rt6->rt6i_idev->dev;
David Ahern1b70d7922017-08-28 13:53:34 -0700435 }
436
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400437 return dev;
438}
439
440static int icmp6_iif(const struct sk_buff *skb)
441{
442 return icmp6_dev(skb)->ifindex;
David Ahern1b70d7922017-08-28 13:53:34 -0700443}
444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445/*
446 * Send an ICMP message in response to a packet in error
447 */
Eric Dumazetcc7a21b2020-06-19 12:02:59 -0700448void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100449 const struct in6_addr *force_saddr,
450 const struct inet6_skb_parm *parm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
452 struct inet6_dev *idev = NULL;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700453 struct ipv6hdr *hdr = ipv6_hdr(skb);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700454 struct sock *sk;
Eric Dumazet8d933672019-01-04 11:00:00 -0800455 struct net *net;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700456 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000457 const struct in6_addr *saddr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 struct dst_entry *dst;
459 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500460 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 struct icmpv6_msg msg;
Wei Wang26879da2016-05-02 21:40:07 -0700462 struct ipcm6_cookie ipc6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 int iif = 0;
464 int addr_type = 0;
465 int len;
Eric Dumazet8d933672019-01-04 11:00:00 -0800466 u32 mark;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700468 if ((u8 *)hdr < skb->head ||
Simon Horman29a3cad2013-05-28 20:34:26 +0000469 (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 return;
471
Eric Dumazet8d933672019-01-04 11:00:00 -0800472 if (!skb->dev)
473 return;
474 net = dev_net(skb->dev);
475 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900477 * Make sure we respect the rules
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 * i.e. RFC 1885 2.4(e)
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000479 * Rule (e.1) is enforced by not using icmp6_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 * in any code that processes icmp errors.
481 */
482 addr_type = ipv6_addr_type(&hdr->daddr);
483
FX Le Bail446fab52014-01-19 17:00:36 +0100484 if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) ||
FX Le Baild94c1f92014-02-07 11:22:37 +0100485 ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 saddr = &hdr->daddr;
487
488 /*
489 * Dest addr check
490 */
491
zhuyj9a6b4b32015-01-14 17:23:59 +0800492 if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (type != ICMPV6_PKT_TOOBIG &&
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900494 !(type == ICMPV6_PARAMPROB &&
495 code == ICMPV6_UNK_OPTION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 (opt_unrec(skb, info))))
497 return;
498
499 saddr = NULL;
500 }
501
502 addr_type = ipv6_addr_type(&hdr->saddr);
503
504 /*
505 * Source addr check
506 */
507
David Ahern4832c302017-08-17 12:17:20 -0700508 if (__ipv6_addr_needs_scope_id(addr_type)) {
David Ahern1b70d7922017-08-28 13:53:34 -0700509 iif = icmp6_iif(skb);
David Ahern4832c302017-08-17 12:17:20 -0700510 } else {
Mathieu Desnoyers272928d2020-10-12 10:50:15 -0400511 /*
512 * The source device is used for looking up which routing table
513 * to use for sending an ICMP error.
514 */
515 iif = l3mdev_master_ifindex(skb->dev);
David Ahern79dc7e32016-11-27 18:52:53 -0800516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 /*
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900519 * Must not send error if the source does not uniquely
520 * identify a single node (RFC2463 Section 2.4).
521 * We check unspecified / multicast addresses here,
522 * and anycast addresses will be checked later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 */
524 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200525 net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n",
526 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 return;
528 }
529
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900530 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 * Never answer to a ICMP packet.
532 */
533 if (is_ineligible(skb)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200534 net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n",
535 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 return;
537 }
538
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100539 /* Needed by both icmp_global_allow and icmpv6_xmit_lock */
540 local_bh_disable();
541
542 /* Check global sysctl_icmp_msgs_per_sec ratelimit */
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400543 if (!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, type))
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100544 goto out_bh_enable;
545
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100546 mip6_addr_swap(skb, parm);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700547
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700548 sk = icmpv6_xmit_lock(net);
549 if (!sk)
550 goto out_bh_enable;
551
David S. Miller4c9483b2011-03-12 16:22:43 -0500552 memset(&fl6, 0, sizeof(fl6));
553 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000554 fl6.daddr = hdr->saddr;
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700555 if (force_saddr)
556 saddr = force_saddr;
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700557 if (saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000558 fl6.saddr = *saddr;
Tim Stallardb93cfb92020-04-03 21:22:57 +0100559 } else if (!icmpv6_rt_has_prefsrc(sk, type, &fl6)) {
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700560 /* select a more meaningful saddr from input if */
561 struct net_device *in_netdev;
562
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100563 in_netdev = dev_get_by_index(net, parm->iif);
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700564 if (in_netdev) {
565 ipv6_dev_get_saddr(net, in_netdev, &fl6.daddr,
566 inet6_sk(sk)->srcprefs,
567 &fl6.saddr);
568 dev_put(in_netdev);
569 }
570 }
Lorenzo Colittie1108612014-05-13 10:17:33 -0700571 fl6.flowi6_mark = mark;
David S. Miller4c9483b2011-03-12 16:22:43 -0500572 fl6.flowi6_oif = iif;
David S. Miller1958b852011-03-12 16:36:19 -0500573 fl6.fl6_icmp_type = type;
574 fl6.fl6_icmp_code = code;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900575 fl6.flowi6_uid = sock_net_uid(net, NULL);
David Ahernb4bac172018-03-02 08:32:18 -0800576 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, NULL);
Paul Moore3df98d72020-09-27 22:38:26 -0400577 security_skb_classify_flow(skb, flowi6_to_flowi_common(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
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 (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 goto out;
583
584 tmp_hdr.icmp6_type = type;
585 tmp_hdr.icmp6_code = code;
586 tmp_hdr.icmp6_cksum = 0;
587 tmp_hdr.icmp6_pointer = htonl(info);
588
David S. Miller4c9483b2011-03-12 16:22:43 -0500589 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
590 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000591 else if (!fl6.flowi6_oif)
592 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Willem de Bruijnb515430a2018-07-06 10:12:55 -0400594 ipcm6_init_sk(&ipc6, np);
Willem de Bruijn0da75362020-07-01 16:00:06 -0400595 ipc6.sockc.mark = mark;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +0200596 fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
597
David S. Miller4c9483b2011-03-12 16:22:43 -0500598 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800599 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 goto out;
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900601
Wei Wang26879da2016-05-02 21:40:07 -0700602 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 msg.skb = skb;
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300605 msg.offset = skb_network_offset(skb);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800606 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 len = skb->len - msg.offset;
Ian Morris67ba4152014-08-24 21:53:10 +0100609 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (len < 0) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200611 net_dbg_ratelimited("icmp: len problem [%pI6c > %pI6c]\n",
612 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 goto out_dst_release;
614 }
615
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000616 rcu_read_lock();
617 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Joe Perches4e64b1e2017-10-05 23:46:14 -0700619 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
620 len + sizeof(struct icmp6hdr),
621 sizeof(struct icmp6hdr),
622 &ipc6, &fl6, (struct rt6_info *)dst,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400623 MSG_DONTWAIT)) {
Hannes Frederic Sowa43a43b62014-03-31 20:14:10 +0200624 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000626 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700627 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
628 len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000630 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631out_dst_release:
632 dst_release(dst);
633out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800634 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100635out_bh_enable:
636 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
Eric Dumazetcc7a21b2020-06-19 12:02:59 -0700638EXPORT_SYMBOL(icmp6_send);
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000639
640/* Slightly more convenient version of icmp6_send.
641 */
642void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
643{
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100644 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL, IP6CB(skb));
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000645 kfree_skb(skb);
646}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900647
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700648/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
649 * if sufficient data bytes are available
650 * @nhs is the size of the tunnel header(s) :
651 * Either an IPv4 header for SIT encap
652 * an IPv4 header + GRE header for GRE encap
653 */
Eric Dumazet20e19542016-06-18 21:52:06 -0700654int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
655 unsigned int data_len)
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700656{
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700657 struct in6_addr temp_saddr;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700658 struct rt6_info *rt;
659 struct sk_buff *skb2;
Eric Dumazet20e19542016-06-18 21:52:06 -0700660 u32 info = 0;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700661
662 if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8))
663 return 1;
664
Eric Dumazet20e19542016-06-18 21:52:06 -0700665 /* RFC 4884 (partial) support for ICMP extensions */
666 if (data_len < 128 || (data_len & 7) || skb->len < data_len)
667 data_len = 0;
668
669 skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700670
671 if (!skb2)
672 return 1;
673
674 skb_dst_drop(skb2);
675 skb_pull(skb2, nhs);
676 skb_reset_network_header(skb2);
677
David Ahernb75cc8f2018-03-02 08:32:17 -0800678 rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0,
679 skb, 0);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700680
681 if (rt && rt->dst.dev)
682 skb2->dev = rt->dst.dev;
683
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700684 ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr);
Eric Dumazet20e19542016-06-18 21:52:06 -0700685
686 if (data_len) {
687 /* RFC 4884 (partial) support :
688 * insert 0 padding at the end, before the extensions
689 */
690 __skb_push(skb2, nhs);
691 skb_reset_network_header(skb2);
692 memmove(skb2->data, skb2->data + nhs, data_len - nhs);
693 memset(skb2->data + data_len - nhs, 0, nhs);
694 /* RFC 4884 4.5 : Length is measured in 64-bit words,
695 * and stored in reserved[0]
696 */
697 info = (data_len/8) << 24;
698 }
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700699 if (type == ICMP_TIME_EXCEEDED)
700 icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100701 info, &temp_saddr, IP6CB(skb2));
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700702 else
703 icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH,
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100704 info, &temp_saddr, IP6CB(skb2));
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700705 if (rt)
706 ip6_rt_put(rt);
707
708 kfree_skb(skb2);
709
710 return 0;
711}
712EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714static void icmpv6_echo_reply(struct sk_buff *skb)
715{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900716 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700717 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700719 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000720 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300721 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500723 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 struct icmpv6_msg msg;
725 struct dst_entry *dst;
Wei Wang26879da2016-05-02 21:40:07 -0700726 struct ipcm6_cookie ipc6;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700727 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400728 bool acast;
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500729 u8 type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -0400731 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) &&
732 net->ipv6.sysctl.icmpv6_echo_ignore_multicast)
733 return;
734
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700735 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400737 acast = ipv6_anycast_destination(skb_dst(skb), saddr);
738 if (acast && net->ipv6.sysctl.icmpv6_echo_ignore_anycast)
739 return;
740
FX Le Bail509aba32014-01-07 14:57:27 +0100741 if (!ipv6_unicast_destination(skb) &&
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400742 !(net->ipv6.sysctl.anycast_src_echo_reply && acast))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 saddr = NULL;
744
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500745 if (icmph->icmp6_type == ICMPV6_EXT_ECHO_REQUEST)
746 type = ICMPV6_EXT_ECHO_REPLY;
747 else
748 type = ICMPV6_ECHO_REPLY;
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500751 tmp_hdr.icmp6_type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
David S. Miller4c9483b2011-03-12 16:22:43 -0500753 memset(&fl6, 0, sizeof(fl6));
Eric Dumazeta346abe2019-07-01 06:39:36 -0700754 if (net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES)
755 fl6.flowlabel = ip6_flowlabel(ipv6_hdr(skb));
756
David S. Miller4c9483b2011-03-12 16:22:43 -0500757 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000758 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000760 fl6.saddr = *saddr;
David Ahern1b70d7922017-08-28 13:53:34 -0700761 fl6.flowi6_oif = icmp6_iif(skb);
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500762 fl6.fl6_icmp_type = type;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700763 fl6.flowi6_mark = mark;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900764 fl6.flowi6_uid = sock_net_uid(net, NULL);
Paul Moore3df98d72020-09-27 22:38:26 -0400765 security_skb_classify_flow(skb, flowi6_to_flowi_common(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100767 local_bh_disable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700768 sk = icmpv6_xmit_lock(net);
Ian Morris63159f22015-03-29 14:00:04 +0100769 if (!sk)
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100770 goto out_bh_enable;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700771 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800772
David S. Miller4c9483b2011-03-12 16:22:43 -0500773 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
774 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000775 else if (!fl6.flowi6_oif)
776 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Joe Perches4e64b1e2017-10-05 23:46:14 -0700778 if (ip6_dst_lookup(net, sk, &dst, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 goto out;
David S. Miller4c9483b2011-03-12 16:22:43 -0500780 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800781 if (IS_ERR(dst))
Patrick McHardye104411b2005-09-08 15:11:55 -0700782 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400784 /* Check the ratelimit */
785 if ((!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, ICMPV6_ECHO_REPLY)) ||
786 !icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6))
787 goto out_dst_release;
788
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000789 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 msg.skb = skb;
792 msg.offset = 0;
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500793 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Willem de Bruijnb515430a2018-07-06 10:12:55 -0400795 ipcm6_init_sk(&ipc6, np);
Wei Wang26879da2016-05-02 21:40:07 -0700796 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
797 ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
Willem de Bruijn0da75362020-07-01 16:00:06 -0400798 ipc6.sockc.mark = mark;
Wei Wang26879da2016-05-02 21:40:07 -0700799
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500800 if (icmph->icmp6_type == ICMPV6_EXT_ECHO_REQUEST)
801 if (!icmp_build_probe(skb, (struct icmphdr *)&tmp_hdr))
802 goto out_dst_release;
803
Joe Perches4e64b1e2017-10-05 23:46:14 -0700804 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
805 skb->len + sizeof(struct icmp6hdr),
806 sizeof(struct icmp6hdr), &ipc6, &fl6,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400807 (struct rt6_info *)dst, MSG_DONTWAIT)) {
Eric Dumazeta16292a2016-04-27 16:44:36 -0700808 __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000810 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700811 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
812 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 }
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400814out_dst_release:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900816out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800817 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100818out_bh_enable:
819 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820}
821
David S. Millerb94f1c02012-07-12 00:33:37 -0700822void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
Andrew Lunne4129442022-01-03 18:11:31 +0100824 struct inet6_skb_parm *opt = IP6CB(skb);
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000825 const struct inet6_protocol *ipprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 int inner_offset;
Jesse Gross75f28112011-11-30 17:05:51 -0800827 __be16 frag_off;
David S. Millerf9242b62012-06-19 18:56:21 -0700828 u8 nexthdr;
Duan Jiong7304fe42014-07-31 17:54:32 +0800829 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
Duan Jiong7304fe42014-07-31 17:54:32 +0800832 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Andrew Lunne4129442022-01-03 18:11:31 +0100834 seg6_icmp_srh(skb, opt);
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
837 if (ipv6_ext_hdr(nexthdr)) {
838 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800839 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
840 &nexthdr, &frag_off);
Ian Morris67ba4152014-08-24 21:53:10 +0100841 if (inner_offset < 0)
Duan Jiong7304fe42014-07-31 17:54:32 +0800842 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 } else {
844 inner_offset = sizeof(struct ipv6hdr);
845 }
846
847 /* Checkin header including 8 bytes of inner protocol header. */
848 if (!pskb_may_pull(skb, inner_offset+8))
Duan Jiong7304fe42014-07-31 17:54:32 +0800849 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
852 Without this we will not able f.e. to make source routed
853 pmtu discovery.
854 Corresponding argument (opt) to notifiers is already added.
855 --ANK (980726)
856 */
857
David S. Millerf9242b62012-06-19 18:56:21 -0700858 ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 if (ipprot && ipprot->err_handler)
Andrew Lunne4129442022-01-03 18:11:31 +0100860 ipprot->err_handler(skb, opt, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800862 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Duan Jiong7304fe42014-07-31 17:54:32 +0800863 return;
864
865out:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700866 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869/*
870 * Handle icmp messages
871 */
872
Herbert Xue5bbef22007-10-15 12:50:28 -0700873static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200875 struct net *net = dev_net(skb->dev);
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400876 struct net_device *dev = icmp6_dev(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000878 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700880 u8 type;
Rick Jonese3e32172014-11-17 14:04:29 -0800881 bool success = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
Herbert Xuaebcf822007-12-12 18:54:16 -0800883 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700884 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800885 int nh;
886
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700887 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Herbert Xuaebcf822007-12-12 18:54:16 -0800888 XFRM_STATE_ICMP))
889 goto drop_no_count;
890
David S. Miller81aded22012-06-15 14:54:11 -0700891 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800892 goto drop_no_count;
893
894 nh = skb_network_offset(skb);
895 skb_set_network_header(skb, sizeof(*hdr));
896
897 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
898 goto drop_no_count;
899
900 skb_set_network_header(skb, nh);
901 }
902
Eric Dumazeta16292a2016-04-27 16:44:36 -0700903 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700905 saddr = &ipv6_hdr(skb)->saddr;
906 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Tom Herbert39471ac2014-05-07 16:52:29 -0700908 if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800909 net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
910 saddr, daddr);
Tom Herbert39471ac2014-05-07 16:52:29 -0700911 goto csum_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 }
913
Herbert Xu8cf22942008-02-05 03:15:50 -0800914 if (!pskb_pull(skb, sizeof(*hdr)))
915 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300917 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 type = hdr->icmp6_type;
920
Eric Dumazetf3832ed2016-04-27 16:44:42 -0700921 ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923 switch (type) {
924 case ICMPV6_ECHO_REQUEST:
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200925 if (!net->ipv6.sysctl.icmpv6_echo_ignore_all)
926 icmpv6_echo_reply(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 break;
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500928 case ICMPV6_EXT_ECHO_REQUEST:
929 if (!net->ipv6.sysctl.icmpv6_echo_ignore_all &&
930 net->ipv4.sysctl_icmp_echo_enable_probe)
931 icmpv6_echo_reply(skb);
932 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
934 case ICMPV6_ECHO_REPLY:
Rick Jonese3e32172014-11-17 14:04:29 -0800935 success = ping_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 break;
937
Andreas Roeseler31433202021-04-12 16:23:56 -0500938 case ICMPV6_EXT_ECHO_REPLY:
939 success = ping_rcv(skb);
940 break;
941
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 case ICMPV6_PKT_TOOBIG:
943 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
944 standard destination cache. Seems, only "advanced"
945 destination cache will allow to solve this problem
946 --ANK (980726)
947 */
948 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
949 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300950 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -0500952 /* to notify */
Joe Perchesa8eceea2020-03-12 15:50:22 -0700953 fallthrough;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 case ICMPV6_DEST_UNREACH:
955 case ICMPV6_TIME_EXCEED:
956 case ICMPV6_PARAMPROB:
957 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
958 break;
959
960 case NDISC_ROUTER_SOLICITATION:
961 case NDISC_ROUTER_ADVERTISEMENT:
962 case NDISC_NEIGHBOUR_SOLICITATION:
963 case NDISC_NEIGHBOUR_ADVERTISEMENT:
964 case NDISC_REDIRECT:
965 ndisc_rcv(skb);
966 break;
967
968 case ICMPV6_MGM_QUERY:
969 igmp6_event_query(skb);
Taehee Yoof185de282021-03-25 16:16:56 +0000970 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972 case ICMPV6_MGM_REPORT:
973 igmp6_event_report(skb);
Taehee Yoof185de282021-03-25 16:16:56 +0000974 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 case ICMPV6_MGM_REDUCTION:
977 case ICMPV6_NI_QUERY:
978 case ICMPV6_NI_REPLY:
979 case ICMPV6_MLD2_REPORT:
980 case ICMPV6_DHAAD_REQUEST:
981 case ICMPV6_DHAAD_REPLY:
982 case ICMPV6_MOBILE_PREFIX_SOL:
983 case ICMPV6_MOBILE_PREFIX_ADV:
984 break;
985
986 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 /* informational */
988 if (type & ICMPV6_INFOMSG_MASK)
989 break;
990
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200991 net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
992 saddr, daddr);
David S. Millerea85a0a2014-10-07 16:33:53 -0400993
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900994 /*
995 * error of unknown type.
996 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 */
998
999 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001000 }
1001
Rick Jonese3e32172014-11-17 14:04:29 -08001002 /* until the v6 path can be better sorted assume failure and
1003 * preserve the status quo behaviour for the rest of the paths to here
1004 */
1005 if (success)
1006 consume_skb(skb);
1007 else
1008 kfree_skb(skb);
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return 0;
1011
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +00001012csum_error:
Eric Dumazeta16292a2016-04-27 16:44:36 -07001013 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014discard_it:
Eric Dumazeta16292a2016-04-27 16:44:36 -07001015 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -08001016drop_no_count:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 kfree_skb(skb);
1018 return 0;
1019}
1020
David S. Miller4c9483b2011-03-12 16:22:43 -05001021void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001022 u8 type,
1023 const struct in6_addr *saddr,
1024 const struct in6_addr *daddr,
1025 int oif)
1026{
David S. Miller4c9483b2011-03-12 16:22:43 -05001027 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001028 fl6->saddr = *saddr;
1029 fl6->daddr = *daddr;
Ian Morris67ba4152014-08-24 21:53:10 +01001030 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -05001031 fl6->fl6_icmp_type = type;
1032 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -05001033 fl6->flowi6_oif = oif;
Paul Moore3df98d72020-09-27 22:38:26 -04001034 security_sk_classify_flow(sk, flowi6_to_flowi_common(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001035}
1036
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001037static void __net_exit icmpv6_sk_exit(struct net *net)
1038{
1039 int i;
1040
1041 for_each_possible_cpu(i)
Kefeng Wang75efc252019-02-23 15:28:28 +08001042 inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv6.icmp_sk, i));
1043 free_percpu(net->ipv6.icmp_sk);
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001044}
1045
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001046static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047{
1048 struct sock *sk;
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001049 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Kefeng Wang75efc252019-02-23 15:28:28 +08001051 net->ipv6.icmp_sk = alloc_percpu(struct sock *);
Ian Morris63159f22015-03-29 14:00:04 +01001052 if (!net->ipv6.icmp_sk)
Denis V. Lunev79c91152008-02-29 11:17:11 -08001053 return -ENOMEM;
1054
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001055 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001056 err = inet_ctl_sock_create(&sk, PF_INET6,
1057 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 if (err < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001059 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 err);
1061 goto fail;
1062 }
1063
Kefeng Wang75efc252019-02-23 15:28:28 +08001064 *per_cpu_ptr(net->ipv6.icmp_sk, i) = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -08001065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 /* Enough space for 2 64K ICMP packets, including
1067 * sk_buff struct overhead.
1068 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +00001069 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return 0;
1072
1073 fail:
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001074 icmpv6_sk_exit(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 return err;
1076}
1077
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001078static struct pernet_operations icmpv6_sk_ops = {
Ian Morris67ba4152014-08-24 21:53:10 +01001079 .init = icmpv6_sk_init,
1080 .exit = icmpv6_sk_exit,
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001081};
1082
1083int __init icmpv6_init(void)
1084{
1085 int err;
1086
1087 err = register_pernet_subsys(&icmpv6_sk_ops);
1088 if (err < 0)
1089 return err;
1090
1091 err = -EAGAIN;
1092 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
1093 goto fail;
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001094
1095 err = inet6_register_icmp_sender(icmp6_send);
1096 if (err)
1097 goto sender_reg_err;
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001098 return 0;
1099
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001100sender_reg_err:
1101 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001102fail:
Joe Perchesf3213832012-05-15 14:11:53 +00001103 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001104 unregister_pernet_subsys(&icmpv6_sk_ops);
1105 return err;
1106}
1107
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001108void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001109{
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001110 inet6_unregister_icmp_sender(icmp6_send);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001111 unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
1113}
1114
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001115
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -08001116static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 int err;
1118 int fatal;
1119} tab_unreach[] = {
1120 { /* NOROUTE */
1121 .err = ENETUNREACH,
1122 .fatal = 0,
1123 },
1124 { /* ADM_PROHIBITED */
1125 .err = EACCES,
1126 .fatal = 1,
1127 },
1128 { /* Was NOT_NEIGHBOUR, now reserved */
1129 .err = EHOSTUNREACH,
1130 .fatal = 0,
1131 },
1132 { /* ADDR_UNREACH */
1133 .err = EHOSTUNREACH,
1134 .fatal = 0,
1135 },
1136 { /* PORT_UNREACH */
1137 .err = ECONNREFUSED,
1138 .fatal = 1,
1139 },
Jiri Bohac61e76b12013-08-30 11:18:45 +02001140 { /* POLICY_FAIL */
1141 .err = EACCES,
1142 .fatal = 1,
1143 },
1144 { /* REJECT_ROUTE */
1145 .err = EACCES,
1146 .fatal = 1,
1147 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148};
1149
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07001150int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151{
1152 int fatal = 0;
1153
1154 *err = EPROTO;
1155
1156 switch (type) {
1157 case ICMPV6_DEST_UNREACH:
1158 fatal = 1;
Jiri Bohac61e76b12013-08-30 11:18:45 +02001159 if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 *err = tab_unreach[code].err;
1161 fatal = tab_unreach[code].fatal;
1162 }
1163 break;
1164
1165 case ICMPV6_PKT_TOOBIG:
1166 *err = EMSGSIZE;
1167 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 case ICMPV6_PARAMPROB:
1170 *err = EPROTO;
1171 fatal = 1;
1172 break;
1173
1174 case ICMPV6_TIME_EXCEED:
1175 *err = EHOSTUNREACH;
1176 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
1179 return fatal;
1180}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001181EXPORT_SYMBOL(icmpv6_err_convert);
1182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183#ifdef CONFIG_SYSCTL
stephen hemmingere8243532013-12-29 14:03:31 -08001184static struct ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -08001187 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 .maxlen = sizeof(int),
1189 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08001190 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 },
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001192 {
1193 .procname = "echo_ignore_all",
1194 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_all,
Eric Dumazeta6175632021-03-31 10:52:12 -07001195 .maxlen = sizeof(u8),
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001196 .mode = 0644,
Eric Dumazeta6175632021-03-31 10:52:12 -07001197 .proc_handler = proc_dou8vec_minmax,
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001198 },
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001199 {
1200 .procname = "echo_ignore_multicast",
1201 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_multicast,
Eric Dumazeta6175632021-03-31 10:52:12 -07001202 .maxlen = sizeof(u8),
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001203 .mode = 0644,
Eric Dumazeta6175632021-03-31 10:52:12 -07001204 .proc_handler = proc_dou8vec_minmax,
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001205 },
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001206 {
1207 .procname = "echo_ignore_anycast",
1208 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_anycast,
Eric Dumazeta6175632021-03-31 10:52:12 -07001209 .maxlen = sizeof(u8),
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001210 .mode = 0644,
Eric Dumazeta6175632021-03-31 10:52:12 -07001211 .proc_handler = proc_dou8vec_minmax,
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001212 },
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001213 {
1214 .procname = "ratemask",
1215 .data = &init_net.ipv6.sysctl.icmpv6_ratemask_ptr,
1216 .maxlen = ICMPV6_MSG_MAX + 1,
1217 .mode = 0644,
1218 .proc_handler = proc_do_large_bitmap,
1219 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001220 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221};
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001222
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001223struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001224{
1225 struct ctl_table *table;
1226
1227 table = kmemdup(ipv6_icmp_table_template,
1228 sizeof(ipv6_icmp_table_template),
1229 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001230
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001231 if (table) {
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001232 table[0].data = &net->ipv6.sysctl.icmpv6_time;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001233 table[1].data = &net->ipv6.sysctl.icmpv6_echo_ignore_all;
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001234 table[2].data = &net->ipv6.sysctl.icmpv6_echo_ignore_multicast;
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001235 table[3].data = &net->ipv6.sysctl.icmpv6_echo_ignore_anycast;
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001236 table[4].data = &net->ipv6.sysctl.icmpv6_ratemask_ptr;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001237 }
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001238 return table;
1239}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240#endif