blob: c245895a3d416b3eed0ab537b61950b618b2944c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Neighbour Discovery for IPv6
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003 * Linux INET6 implementation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Mike Shaver <shaver@ingenia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
15/*
16 * Changes:
17 *
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +000018 * Alexey I. Froloff : RFC6106 (DNSSL) support
Pierre Ynard31910572007-10-10 21:22:05 -070019 * Pierre Ynard : export userland ND options
20 * through netlink (RDNSS support)
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 * Lars Fenneberg : fixed MTU setting on receipt
22 * of an RA.
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 * Janos Farkas : kmalloc failure checks
24 * Alexey Kuznetsov : state machine reworked
25 * and moved to net/core.
26 * Pekka Savola : RFC2461 validation
27 * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
28 */
29
Joe Perches675418d2012-05-16 19:28:38 +000030#define pr_fmt(fmt) "ICMPv6: " fmt
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/types.h>
35#include <linux/socket.h>
36#include <linux/sockios.h>
37#include <linux/sched.h>
38#include <linux/net.h>
39#include <linux/in6.h>
40#include <linux/route.h>
41#include <linux/init.h>
42#include <linux/rcupdate.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090043#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#ifdef CONFIG_SYSCTL
45#include <linux/sysctl.h>
46#endif
47
Thomas Graf18237302006-08-04 23:04:54 -070048#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/if_arp.h>
50#include <linux/ipv6.h>
51#include <linux/icmpv6.h>
52#include <linux/jhash.h>
53
54#include <net/sock.h>
55#include <net/snmp.h>
56
57#include <net/ipv6.h>
58#include <net/protocol.h>
59#include <net/ndisc.h>
60#include <net/ip6_route.h>
61#include <net/addrconf.h>
62#include <net/icmp.h>
63
Pierre Ynard31910572007-10-10 21:22:05 -070064#include <net/netlink.h>
65#include <linux/rtnetlink.h>
66
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <net/flow.h>
68#include <net/ip6_checksum.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070069#include <net/inet_common.h>
David Ahernca254492015-10-12 11:47:10 -070070#include <net/l3mdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#include <linux/proc_fs.h>
72
73#include <linux/netfilter.h>
74#include <linux/netfilter_ipv6.h>
75
Joe Perches675418d2012-05-16 19:28:38 +000076/* Set to 3 to get tracing... */
77#define ND_DEBUG 1
78
79#define ND_PRINTK(val, level, fmt, ...) \
80do { \
81 if (val <= ND_DEBUG) \
82 net_##level##_ratelimited(fmt, ##__VA_ARGS__); \
83} while (0)
84
Eric Dumazetd6bf7812010-10-04 06:15:44 +000085static u32 ndisc_hash(const void *pkey,
86 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -050087 __u32 *hash_rnd);
Eric W. Biederman60395a22015-03-03 17:10:44 -060088static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static int ndisc_constructor(struct neighbour *neigh);
90static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
91static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
92static int pndisc_constructor(struct pneigh_entry *n);
93static void pndisc_destructor(struct pneigh_entry *n);
94static void pndisc_redo(struct sk_buff *skb);
95
Stephen Hemminger89d69d22009-09-01 11:13:19 +000096static const struct neigh_ops ndisc_generic_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 .family = AF_INET6,
98 .solicit = ndisc_solicit,
99 .error_report = ndisc_error_report,
100 .output = neigh_resolve_output,
101 .connected_output = neigh_connected_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102};
103
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000104static const struct neigh_ops ndisc_hh_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 .family = AF_INET6,
106 .solicit = ndisc_solicit,
107 .error_report = ndisc_error_report,
108 .output = neigh_resolve_output,
109 .connected_output = neigh_resolve_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110};
111
112
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000113static const struct neigh_ops ndisc_direct_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 .family = AF_INET6,
David S. Miller8f40b162011-07-17 13:34:11 -0700115 .output = neigh_direct_output,
116 .connected_output = neigh_direct_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117};
118
119struct neigh_table nd_tbl = {
120 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 .key_len = sizeof(struct in6_addr),
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -0600122 .protocol = cpu_to_be16(ETH_P_IPV6),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 .hash = ndisc_hash,
Eric W. Biederman60395a22015-03-03 17:10:44 -0600124 .key_eq = ndisc_key_eq,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 .constructor = ndisc_constructor,
126 .pconstructor = pndisc_constructor,
127 .pdestructor = pndisc_destructor,
128 .proxy_redo = pndisc_redo,
129 .id = "ndisc_cache",
130 .parms = {
Shan Weib6720832010-12-01 18:05:12 +0000131 .tbl = &nd_tbl,
Shan Weib6720832010-12-01 18:05:12 +0000132 .reachable_time = ND_REACHABLE_TIME,
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100133 .data = {
134 [NEIGH_VAR_MCAST_PROBES] = 3,
135 [NEIGH_VAR_UCAST_PROBES] = 3,
136 [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
137 [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
138 [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
139 [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
140 [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
141 [NEIGH_VAR_PROXY_QLEN] = 64,
142 [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
143 [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,
144 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 },
146 .gc_interval = 30 * HZ,
147 .gc_thresh1 = 128,
148 .gc_thresh2 = 512,
149 .gc_thresh3 = 1024,
150};
David Ahernc4850682015-10-12 11:47:08 -0700151EXPORT_SYMBOL_GPL(nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000153static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000155 int pad = ndisc_addr_option_pad(skb->dev->type);
156 int data_len = skb->dev->addr_len;
157 int space = ndisc_opt_addr_space(skb->dev);
158 u8 *opt = skb_put(skb, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
160 opt[0] = type;
161 opt[1] = space>>3;
162
163 memset(opt + 2, 0, pad);
164 opt += pad;
165 space -= pad;
166
167 memcpy(opt+2, data, data_len);
168 data_len += 2;
169 opt += data_len;
Ian Morrise5d08d72014-11-23 21:28:43 +0000170 space -= data_len;
171 if (space > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173}
174
175static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
176 struct nd_opt_hdr *end)
177{
178 int type;
179 if (!cur || !end || cur >= end)
180 return NULL;
181 type = cur->nd_opt_type;
182 do {
183 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100184 } while (cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000185 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
Pierre Ynard31910572007-10-10 21:22:05 -0700188static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
189{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000190 return opt->nd_opt_type == ND_OPT_RDNSS ||
191 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700192}
193
194static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
195 struct nd_opt_hdr *end)
196{
197 if (!cur || !end || cur >= end)
198 return NULL;
199 do {
200 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100201 } while (cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000202 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700203}
204
David S. Miller30f2a5f2012-07-11 23:26:46 -0700205struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
206 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
209
210 if (!nd_opt || opt_len < 0 || !ndopts)
211 return NULL;
212 memset(ndopts, 0, sizeof(*ndopts));
213 while (opt_len) {
214 int l;
215 if (opt_len < sizeof(struct nd_opt_hdr))
216 return NULL;
217 l = nd_opt->nd_opt_len << 3;
218 if (opt_len < l || l == 0)
219 return NULL;
220 switch (nd_opt->nd_opt_type) {
221 case ND_OPT_SOURCE_LL_ADDR:
222 case ND_OPT_TARGET_LL_ADDR:
223 case ND_OPT_MTU:
224 case ND_OPT_REDIRECT_HDR:
225 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000226 ND_PRINTK(2, warn,
227 "%s: duplicated ND6 option found: type=%d\n",
228 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 } else {
230 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
231 }
232 break;
233 case ND_OPT_PREFIX_INFO:
234 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700235 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
237 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800238#ifdef CONFIG_IPV6_ROUTE_INFO
239 case ND_OPT_ROUTE_INFO:
240 ndopts->nd_opts_ri_end = nd_opt;
241 if (!ndopts->nd_opts_ri)
242 ndopts->nd_opts_ri = nd_opt;
243 break;
244#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700246 if (ndisc_is_useropt(nd_opt)) {
247 ndopts->nd_useropts_end = nd_opt;
248 if (!ndopts->nd_useropts)
249 ndopts->nd_useropts = nd_opt;
250 } else {
251 /*
252 * Unknown options must be silently ignored,
253 * to accommodate future extension to the
254 * protocol.
255 */
Joe Perches675418d2012-05-16 19:28:38 +0000256 ND_PRINTK(2, notice,
257 "%s: ignored unsupported option; type=%d, len=%d\n",
258 __func__,
259 nd_opt->nd_opt_type,
260 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 }
263 opt_len -= l;
264 nd_opt = ((void *)nd_opt) + l;
265 }
266 return ndopts;
267}
268
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000269int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{
271 switch (dev->type) {
272 case ARPHRD_ETHER:
273 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
274 case ARPHRD_FDDI:
275 ipv6_eth_mc_map(addr, buf);
276 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 case ARPHRD_ARCNET:
278 ipv6_arcnet_mc_map(addr, buf);
279 return 0;
280 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700281 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000283 case ARPHRD_IPGRE:
284 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 default:
286 if (dir) {
287 memcpy(buf, dev->broadcast, dev->addr_len);
288 return 0;
289 }
290 }
291 return -EINVAL;
292}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900293EXPORT_SYMBOL(ndisc_mc_map);
294
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000295static u32 ndisc_hash(const void *pkey,
296 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500297 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
David S. Miller2c2aba62011-12-28 15:06:58 -0500299 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
Eric W. Biederman60395a22015-03-03 17:10:44 -0600302static bool ndisc_key_eq(const struct neighbour *n, const void *pkey)
303{
304 return neigh_key_eq128(n, pkey);
305}
306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307static int ndisc_constructor(struct neighbour *neigh)
308{
Ian Morris67ba4152014-08-24 21:53:10 +0100309 struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 struct net_device *dev = neigh->dev;
311 struct inet6_dev *in6_dev;
312 struct neigh_parms *parms;
Eric Dumazeta50feda2012-05-18 18:57:34 +0000313 bool is_multicast = ipv6_addr_is_multicast(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 in6_dev = in6_dev_get(dev);
Ian Morris63159f22015-03-29 14:00:04 +0100316 if (!in6_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 return -EINVAL;
318 }
319
320 parms = in6_dev->nd_parms;
321 __neigh_parms_put(neigh->parms);
322 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700325 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 neigh->nud_state = NUD_NOARP;
327 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700328 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 } else {
330 if (is_multicast) {
331 neigh->nud_state = NUD_NOARP;
332 ndisc_mc_map(addr, neigh->ha, dev, 1);
333 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
334 neigh->nud_state = NUD_NOARP;
335 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
336 if (dev->flags&IFF_LOOPBACK)
337 neigh->type = RTN_LOCAL;
338 } else if (dev->flags&IFF_POINTOPOINT) {
339 neigh->nud_state = NUD_NOARP;
340 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
341 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700342 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 neigh->ops = &ndisc_hh_ops;
344 else
345 neigh->ops = &ndisc_generic_ops;
346 if (neigh->nud_state&NUD_VALID)
347 neigh->output = neigh->ops->connected_output;
348 else
349 neigh->output = neigh->ops->output;
350 }
351 in6_dev_put(in6_dev);
352 return 0;
353}
354
355static int pndisc_constructor(struct pneigh_entry *n)
356{
Ian Morris67ba4152014-08-24 21:53:10 +0100357 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 struct in6_addr maddr;
359 struct net_device *dev = n->dev;
360
Ian Morris63159f22015-03-29 14:00:04 +0100361 if (!dev || !__in6_dev_get(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 return -EINVAL;
363 addrconf_addr_solict_mult(addr, &maddr);
364 ipv6_dev_mc_inc(dev, &maddr);
365 return 0;
366}
367
368static void pndisc_destructor(struct pneigh_entry *n)
369{
Ian Morris67ba4152014-08-24 21:53:10 +0100370 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 struct in6_addr maddr;
372 struct net_device *dev = n->dev;
373
Ian Morris63159f22015-03-29 14:00:04 +0100374 if (!dev || !__in6_dev_get(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return;
376 addrconf_addr_solict_mult(addr, &maddr);
377 ipv6_dev_mc_dec(dev, &maddr);
378}
379
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000380static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
381 int len)
382{
383 int hlen = LL_RESERVED_SPACE(dev);
384 int tlen = dev->needed_tailroom;
385 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
386 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000387
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200388 skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000389 if (!skb) {
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200390 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
391 __func__);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000392 return NULL;
393 }
394
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000395 skb->protocol = htons(ETH_P_IPV6);
396 skb->dev = dev;
397
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000398 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki / 吉藤英明5135e632013-01-21 06:48:44 +0000399 skb_reset_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000400
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200401 /* Manually assign socket ownership as we avoid calling
402 * sock_alloc_send_pskb() to bypass wmem buffer limits
403 */
404 skb_set_owner_w(skb, sk);
405
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000406 return skb;
407}
408
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000409static void ip6_nd_hdr(struct sk_buff *skb,
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000410 const struct in6_addr *saddr,
411 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000412 int hop_limit, int len)
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000413{
414 struct ipv6hdr *hdr;
415
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000416 skb_push(skb, sizeof(*hdr));
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000417 skb_reset_network_header(skb);
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000418 hdr = ipv6_hdr(skb);
419
420 ip6_flow_hdr(hdr, 0, 0);
421
422 hdr->payload_len = htons(len);
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000423 hdr->nexthdr = IPPROTO_ICMPV6;
424 hdr->hop_limit = hop_limit;
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000425
426 hdr->saddr = *saddr;
427 hdr->daddr = *daddr;
428}
429
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000430static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900431 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000432 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800433{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000434 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000435 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000436 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800437 struct inet6_dev *idev;
438 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000439 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800440 u8 type;
441
442 type = icmp6h->icmp6_type;
443
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000444 if (!dst) {
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000445 struct flowi6 fl6;
David Ahernca254492015-10-12 11:47:10 -0700446 int oif = l3mdev_fib_oif(skb->dev);
Brian Haley305d5522008-11-04 17:51:14 -0800447
David Ahernca254492015-10-12 11:47:10 -0700448 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif);
449 if (oif != skb->dev->ifindex)
450 fl6.flowi6_flags |= FLOWI_FLAG_L3MDEV_SRC;
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000451 dst = icmp6_dst_alloc(skb->dev, &fl6);
452 if (IS_ERR(dst)) {
453 kfree_skb(skb);
454 return;
455 }
456
457 skb_dst_set(skb, dst);
458 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900459
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000460 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
461 IPPROTO_ICMPV6,
462 csum_partial(icmp6h,
463 skb->len, 0));
464
465 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
466
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000467 rcu_read_lock();
468 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700469 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900470
Eric W. Biederman29a26a52015-09-15 20:04:16 -0500471 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
472 net, sk, skb, NULL, dst->dev,
Eric W. Biederman13206b62015-10-07 16:48:35 -0500473 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900474 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700475 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700476 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900477 }
478
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000479 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900480}
481
Jiri Benc38cf5952015-09-22 18:57:13 +0200482void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
Cong Wangf564f452013-08-31 13:44:36 +0800483 const struct in6_addr *solicited_addr,
484 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000486 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 struct in6_addr tmpaddr;
488 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900489 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000490 struct nd_msg *msg;
491 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900494 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900495 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700497 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300498 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000499 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 in6_ifa_put(ifp);
501 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700502 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900503 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900504 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return;
506 src_addr = &tmpaddr;
507 }
508
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000509 if (!dev->addr_len)
510 inc_opt = 0;
511 if (inc_opt)
512 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000514 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000515 if (!skb)
516 return;
517
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000518 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
519 *msg = (struct nd_msg) {
520 .icmph = {
521 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
522 .icmp6_router = router,
523 .icmp6_solicited = solicited,
524 .icmp6_override = override,
525 },
526 .target = *solicited_addr,
527 };
528
529 if (inc_opt)
530 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
531 dev->dev_addr);
532
533
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000534 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900535}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000537static void ndisc_send_unsol_na(struct net_device *dev)
538{
539 struct inet6_dev *idev;
540 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000541
542 idev = in6_dev_get(dev);
543 if (!idev)
544 return;
545
546 read_lock_bh(&idev->lock);
547 list_for_each_entry(ifa, &idev->addr_list, if_list) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200548 ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000549 /*router=*/ !!idev->cnf.forwarding,
550 /*solicited=*/ false, /*override=*/ true,
551 /*inc_opt=*/ true);
552 }
553 read_unlock_bh(&idev->lock);
554
555 in6_dev_put(idev);
556}
557
Jiri Benc38cf5952015-09-22 18:57:13 +0200558void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
Nicolas Dichtel304d8882015-11-27 18:17:05 +0100559 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000561 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000563 int inc_opt = dev->addr_len;
564 int optlen = 0;
565 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Ian Morris63159f22015-03-29 14:00:04 +0100567 if (!saddr) {
Neil Horman95c385b2007-04-25 17:08:10 -0700568 if (ipv6_get_lladdr(dev, &addr_buf,
569 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 return;
571 saddr = &addr_buf;
572 }
573
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000574 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300575 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000576 if (inc_opt)
577 optlen += ndisc_opt_addr_space(dev);
578
579 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000580 if (!skb)
581 return;
582
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000583 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
584 *msg = (struct nd_msg) {
585 .icmph = {
586 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
587 },
588 .target = *solicit,
589 };
590
591 if (inc_opt)
592 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
593 dev->dev_addr);
594
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000595 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596}
597
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900598void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
599 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000601 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000602 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700603 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000604 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700605
606#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
607 /*
608 * According to section 2.2 of RFC 4429, we must not
609 * send router solicitations with a sllao from
610 * optimistic addresses, but we may send the solicitation
611 * if we don't include the sllao. So here we check
612 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800613 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700614 */
615 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900616 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800617 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700618 if (ifp) {
619 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900620 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700621 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900622 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700623 } else {
624 send_sllao = 0;
625 }
626 }
627#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000628 if (send_sllao)
629 optlen += ndisc_opt_addr_space(dev);
630
631 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000632 if (!skb)
633 return;
634
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000635 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
636 *msg = (struct rs_msg) {
637 .icmph = {
638 .icmp6_type = NDISC_ROUTER_SOLICITATION,
639 },
640 };
641
642 if (send_sllao)
643 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
644 dev->dev_addr);
645
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000646 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
651{
652 /*
653 * "The sender MUST return an ICMP
654 * destination unreachable"
655 */
656 dst_link_failure(skb);
657 kfree_skb(skb);
658}
659
660/* Called with locked neigh: either read or both */
661
662static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
663{
664 struct in6_addr *saddr = NULL;
665 struct in6_addr mcaddr;
666 struct net_device *dev = neigh->dev;
667 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
668 int probes = atomic_read(&neigh->probes);
669
Erik Klinec58da4c2015-02-04 20:01:23 +0900670 if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
671 dev, 1,
672 IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700673 saddr = &ipv6_hdr(skb)->saddr;
Ian Morrise5d08d72014-11-23 21:28:43 +0000674 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
675 if (probes < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000677 ND_PRINTK(1, dbg,
678 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
679 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
Nicolas Dichtel304d8882015-11-27 18:17:05 +0100681 ndisc_send_ns(dev, target, target, saddr);
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100682 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 } else {
685 addrconf_addr_solict_mult(target, &mcaddr);
Nicolas Dichtel304d8882015-11-27 18:17:05 +0100686 ndisc_send_ns(dev, target, &mcaddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688}
689
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900690static int pndisc_is_router(const void *pkey,
691 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700692{
693 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900694 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700695
696 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900697 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
698 if (n)
699 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700700 read_unlock_bh(&nd_tbl.lock);
701
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900702 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700703}
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705static void ndisc_recv_ns(struct sk_buff *skb)
706{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700707 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000708 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
709 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000711 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700712 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 struct ndisc_options ndopts;
714 struct net_device *dev = skb->dev;
715 struct inet6_ifaddr *ifp;
716 struct inet6_dev *idev = NULL;
717 struct neighbour *neigh;
718 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000719 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900720 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000722 if (skb->len < sizeof(struct nd_msg)) {
723 ND_PRINTK(2, warn, "NS: packet too short\n");
724 return;
725 }
726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000728 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 return;
730 }
731
732 /*
733 * RFC2461 7.1.1:
734 * DAD has to be destined for solicited node multicast address.
735 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000736 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000737 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return;
739 }
740
741 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000742 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return;
744 }
745
746 if (ndopts.nd_opts_src_lladdr) {
747 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
748 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000749 ND_PRINTK(2, warn,
750 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return;
752 }
753
754 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900755 * If the IP source address is the unspecified address,
756 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 * in the message.
758 */
759 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000760 ND_PRINTK(2, warn,
761 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return;
763 }
764 }
765
766 inc = ipv6_addr_is_multicast(daddr);
767
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900768 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800769 if (ifp) {
David Ahernca254492015-10-12 11:47:10 -0700770have_ifp:
Neil Horman95c385b2007-04-25 17:08:10 -0700771 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
772 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700773 /*
774 * We are colliding with another node
775 * who is doing DAD
776 * so fail our DAD process
777 */
778 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200779 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700780 } else {
781 /*
782 * This is not a dad solicitation.
783 * If we are an optimistic node,
784 * we should respond.
785 * Otherwise, we should ignore it.
786 */
787 if (!(ifp->flags & IFA_F_OPTIMISTIC))
788 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
792 idev = ifp->idev;
793 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700794 struct net *net = dev_net(dev);
795
David Ahernca254492015-10-12 11:47:10 -0700796 /* perhaps an address on the master device */
797 if (netif_is_l3_slave(dev)) {
798 struct net_device *mdev;
799
800 mdev = netdev_master_upper_dev_get_rcu(dev);
801 if (mdev) {
802 ifp = ipv6_get_ifaddr(net, &msg->target, mdev, 1);
803 if (ifp)
804 goto have_ifp;
805 }
806 }
807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 idev = in6_dev_get(dev);
809 if (!idev) {
810 /* XXX: count this drop? */
811 return;
812 }
813
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700814 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900815 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700816 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900817 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700818 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300820 inc &&
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100821 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 /*
823 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900824 * sender should delay its response
825 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 * MAX_ANYCAST_DELAY_TIME seconds.
827 * (RFC2461) -- yoshfuji
828 */
829 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
830 if (n)
831 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
832 goto out;
833 }
834 } else
835 goto out;
836 }
837
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900838 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000839 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (dad) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200842 ndisc_send_na(dev, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000843 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 goto out;
845 }
846
847 if (inc)
848 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
849 else
850 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
851
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900852 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 * update / create cache entry
854 * for the source address
855 */
856 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
857 !inc || lladdr || !dev->addr_len);
858 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900859 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 NEIGH_UPDATE_F_WEAK_OVERRIDE|
861 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700862 if (neigh || !dev->header_ops) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200863 ndisc_send_na(dev, saddr, &msg->target, !!is_router,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000864 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 if (neigh)
866 neigh_release(neigh);
867 }
868
869out:
870 if (ifp)
871 in6_ifa_put(ifp);
872 else
873 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874}
875
876static void ndisc_recv_na(struct sk_buff *skb)
877{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700878 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800879 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000880 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000882 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700883 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 struct ndisc_options ndopts;
885 struct net_device *dev = skb->dev;
Johannes Berg7a02bf82016-02-04 13:31:20 +0100886 struct inet6_dev *idev = __in6_dev_get(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 struct inet6_ifaddr *ifp;
888 struct neighbour *neigh;
889
890 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000891 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 return;
893 }
894
895 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000896 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return;
898 }
899
900 if (ipv6_addr_is_multicast(daddr) &&
901 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000902 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 return;
904 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900905
Johannes Berg7a02bf82016-02-04 13:31:20 +0100906 /* For some 802.11 wireless deployments (and possibly other networks),
907 * there will be a NA proxy and unsolicitd packets are attacks
908 * and thus should not be accepted.
909 */
910 if (!msg->icmph.icmp6_solicited && idev &&
911 idev->cnf.drop_unsolicited_na)
912 return;
913
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000915 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 return;
917 }
918 if (ndopts.nd_opts_tgt_lladdr) {
919 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
920 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000921 ND_PRINTK(2, warn,
922 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 return;
924 }
925 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900926 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800927 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000928 if (skb->pkt_type != PACKET_LOOPBACK
929 && (ifp->flags & IFA_F_TENTATIVE)) {
930 addrconf_dad_failure(ifp);
931 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 }
933 /* What should we make now? The advertisement
934 is invalid, but ndisc specs say nothing
935 about it. It could be misconfiguration, or
936 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800937
938 We should not print the error if NA has been
939 received from loopback - it is just our own
940 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800942 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000943 ND_PRINTK(1, warn,
944 "NA: someone advertises our address %pI6 on %s!\n",
945 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 in6_ifa_put(ifp);
947 return;
948 }
949 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
950
951 if (neigh) {
952 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700953 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 if (neigh->nud_state & NUD_FAILED)
956 goto out;
957
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700958 /*
959 * Don't update the neighbor cache entry on a proxy NA from
960 * ourselves because either the proxied node is off link or it
961 * has already sent a NA to us.
962 */
963 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700964 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
965 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000966 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700967 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700968 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 neigh_update(neigh, lladdr,
971 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
972 NEIGH_UPDATE_F_WEAK_OVERRIDE|
973 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
974 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
975 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
976
977 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
978 /*
979 * Change: router to host
980 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800981 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
983
984out:
985 neigh_release(neigh);
986 }
987}
988
989static void ndisc_recv_rs(struct sk_buff *skb)
990{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700991 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
993 struct neighbour *neigh;
994 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000995 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 struct ndisc_options ndopts;
997 u8 *lladdr = NULL;
998
999 if (skb->len < sizeof(*rs_msg))
1000 return;
1001
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001002 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +00001004 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return;
1006 }
1007
1008 /* Don't accept RS if we're not in router mode */
1009 if (!idev->cnf.forwarding)
1010 goto out;
1011
1012 /*
1013 * Don't update NCE if src = ::;
1014 * this implies that the source node has no ip address assigned yet.
1015 */
1016 if (ipv6_addr_any(saddr))
1017 goto out;
1018
1019 /* Parse ND options */
1020 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001021 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 goto out;
1023 }
1024
1025 if (ndopts.nd_opts_src_lladdr) {
1026 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1027 skb->dev);
1028 if (!lladdr)
1029 goto out;
1030 }
1031
1032 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1033 if (neigh) {
1034 neigh_update(neigh, lladdr, NUD_STALE,
1035 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1036 NEIGH_UPDATE_F_OVERRIDE|
1037 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1038 neigh_release(neigh);
1039 }
1040out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001041 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042}
1043
Pierre Ynard31910572007-10-10 21:22:05 -07001044static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1045{
1046 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1047 struct sk_buff *skb;
1048 struct nlmsghdr *nlh;
1049 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001050 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001051 int err;
1052 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1053 + (opt->nd_opt_len << 3));
1054 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1055
1056 skb = nlmsg_new(msg_size, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01001057 if (!skb) {
Pierre Ynard31910572007-10-10 21:22:05 -07001058 err = -ENOBUFS;
1059 goto errout;
1060 }
1061
1062 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
Ian Morris63159f22015-03-29 14:00:04 +01001063 if (!nlh) {
Pierre Ynard31910572007-10-10 21:22:05 -07001064 goto nla_put_failure;
1065 }
1066
1067 ndmsg = nlmsg_data(nlh);
1068 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001069 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001070 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1071 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1072 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1073
1074 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1075
Jiri Benc930345e2015-03-29 16:59:25 +02001076 if (nla_put_in6_addr(skb, NDUSEROPT_SRCADDR, &ipv6_hdr(ra)->saddr))
David S. Millerc78679e2012-04-01 20:27:33 -04001077 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001078 nlmsg_end(skb, nlh);
1079
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001080 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001081 return;
1082
1083nla_put_failure:
1084 nlmsg_free(skb);
1085 err = -EMSGSIZE;
1086errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001087 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001088}
1089
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090static void ndisc_router_discovery(struct sk_buff *skb)
1091{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001092 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 struct neighbour *neigh = NULL;
1094 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001095 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 int lifetime;
1097 struct ndisc_options ndopts;
1098 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001099 unsigned int pref = 0;
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001100 __u32 old_if_flags;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001101 bool send_ifinfo_notify = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Ian Morris67ba4152014-08-24 21:53:10 +01001103 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Simon Horman29a3cad2013-05-28 20:34:26 +00001105 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1106 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Ben Greearf2a762d2014-06-25 14:44:52 -07001108 ND_PRINTK(2, info,
1109 "RA: %s, dev: %s\n",
1110 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001111 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001112 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 return;
1114 }
1115 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001116 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 return;
1118 }
1119
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001120#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001121 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001122 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001123 return;
1124 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001125#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 /*
1128 * set the RA_RECV flag in the interface
1129 */
1130
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001131 in6_dev = __in6_dev_get(skb->dev);
Ian Morris63159f22015-03-29 14:00:04 +01001132 if (!in6_dev) {
Joe Perches675418d2012-05-16 19:28:38 +00001133 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1134 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 return;
1136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001139 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 return;
1141 }
1142
Ben Greearf2a762d2014-06-25 14:44:52 -07001143 if (!ipv6_accept_ra(in6_dev)) {
1144 ND_PRINTK(2, info,
1145 "RA: %s, did not accept ra for dev: %s\n",
1146 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001147 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001148 }
David Ward31ce8c72009-08-29 00:04:09 -07001149
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001150#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001151 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001152 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1153 ND_PRINTK(2, info,
1154 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1155 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001156 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001157 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001158#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (in6_dev->if_flags & IF_RS_SENT) {
1161 /*
1162 * flag that an RA was received after an RS was sent
1163 * out on this interface.
1164 */
1165 in6_dev->if_flags |= IF_RA_RCVD;
1166 }
1167
1168 /*
1169 * Remember the managed/otherconf flags from most recently
1170 * received RA message (RFC 2462) -- yoshfuji
1171 */
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001172 old_if_flags = in6_dev->if_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1174 IF_RA_OTHERCONF)) |
1175 (ra_msg->icmph.icmp6_addrconf_managed ?
1176 IF_RA_MANAGED : 0) |
1177 (ra_msg->icmph.icmp6_addrconf_other ?
1178 IF_RA_OTHERCONF : 0);
1179
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001180 if (old_if_flags != in6_dev->if_flags)
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001181 send_ifinfo_notify = true;
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001182
Ben Greearf2a762d2014-06-25 14:44:52 -07001183 if (!in6_dev->cnf.accept_ra_defrtr) {
1184 ND_PRINTK(2, info,
1185 "RA: %s, defrtr is false for dev: %s\n",
1186 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001187 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001188 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001189
Ben Greeard9333192014-06-25 14:44:53 -07001190 /* Do not accept RA with source-addr found on local machine unless
1191 * accept_ra_from_local is set to true.
1192 */
Li RongQingb6428812014-07-10 18:02:46 +08001193 if (!in6_dev->cnf.accept_ra_from_local &&
1194 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
Hannes Frederic Sowac1a9a292015-12-23 22:44:37 +01001195 in6_dev->dev, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001196 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001197 "RA from local address detected on dev: %s: default router ignored\n",
1198 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001199 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001200 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1203
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001204#ifdef CONFIG_IPV6_ROUTER_PREF
1205 pref = ra_msg->icmph.icmp6_router_pref;
1206 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001207 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001208 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001209 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1210#endif
1211
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001212 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
David S. Millereb857182012-01-27 15:07:56 -08001214 if (rt) {
1215 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1216 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001217 ND_PRINTK(0, err,
1218 "RA: %s got default router without neighbour\n",
1219 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001220 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001221 return;
1222 }
1223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001225 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 rt = NULL;
1227 }
1228
Ben Greearf2a762d2014-06-25 14:44:52 -07001229 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1230 rt, lifetime, skb->dev->name);
Ian Morris63159f22015-03-29 14:00:04 +01001231 if (!rt && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001232 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001234 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Ian Morris63159f22015-03-29 14:00:04 +01001235 if (!rt) {
Joe Perches675418d2012-05-16 19:28:38 +00001236 ND_PRINTK(0, err,
1237 "RA: %s failed to add default route\n",
1238 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 return;
1240 }
1241
David S. Millereb857182012-01-27 15:07:56 -08001242 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Ian Morris63159f22015-03-29 14:00:04 +01001243 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001244 ND_PRINTK(0, err,
1245 "RA: %s got default router without neighbour\n",
1246 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001247 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 return;
1249 }
1250 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001251 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001252 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 }
1254
1255 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001256 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001257 if (in6_dev->cnf.accept_ra_min_hop_limit < 256 &&
1258 ra_msg->icmph.icmp6_hop_limit) {
1259 if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) {
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001260 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001261 if (rt)
1262 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1263 ra_msg->icmph.icmp6_hop_limit);
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001264 } else {
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001265 ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than minimum\n");
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 }
1268
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001269skip_defrtr:
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 /*
1272 * Update Reachable Time and Retrans Timer
1273 */
1274
1275 if (in6_dev->nd_parms) {
1276 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1277
1278 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1279 rtime = (rtime*HZ)/1000;
1280 if (rtime < HZ/10)
1281 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001282 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 in6_dev->tstamp = jiffies;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001284 send_ifinfo_notify = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 }
1286
1287 rtime = ntohl(ra_msg->reachable_time);
1288 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1289 rtime = (rtime*HZ)/1000;
1290
1291 if (rtime < HZ/10)
1292 rtime = HZ/10;
1293
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001294 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1295 NEIGH_VAR_SET(in6_dev->nd_parms,
1296 BASE_REACHABLE_TIME, rtime);
1297 NEIGH_VAR_SET(in6_dev->nd_parms,
1298 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1300 in6_dev->tstamp = jiffies;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001301 send_ifinfo_notify = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 }
1303 }
1304 }
1305
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001306 /*
1307 * Send a notify if RA changed managed/otherconf flags or timer settings
1308 */
1309 if (send_ifinfo_notify)
1310 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1311
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001312skip_linkparms:
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 /*
1315 * Process options.
1316 */
1317
1318 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001319 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 skb->dev, 1);
1321 if (neigh) {
1322 u8 *lladdr = NULL;
1323 if (ndopts.nd_opts_src_lladdr) {
1324 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1325 skb->dev);
1326 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001327 ND_PRINTK(2, warn,
1328 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 goto out;
1330 }
1331 }
1332 neigh_update(neigh, lladdr, NUD_STALE,
1333 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1334 NEIGH_UPDATE_F_OVERRIDE|
1335 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1336 NEIGH_UPDATE_F_ISROUTER);
1337 }
1338
Ben Greearf2a762d2014-06-25 14:44:52 -07001339 if (!ipv6_accept_ra(in6_dev)) {
1340 ND_PRINTK(2, info,
1341 "RA: %s, accept_ra is false for dev: %s\n",
1342 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001343 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001344 }
David Ward31ce8c72009-08-29 00:04:09 -07001345
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001346#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001347 if (!in6_dev->cnf.accept_ra_from_local &&
1348 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
Hannes Frederic Sowac1a9a292015-12-23 22:44:37 +01001349 in6_dev->dev, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001350 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001351 "RA from local address detected on dev: %s: router info ignored.\n",
1352 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001353 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001354 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001355
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001356 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001357 struct nd_opt_hdr *p;
1358 for (p = ndopts.nd_opts_ri;
1359 p;
1360 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001361 struct route_info *ri = (struct route_info *)p;
1362#ifdef CONFIG_IPV6_NDISC_NODETYPE
1363 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1364 ri->prefix_len == 0)
1365 continue;
1366#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001367 if (ri->prefix_len == 0 &&
1368 !in6_dev->cnf.accept_ra_defrtr)
1369 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001370 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001371 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001372 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001373 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001374 }
1375 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001376
1377skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001378#endif
1379
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001380#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001381 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001382 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1383 ND_PRINTK(2, info,
1384 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1385 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001386 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001387 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001388#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001389
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001390 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 struct nd_opt_hdr *p;
1392 for (p = ndopts.nd_opts_pi;
1393 p;
1394 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001395 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1396 (p->nd_opt_len) << 3,
1397 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 }
1399 }
1400
Harout Hedeshianc2943f12015-01-20 10:06:05 -07001401 if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001402 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 u32 mtu;
1404
Ian Morris67ba4152014-08-24 21:53:10 +01001405 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4adc2006-11-14 20:56:00 -08001406 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
1408 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001409 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 } else if (in6_dev->cnf.mtu6 != mtu) {
1411 in6_dev->cnf.mtu6 = mtu;
1412
1413 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001414 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
1416 rt6_mtu_change(skb->dev, mtu);
1417 }
1418 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001419
Pierre Ynard31910572007-10-10 21:22:05 -07001420 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001421 struct nd_opt_hdr *p;
1422 for (p = ndopts.nd_useropts;
1423 p;
1424 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1425 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001426 }
1427 }
1428
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001430 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 }
1432out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001433 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001434 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436}
1437
1438static void ndisc_redirect_rcv(struct sk_buff *skb)
1439{
Duan Jiong093d04d2012-12-14 02:59:59 +00001440 u8 *hdr;
1441 struct ndisc_options ndopts;
1442 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001443 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001444 offsetof(struct rd_msg, opt));
1445
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001446#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001447 switch (skb->ndisc_nodetype) {
1448 case NDISC_NODETYPE_HOST:
1449 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001450 ND_PRINTK(2, warn,
1451 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001452 return;
1453 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001454#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001455
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001456 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001457 ND_PRINTK(2, warn,
1458 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 return;
1460 }
1461
Duan Jiong093d04d2012-12-14 02:59:59 +00001462 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1463 return;
1464
Duan Jiongc92a59e2013-08-22 12:07:35 +08001465 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001466 ip6_redirect_no_header(skb, dev_net(skb->dev),
1467 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001468 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001469 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001470
1471 hdr = (u8 *)ndopts.nd_opts_rh;
1472 hdr += 8;
1473 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1474 return;
1475
David S. Millerb94f1c02012-07-12 00:33:37 -07001476 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477}
1478
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001479static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1480 struct sk_buff *orig_skb,
1481 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001482{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001483 u8 *opt = skb_put(skb, rd_len);
1484
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001485 memset(opt, 0, 8);
1486 *(opt++) = ND_OPT_REDIRECT_HDR;
1487 *(opt++) = (rd_len >> 3);
1488 opt += 6;
1489
1490 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001491}
1492
David S. Miller49919692012-01-27 15:30:48 -08001493void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001495 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001496 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001497 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001498 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001499 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001501 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 struct rt6_info *rt;
1504 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001505 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David Ahernca254492015-10-12 11:47:10 -07001508 int oif = l3mdev_fib_oif(dev);
David S. Miller1d861aa2012-07-10 03:58:16 -07001509 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
Neil Horman95c385b2007-04-25 17:08:10 -07001511 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001512 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1513 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001514 return;
1515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001517 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001518 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001519 ND_PRINTK(2, warn,
1520 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001521 return;
1522 }
1523
David S. Miller4c9483b2011-03-12 16:22:43 -05001524 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
David Ahernca254492015-10-12 11:47:10 -07001525 &saddr_buf, &ipv6_hdr(skb)->saddr, oif);
1526
1527 if (oif != skb->dev->ifindex)
1528 fl6.flowi6_flags |= FLOWI_FLAG_L3MDEV_SRC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
David S. Miller4c9483b2011-03-12 16:22:43 -05001530 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001531 if (dst->error) {
1532 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001534 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001535 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001536 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
1539 rt = (struct rt6_info *) dst;
1540
1541 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001542 ND_PRINTK(2, warn,
1543 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001544 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 }
Martin KaFai Laufd0273d2015-05-22 20:55:57 -07001546 peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1);
David S. Miller1d861aa2012-07-10 03:58:16 -07001547 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1548 if (peer)
1549 inet_putpeer(peer);
1550 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001551 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001554 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1555 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001556 ND_PRINTK(2, warn,
1557 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001558 goto release;
1559 }
1560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 read_lock_bh(&neigh->lock);
1562 if (neigh->nud_state & NUD_VALID) {
1563 memcpy(ha_buf, neigh->ha, dev->addr_len);
1564 read_unlock_bh(&neigh->lock);
1565 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001566 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 } else
1568 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001569
1570 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 }
1572
1573 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001574 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1575 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001577 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001579 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001580 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001581 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001583 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1584 *msg = (struct rd_msg) {
1585 .icmph = {
1586 .icmp6_type = NDISC_REDIRECT,
1587 },
1588 .target = *target,
1589 .dest = ipv6_hdr(skb)->daddr,
1590 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 /*
1593 * include target_address option
1594 */
1595
1596 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001597 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
1599 /*
1600 * build redirect option and copy skb over to the new packet.
1601 */
1602
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001603 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001604 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
Eric Dumazetadf30902009-06-02 05:19:30 +00001606 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001607 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001608 return;
1609
1610release:
1611 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612}
1613
1614static void pndisc_redo(struct sk_buff *skb)
1615{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001616 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 kfree_skb(skb);
1618}
1619
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001620static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1621{
1622 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1623
1624 if (!idev)
1625 return true;
1626 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1627 idev->cnf.suppress_frag_ndisc) {
1628 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1629 return true;
1630 }
1631 return false;
1632}
1633
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634int ndisc_rcv(struct sk_buff *skb)
1635{
1636 struct nd_msg *msg;
1637
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001638 if (ndisc_suppress_frag_ndisc(skb))
1639 return 0;
1640
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001641 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 return 0;
1643
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001644 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001646 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001648 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001649 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1650 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 return 0;
1652 }
1653
1654 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001655 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1656 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 return 0;
1658 }
1659
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001660 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1661
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 switch (msg->icmph.icmp6_type) {
1663 case NDISC_NEIGHBOUR_SOLICITATION:
1664 ndisc_recv_ns(skb);
1665 break;
1666
1667 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1668 ndisc_recv_na(skb);
1669 break;
1670
1671 case NDISC_ROUTER_SOLICITATION:
1672 ndisc_recv_rs(skb);
1673 break;
1674
1675 case NDISC_ROUTER_ADVERTISEMENT:
1676 ndisc_router_discovery(skb);
1677 break;
1678
1679 case NDISC_REDIRECT:
1680 ndisc_redirect_rcv(skb);
1681 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
1684 return 0;
1685}
1686
1687static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1688{
Jiri Pirko351638e2013-05-28 01:30:21 +00001689 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazetc8507fb2015-07-29 12:01:41 +02001690 struct netdev_notifier_change_info *change_info;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001691 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001692 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694 switch (event) {
1695 case NETDEV_CHANGEADDR:
1696 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001697 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001698 idev = in6_dev_get(dev);
1699 if (!idev)
1700 break;
1701 if (idev->cnf.ndisc_notify)
1702 ndisc_send_unsol_na(dev);
1703 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 break;
Eric Dumazetc8507fb2015-07-29 12:01:41 +02001705 case NETDEV_CHANGE:
1706 change_info = ptr;
1707 if (change_info->flags_changed & IFF_NOARP)
1708 neigh_changeaddr(&nd_tbl, dev);
1709 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 case NETDEV_DOWN:
1711 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001712 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001714 case NETDEV_NOTIFY_PEERS:
1715 ndisc_send_unsol_na(dev);
1716 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 default:
1718 break;
1719 }
1720
1721 return NOTIFY_DONE;
1722}
1723
1724static struct notifier_block ndisc_netdev_notifier = {
1725 .notifier_call = ndisc_netdev_event,
1726};
1727
1728#ifdef CONFIG_SYSCTL
1729static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1730 const char *func, const char *dev_name)
1731{
1732 static char warncomm[TASK_COMM_LEN];
1733 static int warned;
1734 if (strcmp(warncomm, current->comm) && warned < 5) {
1735 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001736 pr_warn("process `%s' is using deprecated sysctl (%s) net.ipv6.neigh.%s.%s - use net.ipv6.neigh.%s.%s_ms instead\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 warncomm, func,
1738 dev_name, ctl->procname,
1739 dev_name, ctl->procname);
1740 warned++;
1741 }
1742}
1743
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001744int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745{
1746 struct net_device *dev = ctl->extra1;
1747 struct inet6_dev *idev;
1748 int ret;
1749
Eric W. Biedermand12af672007-10-18 03:05:25 -07001750 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1751 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1753
Eric W. Biedermand12af672007-10-18 03:05:25 -07001754 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001755 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001756
1757 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001758 ret = neigh_proc_dointvec_jiffies(ctl, write,
1759 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001760
1761 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001762 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001763 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1764 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001765 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001769 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1770 idev->nd_parms->reachable_time =
1771 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 idev->tstamp = jiffies;
1773 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1774 in6_dev_put(idev);
1775 }
1776 return ret;
1777}
1778
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
1780#endif
1781
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001782static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783{
1784 struct ipv6_pinfo *np;
1785 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001786 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001788 err = inet_ctl_sock_create(&sk, PF_INET6,
1789 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001791 ND_PRINTK(0, err,
1792 "NDISC: Failed to initialize the control socket (err %d)\n",
1793 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 return err;
1795 }
1796
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001797 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001798
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 np->hop_limit = 255;
1801 /* Do not loopback ndisc messages */
1802 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001804 return 0;
1805}
1806
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001807static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001808{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001809 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001810}
1811
1812static struct pernet_operations ndisc_net_ops = {
1813 .init = ndisc_net_init,
1814 .exit = ndisc_net_exit,
1815};
1816
1817int __init ndisc_init(void)
1818{
1819 int err;
1820
1821 err = register_pernet_subsys(&ndisc_net_ops);
1822 if (err)
1823 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001824 /*
1825 * Initialize the neighbour table
1826 */
WANG Congd7480fd2014-11-10 15:59:36 -08001827 neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
1829#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001830 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301831 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001832 if (err)
1833 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001834out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001835#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001836 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001838#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001839out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001840 unregister_pernet_subsys(&ndisc_net_ops);
1841 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001842#endif
1843}
1844
1845int __init ndisc_late_init(void)
1846{
1847 return register_netdevice_notifier(&ndisc_netdev_notifier);
1848}
1849
1850void ndisc_late_cleanup(void)
1851{
1852 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853}
1854
1855void ndisc_cleanup(void)
1856{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857#ifdef CONFIG_SYSCTL
1858 neigh_sysctl_unregister(&nd_tbl.parms);
1859#endif
WANG Congd7480fd2014-11-10 15:59:36 -08001860 neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001861 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}