blob: fc5000370030d67094ba11f15aaaaaa7ba519cde [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 Dumazetb1cadc12016-06-18 21:52:02 -0700442static void 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
Lorenzo Colittie1108612014-05-13 10:17:33 -0700569 sk->sk_mark = mark;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700570 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800571
David S. Miller4c9483b2011-03-12 16:22:43 -0500572 if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 goto out;
574
575 tmp_hdr.icmp6_type = type;
576 tmp_hdr.icmp6_code = code;
577 tmp_hdr.icmp6_cksum = 0;
578 tmp_hdr.icmp6_pointer = htonl(info);
579
David S. Miller4c9483b2011-03-12 16:22:43 -0500580 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
581 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000582 else if (!fl6.flowi6_oif)
583 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
Willem de Bruijnb515430a2018-07-06 10:12:55 -0400585 ipcm6_init_sk(&ipc6, np);
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}
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000628
629/* Slightly more convenient version of icmp6_send.
630 */
631void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
632{
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700633 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL);
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000634 kfree_skb(skb);
635}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900636
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700637/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
638 * if sufficient data bytes are available
639 * @nhs is the size of the tunnel header(s) :
640 * Either an IPv4 header for SIT encap
641 * an IPv4 header + GRE header for GRE encap
642 */
Eric Dumazet20e19542016-06-18 21:52:06 -0700643int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
644 unsigned int data_len)
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700645{
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700646 struct in6_addr temp_saddr;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700647 struct rt6_info *rt;
648 struct sk_buff *skb2;
Eric Dumazet20e19542016-06-18 21:52:06 -0700649 u32 info = 0;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700650
651 if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8))
652 return 1;
653
Eric Dumazet20e19542016-06-18 21:52:06 -0700654 /* RFC 4884 (partial) support for ICMP extensions */
655 if (data_len < 128 || (data_len & 7) || skb->len < data_len)
656 data_len = 0;
657
658 skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700659
660 if (!skb2)
661 return 1;
662
663 skb_dst_drop(skb2);
664 skb_pull(skb2, nhs);
665 skb_reset_network_header(skb2);
666
David Ahernb75cc8f2018-03-02 08:32:17 -0800667 rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0,
668 skb, 0);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700669
670 if (rt && rt->dst.dev)
671 skb2->dev = rt->dst.dev;
672
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700673 ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr);
Eric Dumazet20e19542016-06-18 21:52:06 -0700674
675 if (data_len) {
676 /* RFC 4884 (partial) support :
677 * insert 0 padding at the end, before the extensions
678 */
679 __skb_push(skb2, nhs);
680 skb_reset_network_header(skb2);
681 memmove(skb2->data, skb2->data + nhs, data_len - nhs);
682 memset(skb2->data + data_len - nhs, 0, nhs);
683 /* RFC 4884 4.5 : Length is measured in 64-bit words,
684 * and stored in reserved[0]
685 */
686 info = (data_len/8) << 24;
687 }
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700688 if (type == ICMP_TIME_EXCEEDED)
689 icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
Eric Dumazet20e19542016-06-18 21:52:06 -0700690 info, &temp_saddr);
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700691 else
692 icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH,
Eric Dumazet20e19542016-06-18 21:52:06 -0700693 info, &temp_saddr);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700694 if (rt)
695 ip6_rt_put(rt);
696
697 kfree_skb(skb2);
698
699 return 0;
700}
701EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703static void icmpv6_echo_reply(struct sk_buff *skb)
704{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900705 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700706 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700708 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000709 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300710 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500712 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 struct icmpv6_msg msg;
714 struct dst_entry *dst;
Wei Wang26879da2016-05-02 21:40:07 -0700715 struct ipcm6_cookie ipc6;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700716 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400717 bool acast;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -0400719 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) &&
720 net->ipv6.sysctl.icmpv6_echo_ignore_multicast)
721 return;
722
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700723 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400725 acast = ipv6_anycast_destination(skb_dst(skb), saddr);
726 if (acast && net->ipv6.sysctl.icmpv6_echo_ignore_anycast)
727 return;
728
FX Le Bail509aba32014-01-07 14:57:27 +0100729 if (!ipv6_unicast_destination(skb) &&
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400730 !(net->ipv6.sysctl.anycast_src_echo_reply && acast))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 saddr = NULL;
732
733 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
734 tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
735
David S. Miller4c9483b2011-03-12 16:22:43 -0500736 memset(&fl6, 0, sizeof(fl6));
Eric Dumazeta346abe2019-07-01 06:39:36 -0700737 if (net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES)
738 fl6.flowlabel = ip6_flowlabel(ipv6_hdr(skb));
739
David S. Miller4c9483b2011-03-12 16:22:43 -0500740 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000741 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000743 fl6.saddr = *saddr;
David Ahern1b70d7922017-08-28 13:53:34 -0700744 fl6.flowi6_oif = icmp6_iif(skb);
David S. Miller1958b852011-03-12 16:36:19 -0500745 fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700746 fl6.flowi6_mark = mark;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900747 fl6.flowi6_uid = sock_net_uid(net, NULL);
David S. Miller4c9483b2011-03-12 16:22:43 -0500748 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100750 local_bh_disable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700751 sk = icmpv6_xmit_lock(net);
Ian Morris63159f22015-03-29 14:00:04 +0100752 if (!sk)
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100753 goto out_bh_enable;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700754 sk->sk_mark = mark;
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));
Wei Wang26879da2016-05-02 21:40:07 -0700782
Joe Perches4e64b1e2017-10-05 23:46:14 -0700783 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
784 skb->len + sizeof(struct icmp6hdr),
785 sizeof(struct icmp6hdr), &ipc6, &fl6,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400786 (struct rt6_info *)dst, MSG_DONTWAIT)) {
Eric Dumazeta16292a2016-04-27 16:44:36 -0700787 __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000789 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700790 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
791 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400793out_dst_release:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900795out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800796 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100797out_bh_enable:
798 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799}
800
David S. Millerb94f1c02012-07-12 00:33:37 -0700801void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000803 const struct inet6_protocol *ipprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 int inner_offset;
Jesse Gross75f28112011-11-30 17:05:51 -0800805 __be16 frag_off;
David S. Millerf9242b62012-06-19 18:56:21 -0700806 u8 nexthdr;
Duan Jiong7304fe42014-07-31 17:54:32 +0800807 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
809 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
Duan Jiong7304fe42014-07-31 17:54:32 +0800810 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
813 if (ipv6_ext_hdr(nexthdr)) {
814 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800815 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
816 &nexthdr, &frag_off);
Ian Morris67ba4152014-08-24 21:53:10 +0100817 if (inner_offset < 0)
Duan Jiong7304fe42014-07-31 17:54:32 +0800818 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 } else {
820 inner_offset = sizeof(struct ipv6hdr);
821 }
822
823 /* Checkin header including 8 bytes of inner protocol header. */
824 if (!pskb_may_pull(skb, inner_offset+8))
Duan Jiong7304fe42014-07-31 17:54:32 +0800825 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
828 Without this we will not able f.e. to make source routed
829 pmtu discovery.
830 Corresponding argument (opt) to notifiers is already added.
831 --ANK (980726)
832 */
833
David S. Millerf9242b62012-06-19 18:56:21 -0700834 ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 if (ipprot && ipprot->err_handler)
836 ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800838 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Duan Jiong7304fe42014-07-31 17:54:32 +0800839 return;
840
841out:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700842 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845/*
846 * Handle icmp messages
847 */
848
Herbert Xue5bbef22007-10-15 12:50:28 -0700849static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850{
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200851 struct net *net = dev_net(skb->dev);
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400852 struct net_device *dev = icmp6_dev(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000854 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700856 u8 type;
Rick Jonese3e32172014-11-17 14:04:29 -0800857 bool success = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Herbert Xuaebcf822007-12-12 18:54:16 -0800859 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700860 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800861 int nh;
862
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700863 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Herbert Xuaebcf822007-12-12 18:54:16 -0800864 XFRM_STATE_ICMP))
865 goto drop_no_count;
866
David S. Miller81aded22012-06-15 14:54:11 -0700867 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800868 goto drop_no_count;
869
870 nh = skb_network_offset(skb);
871 skb_set_network_header(skb, sizeof(*hdr));
872
873 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
874 goto drop_no_count;
875
876 skb_set_network_header(skb, nh);
877 }
878
Eric Dumazeta16292a2016-04-27 16:44:36 -0700879 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700881 saddr = &ipv6_hdr(skb)->saddr;
882 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
Tom Herbert39471ac2014-05-07 16:52:29 -0700884 if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800885 net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
886 saddr, daddr);
Tom Herbert39471ac2014-05-07 16:52:29 -0700887 goto csum_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 }
889
Herbert Xu8cf22942008-02-05 03:15:50 -0800890 if (!pskb_pull(skb, sizeof(*hdr)))
891 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300893 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 type = hdr->icmp6_type;
896
Eric Dumazetf3832ed2016-04-27 16:44:42 -0700897 ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
899 switch (type) {
900 case ICMPV6_ECHO_REQUEST:
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200901 if (!net->ipv6.sysctl.icmpv6_echo_ignore_all)
902 icmpv6_echo_reply(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 break;
904
905 case ICMPV6_ECHO_REPLY:
Rick Jonese3e32172014-11-17 14:04:29 -0800906 success = ping_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 break;
908
909 case ICMPV6_PKT_TOOBIG:
910 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
911 standard destination cache. Seems, only "advanced"
912 destination cache will allow to solve this problem
913 --ANK (980726)
914 */
915 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
916 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300917 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -0500919 /* to notify */
Joe Perchesa8eceea2020-03-12 15:50:22 -0700920 fallthrough;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 case ICMPV6_DEST_UNREACH:
922 case ICMPV6_TIME_EXCEED:
923 case ICMPV6_PARAMPROB:
924 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
925 break;
926
927 case NDISC_ROUTER_SOLICITATION:
928 case NDISC_ROUTER_ADVERTISEMENT:
929 case NDISC_NEIGHBOUR_SOLICITATION:
930 case NDISC_NEIGHBOUR_ADVERTISEMENT:
931 case NDISC_REDIRECT:
932 ndisc_rcv(skb);
933 break;
934
935 case ICMPV6_MGM_QUERY:
936 igmp6_event_query(skb);
937 break;
938
939 case ICMPV6_MGM_REPORT:
940 igmp6_event_report(skb);
941 break;
942
943 case ICMPV6_MGM_REDUCTION:
944 case ICMPV6_NI_QUERY:
945 case ICMPV6_NI_REPLY:
946 case ICMPV6_MLD2_REPORT:
947 case ICMPV6_DHAAD_REQUEST:
948 case ICMPV6_DHAAD_REPLY:
949 case ICMPV6_MOBILE_PREFIX_SOL:
950 case ICMPV6_MOBILE_PREFIX_ADV:
951 break;
952
953 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 /* informational */
955 if (type & ICMPV6_INFOMSG_MASK)
956 break;
957
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200958 net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
959 saddr, daddr);
David S. Millerea85a0a2014-10-07 16:33:53 -0400960
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900961 /*
962 * error of unknown type.
963 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 */
965
966 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700967 }
968
Rick Jonese3e32172014-11-17 14:04:29 -0800969 /* until the v6 path can be better sorted assume failure and
970 * preserve the status quo behaviour for the rest of the paths to here
971 */
972 if (success)
973 consume_skb(skb);
974 else
975 kfree_skb(skb);
976
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 return 0;
978
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +0000979csum_error:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700980 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981discard_it:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700982 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800983drop_no_count:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 kfree_skb(skb);
985 return 0;
986}
987
David S. Miller4c9483b2011-03-12 16:22:43 -0500988void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800989 u8 type,
990 const struct in6_addr *saddr,
991 const struct in6_addr *daddr,
992 int oif)
993{
David S. Miller4c9483b2011-03-12 16:22:43 -0500994 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000995 fl6->saddr = *saddr;
996 fl6->daddr = *daddr;
Ian Morris67ba4152014-08-24 21:53:10 +0100997 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -0500998 fl6->fl6_icmp_type = type;
999 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -05001000 fl6->flowi6_oif = oif;
1001 security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001002}
1003
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001004static void __net_exit icmpv6_sk_exit(struct net *net)
1005{
1006 int i;
1007
1008 for_each_possible_cpu(i)
Kefeng Wang75efc252019-02-23 15:28:28 +08001009 inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv6.icmp_sk, i));
1010 free_percpu(net->ipv6.icmp_sk);
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001011}
1012
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001013static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014{
1015 struct sock *sk;
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001016 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Kefeng Wang75efc252019-02-23 15:28:28 +08001018 net->ipv6.icmp_sk = alloc_percpu(struct sock *);
Ian Morris63159f22015-03-29 14:00:04 +01001019 if (!net->ipv6.icmp_sk)
Denis V. Lunev79c91152008-02-29 11:17:11 -08001020 return -ENOMEM;
1021
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001022 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001023 err = inet_ctl_sock_create(&sk, PF_INET6,
1024 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 if (err < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001026 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 err);
1028 goto fail;
1029 }
1030
Kefeng Wang75efc252019-02-23 15:28:28 +08001031 *per_cpu_ptr(net->ipv6.icmp_sk, i) = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -08001032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 /* Enough space for 2 64K ICMP packets, including
1034 * sk_buff struct overhead.
1035 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +00001036 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return 0;
1039
1040 fail:
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001041 icmpv6_sk_exit(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 return err;
1043}
1044
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001045static struct pernet_operations icmpv6_sk_ops = {
Ian Morris67ba4152014-08-24 21:53:10 +01001046 .init = icmpv6_sk_init,
1047 .exit = icmpv6_sk_exit,
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001048};
1049
1050int __init icmpv6_init(void)
1051{
1052 int err;
1053
1054 err = register_pernet_subsys(&icmpv6_sk_ops);
1055 if (err < 0)
1056 return err;
1057
1058 err = -EAGAIN;
1059 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
1060 goto fail;
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001061
1062 err = inet6_register_icmp_sender(icmp6_send);
1063 if (err)
1064 goto sender_reg_err;
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001065 return 0;
1066
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001067sender_reg_err:
1068 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001069fail:
Joe Perchesf3213832012-05-15 14:11:53 +00001070 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001071 unregister_pernet_subsys(&icmpv6_sk_ops);
1072 return err;
1073}
1074
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001075void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001076{
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001077 inet6_unregister_icmp_sender(icmp6_send);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001078 unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
1080}
1081
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001082
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -08001083static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 int err;
1085 int fatal;
1086} tab_unreach[] = {
1087 { /* NOROUTE */
1088 .err = ENETUNREACH,
1089 .fatal = 0,
1090 },
1091 { /* ADM_PROHIBITED */
1092 .err = EACCES,
1093 .fatal = 1,
1094 },
1095 { /* Was NOT_NEIGHBOUR, now reserved */
1096 .err = EHOSTUNREACH,
1097 .fatal = 0,
1098 },
1099 { /* ADDR_UNREACH */
1100 .err = EHOSTUNREACH,
1101 .fatal = 0,
1102 },
1103 { /* PORT_UNREACH */
1104 .err = ECONNREFUSED,
1105 .fatal = 1,
1106 },
Jiri Bohac61e76b12013-08-30 11:18:45 +02001107 { /* POLICY_FAIL */
1108 .err = EACCES,
1109 .fatal = 1,
1110 },
1111 { /* REJECT_ROUTE */
1112 .err = EACCES,
1113 .fatal = 1,
1114 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115};
1116
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07001117int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118{
1119 int fatal = 0;
1120
1121 *err = EPROTO;
1122
1123 switch (type) {
1124 case ICMPV6_DEST_UNREACH:
1125 fatal = 1;
Jiri Bohac61e76b12013-08-30 11:18:45 +02001126 if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 *err = tab_unreach[code].err;
1128 fatal = tab_unreach[code].fatal;
1129 }
1130 break;
1131
1132 case ICMPV6_PKT_TOOBIG:
1133 *err = EMSGSIZE;
1134 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 case ICMPV6_PARAMPROB:
1137 *err = EPROTO;
1138 fatal = 1;
1139 break;
1140
1141 case ICMPV6_TIME_EXCEED:
1142 *err = EHOSTUNREACH;
1143 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
1146 return fatal;
1147}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001148EXPORT_SYMBOL(icmpv6_err_convert);
1149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150#ifdef CONFIG_SYSCTL
stephen hemmingere8243532013-12-29 14:03:31 -08001151static struct ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -08001154 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 .maxlen = sizeof(int),
1156 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08001157 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 },
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001159 {
1160 .procname = "echo_ignore_all",
1161 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_all,
1162 .maxlen = sizeof(int),
1163 .mode = 0644,
1164 .proc_handler = proc_dointvec,
1165 },
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001166 {
1167 .procname = "echo_ignore_multicast",
1168 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_multicast,
1169 .maxlen = sizeof(int),
1170 .mode = 0644,
1171 .proc_handler = proc_dointvec,
1172 },
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001173 {
1174 .procname = "echo_ignore_anycast",
1175 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_anycast,
1176 .maxlen = sizeof(int),
1177 .mode = 0644,
1178 .proc_handler = proc_dointvec,
1179 },
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001180 {
1181 .procname = "ratemask",
1182 .data = &init_net.ipv6.sysctl.icmpv6_ratemask_ptr,
1183 .maxlen = ICMPV6_MSG_MAX + 1,
1184 .mode = 0644,
1185 .proc_handler = proc_do_large_bitmap,
1186 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001187 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188};
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001189
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001190struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001191{
1192 struct ctl_table *table;
1193
1194 table = kmemdup(ipv6_icmp_table_template,
1195 sizeof(ipv6_icmp_table_template),
1196 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001197
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001198 if (table) {
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001199 table[0].data = &net->ipv6.sysctl.icmpv6_time;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001200 table[1].data = &net->ipv6.sysctl.icmpv6_echo_ignore_all;
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001201 table[2].data = &net->ipv6.sysctl.icmpv6_echo_ignore_multicast;
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001202 table[3].data = &net->ipv6.sysctl.icmpv6_echo_ignore_anycast;
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001203 table[4].data = &net->ipv6.sysctl.icmpv6_ratemask_ptr;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001204 }
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001205 return table;
1206}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207#endif