blob: 1635da07285f263509a68624369a2746f3deb076 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * Internet Control Message Protocol (ICMPv6)
4 * Linux INET6 implementation
5 *
6 * Authors:
7 * Pedro Roque <roque@di.fc.ul.pt>
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Based on net/ipv4/icmp.c
10 *
11 * RFC 1885
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
13
14/*
15 * Changes:
16 *
17 * Andi Kleen : exception handling
18 * Andi Kleen add rate limits. never reply to a icmp.
19 * add more length checks and other fixes.
20 * yoshfuji : ensure to sent parameter problem for
21 * fragments.
22 * YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit.
23 * Randy Dunlap and
24 * YOSHIFUJI Hideaki @USAGI: Per-interface statistics support
25 * Kazunori MIYAZAWA @USAGI: change output process to use ip6_append_data
26 */
27
Joe Perchesf3213832012-05-15 14:11:53 +000028#define pr_fmt(fmt) "IPv6: " fmt
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31#include <linux/errno.h>
32#include <linux/types.h>
33#include <linux/socket.h>
34#include <linux/in.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sockios.h>
37#include <linux/net.h>
38#include <linux/skbuff.h>
39#include <linux/init.h>
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -080040#include <linux/netfilter.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090041#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#ifdef CONFIG_SYSCTL
44#include <linux/sysctl.h>
45#endif
46
47#include <linux/inet.h>
48#include <linux/netdevice.h>
49#include <linux/icmpv6.h>
50
51#include <net/ip.h>
52#include <net/sock.h>
53
54#include <net/ipv6.h>
55#include <net/ip6_checksum.h>
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000056#include <net/ping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <net/protocol.h>
58#include <net/raw.h>
59#include <net/rawv6.h>
Andrew Lunne4129442022-01-03 18:11:31 +010060#include <net/seg6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <net/transp_v6.h>
62#include <net/ip6_route.h>
63#include <net/addrconf.h>
64#include <net/icmp.h>
Herbert Xu8b7817f2007-12-12 10:44:43 -080065#include <net/xfrm.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070066#include <net/inet_common.h>
Hannes Frederic Sowa825edac2014-01-11 11:55:46 +010067#include <net/dsfield.h>
David Ahernca254492015-10-12 11:47:10 -070068#include <net/l3mdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080070#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Eric Dumazet6a17b962022-01-24 12:24:56 -080072static DEFINE_PER_CPU(struct sock *, ipv6_icmp_sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
Stefano Brivio32bbd872018-11-08 12:19:21 +010074static int icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Steffen Klassert6f809da2013-01-16 22:09:49 +000075 u8 type, u8 code, int offset, __be32 info)
76{
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000077 /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
78 struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
Steffen Klassert6f809da2013-01-16 22:09:49 +000079 struct net *net = dev_net(skb->dev);
80
81 if (type == ICMPV6_PKT_TOOBIG)
Georg Kohmann5f379ef2018-08-02 13:56:58 +020082 ip6_update_pmtu(skb, net, info, skb->dev->ifindex, 0, sock_net_uid(net, NULL));
Steffen Klassert6f809da2013-01-16 22:09:49 +000083 else if (type == NDISC_REDIRECT)
Lorenzo Colittie2d118a2016-11-04 02:23:43 +090084 ip6_redirect(skb, net, skb->dev->ifindex, 0,
85 sock_net_uid(net, NULL));
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000086
87 if (!(type & ICMPV6_INFOMSG_MASK))
88 if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
Hannes Frederic Sowadcb94b82016-06-11 20:32:06 +020089 ping_err(skb, offset, ntohl(info));
Stefano Brivio32bbd872018-11-08 12:19:21 +010090
91 return 0;
Steffen Klassert6f809da2013-01-16 22:09:49 +000092}
93
Herbert Xue5bbef22007-10-15 12:50:28 -070094static int icmpv6_rcv(struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Alexey Dobriyan41135cc2009-09-14 12:22:28 +000096static const struct inet6_protocol icmpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 .handler = icmpv6_rcv,
Steffen Klassert6f809da2013-01-16 22:09:49 +000098 .err_handler = icmpv6_err,
Herbert Xu8b7817f2007-12-12 10:44:43 -080099 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100};
101
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100102/* Called with BH disabled */
Eric Dumazet6a17b962022-01-24 12:24:56 -0800103static struct sock *icmpv6_xmit_lock(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700105 struct sock *sk;
106
Eric Dumazet6a17b962022-01-24 12:24:56 -0800107 sk = this_cpu_read(ipv6_icmp_sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800108 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 /* This can happen if the output path (f.e. SIT or
110 * ip6ip6 tunnel) signals dst_link_failure() for an
111 * outgoing ICMP6 packet.
112 */
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700113 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 }
Eric Dumazet6a17b962022-01-24 12:24:56 -0800115 sock_net_set(sk, net);
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700116 return sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117}
118
Eric Dumazet6a17b962022-01-24 12:24:56 -0800119static void icmpv6_xmit_unlock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120{
Eric Dumazet6a17b962022-01-24 12:24:56 -0800121 sock_net_set(sk, &init_net);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100122 spin_unlock(&sk->sk_lock.slock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123}
124
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900125/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 * Figure out, may we reply to this packet with icmp error.
127 *
128 * We do not reply, if:
129 * - it was icmp error message.
130 * - it is truncated, so that it is known, that protocol is ICMPV6
131 * (i.e. in the middle of some exthdr)
132 *
133 * --ANK (980726)
134 */
135
Eric Dumazeta50feda2012-05-18 18:57:34 +0000136static bool is_ineligible(const struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700138 int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 int len = skb->len - ptr;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700140 __u8 nexthdr = ipv6_hdr(skb)->nexthdr;
Jesse Gross75f28112011-11-30 17:05:51 -0800141 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 if (len < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000144 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Jesse Gross75f28112011-11-30 17:05:51 -0800146 ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 if (ptr < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000148 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 if (nexthdr == IPPROTO_ICMPV6) {
150 u8 _type, *tp;
151 tp = skb_header_pointer(skb,
152 ptr+offsetof(struct icmp6hdr, icmp6_type),
153 sizeof(_type), &_type);
Hangbin Liu2efdaaa2020-10-27 20:33:13 +0800154
155 /* Based on RFC 8200, Section 4.5 Fragment Header, return
156 * false if this is a fragment packet with no icmp header info.
157 */
158 if (!tp && frag_off != 0)
159 return false;
160 else if (!tp || !(*tp & ICMPV6_INFOMSG_MASK))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000161 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000163 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
165
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400166static bool icmpv6_mask_allow(struct net *net, int type)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100167{
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400168 if (type > ICMPV6_MSG_MAX)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100169 return true;
170
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400171 /* Limit if icmp type is set in ratemask. */
172 if (!test_bit(type, net->ipv6.sysctl.icmpv6_ratemask))
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100173 return true;
174
175 return false;
176}
177
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400178static bool icmpv6_global_allow(struct net *net, int type)
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100179{
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400180 if (icmpv6_mask_allow(net, type))
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100181 return true;
182
183 if (icmp_global_allow())
184 return true;
185
Jamie Bainbridged0941132023-01-25 11:16:52 +1100186 __ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100187 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 }
Jamie Bainbridged0941132023-01-25 11:16:52 +1100228 if (!res)
229 __ICMP6_INC_STATS(net, ip6_dst_idev(dst),
230 ICMP6_MIB_RATELIMITHOST);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 dst_release(dst);
232 return res;
233}
234
Tim Stallardb93cfb92020-04-03 21:22:57 +0100235static bool icmpv6_rt_has_prefsrc(struct sock *sk, u8 type,
236 struct flowi6 *fl6)
237{
238 struct net *net = sock_net(sk);
239 struct dst_entry *dst;
240 bool res = false;
241
242 dst = ip6_route_output(net, sk, fl6);
243 if (!dst->error) {
244 struct rt6_info *rt = (struct rt6_info *)dst;
245 struct in6_addr prefsrc;
246
247 rt6_get_prefsrc(rt, &prefsrc);
248 res = !ipv6_addr_any(&prefsrc);
249 }
250 dst_release(dst);
251 return res;
252}
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254/*
255 * an inline helper for the "simple" if statement below
256 * checks if parameter problem report is caused by an
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900257 * unrecognized IPv6 option that has the Option Type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 * highest-order two bits set to 10
259 */
260
Eric Dumazeta50feda2012-05-18 18:57:34 +0000261static bool opt_unrec(struct sk_buff *skb, __u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262{
263 u8 _optval, *op;
264
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300265 offset += skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
Ian Morris63159f22015-03-29 14:00:04 +0100267 if (!op)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000268 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 return (*op & 0xC0) == 0x80;
270}
271
Joe Perches4e64b1e2017-10-05 23:46:14 -0700272void icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
273 struct icmp6hdr *thdr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
275 struct sk_buff *skb;
276 struct icmp6hdr *icmp6h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Ian Morrise5d08d72014-11-23 21:28:43 +0000278 skb = skb_peek(&sk->sk_write_queue);
Ian Morris63159f22015-03-29 14:00:04 +0100279 if (!skb)
Joe Perches4e64b1e2017-10-05 23:46:14 -0700280 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300282 icmp6h = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
284 icmp6h->icmp6_cksum = 0;
285
286 if (skb_queue_len(&sk->sk_write_queue) == 1) {
Joe Perches07f07572008-11-19 15:44:53 -0800287 skb->csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 sizeof(struct icmp6hdr), skb->csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500289 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
290 &fl6->daddr,
291 len, fl6->flowi6_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 skb->csum);
293 } else {
Al Viro868c86b2006-11-14 21:35:48 -0800294 __wsum tmp_csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296 skb_queue_walk(&sk->sk_write_queue, skb) {
297 tmp_csum = csum_add(tmp_csum, skb->csum);
298 }
299
Joe Perches07f07572008-11-19 15:44:53 -0800300 tmp_csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 sizeof(struct icmp6hdr), tmp_csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500302 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
303 &fl6->daddr,
304 len, fl6->flowi6_proto,
Al Viro868c86b2006-11-14 21:35:48 -0800305 tmp_csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 ip6_push_pending_frames(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308}
309
310struct icmpv6_msg {
311 struct sk_buff *skb;
312 int offset;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800313 uint8_t type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314};
315
316static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
317{
318 struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
319 struct sk_buff *org_skb = msg->skb;
Al Viro8d5930d2020-07-10 20:07:10 -0400320 __wsum csum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
Al Viro8d5930d2020-07-10 20:07:10 -0400323 to, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 skb->csum = csum_block_add(skb->csum, csum, odd);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800325 if (!(msg->type & ICMPV6_INFOMSG_MASK))
326 nf_ct_attach(skb, org_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 return 0;
328}
329
Amerigo Wang07a93622012-10-29 16:23:10 +0000330#if IS_ENABLED(CONFIG_IPV6_MIP6)
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100331static void mip6_addr_swap(struct sk_buff *skb, const struct inet6_skb_parm *opt)
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700332{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700333 struct ipv6hdr *iph = ipv6_hdr(skb);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700334 struct ipv6_destopt_hao *hao;
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700335 int off;
336
337 if (opt->dsthao) {
338 off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
339 if (likely(off >= 0)) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700340 hao = (struct ipv6_destopt_hao *)
341 (skb_network_header(skb) + off);
Jiapeng Chongbc617612023-01-31 14:34:56 +0800342 swap(iph->saddr, hao->addr);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700343 }
344 }
345}
346#else
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100347static inline void mip6_addr_swap(struct sk_buff *skb, const struct inet6_skb_parm *opt) {}
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700348#endif
349
stephen hemmingere8243532013-12-29 14:03:31 -0800350static struct dst_entry *icmpv6_route_lookup(struct net *net,
351 struct sk_buff *skb,
352 struct sock *sk,
353 struct flowi6 *fl6)
David S. Millerb42835d2011-03-01 22:06:22 -0800354{
355 struct dst_entry *dst, *dst2;
David S. Miller4c9483b2011-03-12 16:22:43 -0500356 struct flowi6 fl2;
David S. Millerb42835d2011-03-01 22:06:22 -0800357 int err;
358
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700359 err = ip6_dst_lookup(net, sk, &dst, fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800360 if (err)
361 return ERR_PTR(err);
362
363 /*
364 * We won't send icmp if the destination is known
Mahesh Bandewar7ab75452023-04-18 18:32:38 -0700365 * anycast unless we need to treat anycast as unicast.
David S. Millerb42835d2011-03-01 22:06:22 -0800366 */
Mahesh Bandewar7ab75452023-04-18 18:32:38 -0700367 if (!READ_ONCE(net->ipv6.sysctl.icmpv6_error_anycast_as_unicast) &&
368 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
Florian Westphal2b1dc622023-10-04 18:09:51 +0200388 err = xfrm_decode_session_reverse(net, 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
Kuniyuki Iwashima2aaa8a12023-07-07 18:43:27 -0700427 /* The destination could be an external IP in Ext Hdr (SRv6, RPL, etc.),
428 * and ip6_null_entry could be set to skb if no route is found.
429 */
430 if (rt6 && rt6->rt6i_idev)
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400431 dev = rt6->rt6i_idev->dev;
David Ahern1b70d7922017-08-28 13:53:34 -0700432 }
433
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400434 return dev;
435}
436
437static int icmp6_iif(const struct sk_buff *skb)
438{
439 return icmp6_dev(skb)->ifindex;
David Ahern1b70d7922017-08-28 13:53:34 -0700440}
441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442/*
443 * Send an ICMP message in response to a packet in error
444 */
Eric Dumazetcc7a21b2020-06-19 12:02:59 -0700445void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100446 const struct in6_addr *force_saddr,
447 const struct inet6_skb_parm *parm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 struct inet6_dev *idev = NULL;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700450 struct ipv6hdr *hdr = ipv6_hdr(skb);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700451 struct sock *sk;
Eric Dumazet8d933672019-01-04 11:00:00 -0800452 struct net *net;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700453 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000454 const struct in6_addr *saddr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 struct dst_entry *dst;
456 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500457 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 struct icmpv6_msg msg;
Wei Wang26879da2016-05-02 21:40:07 -0700459 struct ipcm6_cookie ipc6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 int iif = 0;
461 int addr_type = 0;
462 int len;
Eric Dumazet8d933672019-01-04 11:00:00 -0800463 u32 mark;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700465 if ((u8 *)hdr < skb->head ||
Simon Horman29a3cad2013-05-28 20:34:26 +0000466 (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 return;
468
Eric Dumazet8d933672019-01-04 11:00:00 -0800469 if (!skb->dev)
470 return;
471 net = dev_net(skb->dev);
472 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900474 * Make sure we respect the rules
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 * i.e. RFC 1885 2.4(e)
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000476 * Rule (e.1) is enforced by not using icmp6_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 * in any code that processes icmp errors.
478 */
479 addr_type = ipv6_addr_type(&hdr->daddr);
480
FX Le Bail446fab52014-01-19 17:00:36 +0100481 if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) ||
FX Le Baild94c1f92014-02-07 11:22:37 +0100482 ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 saddr = &hdr->daddr;
484
485 /*
486 * Dest addr check
487 */
488
zhuyj9a6b4b32015-01-14 17:23:59 +0800489 if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (type != ICMPV6_PKT_TOOBIG &&
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900491 !(type == ICMPV6_PARAMPROB &&
492 code == ICMPV6_UNK_OPTION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 (opt_unrec(skb, info))))
494 return;
495
496 saddr = NULL;
497 }
498
499 addr_type = ipv6_addr_type(&hdr->saddr);
500
501 /*
502 * Source addr check
503 */
504
David Ahern4832c302017-08-17 12:17:20 -0700505 if (__ipv6_addr_needs_scope_id(addr_type)) {
David Ahern1b70d7922017-08-28 13:53:34 -0700506 iif = icmp6_iif(skb);
David Ahern4832c302017-08-17 12:17:20 -0700507 } else {
Mathieu Desnoyers272928d2020-10-12 10:50:15 -0400508 /*
509 * The source device is used for looking up which routing table
510 * to use for sending an ICMP error.
511 */
512 iif = l3mdev_master_ifindex(skb->dev);
David Ahern79dc7e32016-11-27 18:52:53 -0800513 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515 /*
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900516 * Must not send error if the source does not uniquely
517 * identify a single node (RFC2463 Section 2.4).
518 * We check unspecified / multicast addresses here,
519 * and anycast addresses will be checked later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 */
521 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200522 net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n",
523 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return;
525 }
526
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900527 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 * Never answer to a ICMP packet.
529 */
530 if (is_ineligible(skb)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200531 net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n",
532 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 return;
534 }
535
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100536 /* Needed by both icmp_global_allow and icmpv6_xmit_lock */
537 local_bh_disable();
538
539 /* Check global sysctl_icmp_msgs_per_sec ratelimit */
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400540 if (!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, type))
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100541 goto out_bh_enable;
542
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100543 mip6_addr_swap(skb, parm);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700544
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700545 sk = icmpv6_xmit_lock(net);
546 if (!sk)
547 goto out_bh_enable;
548
David S. Miller4c9483b2011-03-12 16:22:43 -0500549 memset(&fl6, 0, sizeof(fl6));
550 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000551 fl6.daddr = hdr->saddr;
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700552 if (force_saddr)
553 saddr = force_saddr;
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700554 if (saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000555 fl6.saddr = *saddr;
Tim Stallardb93cfb92020-04-03 21:22:57 +0100556 } else if (!icmpv6_rt_has_prefsrc(sk, type, &fl6)) {
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700557 /* select a more meaningful saddr from input if */
558 struct net_device *in_netdev;
559
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100560 in_netdev = dev_get_by_index(net, parm->iif);
Francesco Ruggerifac6fce2019-10-30 17:40:02 -0700561 if (in_netdev) {
562 ipv6_dev_get_saddr(net, in_netdev, &fl6.daddr,
563 inet6_sk(sk)->srcprefs,
564 &fl6.saddr);
565 dev_put(in_netdev);
566 }
567 }
Lorenzo Colittie1108612014-05-13 10:17:33 -0700568 fl6.flowi6_mark = mark;
David S. Miller4c9483b2011-03-12 16:22:43 -0500569 fl6.flowi6_oif = iif;
David S. Miller1958b852011-03-12 16:36:19 -0500570 fl6.fl6_icmp_type = type;
571 fl6.fl6_icmp_code = code;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900572 fl6.flowi6_uid = sock_net_uid(net, NULL);
David Ahernb4bac172018-03-02 08:32:18 -0800573 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, NULL);
Paul Moore3df98d72020-09-27 22:38:26 -0400574 security_skb_classify_flow(skb, flowi6_to_flowi_common(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700576 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800577
David S. Miller4c9483b2011-03-12 16:22:43 -0500578 if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 goto out;
580
581 tmp_hdr.icmp6_type = type;
582 tmp_hdr.icmp6_code = code;
583 tmp_hdr.icmp6_cksum = 0;
584 tmp_hdr.icmp6_pointer = htonl(info);
585
David S. Miller4c9483b2011-03-12 16:22:43 -0500586 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
Eric Dumazetd2f011a2023-12-08 10:12:43 +0000587 fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000588 else if (!fl6.flowi6_oif)
Eric Dumazet1ac13ef2023-12-08 10:12:44 +0000589 fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Eric Dumazet1086ca72023-09-12 16:02:07 +0000591 ipcm6_init_sk(&ipc6, sk);
Willem de Bruijn0da75362020-07-01 16:00:06 -0400592 ipc6.sockc.mark = mark;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +0200593 fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
594
David S. Miller4c9483b2011-03-12 16:22:43 -0500595 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800596 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 goto out;
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900598
Wei Wang26879da2016-05-02 21:40:07 -0700599 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
601 msg.skb = skb;
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300602 msg.offset = skb_network_offset(skb);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800603 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605 len = skb->len - msg.offset;
Ian Morris67ba4152014-08-24 21:53:10 +0100606 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 if (len < 0) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200608 net_dbg_ratelimited("icmp: len problem [%pI6c > %pI6c]\n",
609 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 goto out_dst_release;
611 }
612
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000613 rcu_read_lock();
614 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Joe Perches4e64b1e2017-10-05 23:46:14 -0700616 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
617 len + sizeof(struct icmp6hdr),
618 sizeof(struct icmp6hdr),
619 &ipc6, &fl6, (struct rt6_info *)dst,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400620 MSG_DONTWAIT)) {
Hannes Frederic Sowa43a43b62014-03-31 20:14:10 +0200621 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000623 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700624 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
625 len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000627 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628out_dst_release:
629 dst_release(dst);
630out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800631 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100632out_bh_enable:
633 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
Eric Dumazetcc7a21b2020-06-19 12:02:59 -0700635EXPORT_SYMBOL(icmp6_send);
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000636
Menglong Dong1ad6d542022-04-13 16:15:56 +0800637/* Slightly more convenient version of icmp6_send with drop reasons.
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000638 */
Menglong Dong1ad6d542022-04-13 16:15:56 +0800639void icmpv6_param_prob_reason(struct sk_buff *skb, u8 code, int pos,
640 enum skb_drop_reason reason)
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000641{
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100642 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL, IP6CB(skb));
Menglong Dong1ad6d542022-04-13 16:15:56 +0800643 kfree_skb_reason(skb, reason);
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000644}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900645
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700646/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
647 * if sufficient data bytes are available
648 * @nhs is the size of the tunnel header(s) :
649 * Either an IPv4 header for SIT encap
650 * an IPv4 header + GRE header for GRE encap
651 */
Eric Dumazet20e19542016-06-18 21:52:06 -0700652int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
653 unsigned int data_len)
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700654{
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700655 struct in6_addr temp_saddr;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700656 struct rt6_info *rt;
657 struct sk_buff *skb2;
Eric Dumazet20e19542016-06-18 21:52:06 -0700658 u32 info = 0;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700659
660 if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8))
661 return 1;
662
Eric Dumazet20e19542016-06-18 21:52:06 -0700663 /* RFC 4884 (partial) support for ICMP extensions */
664 if (data_len < 128 || (data_len & 7) || skb->len < data_len)
665 data_len = 0;
666
667 skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700668
669 if (!skb2)
670 return 1;
671
672 skb_dst_drop(skb2);
673 skb_pull(skb2, nhs);
674 skb_reset_network_header(skb2);
675
David Ahernb75cc8f2018-03-02 08:32:17 -0800676 rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0,
677 skb, 0);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700678
679 if (rt && rt->dst.dev)
680 skb2->dev = rt->dst.dev;
681
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700682 ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr);
Eric Dumazet20e19542016-06-18 21:52:06 -0700683
684 if (data_len) {
685 /* RFC 4884 (partial) support :
686 * insert 0 padding at the end, before the extensions
687 */
688 __skb_push(skb2, nhs);
689 skb_reset_network_header(skb2);
690 memmove(skb2->data, skb2->data + nhs, data_len - nhs);
691 memset(skb2->data + data_len - nhs, 0, nhs);
692 /* RFC 4884 4.5 : Length is measured in 64-bit words,
693 * and stored in reserved[0]
694 */
695 info = (data_len/8) << 24;
696 }
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700697 if (type == ICMP_TIME_EXCEEDED)
698 icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100699 info, &temp_saddr, IP6CB(skb2));
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700700 else
701 icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH,
Jason A. Donenfeldee576c42021-02-23 14:18:58 +0100702 info, &temp_saddr, IP6CB(skb2));
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700703 if (rt)
704 ip6_rt_put(rt);
705
706 kfree_skb(skb2);
707
708 return 0;
709}
710EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
711
Eric Dumazetac036942023-02-16 16:28:42 +0000712static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900714 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700715 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700717 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000718 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300719 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500721 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 struct icmpv6_msg msg;
723 struct dst_entry *dst;
Wei Wang26879da2016-05-02 21:40:07 -0700724 struct ipcm6_cookie ipc6;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700725 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Eric Dumazetac036942023-02-16 16:28:42 +0000726 SKB_DR(reason);
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400727 bool acast;
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500728 u8 type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -0400730 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) &&
731 net->ipv6.sysctl.icmpv6_echo_ignore_multicast)
Eric Dumazetac036942023-02-16 16:28:42 +0000732 return reason;
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -0400733
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700734 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400736 acast = ipv6_anycast_destination(skb_dst(skb), saddr);
737 if (acast && net->ipv6.sysctl.icmpv6_echo_ignore_anycast)
Eric Dumazetac036942023-02-16 16:28:42 +0000738 return reason;
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400739
FX Le Bail509aba32014-01-07 14:57:27 +0100740 if (!ipv6_unicast_destination(skb) &&
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -0400741 !(net->ipv6.sysctl.anycast_src_echo_reply && acast))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 saddr = NULL;
743
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500744 if (icmph->icmp6_type == ICMPV6_EXT_ECHO_REQUEST)
745 type = ICMPV6_EXT_ECHO_REPLY;
746 else
747 type = ICMPV6_ECHO_REPLY;
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500750 tmp_hdr.icmp6_type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
David S. Miller4c9483b2011-03-12 16:22:43 -0500752 memset(&fl6, 0, sizeof(fl6));
Eric Dumazeta346abe2019-07-01 06:39:36 -0700753 if (net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES)
754 fl6.flowlabel = ip6_flowlabel(ipv6_hdr(skb));
755
David S. Miller4c9483b2011-03-12 16:22:43 -0500756 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000757 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000759 fl6.saddr = *saddr;
David Ahern1b70d7922017-08-28 13:53:34 -0700760 fl6.flowi6_oif = icmp6_iif(skb);
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500761 fl6.fl6_icmp_type = type;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700762 fl6.flowi6_mark = mark;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900763 fl6.flowi6_uid = sock_net_uid(net, NULL);
Paul Moore3df98d72020-09-27 22:38:26 -0400764 security_skb_classify_flow(skb, flowi6_to_flowi_common(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100766 local_bh_disable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700767 sk = icmpv6_xmit_lock(net);
Ian Morris63159f22015-03-29 14:00:04 +0100768 if (!sk)
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100769 goto out_bh_enable;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700770 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800771
David S. Miller4c9483b2011-03-12 16:22:43 -0500772 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
Eric Dumazetd2f011a2023-12-08 10:12:43 +0000773 fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000774 else if (!fl6.flowi6_oif)
Eric Dumazet1ac13ef2023-12-08 10:12:44 +0000775 fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Joe Perches4e64b1e2017-10-05 23:46:14 -0700777 if (ip6_dst_lookup(net, sk, &dst, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 goto out;
David S. Miller4c9483b2011-03-12 16:22:43 -0500779 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800780 if (IS_ERR(dst))
Patrick McHardye104411b2005-09-08 15:11:55 -0700781 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400783 /* Check the ratelimit */
784 if ((!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, ICMPV6_ECHO_REPLY)) ||
785 !icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6))
786 goto out_dst_release;
787
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000788 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 msg.skb = skb;
791 msg.offset = 0;
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500792 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Eric Dumazet1086ca72023-09-12 16:02:07 +0000794 ipcm6_init_sk(&ipc6, sk);
Wei Wang26879da2016-05-02 21:40:07 -0700795 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
796 ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
Willem de Bruijn0da75362020-07-01 16:00:06 -0400797 ipc6.sockc.mark = mark;
Wei Wang26879da2016-05-02 21:40:07 -0700798
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500799 if (icmph->icmp6_type == ICMPV6_EXT_ECHO_REQUEST)
800 if (!icmp_build_probe(skb, (struct icmphdr *)&tmp_hdr))
801 goto out_dst_release;
802
Joe Perches4e64b1e2017-10-05 23:46:14 -0700803 if (ip6_append_data(sk, icmpv6_getfrag, &msg,
804 skb->len + sizeof(struct icmp6hdr),
805 sizeof(struct icmp6hdr), &ipc6, &fl6,
Willem de Bruijn5fdaa882018-07-06 10:12:57 -0400806 (struct rt6_info *)dst, MSG_DONTWAIT)) {
Eric Dumazeta16292a2016-04-27 16:44:36 -0700807 __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000809 } else {
Joe Perches4e64b1e2017-10-05 23:46:14 -0700810 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
811 skb->len + sizeof(struct icmp6hdr));
Eric Dumazetac036942023-02-16 16:28:42 +0000812 reason = SKB_CONSUMED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 }
Stephen Suryaputra0bc19982019-04-17 16:35:49 -0400814out_dst_release:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900816out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800817 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100818out_bh_enable:
819 local_bh_enable();
Eric Dumazetac036942023-02-16 16:28:42 +0000820 return reason;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821}
822
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000823enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type,
824 u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825{
Andrew Lunne4129442022-01-03 18:11:31 +0100826 struct inet6_skb_parm *opt = IP6CB(skb);
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000827 struct net *net = dev_net(skb->dev);
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000828 const struct inet6_protocol *ipprot;
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000829 enum skb_drop_reason reason;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 int inner_offset;
Jesse Gross75f28112011-11-30 17:05:51 -0800831 __be16 frag_off;
David S. Millerf9242b62012-06-19 18:56:21 -0700832 u8 nexthdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000834 reason = pskb_may_pull_reason(skb, sizeof(struct ipv6hdr));
835 if (reason != SKB_NOT_DROPPED_YET)
Duan Jiong7304fe42014-07-31 17:54:32 +0800836 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Andrew Lunne4129442022-01-03 18:11:31 +0100838 seg6_icmp_srh(skb, opt);
839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
841 if (ipv6_ext_hdr(nexthdr)) {
842 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800843 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
844 &nexthdr, &frag_off);
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000845 if (inner_offset < 0) {
846 SKB_DR_SET(reason, IPV6_BAD_EXTHDR);
Duan Jiong7304fe42014-07-31 17:54:32 +0800847 goto out;
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 } else {
850 inner_offset = sizeof(struct ipv6hdr);
851 }
852
853 /* Checkin header including 8 bytes of inner protocol header. */
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000854 reason = pskb_may_pull_reason(skb, inner_offset + 8);
855 if (reason != SKB_NOT_DROPPED_YET)
Duan Jiong7304fe42014-07-31 17:54:32 +0800856 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
859 Without this we will not able f.e. to make source routed
860 pmtu discovery.
861 Corresponding argument (opt) to notifiers is already added.
862 --ANK (980726)
863 */
864
David S. Millerf9242b62012-06-19 18:56:21 -0700865 ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 if (ipprot && ipprot->err_handler)
Andrew Lunne4129442022-01-03 18:11:31 +0100867 ipprot->err_handler(skb, opt, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800869 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000870 return SKB_CONSUMED;
Duan Jiong7304fe42014-07-31 17:54:32 +0800871
872out:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700873 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000874 return reason;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877/*
878 * Handle icmp messages
879 */
880
Herbert Xue5bbef22007-10-15 12:50:28 -0700881static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882{
Menglong Dongb384c952022-04-07 14:20:52 +0800883 enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200884 struct net *net = dev_net(skb->dev);
Stephen Suryaputrae1ae5c22019-06-10 10:32:50 -0400885 struct net_device *dev = icmp6_dev(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000887 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700889 u8 type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Herbert Xuaebcf822007-12-12 18:54:16 -0800891 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700892 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800893 int nh;
894
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700895 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Menglong Dongb384c952022-04-07 14:20:52 +0800896 XFRM_STATE_ICMP)) {
897 reason = SKB_DROP_REASON_XFRM_POLICY;
Herbert Xuaebcf822007-12-12 18:54:16 -0800898 goto drop_no_count;
Menglong Dongb384c952022-04-07 14:20:52 +0800899 }
Herbert Xuaebcf822007-12-12 18:54:16 -0800900
David S. Miller81aded22012-06-15 14:54:11 -0700901 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800902 goto drop_no_count;
903
904 nh = skb_network_offset(skb);
905 skb_set_network_header(skb, sizeof(*hdr));
906
Menglong Dongb384c952022-04-07 14:20:52 +0800907 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN,
908 skb)) {
909 reason = SKB_DROP_REASON_XFRM_POLICY;
Herbert Xu8b7817f2007-12-12 10:44:43 -0800910 goto drop_no_count;
Menglong Dongb384c952022-04-07 14:20:52 +0800911 }
Herbert Xu8b7817f2007-12-12 10:44:43 -0800912
913 skb_set_network_header(skb, nh);
914 }
915
Eric Dumazeta16292a2016-04-27 16:44:36 -0700916 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700918 saddr = &ipv6_hdr(skb)->saddr;
919 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Tom Herbert39471ac2014-05-07 16:52:29 -0700921 if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800922 net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
923 saddr, daddr);
Tom Herbert39471ac2014-05-07 16:52:29 -0700924 goto csum_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926
Herbert Xu8cf22942008-02-05 03:15:50 -0800927 if (!pskb_pull(skb, sizeof(*hdr)))
928 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300930 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 type = hdr->icmp6_type;
933
Eric Dumazetf3832ed2016-04-27 16:44:42 -0700934 ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 switch (type) {
937 case ICMPV6_ECHO_REQUEST:
Virgile Jarrye6f86b02018-08-10 17:48:15 +0200938 if (!net->ipv6.sysctl.icmpv6_echo_ignore_all)
Eric Dumazetac036942023-02-16 16:28:42 +0000939 reason = icmpv6_echo_reply(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 break;
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500941 case ICMPV6_EXT_ECHO_REQUEST:
942 if (!net->ipv6.sysctl.icmpv6_echo_ignore_all &&
Kuniyuki Iwashima4a2f7082022-07-11 17:15:23 -0700943 READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe))
Eric Dumazetac036942023-02-16 16:28:42 +0000944 reason = icmpv6_echo_reply(skb);
Andreas Roeseler1fd07f32021-06-26 09:07:46 -0500945 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 case ICMPV6_ECHO_REPLY:
Menglong Dongb384c952022-04-07 14:20:52 +0800948 reason = ping_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 break;
950
Andreas Roeseler31433202021-04-12 16:23:56 -0500951 case ICMPV6_EXT_ECHO_REPLY:
Menglong Dongb384c952022-04-07 14:20:52 +0800952 reason = ping_rcv(skb);
Andreas Roeseler31433202021-04-12 16:23:56 -0500953 break;
954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 case ICMPV6_PKT_TOOBIG:
956 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
957 standard destination cache. Seems, only "advanced"
958 destination cache will allow to solve this problem
959 --ANK (980726)
960 */
961 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
962 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300963 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -0500965 /* to notify */
Joe Perchesa8eceea2020-03-12 15:50:22 -0700966 fallthrough;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 case ICMPV6_DEST_UNREACH:
968 case ICMPV6_TIME_EXCEED:
969 case ICMPV6_PARAMPROB:
Eric Dumazet30c89ba2023-02-10 18:47:07 +0000970 reason = icmpv6_notify(skb, type, hdr->icmp6_code,
971 hdr->icmp6_mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 break;
973
974 case NDISC_ROUTER_SOLICITATION:
975 case NDISC_ROUTER_ADVERTISEMENT:
976 case NDISC_NEIGHBOUR_SOLICITATION:
977 case NDISC_NEIGHBOUR_ADVERTISEMENT:
978 case NDISC_REDIRECT:
Eric Dumazet545dbcd2023-02-10 18:47:08 +0000979 reason = ndisc_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 break;
981
982 case ICMPV6_MGM_QUERY:
983 igmp6_event_query(skb);
Taehee Yoof185de282021-03-25 16:16:56 +0000984 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 case ICMPV6_MGM_REPORT:
987 igmp6_event_report(skb);
Taehee Yoof185de282021-03-25 16:16:56 +0000988 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 case ICMPV6_MGM_REDUCTION:
991 case ICMPV6_NI_QUERY:
992 case ICMPV6_NI_REPLY:
993 case ICMPV6_MLD2_REPORT:
994 case ICMPV6_DHAAD_REQUEST:
995 case ICMPV6_DHAAD_REPLY:
996 case ICMPV6_MOBILE_PREFIX_SOL:
997 case ICMPV6_MOBILE_PREFIX_ADV:
998 break;
999
1000 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 /* informational */
1002 if (type & ICMPV6_INFOMSG_MASK)
1003 break;
1004
Bjørn Mork4b3418f2015-10-24 14:00:20 +02001005 net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
1006 saddr, daddr);
David S. Millerea85a0a2014-10-07 16:33:53 -04001007
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001008 /*
1009 * error of unknown type.
1010 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 */
1012
Eric Dumazet30c89ba2023-02-10 18:47:07 +00001013 reason = icmpv6_notify(skb, type, hdr->icmp6_code,
1014 hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001015 }
1016
Rick Jonese3e32172014-11-17 14:04:29 -08001017 /* until the v6 path can be better sorted assume failure and
1018 * preserve the status quo behaviour for the rest of the paths to here
1019 */
Menglong Dongb384c952022-04-07 14:20:52 +08001020 if (reason)
1021 kfree_skb_reason(skb, reason);
Rick Jonese3e32172014-11-17 14:04:29 -08001022 else
Menglong Dongb384c952022-04-07 14:20:52 +08001023 consume_skb(skb);
Rick Jonese3e32172014-11-17 14:04:29 -08001024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return 0;
1026
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +00001027csum_error:
Menglong Dongb384c952022-04-07 14:20:52 +08001028 reason = SKB_DROP_REASON_ICMP_CSUM;
Eric Dumazeta16292a2016-04-27 16:44:36 -07001029 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030discard_it:
Eric Dumazeta16292a2016-04-27 16:44:36 -07001031 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -08001032drop_no_count:
Menglong Dongb384c952022-04-07 14:20:52 +08001033 kfree_skb_reason(skb, reason);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 return 0;
1035}
1036
Guillaume Nault5bc67a82023-07-11 15:06:21 +02001037void icmpv6_flow_init(const struct sock *sk, struct flowi6 *fl6, u8 type,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001038 const struct in6_addr *saddr,
Guillaume Nault5bc67a82023-07-11 15:06:21 +02001039 const struct in6_addr *daddr, int oif)
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001040{
David S. Miller4c9483b2011-03-12 16:22:43 -05001041 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001042 fl6->saddr = *saddr;
1043 fl6->daddr = *daddr;
Ian Morris67ba4152014-08-24 21:53:10 +01001044 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -05001045 fl6->fl6_icmp_type = type;
1046 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -05001047 fl6->flowi6_oif = oif;
Paul Moore3df98d72020-09-27 22:38:26 -04001048 security_sk_classify_flow(sk, flowi6_to_flowi_common(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001049}
1050
Eric Dumazet6a17b962022-01-24 12:24:56 -08001051int __init icmpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052{
1053 struct sock *sk;
Kefeng Wang3232a1e2019-02-23 15:28:27 +08001054 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001056 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001057 err = inet_ctl_sock_create(&sk, PF_INET6,
Eric Dumazet6a17b962022-01-24 12:24:56 -08001058 SOCK_RAW, IPPROTO_ICMPV6, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 if (err < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001060 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 err);
Eric Dumazet6a17b962022-01-24 12:24:56 -08001062 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
1064
Eric Dumazet6a17b962022-01-24 12:24:56 -08001065 per_cpu(ipv6_icmp_sk, i) = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -08001066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 /* Enough space for 2 64K ICMP packets, including
1068 * sk_buff struct overhead.
1069 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +00001070 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001072
1073 err = -EAGAIN;
1074 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
1075 goto fail;
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001076
1077 err = inet6_register_icmp_sender(icmp6_send);
1078 if (err)
1079 goto sender_reg_err;
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001080 return 0;
1081
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001082sender_reg_err:
1083 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001084fail:
Joe Perchesf3213832012-05-15 14:11:53 +00001085 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001086 return err;
1087}
1088
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001089void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001090{
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001091 inet6_unregister_icmp_sender(icmp6_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
1093}
1094
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001095
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -08001096static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 int err;
1098 int fatal;
1099} tab_unreach[] = {
1100 { /* NOROUTE */
1101 .err = ENETUNREACH,
1102 .fatal = 0,
1103 },
1104 { /* ADM_PROHIBITED */
1105 .err = EACCES,
1106 .fatal = 1,
1107 },
1108 { /* Was NOT_NEIGHBOUR, now reserved */
1109 .err = EHOSTUNREACH,
1110 .fatal = 0,
1111 },
1112 { /* ADDR_UNREACH */
1113 .err = EHOSTUNREACH,
1114 .fatal = 0,
1115 },
1116 { /* PORT_UNREACH */
1117 .err = ECONNREFUSED,
1118 .fatal = 1,
1119 },
Jiri Bohac61e76b12013-08-30 11:18:45 +02001120 { /* POLICY_FAIL */
1121 .err = EACCES,
1122 .fatal = 1,
1123 },
1124 { /* REJECT_ROUTE */
1125 .err = EACCES,
1126 .fatal = 1,
1127 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128};
1129
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07001130int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131{
1132 int fatal = 0;
1133
1134 *err = EPROTO;
1135
1136 switch (type) {
1137 case ICMPV6_DEST_UNREACH:
1138 fatal = 1;
Jiri Bohac61e76b12013-08-30 11:18:45 +02001139 if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 *err = tab_unreach[code].err;
1141 fatal = tab_unreach[code].fatal;
1142 }
1143 break;
1144
1145 case ICMPV6_PKT_TOOBIG:
1146 *err = EMSGSIZE;
1147 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001148
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 case ICMPV6_PARAMPROB:
1150 *err = EPROTO;
1151 fatal = 1;
1152 break;
1153
1154 case ICMPV6_TIME_EXCEED:
1155 *err = EHOSTUNREACH;
1156 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
1159 return fatal;
1160}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001161EXPORT_SYMBOL(icmpv6_err_convert);
1162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163#ifdef CONFIG_SYSCTL
stephen hemmingere8243532013-12-29 14:03:31 -08001164static struct ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -08001167 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 .maxlen = sizeof(int),
1169 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08001170 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 },
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001172 {
1173 .procname = "echo_ignore_all",
1174 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_all,
Eric Dumazeta6175632021-03-31 10:52:12 -07001175 .maxlen = sizeof(u8),
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001176 .mode = 0644,
Eric Dumazeta6175632021-03-31 10:52:12 -07001177 .proc_handler = proc_dou8vec_minmax,
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001178 },
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001179 {
1180 .procname = "echo_ignore_multicast",
1181 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_multicast,
Eric Dumazeta6175632021-03-31 10:52:12 -07001182 .maxlen = sizeof(u8),
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001183 .mode = 0644,
Eric Dumazeta6175632021-03-31 10:52:12 -07001184 .proc_handler = proc_dou8vec_minmax,
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001185 },
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001186 {
1187 .procname = "echo_ignore_anycast",
1188 .data = &init_net.ipv6.sysctl.icmpv6_echo_ignore_anycast,
Eric Dumazeta6175632021-03-31 10:52:12 -07001189 .maxlen = sizeof(u8),
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001190 .mode = 0644,
Eric Dumazeta6175632021-03-31 10:52:12 -07001191 .proc_handler = proc_dou8vec_minmax,
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001192 },
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001193 {
1194 .procname = "ratemask",
1195 .data = &init_net.ipv6.sysctl.icmpv6_ratemask_ptr,
1196 .maxlen = ICMPV6_MSG_MAX + 1,
1197 .mode = 0644,
1198 .proc_handler = proc_do_large_bitmap,
1199 },
Mahesh Bandewar7ab75452023-04-18 18:32:38 -07001200 {
1201 .procname = "error_anycast_as_unicast",
1202 .data = &init_net.ipv6.sysctl.icmpv6_error_anycast_as_unicast,
1203 .maxlen = sizeof(u8),
1204 .mode = 0644,
1205 .proc_handler = proc_dou8vec_minmax,
1206 .extra1 = SYSCTL_ZERO,
1207 .extra2 = SYSCTL_ONE,
1208 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001209 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210};
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001211
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001212struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001213{
1214 struct ctl_table *table;
1215
1216 table = kmemdup(ipv6_icmp_table_template,
1217 sizeof(ipv6_icmp_table_template),
1218 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001219
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001220 if (table) {
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001221 table[0].data = &net->ipv6.sysctl.icmpv6_time;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001222 table[1].data = &net->ipv6.sysctl.icmpv6_echo_ignore_all;
Stephen Suryaputra03f1ecc2019-03-19 12:37:12 -04001223 table[2].data = &net->ipv6.sysctl.icmpv6_echo_ignore_multicast;
Stephen Suryaputra0b03a5c2019-03-20 10:29:27 -04001224 table[3].data = &net->ipv6.sysctl.icmpv6_echo_ignore_anycast;
Stephen Suryaputra0bc19982019-04-17 16:35:49 -04001225 table[4].data = &net->ipv6.sysctl.icmpv6_ratemask_ptr;
Mahesh Bandewar7ab75452023-04-18 18:32:38 -07001226 table[5].data = &net->ipv6.sysctl.icmpv6_error_anycast_as_unicast;
Virgile Jarrye6f86b02018-08-10 17:48:15 +02001227 }
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001228 return table;
1229}
Joel Granadosc8997102023-08-09 12:50:03 +02001230
1231size_t ipv6_icmp_sysctl_table_size(void)
1232{
1233 return ARRAY_SIZE(ipv6_icmp_table_template);
1234}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235#endif