blob: 5acb54405b10b637962a7c59c9badb6b4f4f17bd [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Internet Control Message Protocol (ICMPv6)
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Based on net/ipv4/icmp.c
9 *
10 * RFC 1885
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18/*
19 * Changes:
20 *
21 * Andi Kleen : exception handling
22 * Andi Kleen add rate limits. never reply to a icmp.
23 * add more length checks and other fixes.
24 * yoshfuji : ensure to sent parameter problem for
25 * fragments.
26 * YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit.
27 * Randy Dunlap and
28 * YOSHIFUJI Hideaki @USAGI: Per-interface statistics support
29 * Kazunori MIYAZAWA @USAGI: change output process to use ip6_append_data
30 */
31
Joe Perchesf3213832012-05-15 14:11:53 +000032#define pr_fmt(fmt) "IPv6: " fmt
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
35#include <linux/errno.h>
36#include <linux/types.h>
37#include <linux/socket.h>
38#include <linux/in.h>
39#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/sockios.h>
41#include <linux/net.h>
42#include <linux/skbuff.h>
43#include <linux/init.h>
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -080044#include <linux/netfilter.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090045#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_SYSCTL
48#include <linux/sysctl.h>
49#endif
50
51#include <linux/inet.h>
52#include <linux/netdevice.h>
53#include <linux/icmpv6.h>
54
55#include <net/ip.h>
56#include <net/sock.h>
57
58#include <net/ipv6.h>
59#include <net/ip6_checksum.h>
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000060#include <net/ping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <net/protocol.h>
62#include <net/raw.h>
63#include <net/rawv6.h>
64#include <net/transp_v6.h>
65#include <net/ip6_route.h>
66#include <net/addrconf.h>
67#include <net/icmp.h>
Herbert Xu8b7817f2007-12-12 10:44:43 -080068#include <net/xfrm.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070069#include <net/inet_common.h>
Hannes Frederic Sowa825edac2014-01-11 11:55:46 +010070#include <net/dsfield.h>
David Ahernca254492015-10-12 11:47:10 -070071#include <net/l3mdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080073#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075/*
76 * The ICMP socket(s). This is the most convenient way to flow control
77 * our ICMP output as well as maintain a clean interface throughout
78 * all layers. All Socketless IP sends will soon be gone.
79 *
80 * On SMP we have one ICMP socket per-cpu.
81 */
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -080082static inline struct sock *icmpv6_sk(struct net *net)
83{
84 return net->ipv6.icmp_sk[smp_processor_id()];
85}
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Steffen Klassert6f809da2013-01-16 22:09:49 +000087static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
88 u8 type, u8 code, int offset, __be32 info)
89{
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000090 /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
91 struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
Steffen Klassert6f809da2013-01-16 22:09:49 +000092 struct net *net = dev_net(skb->dev);
93
94 if (type == ICMPV6_PKT_TOOBIG)
Lorenzo Colittie2d118a2016-11-04 02:23:43 +090095 ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
Steffen Klassert6f809da2013-01-16 22:09:49 +000096 else if (type == NDISC_REDIRECT)
Lorenzo Colittie2d118a2016-11-04 02:23:43 +090097 ip6_redirect(skb, net, skb->dev->ifindex, 0,
98 sock_net_uid(net, NULL));
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +000099
100 if (!(type & ICMPV6_INFOMSG_MASK))
101 if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
Hannes Frederic Sowadcb94b82016-06-11 20:32:06 +0200102 ping_err(skb, offset, ntohl(info));
Steffen Klassert6f809da2013-01-16 22:09:49 +0000103}
104
Herbert Xue5bbef22007-10-15 12:50:28 -0700105static int icmpv6_rcv(struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000107static const struct inet6_protocol icmpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 .handler = icmpv6_rcv,
Steffen Klassert6f809da2013-01-16 22:09:49 +0000109 .err_handler = icmpv6_err,
Herbert Xu8b7817f2007-12-12 10:44:43 -0800110 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100113/* Called with BH disabled */
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700114static __inline__ struct sock *icmpv6_xmit_lock(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700116 struct sock *sk;
117
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700118 sk = icmpv6_sk(net);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800119 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 /* This can happen if the output path (f.e. SIT or
121 * ip6ip6 tunnel) signals dst_link_failure() for an
122 * outgoing ICMP6 packet.
123 */
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700124 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 }
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700126 return sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
Denis V. Lunev405666d2008-02-29 11:16:46 -0800129static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100131 spin_unlock(&sk->sk_lock.slock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900134/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 * Figure out, may we reply to this packet with icmp error.
136 *
137 * We do not reply, if:
138 * - it was icmp error message.
139 * - it is truncated, so that it is known, that protocol is ICMPV6
140 * (i.e. in the middle of some exthdr)
141 *
142 * --ANK (980726)
143 */
144
Eric Dumazeta50feda2012-05-18 18:57:34 +0000145static bool is_ineligible(const struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700147 int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 int len = skb->len - ptr;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700149 __u8 nexthdr = ipv6_hdr(skb)->nexthdr;
Jesse Gross75f28112011-11-30 17:05:51 -0800150 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152 if (len < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000153 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Jesse Gross75f28112011-11-30 17:05:51 -0800155 ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 if (ptr < 0)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000157 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 if (nexthdr == IPPROTO_ICMPV6) {
159 u8 _type, *tp;
160 tp = skb_header_pointer(skb,
161 ptr+offsetof(struct icmp6hdr, icmp6_type),
162 sizeof(_type), &_type);
Ian Morris63159f22015-03-29 14:00:04 +0100163 if (!tp || !(*tp & ICMPV6_INFOMSG_MASK))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000164 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000166 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167}
168
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100169static bool icmpv6_mask_allow(int type)
170{
171 /* Informational messages are not limited. */
172 if (type & ICMPV6_INFOMSG_MASK)
173 return true;
174
175 /* Do not limit pmtu discovery, it would break it. */
176 if (type == ICMPV6_PKT_TOOBIG)
177 return true;
178
179 return false;
180}
181
182static bool icmpv6_global_allow(int type)
183{
184 if (icmpv6_mask_allow(type))
185 return true;
186
187 if (icmp_global_allow())
188 return true;
189
190 return false;
191}
192
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900193/*
194 * Check the ICMP output rate limit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 */
Eric Dumazet4cdf5072014-09-19 07:38:40 -0700196static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
197 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900199 struct net *net = sock_net(sk);
Eric Dumazet4cdf5072014-09-19 07:38:40 -0700200 struct dst_entry *dst;
David S. Miller92d86822011-02-04 15:55:25 -0800201 bool res = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100203 if (icmpv6_mask_allow(type))
David S. Miller92d86822011-02-04 15:55:25 -0800204 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900206 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 * Look up the output route.
208 * XXX: perhaps the expire for routing entries cloned by
209 * this lookup should be more aggressive (not longer than timeout).
210 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500211 dst = ip6_route_output(net, sk, fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 if (dst->error) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -0700213 IP6_INC_STATS(net, ip6_dst_idev(dst),
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900214 IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
David S. Miller92d86822011-02-04 15:55:25 -0800216 res = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 } else {
218 struct rt6_info *rt = (struct rt6_info *)dst;
Benjamin Thery9a43b702008-03-05 10:49:18 -0800219 int tmo = net->ipv6.sysctl.icmpv6_time;
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100220 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222 /* Give more bandwidth to wider prefixes. */
223 if (rt->rt6i_dst.plen < 128)
224 tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
225
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100226 peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr, 1);
227 res = inet_peer_xrlim_allow(peer, tmo);
228 if (peer)
229 inet_putpeer(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 }
231 dst_release(dst);
232 return res;
233}
234
235/*
236 * an inline helper for the "simple" if statement below
237 * checks if parameter problem report is caused by an
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900238 * unrecognized IPv6 option that has the Option Type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 * highest-order two bits set to 10
240 */
241
Eric Dumazeta50feda2012-05-18 18:57:34 +0000242static bool opt_unrec(struct sk_buff *skb, __u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
244 u8 _optval, *op;
245
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300246 offset += skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
Ian Morris63159f22015-03-29 14:00:04 +0100248 if (!op)
Eric Dumazeta50feda2012-05-18 18:57:34 +0000249 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 return (*op & 0xC0) == 0x80;
251}
252
Lorenzo Colitti6d0bfe22013-05-22 20:17:31 +0000253int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
254 struct icmp6hdr *thdr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 struct sk_buff *skb;
257 struct icmp6hdr *icmp6h;
258 int err = 0;
259
Ian Morrise5d08d72014-11-23 21:28:43 +0000260 skb = skb_peek(&sk->sk_write_queue);
Ian Morris63159f22015-03-29 14:00:04 +0100261 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 goto out;
263
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300264 icmp6h = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
266 icmp6h->icmp6_cksum = 0;
267
268 if (skb_queue_len(&sk->sk_write_queue) == 1) {
Joe Perches07f07572008-11-19 15:44:53 -0800269 skb->csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sizeof(struct icmp6hdr), skb->csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500271 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
272 &fl6->daddr,
273 len, fl6->flowi6_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 skb->csum);
275 } else {
Al Viro868c86b2006-11-14 21:35:48 -0800276 __wsum tmp_csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
278 skb_queue_walk(&sk->sk_write_queue, skb) {
279 tmp_csum = csum_add(tmp_csum, skb->csum);
280 }
281
Joe Perches07f07572008-11-19 15:44:53 -0800282 tmp_csum = csum_partial(icmp6h,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 sizeof(struct icmp6hdr), tmp_csum);
David S. Miller4c9483b2011-03-12 16:22:43 -0500284 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr,
285 &fl6->daddr,
286 len, fl6->flowi6_proto,
Al Viro868c86b2006-11-14 21:35:48 -0800287 tmp_csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 ip6_push_pending_frames(sk);
290out:
291 return err;
292}
293
294struct icmpv6_msg {
295 struct sk_buff *skb;
296 int offset;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800297 uint8_t type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298};
299
300static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
301{
302 struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
303 struct sk_buff *org_skb = msg->skb;
Al Viro5f92a732006-11-14 21:36:54 -0800304 __wsum csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
307 to, len, csum);
308 skb->csum = csum_block_add(skb->csum, csum, odd);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800309 if (!(msg->type & ICMPV6_INFOMSG_MASK))
310 nf_ct_attach(skb, org_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 return 0;
312}
313
Amerigo Wang07a93622012-10-29 16:23:10 +0000314#if IS_ENABLED(CONFIG_IPV6_MIP6)
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700315static void mip6_addr_swap(struct sk_buff *skb)
316{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700317 struct ipv6hdr *iph = ipv6_hdr(skb);
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700318 struct inet6_skb_parm *opt = IP6CB(skb);
319 struct ipv6_destopt_hao *hao;
320 struct in6_addr tmp;
321 int off;
322
323 if (opt->dsthao) {
324 off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
325 if (likely(off >= 0)) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700326 hao = (struct ipv6_destopt_hao *)
327 (skb_network_header(skb) + off);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000328 tmp = iph->saddr;
329 iph->saddr = hao->addr;
330 hao->addr = tmp;
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700331 }
332 }
333}
334#else
335static inline void mip6_addr_swap(struct sk_buff *skb) {}
336#endif
337
stephen hemmingere8243532013-12-29 14:03:31 -0800338static struct dst_entry *icmpv6_route_lookup(struct net *net,
339 struct sk_buff *skb,
340 struct sock *sk,
341 struct flowi6 *fl6)
David S. Millerb42835d2011-03-01 22:06:22 -0800342{
343 struct dst_entry *dst, *dst2;
David S. Miller4c9483b2011-03-12 16:22:43 -0500344 struct flowi6 fl2;
David S. Millerb42835d2011-03-01 22:06:22 -0800345 int err;
346
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700347 err = ip6_dst_lookup(net, sk, &dst, fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800348 if (err)
349 return ERR_PTR(err);
350
351 /*
352 * We won't send icmp if the destination is known
353 * anycast.
354 */
Martin KaFai Lau2647a9b2015-05-22 20:55:58 -0700355 if (ipv6_anycast_destination(dst, &fl6->daddr)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800356 net_dbg_ratelimited("icmp6_send: acast source\n");
David S. Millerb42835d2011-03-01 22:06:22 -0800357 dst_release(dst);
358 return ERR_PTR(-EINVAL);
359 }
360
361 /* No need to clone since we're just using its address. */
362 dst2 = dst;
363
David S. Miller4c9483b2011-03-12 16:22:43 -0500364 dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800365 if (!IS_ERR(dst)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800366 if (dst != dst2)
367 return dst;
David S. Miller452edd52011-03-02 13:27:41 -0800368 } else {
369 if (PTR_ERR(dst) == -EPERM)
370 dst = NULL;
371 else
372 return dst;
David S. Millerb42835d2011-03-01 22:06:22 -0800373 }
374
David S. Miller4c9483b2011-03-12 16:22:43 -0500375 err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6);
David S. Millerb42835d2011-03-01 22:06:22 -0800376 if (err)
377 goto relookup_failed;
378
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700379 err = ip6_dst_lookup(net, sk, &dst2, &fl2);
David S. Millerb42835d2011-03-01 22:06:22 -0800380 if (err)
381 goto relookup_failed;
382
David S. Miller4c9483b2011-03-12 16:22:43 -0500383 dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP);
David S. Miller452edd52011-03-02 13:27:41 -0800384 if (!IS_ERR(dst2)) {
David S. Millerb42835d2011-03-01 22:06:22 -0800385 dst_release(dst);
386 dst = dst2;
David S. Miller452edd52011-03-02 13:27:41 -0800387 } else {
388 err = PTR_ERR(dst2);
389 if (err == -EPERM) {
390 dst_release(dst);
391 return dst2;
392 } else
393 goto relookup_failed;
David S. Millerb42835d2011-03-01 22:06:22 -0800394 }
395
396relookup_failed:
397 if (dst)
398 return dst;
399 return ERR_PTR(err);
400}
401
David Ahern1b70d7922017-08-28 13:53:34 -0700402static int icmp6_iif(const struct sk_buff *skb)
403{
404 int iif = skb->dev->ifindex;
405
406 /* for local traffic to local address, skb dev is the loopback
407 * device. Check if there is a dst attached to the skb and if so
408 * get the real device index.
409 */
410 if (unlikely(iif == LOOPBACK_IFINDEX)) {
411 const struct rt6_info *rt6 = skb_rt6_info(skb);
412
413 if (rt6)
414 iif = rt6->rt6i_idev->dev->ifindex;
415 }
416
417 return iif;
418}
419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420/*
421 * Send an ICMP message in response to a packet in error
422 */
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700423static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
424 const struct in6_addr *force_saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900426 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 struct inet6_dev *idev = NULL;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700428 struct ipv6hdr *hdr = ipv6_hdr(skb);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700429 struct sock *sk;
430 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000431 const struct in6_addr *saddr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 struct dst_entry *dst;
433 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500434 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 struct icmpv6_msg msg;
Soheil Hassas Yeganehc14ac942016-04-02 23:08:12 -0400436 struct sockcm_cookie sockc_unused = {0};
Wei Wang26879da2016-05-02 21:40:07 -0700437 struct ipcm6_cookie ipc6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 int iif = 0;
439 int addr_type = 0;
440 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 int err = 0;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700442 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700444 if ((u8 *)hdr < skb->head ||
Simon Horman29a3cad2013-05-28 20:34:26 +0000445 (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 return;
447
448 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900449 * Make sure we respect the rules
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 * i.e. RFC 1885 2.4(e)
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000451 * Rule (e.1) is enforced by not using icmp6_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 * in any code that processes icmp errors.
453 */
454 addr_type = ipv6_addr_type(&hdr->daddr);
455
FX Le Bail446fab52014-01-19 17:00:36 +0100456 if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) ||
FX Le Baild94c1f92014-02-07 11:22:37 +0100457 ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 saddr = &hdr->daddr;
459
460 /*
461 * Dest addr check
462 */
463
zhuyj9a6b4b32015-01-14 17:23:59 +0800464 if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (type != ICMPV6_PKT_TOOBIG &&
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900466 !(type == ICMPV6_PARAMPROB &&
467 code == ICMPV6_UNK_OPTION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 (opt_unrec(skb, info))))
469 return;
470
471 saddr = NULL;
472 }
473
474 addr_type = ipv6_addr_type(&hdr->saddr);
475
476 /*
477 * Source addr check
478 */
479
David Ahern4832c302017-08-17 12:17:20 -0700480 if (__ipv6_addr_needs_scope_id(addr_type)) {
David Ahern1b70d7922017-08-28 13:53:34 -0700481 iif = icmp6_iif(skb);
David Ahern4832c302017-08-17 12:17:20 -0700482 } else {
David Ahern79dc7e32016-11-27 18:52:53 -0800483 dst = skb_dst(skb);
484 iif = l3mdev_master_ifindex(dst ? dst->dev : skb->dev);
485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487 /*
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900488 * Must not send error if the source does not uniquely
489 * identify a single node (RFC2463 Section 2.4).
490 * We check unspecified / multicast addresses here,
491 * and anycast addresses will be checked later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 */
493 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200494 net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n",
495 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 return;
497 }
498
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900499 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 * Never answer to a ICMP packet.
501 */
502 if (is_ineligible(skb)) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200503 net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n",
504 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return;
506 }
507
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100508 /* Needed by both icmp_global_allow and icmpv6_xmit_lock */
509 local_bh_disable();
510
511 /* Check global sysctl_icmp_msgs_per_sec ratelimit */
Jesper Dangaard Brouer849a44d2017-06-14 13:27:37 +0200512 if (!(skb->dev->flags&IFF_LOOPBACK) && !icmpv6_global_allow(type))
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100513 goto out_bh_enable;
514
Masahide NAKAMURA79383232006-08-23 19:27:25 -0700515 mip6_addr_swap(skb);
516
David S. Miller4c9483b2011-03-12 16:22:43 -0500517 memset(&fl6, 0, sizeof(fl6));
518 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000519 fl6.daddr = hdr->saddr;
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700520 if (force_saddr)
521 saddr = force_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000523 fl6.saddr = *saddr;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700524 fl6.flowi6_mark = mark;
David S. Miller4c9483b2011-03-12 16:22:43 -0500525 fl6.flowi6_oif = iif;
David S. Miller1958b852011-03-12 16:36:19 -0500526 fl6.fl6_icmp_type = type;
527 fl6.fl6_icmp_code = code;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900528 fl6.flowi6_uid = sock_net_uid(net, NULL);
Jakub Sitnicki23aebda2017-08-23 09:58:29 +0200529 fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
David S. Miller4c9483b2011-03-12 16:22:43 -0500530 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700532 sk = icmpv6_xmit_lock(net);
Ian Morris63159f22015-03-29 14:00:04 +0100533 if (!sk)
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100534 goto out_bh_enable;
Jesper Dangaard Brouerc0303ef2017-01-09 16:04:09 +0100535
Lorenzo Colittie1108612014-05-13 10:17:33 -0700536 sk->sk_mark = mark;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700537 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800538
David S. Miller4c9483b2011-03-12 16:22:43 -0500539 if (!icmpv6_xrlim_allow(sk, type, &fl6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 goto out;
541
542 tmp_hdr.icmp6_type = type;
543 tmp_hdr.icmp6_code = code;
544 tmp_hdr.icmp6_cksum = 0;
545 tmp_hdr.icmp6_pointer = htonl(info);
546
David S. Miller4c9483b2011-03-12 16:22:43 -0500547 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
548 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000549 else if (!fl6.flowi6_oif)
550 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +0200552 ipc6.tclass = np->tclass;
553 fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
554
David S. Miller4c9483b2011-03-12 16:22:43 -0500555 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
David S. Millerb42835d2011-03-01 22:06:22 -0800556 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 goto out;
YOSHIFUJI Hideaki8de33512005-12-21 22:57:06 +0900558
Wei Wang26879da2016-05-02 21:40:07 -0700559 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
Wei Wang26879da2016-05-02 21:40:07 -0700560 ipc6.dontfrag = np->dontfrag;
561 ipc6.opt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 msg.skb = skb;
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -0300564 msg.offset = skb_network_offset(skb);
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800565 msg.type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 len = skb->len - msg.offset;
Ian Morris67ba4152014-08-24 21:53:10 +0100568 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (len < 0) {
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200570 net_dbg_ratelimited("icmp: len problem [%pI6c > %pI6c]\n",
571 &hdr->saddr, &hdr->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 goto out_dst_release;
573 }
574
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000575 rcu_read_lock();
576 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 err = ip6_append_data(sk, icmpv6_getfrag, &msg,
579 len + sizeof(struct icmp6hdr),
Wei Wang26879da2016-05-02 21:40:07 -0700580 sizeof(struct icmp6hdr),
581 &ipc6, &fl6, (struct rt6_info *)dst,
582 MSG_DONTWAIT, &sockc_unused);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 if (err) {
Hannes Frederic Sowa43a43b62014-03-31 20:14:10 +0200584 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000586 } else {
587 err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
588 len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 }
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000590 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591out_dst_release:
592 dst_release(dst);
593out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800594 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100595out_bh_enable:
596 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597}
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000598
599/* Slightly more convenient version of icmp6_send.
600 */
601void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
602{
Eric Dumazetb1cadc12016-06-18 21:52:02 -0700603 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL);
Pravin B Shelar5f5624c2013-04-25 11:08:30 +0000604 kfree_skb(skb);
605}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900606
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700607/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
608 * if sufficient data bytes are available
609 * @nhs is the size of the tunnel header(s) :
610 * Either an IPv4 header for SIT encap
611 * an IPv4 header + GRE header for GRE encap
612 */
Eric Dumazet20e19542016-06-18 21:52:06 -0700613int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
614 unsigned int data_len)
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700615{
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700616 struct in6_addr temp_saddr;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700617 struct rt6_info *rt;
618 struct sk_buff *skb2;
Eric Dumazet20e19542016-06-18 21:52:06 -0700619 u32 info = 0;
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700620
621 if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8))
622 return 1;
623
Eric Dumazet20e19542016-06-18 21:52:06 -0700624 /* RFC 4884 (partial) support for ICMP extensions */
625 if (data_len < 128 || (data_len & 7) || skb->len < data_len)
626 data_len = 0;
627
628 skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700629
630 if (!skb2)
631 return 1;
632
633 skb_dst_drop(skb2);
634 skb_pull(skb2, nhs);
635 skb_reset_network_header(skb2);
636
637 rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0);
638
639 if (rt && rt->dst.dev)
640 skb2->dev = rt->dst.dev;
641
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700642 ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr);
Eric Dumazet20e19542016-06-18 21:52:06 -0700643
644 if (data_len) {
645 /* RFC 4884 (partial) support :
646 * insert 0 padding at the end, before the extensions
647 */
648 __skb_push(skb2, nhs);
649 skb_reset_network_header(skb2);
650 memmove(skb2->data, skb2->data + nhs, data_len - nhs);
651 memset(skb2->data + data_len - nhs, 0, nhs);
652 /* RFC 4884 4.5 : Length is measured in 64-bit words,
653 * and stored in reserved[0]
654 */
655 info = (data_len/8) << 24;
656 }
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700657 if (type == ICMP_TIME_EXCEEDED)
658 icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
Eric Dumazet20e19542016-06-18 21:52:06 -0700659 info, &temp_saddr);
Eric Dumazet2d7a3b22016-06-18 21:52:04 -0700660 else
661 icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH,
Eric Dumazet20e19542016-06-18 21:52:06 -0700662 info, &temp_saddr);
Eric Dumazet5fbba8a2016-06-18 21:52:03 -0700663 if (rt)
664 ip6_rt_put(rt);
665
666 kfree_skb(skb2);
667
668 return 0;
669}
670EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672static void icmpv6_echo_reply(struct sk_buff *skb)
673{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900674 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700675 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 struct inet6_dev *idev;
YOSHIFUJI Hideaki84427d52005-06-13 14:59:44 -0700677 struct ipv6_pinfo *np;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000678 const struct in6_addr *saddr = NULL;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300679 struct icmp6hdr *icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 struct icmp6hdr tmp_hdr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500681 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 struct icmpv6_msg msg;
683 struct dst_entry *dst;
Wei Wang26879da2016-05-02 21:40:07 -0700684 struct ipcm6_cookie ipc6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 int err = 0;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700686 u32 mark = IP6_REPLY_MARK(net, skb->mark);
Soheil Hassas Yeganehc14ac942016-04-02 23:08:12 -0400687 struct sockcm_cookie sockc_unused = {0};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700689 saddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
FX Le Bail509aba32014-01-07 14:57:27 +0100691 if (!ipv6_unicast_destination(skb) &&
FX Le Bailec35b612014-01-13 15:59:01 +0100692 !(net->ipv6.sysctl.anycast_src_echo_reply &&
Martin KaFai Lau2647a9b2015-05-22 20:55:58 -0700693 ipv6_anycast_destination(skb_dst(skb), saddr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 saddr = NULL;
695
696 memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
697 tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
698
David S. Miller4c9483b2011-03-12 16:22:43 -0500699 memset(&fl6, 0, sizeof(fl6));
700 fl6.flowi6_proto = IPPROTO_ICMPV6;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000701 fl6.daddr = ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 if (saddr)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000703 fl6.saddr = *saddr;
David Ahern1b70d7922017-08-28 13:53:34 -0700704 fl6.flowi6_oif = icmp6_iif(skb);
David S. Miller1958b852011-03-12 16:36:19 -0500705 fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700706 fl6.flowi6_mark = mark;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +0900707 fl6.flowi6_uid = sock_net_uid(net, NULL);
David S. Miller4c9483b2011-03-12 16:22:43 -0500708 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100710 local_bh_disable();
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700711 sk = icmpv6_xmit_lock(net);
Ian Morris63159f22015-03-29 14:00:04 +0100712 if (!sk)
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100713 goto out_bh_enable;
Lorenzo Colittie1108612014-05-13 10:17:33 -0700714 sk->sk_mark = mark;
Denis V. Lunevfdc0bde2008-08-23 04:43:33 -0700715 np = inet6_sk(sk);
Denis V. Lunev405666d2008-02-29 11:16:46 -0800716
David S. Miller4c9483b2011-03-12 16:22:43 -0500717 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
718 fl6.flowi6_oif = np->mcast_oif;
Erich E. Hooverc4062df2012-02-08 09:11:08 +0000719 else if (!fl6.flowi6_oif)
720 fl6.flowi6_oif = np->ucast_oif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Roopa Prabhu343d60a2015-07-30 13:34:53 -0700722 err = ip6_dst_lookup(net, sk, &dst, &fl6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 if (err)
724 goto out;
David S. Miller4c9483b2011-03-12 16:22:43 -0500725 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
David S. Miller452edd52011-03-02 13:27:41 -0800726 if (IS_ERR(dst))
Patrick McHardye104411b2005-09-08 15:11:55 -0700727 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000729 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
731 msg.skb = skb;
732 msg.offset = 0;
Yasuyuki Kozakai763ecff2006-02-15 15:24:15 -0800733 msg.type = ICMPV6_ECHO_REPLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Wei Wang26879da2016-05-02 21:40:07 -0700735 ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
736 ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
737 ipc6.dontfrag = np->dontfrag;
738 ipc6.opt = NULL;
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
Wei Wang26879da2016-05-02 21:40:07 -0700741 sizeof(struct icmp6hdr), &ipc6, &fl6,
Eldad Zacka2d91a02012-04-01 07:49:07 +0000742 (struct rt6_info *)dst, MSG_DONTWAIT,
Wei Wang26879da2016-05-02 21:40:07 -0700743 &sockc_unused);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745 if (err) {
Eric Dumazeta16292a2016-04-27 16:44:36 -0700746 __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 ip6_flush_pending_frames(sk);
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000748 } else {
749 err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
750 skb->len + sizeof(struct icmp6hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 dst_release(dst);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900753out:
Denis V. Lunev405666d2008-02-29 11:16:46 -0800754 icmpv6_xmit_unlock(sk);
Jesper Dangaard Brouer7ba91ec2017-01-09 16:04:14 +0100755out_bh_enable:
756 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
David S. Millerb94f1c02012-07-12 00:33:37 -0700759void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000761 const struct inet6_protocol *ipprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 int inner_offset;
Jesse Gross75f28112011-11-30 17:05:51 -0800763 __be16 frag_off;
David S. Millerf9242b62012-06-19 18:56:21 -0700764 u8 nexthdr;
Duan Jiong7304fe42014-07-31 17:54:32 +0800765 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
Duan Jiong7304fe42014-07-31 17:54:32 +0800768 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
771 if (ipv6_ext_hdr(nexthdr)) {
772 /* now skip over extension headers */
Jesse Gross75f28112011-11-30 17:05:51 -0800773 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
774 &nexthdr, &frag_off);
Ian Morris67ba4152014-08-24 21:53:10 +0100775 if (inner_offset < 0)
Duan Jiong7304fe42014-07-31 17:54:32 +0800776 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 } else {
778 inner_offset = sizeof(struct ipv6hdr);
779 }
780
781 /* Checkin header including 8 bytes of inner protocol header. */
782 if (!pskb_may_pull(skb, inner_offset+8))
Duan Jiong7304fe42014-07-31 17:54:32 +0800783 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
786 Without this we will not able f.e. to make source routed
787 pmtu discovery.
788 Corresponding argument (opt) to notifiers is already added.
789 --ANK (980726)
790 */
791
David S. Millerf9242b62012-06-19 18:56:21 -0700792 ipprot = rcu_dereference(inet6_protos[nexthdr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 if (ipprot && ipprot->err_handler)
794 ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Pavel Emelyanov69d6da02007-11-19 22:35:57 -0800796 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
Duan Jiong7304fe42014-07-31 17:54:32 +0800797 return;
798
799out:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700800 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803/*
804 * Handle icmp messages
805 */
806
Herbert Xue5bbef22007-10-15 12:50:28 -0700807static int icmpv6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 struct net_device *dev = skb->dev;
810 struct inet6_dev *idev = __in6_dev_get(dev);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000811 const struct in6_addr *saddr, *daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 struct icmp6hdr *hdr;
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700813 u8 type;
Rick Jonese3e32172014-11-17 14:04:29 -0800814 bool success = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Herbert Xuaebcf822007-12-12 18:54:16 -0800816 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700817 struct sec_path *sp = skb_sec_path(skb);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800818 int nh;
819
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -0700820 if (!(sp && sp->xvec[sp->len - 1]->props.flags &
Herbert Xuaebcf822007-12-12 18:54:16 -0800821 XFRM_STATE_ICMP))
822 goto drop_no_count;
823
David S. Miller81aded22012-06-15 14:54:11 -0700824 if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
Herbert Xu8b7817f2007-12-12 10:44:43 -0800825 goto drop_no_count;
826
827 nh = skb_network_offset(skb);
828 skb_set_network_header(skb, sizeof(*hdr));
829
830 if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
831 goto drop_no_count;
832
833 skb_set_network_header(skb, nh);
834 }
835
Eric Dumazeta16292a2016-04-27 16:44:36 -0700836 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700838 saddr = &ipv6_hdr(skb)->saddr;
839 daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Tom Herbert39471ac2014-05-07 16:52:29 -0700841 if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
Joe Perchesba7a46f2014-11-11 10:59:17 -0800842 net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
843 saddr, daddr);
Tom Herbert39471ac2014-05-07 16:52:29 -0700844 goto csum_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 }
846
Herbert Xu8cf22942008-02-05 03:15:50 -0800847 if (!pskb_pull(skb, sizeof(*hdr)))
848 goto discard_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300850 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
852 type = hdr->icmp6_type;
853
Eric Dumazetf3832ed2016-04-27 16:44:42 -0700854 ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
856 switch (type) {
857 case ICMPV6_ECHO_REQUEST:
858 icmpv6_echo_reply(skb);
859 break;
860
861 case ICMPV6_ECHO_REPLY:
Rick Jonese3e32172014-11-17 14:04:29 -0800862 success = ping_rcv(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 break;
864
865 case ICMPV6_PKT_TOOBIG:
866 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
867 standard destination cache. Seems, only "advanced"
868 destination cache will allow to solve this problem
869 --ANK (980726)
870 */
871 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
872 goto discard_it;
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -0300873 hdr = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875 /*
876 * Drop through to notify
877 */
878
879 case ICMPV6_DEST_UNREACH:
880 case ICMPV6_TIME_EXCEED:
881 case ICMPV6_PARAMPROB:
882 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
883 break;
884
885 case NDISC_ROUTER_SOLICITATION:
886 case NDISC_ROUTER_ADVERTISEMENT:
887 case NDISC_NEIGHBOUR_SOLICITATION:
888 case NDISC_NEIGHBOUR_ADVERTISEMENT:
889 case NDISC_REDIRECT:
890 ndisc_rcv(skb);
891 break;
892
893 case ICMPV6_MGM_QUERY:
894 igmp6_event_query(skb);
895 break;
896
897 case ICMPV6_MGM_REPORT:
898 igmp6_event_report(skb);
899 break;
900
901 case ICMPV6_MGM_REDUCTION:
902 case ICMPV6_NI_QUERY:
903 case ICMPV6_NI_REPLY:
904 case ICMPV6_MLD2_REPORT:
905 case ICMPV6_DHAAD_REQUEST:
906 case ICMPV6_DHAAD_REPLY:
907 case ICMPV6_MOBILE_PREFIX_SOL:
908 case ICMPV6_MOBILE_PREFIX_ADV:
909 break;
910
911 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 /* informational */
913 if (type & ICMPV6_INFOMSG_MASK)
914 break;
915
Bjørn Mork4b3418f2015-10-24 14:00:20 +0200916 net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
917 saddr, daddr);
David S. Millerea85a0a2014-10-07 16:33:53 -0400918
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900919 /*
920 * error of unknown type.
921 * must pass to upper level
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 */
923
924 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700925 }
926
Rick Jonese3e32172014-11-17 14:04:29 -0800927 /* until the v6 path can be better sorted assume failure and
928 * preserve the status quo behaviour for the rest of the paths to here
929 */
930 if (success)
931 consume_skb(skb);
932 else
933 kfree_skb(skb);
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 return 0;
936
Eric Dumazet6a5dc9e2013-04-29 08:39:56 +0000937csum_error:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700938 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939discard_it:
Eric Dumazeta16292a2016-04-27 16:44:36 -0700940 __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS);
Herbert Xu8b7817f2007-12-12 10:44:43 -0800941drop_no_count:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 kfree_skb(skb);
943 return 0;
944}
945
David S. Miller4c9483b2011-03-12 16:22:43 -0500946void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800947 u8 type,
948 const struct in6_addr *saddr,
949 const struct in6_addr *daddr,
950 int oif)
951{
David S. Miller4c9483b2011-03-12 16:22:43 -0500952 memset(fl6, 0, sizeof(*fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000953 fl6->saddr = *saddr;
954 fl6->daddr = *daddr;
Ian Morris67ba4152014-08-24 21:53:10 +0100955 fl6->flowi6_proto = IPPROTO_ICMPV6;
David S. Miller1958b852011-03-12 16:36:19 -0500956 fl6->fl6_icmp_type = type;
957 fl6->fl6_icmp_code = 0;
David S. Miller4c9483b2011-03-12 16:22:43 -0500958 fl6->flowi6_oif = oif;
959 security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -0800960}
961
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800962static int __net_init icmpv6_sk_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
964 struct sock *sk;
965 int err, i, j;
966
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800967 net->ipv6.icmp_sk =
968 kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
Ian Morris63159f22015-03-29 14:00:04 +0100969 if (!net->ipv6.icmp_sk)
Denis V. Lunev79c91152008-02-29 11:17:11 -0800970 return -ENOMEM;
971
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700972 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700973 err = inet_ctl_sock_create(&sk, PF_INET6,
974 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (err < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +0000976 pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 err);
978 goto fail;
979 }
980
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700981 net->ipv6.icmp_sk[i] = sk;
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -0800982
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 /* Enough space for 2 64K ICMP packets, including
984 * sk_buff struct overhead.
985 */
Eric Dumazet87fb4b72011-10-13 07:28:54 +0000986 sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 return 0;
989
990 fail:
Denis V. Lunev5c8cafd2008-02-29 11:19:22 -0800991 for (j = 0; j < i; j++)
Denis V. Lunev1ed85162008-04-03 14:31:03 -0700992 inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800993 kfree(net->ipv6.icmp_sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 return err;
995}
996
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -0800997static void __net_exit icmpv6_sk_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
999 int i;
1000
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001001 for_each_possible_cpu(i) {
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001002 inet_ctl_sock_destroy(net->ipv6.icmp_sk[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001004 kfree(net->ipv6.icmp_sk);
1005}
1006
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001007static struct pernet_operations icmpv6_sk_ops = {
Ian Morris67ba4152014-08-24 21:53:10 +01001008 .init = icmpv6_sk_init,
1009 .exit = icmpv6_sk_exit,
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001010};
1011
1012int __init icmpv6_init(void)
1013{
1014 int err;
1015
1016 err = register_pernet_subsys(&icmpv6_sk_ops);
1017 if (err < 0)
1018 return err;
1019
1020 err = -EAGAIN;
1021 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
1022 goto fail;
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001023
1024 err = inet6_register_icmp_sender(icmp6_send);
1025 if (err)
1026 goto sender_reg_err;
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001027 return 0;
1028
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001029sender_reg_err:
1030 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001031fail:
Joe Perchesf3213832012-05-15 14:11:53 +00001032 pr_err("Failed to register ICMP6 protocol\n");
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001033 unregister_pernet_subsys(&icmpv6_sk_ops);
1034 return err;
1035}
1036
Alexey Dobriyan8ed7edc2008-03-03 12:02:54 -08001037void icmpv6_cleanup(void)
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001038{
Pravin B Shelar5f5624c2013-04-25 11:08:30 +00001039 inet6_unregister_icmp_sender(icmp6_send);
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001040 unregister_pernet_subsys(&icmpv6_sk_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
1042}
1043
Denis V. Lunev98c6d1b2008-02-29 11:21:22 -08001044
Arjan van de Ven9b5b5cf2005-11-29 16:21:38 -08001045static const struct icmp6_err {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 int err;
1047 int fatal;
1048} tab_unreach[] = {
1049 { /* NOROUTE */
1050 .err = ENETUNREACH,
1051 .fatal = 0,
1052 },
1053 { /* ADM_PROHIBITED */
1054 .err = EACCES,
1055 .fatal = 1,
1056 },
1057 { /* Was NOT_NEIGHBOUR, now reserved */
1058 .err = EHOSTUNREACH,
1059 .fatal = 0,
1060 },
1061 { /* ADDR_UNREACH */
1062 .err = EHOSTUNREACH,
1063 .fatal = 0,
1064 },
1065 { /* PORT_UNREACH */
1066 .err = ECONNREFUSED,
1067 .fatal = 1,
1068 },
Jiri Bohac61e76b12013-08-30 11:18:45 +02001069 { /* POLICY_FAIL */
1070 .err = EACCES,
1071 .fatal = 1,
1072 },
1073 { /* REJECT_ROUTE */
1074 .err = EACCES,
1075 .fatal = 1,
1076 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077};
1078
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07001079int icmpv6_err_convert(u8 type, u8 code, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080{
1081 int fatal = 0;
1082
1083 *err = EPROTO;
1084
1085 switch (type) {
1086 case ICMPV6_DEST_UNREACH:
1087 fatal = 1;
Jiri Bohac61e76b12013-08-30 11:18:45 +02001088 if (code < ARRAY_SIZE(tab_unreach)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 *err = tab_unreach[code].err;
1090 fatal = tab_unreach[code].fatal;
1091 }
1092 break;
1093
1094 case ICMPV6_PKT_TOOBIG:
1095 *err = EMSGSIZE;
1096 break;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 case ICMPV6_PARAMPROB:
1099 *err = EPROTO;
1100 fatal = 1;
1101 break;
1102
1103 case ICMPV6_TIME_EXCEED:
1104 *err = EHOSTUNREACH;
1105 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001106 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108 return fatal;
1109}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001110EXPORT_SYMBOL(icmpv6_err_convert);
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112#ifdef CONFIG_SYSCTL
stephen hemmingere8243532013-12-29 14:03:31 -08001113static struct ctl_table ipv6_icmp_table_template[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 .procname = "ratelimit",
Daniel Lezcano41a76902008-01-10 03:02:40 -08001116 .data = &init_net.ipv6.sysctl.icmpv6_time,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 .maxlen = sizeof(int),
1118 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08001119 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001121 { },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122};
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001123
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001124struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001125{
1126 struct ctl_table *table;
1127
1128 table = kmemdup(ipv6_icmp_table_template,
1129 sizeof(ipv6_icmp_table_template),
1130 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001131
Eric W. Biedermanc027aab2012-11-16 03:03:10 +00001132 if (table)
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09001133 table[0].data = &net->ipv6.sysctl.icmpv6_time;
1134
Daniel Lezcano760f2d02008-01-10 02:53:43 -08001135 return table;
1136}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137#endif