blob: a4e4912ad607b38d07fec24caa4dfb834a6a1099 [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);
Ian Morris63159f22015-03-29 14:00:04 +0100161 if (!tp || !(*tp & ICMPV6_INFOMSG_MASK))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000162 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000164 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165}
166
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400167static bool icmpv6_mask_allow(struct net *net, int type)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100168{
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400169 if (type > ICMPV6_MSG_MAX)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100170 return true;
171
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400172 /* Limit if icmp type is set in ratemask. */
173 if (!test_bit(type, net->ipv6.sysctl.icmpv6_ratemask))
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100174 return true;
175
176 return false;
177}
178
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400179static bool icmpv6_global_allow(struct net *net, int type)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100180{
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400181 if (icmpv6_mask_allow(net, type))
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100182 return true;
183
184 if (icmp_global_allow())
185 return true;
186
187 return false;
188}
189
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900190/*
191 * Check the ICMP output rate limit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 */
Eric Dumazet4cdf5072014-09-19 07:38:40 -0700193static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
194 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900196 struct net *net = sock_net(sk);
Eric Dumazet4cdf5072014-09-19 07:38:40 -0700197 struct dst_entry *dst;
David S. Miller92d86822011-02-04 15:55:25 -0800198 bool res = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400200 if (icmpv6_mask_allow(net, type))
David S. Miller92d86822011-02-04 15:55:25 -0800201 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900203 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 * Look up the output route.
205 * XXX: perhaps the expire for routing entries cloned by
206 * this lookup should be more aggressive (not longer than timeout).
207 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500208 dst = ip6_route_output(net, sk, fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 if (dst->error) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -0700210 IP6_INC_STATS(net, ip6_dst_idev(dst),
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900211 IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
David S. Miller92d86822011-02-04 15:55:25 -0800213 res = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 } else {
215 struct rt6_info *rt = (struct rt6_info *)dst;
Benjamin Thery9a43b702008-03-05 10:49:18 -0800216 int tmo = net->ipv6.sysctl.icmpv6_time;
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100217 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 /* Give more bandwidth to wider prefixes. */
220 if (rt->rt6i_dst.plen < 128)
221 tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
222
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100223 peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr, 1);
224 res = inet_peer_xrlim_allow(peer, tmo);
225 if (peer)
226 inet_putpeer(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 }
228 dst_release(dst);
229 return res;
230}
231
Tim Stallardb93cfb92020-04-03 21:22:57 +0100232static bool icmpv6_rt_has_prefsrc(struct sock *sk, u8 type,
233 struct flowi6 *fl6)
234{
235 struct net *net = sock_net(sk);
236 struct dst_entry *dst;
237 bool res = false;
238
239 dst = ip6_route_output(net, sk, fl6);
240 if (!dst->error) {
241 struct rt6_info *rt = (struct rt6_info *)dst;
242 struct in6_addr prefsrc;
243
244 rt6_get_prefsrc(rt, &prefsrc);
245 res = !ipv6_addr_any(&prefsrc);
246 }
247 dst_release(dst);
248 return res;
249}
250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251/*
252 * an inline helper for the "simple" if statement below
253 * checks if parameter problem report is caused by an
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900254 * unrecognized IPv6 option that has the Option Type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 * highest-order two bits set to 10
256 */
257
Eric Dumazeta50feda2012-05-18 18:57:34 +0000258static bool opt_unrec(struct sk_buff *skb, __u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
260 u8 _optval, *op;
261
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300262 offset += skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
Ian Morris63159f22015-03-29 14:00:04 +0100264 if (!op)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000265 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 return (*op & 0xC0) == 0x80;
267}
268
Joe Perches4e64b1e2017-10-05 23:46:14 -0700269void icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
270 struct icmp6hdr *thdr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
272 struct sk_buff *skb;
273 struct icmp6hdr *icmp6h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Ian Morrise5d08d72014-11-23 21:28:43 +0000275 skb = skb_peek(&sk->sk_write_queue);
Ian Morris63159f22015-03-29 14:00:04 +0100276 if (!skb)
Joe Perches4e64b1e2017-10-05 23:46:14 -0700277 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300279 icmp6h = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
281 icmp6h->icmp6_cksum = 0;
282
283 if (skb_queue_len(&sk->sk_write_queue) == 1) {
Joe Perches07f07572008-11-19 15:44:53 -0800284 skb->csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 sizeof(struct icmp6hdr), skb->csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500286 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
287 &fl6->daddr,
288 len, fl6->flowi6_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 skb->csum);
290 } else {
Al Viro868c86b2006-11-14 21:35:48 -0800291 __wsum tmp_csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
293 skb_queue_walk(&sk->sk_write_queue, skb) {
294 tmp_csum = csum_add(tmp_csum, skb->csum);
295 }
296
Joe Perches07f07572008-11-19 15:44:53 -0800297 tmp_csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 sizeof(struct icmp6hdr), tmp_csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500299 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
300 &fl6->daddr,
301 len, fl6->flowi6_proto,
Al Viro868c86b2006-11-14 21:35:48 -0800302 tmp_csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 ip6_push_pending_frames(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305}
306
307struct icmpv6_msg {
308 struct sk_buff *skb;
309 int offset;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800310 uint8_t type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311};
312
313static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
314{
315 struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
316 struct sk_buff *org_skb = msg->skb;
Al Viro5f92a732006-11-14 21:36:54 -0800317 __wsum csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
320 to, len, csum);
321 skb->csum = csum_block_add(skb->csum, csum, odd);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800322 if (!(msg->type & ICMPV6_INFOMSG_MASK))
323 nf_ct_attach(skb, org_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 return 0;
325}
326
Amerigo Wang07a93622012-10-29 16:23:10 +0000327#if IS_ENABLED(CONFIG_IPV6_MIP6)
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700328static void mip6_addr_swap(struct sk_buff *skb)
329{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700330 struct ipv6hdr *iph = ipv6_hdr(skb);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700331 struct inet6_skb_parm *opt = IP6CB(skb);
332 struct ipv6_destopt_hao *hao;
333 struct in6_addr tmp;
334 int off;
335
336 if (opt->dsthao) {
337 off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
338 if (likely(off >= 0)) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700339 hao = (struct ipv6_destopt_hao *)
340 (skb_network_header(skb) + off);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000341 tmp = iph->saddr;
342 iph->saddr = hao->addr;
343 hao->addr = tmp;
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700344 }
345 }
346}
347#else
348static inline void mip6_addr_swap(struct sk_buff *skb) {}
349#endif
350
stephen hemmingere8243532013-12-29 14:03:31 -0800351static struct dst_entry *icmpv6_route_lookup(struct net *net,
352 struct sk_buff *skb,
353 struct sock *sk,
354 struct flowi6 *fl6)
David S. Millerb42835d2011-03-01 22:06:22 -0800355{
356 struct dst_entry *dst, *dst2;
David S. Miller4c9483b2011-03-12 16:22:43 -0500357 struct flowi6 fl2;
David S. Millerb42835d2011-03-01 22:06:22 -0800358 int err;
359
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700360 err = ip6_dst_lookup(net, sk, &dst, fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800361 if (err)
362 return ERR_PTR(err);
363
364 /*
365 * We won't send icmp if the destination is known
366 * anycast.
367 */
Martin KaFai Lau2647a9b2015-05-22 20:55:58 -0700368 if (ipv6_anycast_destination(dst, &fl6->daddr)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800369 net_dbg_ratelimited("icmp6_send: acast source\n");
David S. Millerb42835d2011-03-01 22:06:22 -0800370 dst_release(dst);
371 return ERR_PTR(-EINVAL);
372 }
373
374 /* No need to clone since we're just using its address. */
375 dst2 = dst;
376
David S. Miller4c9483b2011-03-12 16:22:43 -0500377 dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800378 if (!IS_ERR(dst)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800379 if (dst != dst2)
380 return dst;
David S. Miller452edd52011-03-02 13:27:41 -0800381 } else {
382 if (PTR_ERR(dst) == -EPERM)
383 dst = NULL;
384 else
385 return dst;
David S. Millerb42835d2011-03-01 22:06:22 -0800386 }
387
David S. Miller4c9483b2011-03-12 16:22:43 -0500388 err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6);
David S. Millerb42835d2011-03-01 22:06:22 -0800389 if (err)
390 goto relookup_failed;
391
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700392 err = ip6_dst_lookup(net, sk, &dst2, &fl2);
David S. Millerb42835d2011-03-01 22:06:22 -0800393 if (err)
394 goto relookup_failed;
395
David S. Miller4c9483b2011-03-12 16:22:43 -0500396 dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP);
David S. Miller452edd52011-03-02 13:27:41 -0800397 if (!IS_ERR(dst2)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800398 dst_release(dst);
399 dst = dst2;
David S. Miller452edd52011-03-02 13:27:41 -0800400 } else {
401 err = PTR_ERR(dst2);
402 if (err == -EPERM) {
403 dst_release(dst);
404 return dst2;
405 } else
406 goto relookup_failed;
David S. Millerb42835d2011-03-01 22:06:22 -0800407 }
408
409relookup_failed:
410 if (dst)
411 return dst;
412 return ERR_PTR(err);
413}
414
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400415static struct net_device *icmp6_dev(const struct sk_buff *skb)
David Ahern1b70d7922017-08-28 13:53:34 -0700416{
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400417 struct net_device *dev = skb->dev;
David Ahern1b70d7922017-08-28 13:53:34 -0700418
419 /* for local traffic to local address, skb dev is the loopback
420 * device. Check if there is a dst attached to the skb and if so
David Ahern24b711e2018-07-19 12:41:18 -0700421 * get the real device index. Same is needed for replies to a link
422 * local address on a device enslaved to an L3 master device
David Ahern1b70d7922017-08-28 13:53:34 -0700423 */
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400424 if (unlikely(dev->ifindex == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) {
David Ahern1b70d7922017-08-28 13:53:34 -0700425 const struct rt6_info *rt6 = skb_rt6_info(skb);
426
427 if (rt6)
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400428 dev = rt6->rt6i_idev->dev;
David Ahern1b70d7922017-08-28 13:53:34 -0700429 }
430
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400431 return dev;
432}
433
434static int icmp6_iif(const struct sk_buff *skb)
435{
436 return icmp6_dev(skb)->ifindex;
David Ahern1b70d7922017-08-28 13:53:34 -0700437}
438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439/*
440 * Send an ICMP message in response to a packet in error
441 */
Eric Dumazetcc7a21b2020-06-19 12:02:59 -0700442void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
443 const struct in6_addr *force_saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
445 struct inet6_dev *idev = NULL;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700446 struct ipv6hdr *hdr = ipv6_hdr(skb);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700447 struct sock *sk;
Eric Dumazet8d933672019-01-04 11:00:00 -0800448 struct net *net;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700449 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000450 const struct in6_addr *saddr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 struct dst_entry *dst;
452 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500453 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 struct icmpv6_msg msg;
Wei Wang26879da2016-05-02 21:40:07 -0700455 struct ipcm6_cookie ipc6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 int iif = 0;
457 int addr_type = 0;
458 int len;
Eric Dumazet8d933672019-01-04 11:00:00 -0800459 u32 mark;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700461 if ((u8 *)hdr < skb->head ||
Simon Horman29a3cad2013-05-28 20:34:26 +0000462 (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 return;
464
Eric Dumazet8d933672019-01-04 11:00:00 -0800465 if (!skb->dev)
466 return;
467 net = dev_net(skb->dev);
468 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900470 * Make sure we respect the rules
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 * i.e. RFC 1885 2.4(e)
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000472 * Rule (e.1) is enforced by not using icmp6_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 * in any code that processes icmp errors.
474 */
475 addr_type = ipv6_addr_type(&hdr->daddr);
476
FX Le Bail446fab52014-01-19 17:00:36 +0100477 if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) ||
FX Le Baild94c1f92014-02-07 11:22:37 +0100478 ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 saddr = &hdr->daddr;
480
481 /*
482 * Dest addr check
483 */
484
zhuyj9a6b4b32015-01-14 17:23:59 +0800485 if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (type != ICMPV6_PKT_TOOBIG &&
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900487 !(type == ICMPV6_PARAMPROB &&
488 code == ICMPV6_UNK_OPTION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 (opt_unrec(skb, info))))
490 return;
491
492 saddr = NULL;
493 }
494
495 addr_type = ipv6_addr_type(&hdr->saddr);
496
497 /*
498 * Source addr check
499 */
500
David Ahern4832c302017-08-17 12:17:20 -0700501 if (__ipv6_addr_needs_scope_id(addr_type)) {
David Ahern1b70d7922017-08-28 13:53:34 -0700502 iif = icmp6_iif(skb);
David Ahern4832c302017-08-17 12:17:20 -0700503 } else {
David Ahern79dc7e32016-11-27 18:52:53 -0800504 dst = skb_dst(skb);
505 iif = l3mdev_master_ifindex(dst ? dst->dev : skb->dev);
506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 /*
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900509 * Must not send error if the source does not uniquely
510 * identify a single node (RFC2463 Section 2.4).
511 * We check unspecified / multicast addresses here,
512 * and anycast addresses will be checked later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 */
514 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200515 net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n",
516 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 return;
518 }
519
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900520 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 * Never answer to a ICMP packet.
522 */
523 if (is_ineligible(skb)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200524 net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n",
525 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 return;
527 }
528
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100529 /* Needed by both icmp_global_allow and icmpv6_xmit_lock */
530 local_bh_disable();
531
532 /* Check global sysctl_icmp_msgs_per_sec ratelimit */
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400533 if (!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, type))
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100534 goto out_bh_enable;
535
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700536 mip6_addr_swap(skb);
537
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700538 sk = icmpv6_xmit_lock(net);
539 if (!sk)
540 goto out_bh_enable;
541
David S. Miller4c9483b2011-03-12 16:22:43 -0500542 memset(&fl6, 0, sizeof(fl6));
543 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000544 fl6.daddr = hdr->saddr;
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700545 if (force_saddr)
546 saddr = force_saddr;
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700547 if (saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000548 fl6.saddr = *saddr;
Tim Stallardb93cfb92020-04-03 21:22:57 +0100549 } else if (!icmpv6_rt_has_prefsrc(sk, type, &fl6)) {
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700550 /* select a more meaningful saddr from input if */
551 struct net_device *in_netdev;
552
553 in_netdev = dev_get_by_index(net, IP6CB(skb)->iif);
554 if (in_netdev) {
555 ipv6_dev_get_saddr(net, in_netdev, &fl6.daddr,
556 inet6_sk(sk)->srcprefs,
557 &fl6.saddr);
558 dev_put(in_netdev);
559 }
560 }
Lorenzo Colittie1108612014-05-13 10:17:33 -0700561 fl6.flowi6_mark = mark;
David S. Miller4c9483b2011-03-12 16:22:43 -0500562 fl6.flowi6_oif = iif;
David S. Miller1958b852011-03-12 16:36:19 -0500563 fl6.fl6_icmp_type = type;
564 fl6.fl6_icmp_code = code;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900565 fl6.flowi6_uid = sock_net_uid(net, NULL);
David Ahernb4bac172018-03-02 08:32:18 -0800566 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, NULL);
David S. Miller4c9483b2011-03-12 16:22:43 -0500567 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700569 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800570
David S. Miller4c9483b2011-03-12 16:22:43 -0500571 if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 goto out;
573
574 tmp_hdr.icmp6_type = type;
575 tmp_hdr.icmp6_code = code;
576 tmp_hdr.icmp6_cksum = 0;
577 tmp_hdr.icmp6_pointer = htonl(info);
578
David S. Miller4c9483b2011-03-12 16:22:43 -0500579 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
580 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000581 else if (!fl6.flowi6_oif)
582 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Willem de Bruijnb515430a2018-07-06 10:12:55 -0400584 ipcm6_init_sk(&ipc6, np);
Willem de Bruijn0da75362020-07-01 16:00:06 -0400585 ipc6.sockc.mark = mark;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +0200586 fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
587
David S. Miller4c9483b2011-03-12 16:22:43 -0500588 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800589 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 goto out;
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900591
Wei Wang26879da2016-05-02 21:40:07 -0700592 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 msg.skb = skb;
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300595 msg.offset = skb_network_offset(skb);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800596 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
598 len = skb->len - msg.offset;
Ian Morris67ba4152014-08-24 21:53:10 +0100599 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (len < 0) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200601 net_dbg_ratelimited("icmp: len problem [%pI6c > %pI6c]\n",
602 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 goto out_dst_release;
604 }
605
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000606 rcu_read_lock();
607 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Joe Perches4e64b1e2017-10-05 23:46:14 -0700609 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
610 len + sizeof(struct icmp6hdr),
611 sizeof(struct icmp6hdr),
612 &ipc6, &fl6, (struct rt6_info *)dst,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400613 MSG_DONTWAIT)) {
Hannes Frederic Sowa43a43b62014-03-31 20:14:10 +0200614 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000616 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700617 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
618 len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 }
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000620 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621out_dst_release:
622 dst_release(dst);
623out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800624 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100625out_bh_enable:
626 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627}
Eric Dumazetcc7a21b2020-06-19 12:02:59 -0700628EXPORT_SYMBOL(icmp6_send);
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000629
630/* Slightly more convenient version of icmp6_send.
631 */
632void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
633{
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700634 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL);
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000635 kfree_skb(skb);
636}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900637
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700638/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
639 * if sufficient data bytes are available
640 * @nhs is the size of the tunnel header(s) :
641 * Either an IPv4 header for SIT encap
642 * an IPv4 header + GRE header for GRE encap
643 */
Eric Dumazet20e19542016-06-18 21:52:06 -0700644int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
645 unsigned int data_len)
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700646{
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700647 struct in6_addr temp_saddr;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700648 struct rt6_info *rt;
649 struct sk_buff *skb2;
Eric Dumazet20e19542016-06-18 21:52:06 -0700650 u32 info = 0;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700651
652 if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8))
653 return 1;
654
Eric Dumazet20e19542016-06-18 21:52:06 -0700655 /* RFC 4884 (partial) support for ICMP extensions */
656 if (data_len < 128 || (data_len & 7) || skb->len < data_len)
657 data_len = 0;
658
659 skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700660
661 if (!skb2)
662 return 1;
663
664 skb_dst_drop(skb2);
665 skb_pull(skb2, nhs);
666 skb_reset_network_header(skb2);
667
David Ahernb75cc8f2018-03-02 08:32:17 -0800668 rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0,
669 skb, 0);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700670
671 if (rt && rt->dst.dev)
672 skb2->dev = rt->dst.dev;
673
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700674 ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr);
Eric Dumazet20e19542016-06-18 21:52:06 -0700675
676 if (data_len) {
677 /* RFC 4884 (partial) support :
678 * insert 0 padding at the end, before the extensions
679 */
680 __skb_push(skb2, nhs);
681 skb_reset_network_header(skb2);
682 memmove(skb2->data, skb2->data + nhs, data_len - nhs);
683 memset(skb2->data + data_len - nhs, 0, nhs);
684 /* RFC 4884 4.5 : Length is measured in 64-bit words,
685 * and stored in reserved[0]
686 */
687 info = (data_len/8) << 24;
688 }
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700689 if (type == ICMP_TIME_EXCEEDED)
690 icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
Eric Dumazet20e19542016-06-18 21:52:06 -0700691 info, &temp_saddr);
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700692 else
693 icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH,
Eric Dumazet20e19542016-06-18 21:52:06 -0700694 info, &temp_saddr);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700695 if (rt)
696 ip6_rt_put(rt);
697
698 kfree_skb(skb2);
699
700 return 0;
701}
702EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704static void icmpv6_echo_reply(struct sk_buff *skb)
705{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900706 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700707 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700709 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000710 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300711 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500713 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 struct icmpv6_msg msg;
715 struct dst_entry *dst;
Wei Wang26879da2016-05-02 21:40:07 -0700716 struct ipcm6_cookie ipc6;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700717 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400718 bool acast;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -0400720 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) &&
721 net->ipv6.sysctl.icmpv6_echo_ignore_multicast)
722 return;
723
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700724 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400726 acast = ipv6_anycast_destination(skb_dst(skb), saddr);
727 if (acast && net->ipv6.sysctl.icmpv6_echo_ignore_anycast)
728 return;
729
FX Le Bail509aba32014-01-07 14:57:27 +0100730 if (!ipv6_unicast_destination(skb) &&
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400731 !(net->ipv6.sysctl.anycast_src_echo_reply && acast))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 saddr = NULL;
733
734 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
735 tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
736
David S. Miller4c9483b2011-03-12 16:22:43 -0500737 memset(&fl6, 0, sizeof(fl6));
Eric Dumazeta346abe2019-07-01 06:39:36 -0700738 if (net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES)
739 fl6.flowlabel = ip6_flowlabel(ipv6_hdr(skb));
740
David S. Miller4c9483b2011-03-12 16:22:43 -0500741 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000742 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000744 fl6.saddr = *saddr;
David Ahern1b70d7922017-08-28 13:53:34 -0700745 fl6.flowi6_oif = icmp6_iif(skb);
David S. Miller1958b852011-03-12 16:36:19 -0500746 fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700747 fl6.flowi6_mark = mark;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900748 fl6.flowi6_uid = sock_net_uid(net, NULL);
David S. Miller4c9483b2011-03-12 16:22:43 -0500749 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100751 local_bh_disable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700752 sk = icmpv6_xmit_lock(net);
Ian Morris63159f22015-03-29 14:00:04 +0100753 if (!sk)
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100754 goto out_bh_enable;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700755 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800756
David S. Miller4c9483b2011-03-12 16:22:43 -0500757 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
758 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000759 else if (!fl6.flowi6_oif)
760 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Joe Perches4e64b1e2017-10-05 23:46:14 -0700762 if (ip6_dst_lookup(net, sk, &dst, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 goto out;
David S. Miller4c9483b2011-03-12 16:22:43 -0500764 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800765 if (IS_ERR(dst))
Patrick McHardye104411b2005-09-08 15:11:55 -0700766 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400768 /* Check the ratelimit */
769 if ((!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, ICMPV6_ECHO_REPLY)) ||
770 !icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6))
771 goto out_dst_release;
772
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000773 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775 msg.skb = skb;
776 msg.offset = 0;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800777 msg.type = ICMPV6_ECHO_REPLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Willem de Bruijnb515430a2018-07-06 10:12:55 -0400779 ipcm6_init_sk(&ipc6, np);
Wei Wang26879da2016-05-02 21:40:07 -0700780 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
781 ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
Willem de Bruijn0da75362020-07-01 16:00:06 -0400782 ipc6.sockc.mark = mark;
Wei Wang26879da2016-05-02 21:40:07 -0700783
Joe Perches4e64b1e2017-10-05 23:46:14 -0700784 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
785 skb->len + sizeof(struct icmp6hdr),
786 sizeof(struct icmp6hdr), &ipc6, &fl6,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400787 (struct rt6_info *)dst, MSG_DONTWAIT)) {
Eric Dumazeta16292a2016-04-27 16:44:36 -0700788 __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000790 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700791 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
792 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400794out_dst_release:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900796out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800797 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100798out_bh_enable:
799 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800}
801
David S. Millerb94f1c02012-07-12 00:33:37 -0700802void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000804 const struct inet6_protocol *ipprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 int inner_offset;
Jesse Gross75f28112011-11-30 17:05:51 -0800806 __be16 frag_off;
David S. Millerf9242b62012-06-19 18:56:21 -0700807 u8 nexthdr;
Duan Jiong7304fe42014-07-31 17:54:32 +0800808 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
810 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
Duan Jiong7304fe42014-07-31 17:54:32 +0800811 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
814 if (ipv6_ext_hdr(nexthdr)) {
815 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800816 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
817 &nexthdr, &frag_off);
Ian Morris67ba4152014-08-24 21:53:10 +0100818 if (inner_offset < 0)
Duan Jiong7304fe42014-07-31 17:54:32 +0800819 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 } else {
821 inner_offset = sizeof(struct ipv6hdr);
822 }
823
824 /* Checkin header including 8 bytes of inner protocol header. */
825 if (!pskb_may_pull(skb, inner_offset+8))
Duan Jiong7304fe42014-07-31 17:54:32 +0800826 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
829 Without this we will not able f.e. to make source routed
830 pmtu discovery.
831 Corresponding argument (opt) to notifiers is already added.
832 --ANK (980726)
833 */
834
David S. Millerf9242b62012-06-19 18:56:21 -0700835 ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (ipprot && ipprot->err_handler)
837 ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800839 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Duan Jiong7304fe42014-07-31 17:54:32 +0800840 return;
841
842out:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700843 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846/*
847 * Handle icmp messages
848 */
849
Herbert Xue5bbef22007-10-15 12:50:28 -0700850static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851{
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200852 struct net *net = dev_net(skb->dev);
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400853 struct net_device *dev = icmp6_dev(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000855 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700857 u8 type;
Rick Jonese3e32172014-11-17 14:04:29 -0800858 bool success = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
Herbert Xuaebcf822007-12-12 18:54:16 -0800860 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700861 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800862 int nh;
863
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700864 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Herbert Xuaebcf822007-12-12 18:54:16 -0800865 XFRM_STATE_ICMP))
866 goto drop_no_count;
867
David S. Miller81aded22012-06-15 14:54:11 -0700868 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800869 goto drop_no_count;
870
871 nh = skb_network_offset(skb);
872 skb_set_network_header(skb, sizeof(*hdr));
873
874 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
875 goto drop_no_count;
876
877 skb_set_network_header(skb, nh);
878 }
879
Eric Dumazeta16292a2016-04-27 16:44:36 -0700880 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700882 saddr = &ipv6_hdr(skb)->saddr;
883 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Tom Herbert39471ac2014-05-07 16:52:29 -0700885 if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800886 net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
887 saddr, daddr);
Tom Herbert39471ac2014-05-07 16:52:29 -0700888 goto csum_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 }
890
Herbert Xu8cf22942008-02-05 03:15:50 -0800891 if (!pskb_pull(skb, sizeof(*hdr)))
892 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300894 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896 type = hdr->icmp6_type;
897
Eric Dumazetf3832ed2016-04-27 16:44:42 -0700898 ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 switch (type) {
901 case ICMPV6_ECHO_REQUEST:
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200902 if (!net->ipv6.sysctl.icmpv6_echo_ignore_all)
903 icmpv6_echo_reply(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 break;
905
906 case ICMPV6_ECHO_REPLY:
Rick Jonese3e32172014-11-17 14:04:29 -0800907 success = ping_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 break;
909
910 case ICMPV6_PKT_TOOBIG:
911 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
912 standard destination cache. Seems, only "advanced"
913 destination cache will allow to solve this problem
914 --ANK (980726)
915 */
916 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
917 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300918 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -0500920 /* to notify */
Joe Perchesa8eceea2020-03-12 15:50:22 -0700921 fallthrough;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 case ICMPV6_DEST_UNREACH:
923 case ICMPV6_TIME_EXCEED:
924 case ICMPV6_PARAMPROB:
925 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
926 break;
927
928 case NDISC_ROUTER_SOLICITATION:
929 case NDISC_ROUTER_ADVERTISEMENT:
930 case NDISC_NEIGHBOUR_SOLICITATION:
931 case NDISC_NEIGHBOUR_ADVERTISEMENT:
932 case NDISC_REDIRECT:
933 ndisc_rcv(skb);
934 break;
935
936 case ICMPV6_MGM_QUERY:
937 igmp6_event_query(skb);
938 break;
939
940 case ICMPV6_MGM_REPORT:
941 igmp6_event_report(skb);
942 break;
943
944 case ICMPV6_MGM_REDUCTION:
945 case ICMPV6_NI_QUERY:
946 case ICMPV6_NI_REPLY:
947 case ICMPV6_MLD2_REPORT:
948 case ICMPV6_DHAAD_REQUEST:
949 case ICMPV6_DHAAD_REPLY:
950 case ICMPV6_MOBILE_PREFIX_SOL:
951 case ICMPV6_MOBILE_PREFIX_ADV:
952 break;
953
954 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 /* informational */
956 if (type & ICMPV6_INFOMSG_MASK)
957 break;
958
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200959 net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
960 saddr, daddr);
David S. Millerea85a0a2014-10-07 16:33:53 -0400961
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900962 /*
963 * error of unknown type.
964 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 */
966
967 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700968 }
969
Rick Jonese3e32172014-11-17 14:04:29 -0800970 /* until the v6 path can be better sorted assume failure and
971 * preserve the status quo behaviour for the rest of the paths to here
972 */
973 if (success)
974 consume_skb(skb);
975 else
976 kfree_skb(skb);
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return 0;
979
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +0000980csum_error:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700981 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982discard_it:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700983 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800984drop_no_count:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 kfree_skb(skb);
986 return 0;
987}
988
David S. Miller4c9483b2011-03-12 16:22:43 -0500989void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800990 u8 type,
991 const struct in6_addr *saddr,
992 const struct in6_addr *daddr,
993 int oif)
994{
David S. Miller4c9483b2011-03-12 16:22:43 -0500995 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000996 fl6->saddr = *saddr;
997 fl6->daddr = *daddr;
Ian Morris67ba4152014-08-24 21:53:10 +0100998 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -0500999 fl6->fl6_icmp_type = type;
1000 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -05001001 fl6->flowi6_oif = oif;
1002 security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001003}
1004
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001005static void __net_exit icmpv6_sk_exit(struct net *net)
1006{
1007 int i;
1008
1009 for_each_possible_cpu(i)
Kefeng Wang75efc252019-02-23 15:28:28 +08001010 inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv6.icmp_sk, i));
1011 free_percpu(net->ipv6.icmp_sk);
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001012}
1013
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001014static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015{
1016 struct sock *sk;
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001017 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Kefeng Wang75efc252019-02-23 15:28:28 +08001019 net->ipv6.icmp_sk = alloc_percpu(struct sock *);
Ian Morris63159f22015-03-29 14:00:04 +01001020 if (!net->ipv6.icmp_sk)
Denis V. Lunev79c91152008-02-29 11:17:11 -08001021 return -ENOMEM;
1022
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001023 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001024 err = inet_ctl_sock_create(&sk, PF_INET6,
1025 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if (err < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001027 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 err);
1029 goto fail;
1030 }
1031
Kefeng Wang75efc252019-02-23 15:28:28 +08001032 *per_cpu_ptr(net->ipv6.icmp_sk, i) = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -08001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 /* Enough space for 2 64K ICMP packets, including
1035 * sk_buff struct overhead.
1036 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +00001037 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 return 0;
1040
1041 fail:
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001042 icmpv6_sk_exit(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 return err;
1044}
1045
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001046static struct pernet_operations icmpv6_sk_ops = {
Ian Morris67ba4152014-08-24 21:53:10 +01001047 .init = icmpv6_sk_init,
1048 .exit = icmpv6_sk_exit,
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001049};
1050
1051int __init icmpv6_init(void)
1052{
1053 int err;
1054
1055 err = register_pernet_subsys(&icmpv6_sk_ops);
1056 if (err < 0)
1057 return err;
1058
1059 err = -EAGAIN;
1060 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
1061 goto fail;
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001062
1063 err = inet6_register_icmp_sender(icmp6_send);
1064 if (err)
1065 goto sender_reg_err;
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001066 return 0;
1067
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001068sender_reg_err:
1069 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001070fail:
Joe Perchesf3213832012-05-15 14:11:53 +00001071 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001072 unregister_pernet_subsys(&icmpv6_sk_ops);
1073 return err;
1074}
1075
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001076void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001077{
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001078 inet6_unregister_icmp_sender(icmp6_send);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001079 unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
1081}
1082
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001083
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -08001084static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 int err;
1086 int fatal;
1087} tab_unreach[] = {
1088 { /* NOROUTE */
1089 .err = ENETUNREACH,
1090 .fatal = 0,
1091 },
1092 { /* ADM_PROHIBITED */
1093 .err = EACCES,
1094 .fatal = 1,
1095 },
1096 { /* Was NOT_NEIGHBOUR, now reserved */
1097 .err = EHOSTUNREACH,
1098 .fatal = 0,
1099 },
1100 { /* ADDR_UNREACH */
1101 .err = EHOSTUNREACH,
1102 .fatal = 0,
1103 },
1104 { /* PORT_UNREACH */
1105 .err = ECONNREFUSED,
1106 .fatal = 1,
1107 },
Jiri Bohac61e76b12013-08-30 11:18:45 +02001108 { /* POLICY_FAIL */
1109 .err = EACCES,
1110 .fatal = 1,
1111 },
1112 { /* REJECT_ROUTE */
1113 .err = EACCES,
1114 .fatal = 1,
1115 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116};
1117
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07001118int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119{
1120 int fatal = 0;
1121
1122 *err = EPROTO;
1123
1124 switch (type) {
1125 case ICMPV6_DEST_UNREACH:
1126 fatal = 1;
Jiri Bohac61e76b12013-08-30 11:18:45 +02001127 if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 *err = tab_unreach[code].err;
1129 fatal = tab_unreach[code].fatal;
1130 }
1131 break;
1132
1133 case ICMPV6_PKT_TOOBIG:
1134 *err = EMSGSIZE;
1135 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 case ICMPV6_PARAMPROB:
1138 *err = EPROTO;
1139 fatal = 1;
1140 break;
1141
1142 case ICMPV6_TIME_EXCEED:
1143 *err = EHOSTUNREACH;
1144 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
1147 return fatal;
1148}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001149EXPORT_SYMBOL(icmpv6_err_convert);
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151#ifdef CONFIG_SYSCTL
stephen hemmingere8243532013-12-29 14:03:31 -08001152static struct ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -08001155 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 .maxlen = sizeof(int),
1157 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08001158 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 },
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001160 {
1161 .procname = "echo_ignore_all",
1162 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_all,
1163 .maxlen = sizeof(int),
1164 .mode = 0644,
1165 .proc_handler = proc_dointvec,
1166 },
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001167 {
1168 .procname = "echo_ignore_multicast",
1169 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_multicast,
1170 .maxlen = sizeof(int),
1171 .mode = 0644,
1172 .proc_handler = proc_dointvec,
1173 },
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001174 {
1175 .procname = "echo_ignore_anycast",
1176 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_anycast,
1177 .maxlen = sizeof(int),
1178 .mode = 0644,
1179 .proc_handler = proc_dointvec,
1180 },
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001181 {
1182 .procname = "ratemask",
1183 .data = &init_net.ipv6.sysctl.icmpv6_ratemask_ptr,
1184 .maxlen = ICMPV6_MSG_MAX + 1,
1185 .mode = 0644,
1186 .proc_handler = proc_do_large_bitmap,
1187 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001188 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189};
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001190
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001191struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001192{
1193 struct ctl_table *table;
1194
1195 table = kmemdup(ipv6_icmp_table_template,
1196 sizeof(ipv6_icmp_table_template),
1197 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001198
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001199 if (table) {
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001200 table[0].data = &net->ipv6.sysctl.icmpv6_time;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001201 table[1].data = &net->ipv6.sysctl.icmpv6_echo_ignore_all;
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001202 table[2].data = &net->ipv6.sysctl.icmpv6_echo_ignore_multicast;
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001203 table[3].data = &net->ipv6.sysctl.icmpv6_echo_ignore_anycast;
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001204 table[4].data = &net->ipv6.sysctl.icmpv6_ratemask_ptr;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001205 }
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001206 return table;
1207}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208#endif