blob: a7b9468e684a9764cade298795f2c8753f5c4659 [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
Alexander Aring8ec5da42016-06-15 21:20:21 +0200153static void __ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data,
154 int data_len, int pad)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155{
Alexander Aring8ec5da42016-06-15 21:20:21 +0200156 int space = __ndisc_opt_addr_space(data_len, pad);
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000157 u8 *opt = skb_put(skb, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 opt[0] = type;
160 opt[1] = space>>3;
161
162 memset(opt + 2, 0, pad);
163 opt += pad;
164 space -= pad;
165
166 memcpy(opt+2, data, data_len);
167 data_len += 2;
168 opt += data_len;
Ian Morrise5d08d72014-11-23 21:28:43 +0000169 space -= data_len;
170 if (space > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172}
173
Alexander Aring8ec5da42016-06-15 21:20:21 +0200174static inline void ndisc_fill_addr_option(struct sk_buff *skb, int type,
175 void *data)
176{
177 __ndisc_fill_addr_option(skb, type, data, skb->dev->addr_len,
178 ndisc_addr_option_pad(skb->dev->type));
179}
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
182 struct nd_opt_hdr *end)
183{
184 int type;
185 if (!cur || !end || cur >= end)
186 return NULL;
187 type = cur->nd_opt_type;
188 do {
189 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100190 } while (cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000191 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192}
193
Pierre Ynard31910572007-10-10 21:22:05 -0700194static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
195{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000196 return opt->nd_opt_type == ND_OPT_RDNSS ||
197 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700198}
199
200static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
201 struct nd_opt_hdr *end)
202{
203 if (!cur || !end || cur >= end)
204 return NULL;
205 do {
206 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100207 } while (cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000208 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700209}
210
David S. Miller30f2a5f2012-07-11 23:26:46 -0700211struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
212 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
214 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
215
216 if (!nd_opt || opt_len < 0 || !ndopts)
217 return NULL;
218 memset(ndopts, 0, sizeof(*ndopts));
219 while (opt_len) {
220 int l;
221 if (opt_len < sizeof(struct nd_opt_hdr))
222 return NULL;
223 l = nd_opt->nd_opt_len << 3;
224 if (opt_len < l || l == 0)
225 return NULL;
226 switch (nd_opt->nd_opt_type) {
227 case ND_OPT_SOURCE_LL_ADDR:
228 case ND_OPT_TARGET_LL_ADDR:
229 case ND_OPT_MTU:
230 case ND_OPT_REDIRECT_HDR:
231 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000232 ND_PRINTK(2, warn,
233 "%s: duplicated ND6 option found: type=%d\n",
234 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 } else {
236 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
237 }
238 break;
239 case ND_OPT_PREFIX_INFO:
240 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700241 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
243 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800244#ifdef CONFIG_IPV6_ROUTE_INFO
245 case ND_OPT_ROUTE_INFO:
246 ndopts->nd_opts_ri_end = nd_opt;
247 if (!ndopts->nd_opts_ri)
248 ndopts->nd_opts_ri = nd_opt;
249 break;
250#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700252 if (ndisc_is_useropt(nd_opt)) {
253 ndopts->nd_useropts_end = nd_opt;
254 if (!ndopts->nd_useropts)
255 ndopts->nd_useropts = nd_opt;
256 } else {
257 /*
258 * Unknown options must be silently ignored,
259 * to accommodate future extension to the
260 * protocol.
261 */
Joe Perches675418d2012-05-16 19:28:38 +0000262 ND_PRINTK(2, notice,
263 "%s: ignored unsupported option; type=%d, len=%d\n",
264 __func__,
265 nd_opt->nd_opt_type,
266 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 }
269 opt_len -= l;
270 nd_opt = ((void *)nd_opt) + l;
271 }
272 return ndopts;
273}
274
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000275int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
277 switch (dev->type) {
278 case ARPHRD_ETHER:
279 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
280 case ARPHRD_FDDI:
281 ipv6_eth_mc_map(addr, buf);
282 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 case ARPHRD_ARCNET:
284 ipv6_arcnet_mc_map(addr, buf);
285 return 0;
286 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700287 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000289 case ARPHRD_IPGRE:
290 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 default:
292 if (dir) {
293 memcpy(buf, dev->broadcast, dev->addr_len);
294 return 0;
295 }
296 }
297 return -EINVAL;
298}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900299EXPORT_SYMBOL(ndisc_mc_map);
300
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000301static u32 ndisc_hash(const void *pkey,
302 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500303 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
David S. Miller2c2aba62011-12-28 15:06:58 -0500305 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
Eric W. Biederman60395a22015-03-03 17:10:44 -0600308static bool ndisc_key_eq(const struct neighbour *n, const void *pkey)
309{
310 return neigh_key_eq128(n, pkey);
311}
312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313static int ndisc_constructor(struct neighbour *neigh)
314{
Ian Morris67ba4152014-08-24 21:53:10 +0100315 struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 struct net_device *dev = neigh->dev;
317 struct inet6_dev *in6_dev;
318 struct neigh_parms *parms;
Eric Dumazeta50feda2012-05-18 18:57:34 +0000319 bool is_multicast = ipv6_addr_is_multicast(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 in6_dev = in6_dev_get(dev);
Ian Morris63159f22015-03-29 14:00:04 +0100322 if (!in6_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 return -EINVAL;
324 }
325
326 parms = in6_dev->nd_parms;
327 __neigh_parms_put(neigh->parms);
328 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700331 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 neigh->nud_state = NUD_NOARP;
333 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700334 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 } else {
336 if (is_multicast) {
337 neigh->nud_state = NUD_NOARP;
338 ndisc_mc_map(addr, neigh->ha, dev, 1);
339 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
340 neigh->nud_state = NUD_NOARP;
341 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
342 if (dev->flags&IFF_LOOPBACK)
343 neigh->type = RTN_LOCAL;
344 } else if (dev->flags&IFF_POINTOPOINT) {
345 neigh->nud_state = NUD_NOARP;
346 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
347 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700348 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 neigh->ops = &ndisc_hh_ops;
350 else
351 neigh->ops = &ndisc_generic_ops;
352 if (neigh->nud_state&NUD_VALID)
353 neigh->output = neigh->ops->connected_output;
354 else
355 neigh->output = neigh->ops->output;
356 }
357 in6_dev_put(in6_dev);
358 return 0;
359}
360
361static int pndisc_constructor(struct pneigh_entry *n)
362{
Ian Morris67ba4152014-08-24 21:53:10 +0100363 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 struct in6_addr maddr;
365 struct net_device *dev = n->dev;
366
Ian Morris63159f22015-03-29 14:00:04 +0100367 if (!dev || !__in6_dev_get(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 return -EINVAL;
369 addrconf_addr_solict_mult(addr, &maddr);
370 ipv6_dev_mc_inc(dev, &maddr);
371 return 0;
372}
373
374static void pndisc_destructor(struct pneigh_entry *n)
375{
Ian Morris67ba4152014-08-24 21:53:10 +0100376 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 struct in6_addr maddr;
378 struct net_device *dev = n->dev;
379
Ian Morris63159f22015-03-29 14:00:04 +0100380 if (!dev || !__in6_dev_get(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 return;
382 addrconf_addr_solict_mult(addr, &maddr);
383 ipv6_dev_mc_dec(dev, &maddr);
384}
385
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000386static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
387 int len)
388{
389 int hlen = LL_RESERVED_SPACE(dev);
390 int tlen = dev->needed_tailroom;
391 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
392 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000393
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200394 skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000395 if (!skb) {
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200396 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
397 __func__);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000398 return NULL;
399 }
400
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000401 skb->protocol = htons(ETH_P_IPV6);
402 skb->dev = dev;
403
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000404 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki / 吉藤英明5135e632013-01-21 06:48:44 +0000405 skb_reset_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000406
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200407 /* Manually assign socket ownership as we avoid calling
408 * sock_alloc_send_pskb() to bypass wmem buffer limits
409 */
410 skb_set_owner_w(skb, sk);
411
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000412 return skb;
413}
414
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000415static void ip6_nd_hdr(struct sk_buff *skb,
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000416 const struct in6_addr *saddr,
417 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000418 int hop_limit, int len)
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000419{
420 struct ipv6hdr *hdr;
421
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000422 skb_push(skb, sizeof(*hdr));
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000423 skb_reset_network_header(skb);
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000424 hdr = ipv6_hdr(skb);
425
426 ip6_flow_hdr(hdr, 0, 0);
427
428 hdr->payload_len = htons(len);
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000429 hdr->nexthdr = IPPROTO_ICMPV6;
430 hdr->hop_limit = hop_limit;
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000431
432 hdr->saddr = *saddr;
433 hdr->daddr = *daddr;
434}
435
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000436static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900437 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000438 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800439{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000440 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000441 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000442 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800443 struct inet6_dev *idev;
444 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000445 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800446 u8 type;
447
448 type = icmp6h->icmp6_type;
449
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000450 if (!dst) {
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000451 struct flowi6 fl6;
David Ahernca254492015-10-12 11:47:10 -0700452 int oif = l3mdev_fib_oif(skb->dev);
Brian Haley305d5522008-11-04 17:51:14 -0800453
David Ahernca254492015-10-12 11:47:10 -0700454 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif);
455 if (oif != skb->dev->ifindex)
456 fl6.flowi6_flags |= FLOWI_FLAG_L3MDEV_SRC;
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000457 dst = icmp6_dst_alloc(skb->dev, &fl6);
458 if (IS_ERR(dst)) {
459 kfree_skb(skb);
460 return;
461 }
462
463 skb_dst_set(skb, dst);
464 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900465
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000466 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
467 IPPROTO_ICMPV6,
468 csum_partial(icmp6h,
469 skb->len, 0));
470
471 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
472
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000473 rcu_read_lock();
474 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700475 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900476
Eric W. Biederman29a26a52015-09-15 20:04:16 -0500477 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
478 net, sk, skb, NULL, dst->dev,
Eric W. Biederman13206b62015-10-07 16:48:35 -0500479 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900480 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700481 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700482 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900483 }
484
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000485 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900486}
487
Jiri Benc38cf5952015-09-22 18:57:13 +0200488void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
Cong Wangf564f452013-08-31 13:44:36 +0800489 const struct in6_addr *solicited_addr,
490 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000492 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 struct in6_addr tmpaddr;
494 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900495 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000496 struct nd_msg *msg;
497 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900500 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900501 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700503 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300504 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000505 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 in6_ifa_put(ifp);
507 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700508 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900509 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900510 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 return;
512 src_addr = &tmpaddr;
513 }
514
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000515 if (!dev->addr_len)
516 inc_opt = 0;
517 if (inc_opt)
518 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000520 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000521 if (!skb)
522 return;
523
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000524 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
525 *msg = (struct nd_msg) {
526 .icmph = {
527 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
528 .icmp6_router = router,
529 .icmp6_solicited = solicited,
530 .icmp6_override = override,
531 },
532 .target = *solicited_addr,
533 };
534
535 if (inc_opt)
536 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
537 dev->dev_addr);
538
539
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000540 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900541}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000543static void ndisc_send_unsol_na(struct net_device *dev)
544{
545 struct inet6_dev *idev;
546 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000547
548 idev = in6_dev_get(dev);
549 if (!idev)
550 return;
551
552 read_lock_bh(&idev->lock);
553 list_for_each_entry(ifa, &idev->addr_list, if_list) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200554 ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000555 /*router=*/ !!idev->cnf.forwarding,
556 /*solicited=*/ false, /*override=*/ true,
557 /*inc_opt=*/ true);
558 }
559 read_unlock_bh(&idev->lock);
560
561 in6_dev_put(idev);
562}
563
Jiri Benc38cf5952015-09-22 18:57:13 +0200564void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
Nicolas Dichtel304d8882015-11-27 18:17:05 +0100565 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000567 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000569 int inc_opt = dev->addr_len;
570 int optlen = 0;
571 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Ian Morris63159f22015-03-29 14:00:04 +0100573 if (!saddr) {
Neil Horman95c385b2007-04-25 17:08:10 -0700574 if (ipv6_get_lladdr(dev, &addr_buf,
575 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return;
577 saddr = &addr_buf;
578 }
579
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000580 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300581 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000582 if (inc_opt)
583 optlen += ndisc_opt_addr_space(dev);
584
585 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000586 if (!skb)
587 return;
588
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000589 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
590 *msg = (struct nd_msg) {
591 .icmph = {
592 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
593 },
594 .target = *solicit,
595 };
596
597 if (inc_opt)
598 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
599 dev->dev_addr);
600
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000601 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602}
603
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900604void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
605 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000607 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000608 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700609 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000610 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700611
612#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
613 /*
614 * According to section 2.2 of RFC 4429, we must not
615 * send router solicitations with a sllao from
616 * optimistic addresses, but we may send the solicitation
617 * if we don't include the sllao. So here we check
618 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800619 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700620 */
621 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900622 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800623 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700624 if (ifp) {
625 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900626 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700627 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900628 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700629 } else {
630 send_sllao = 0;
631 }
632 }
633#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000634 if (send_sllao)
635 optlen += ndisc_opt_addr_space(dev);
636
637 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000638 if (!skb)
639 return;
640
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000641 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
642 *msg = (struct rs_msg) {
643 .icmph = {
644 .icmp6_type = NDISC_ROUTER_SOLICITATION,
645 },
646 };
647
648 if (send_sllao)
649 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
650 dev->dev_addr);
651
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000652 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
657{
658 /*
659 * "The sender MUST return an ICMP
660 * destination unreachable"
661 */
662 dst_link_failure(skb);
663 kfree_skb(skb);
664}
665
666/* Called with locked neigh: either read or both */
667
668static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
669{
670 struct in6_addr *saddr = NULL;
671 struct in6_addr mcaddr;
672 struct net_device *dev = neigh->dev;
673 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
674 int probes = atomic_read(&neigh->probes);
675
Erik Klinec58da4c2015-02-04 20:01:23 +0900676 if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
677 dev, 1,
678 IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700679 saddr = &ipv6_hdr(skb)->saddr;
Ian Morrise5d08d72014-11-23 21:28:43 +0000680 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
681 if (probes < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000683 ND_PRINTK(1, dbg,
684 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
685 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
Nicolas Dichtel304d8882015-11-27 18:17:05 +0100687 ndisc_send_ns(dev, target, target, saddr);
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100688 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 } else {
691 addrconf_addr_solict_mult(target, &mcaddr);
Nicolas Dichtel304d8882015-11-27 18:17:05 +0100692 ndisc_send_ns(dev, target, &mcaddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
694}
695
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900696static int pndisc_is_router(const void *pkey,
697 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700698{
699 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900700 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700701
702 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900703 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
704 if (n)
705 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700706 read_unlock_bh(&nd_tbl.lock);
707
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900708 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700709}
710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711static void ndisc_recv_ns(struct sk_buff *skb)
712{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700713 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000714 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
715 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000717 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700718 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 struct ndisc_options ndopts;
720 struct net_device *dev = skb->dev;
721 struct inet6_ifaddr *ifp;
722 struct inet6_dev *idev = NULL;
723 struct neighbour *neigh;
724 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000725 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900726 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000728 if (skb->len < sizeof(struct nd_msg)) {
729 ND_PRINTK(2, warn, "NS: packet too short\n");
730 return;
731 }
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000734 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return;
736 }
737
738 /*
739 * RFC2461 7.1.1:
740 * DAD has to be destined for solicited node multicast address.
741 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000742 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000743 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return;
745 }
746
747 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000748 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 return;
750 }
751
752 if (ndopts.nd_opts_src_lladdr) {
753 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
754 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000755 ND_PRINTK(2, warn,
756 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return;
758 }
759
760 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900761 * If the IP source address is the unspecified address,
762 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 * in the message.
764 */
765 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000766 ND_PRINTK(2, warn,
767 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 return;
769 }
770 }
771
772 inc = ipv6_addr_is_multicast(daddr);
773
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900774 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800775 if (ifp) {
David Ahernca254492015-10-12 11:47:10 -0700776have_ifp:
Neil Horman95c385b2007-04-25 17:08:10 -0700777 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
778 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700779 /*
780 * We are colliding with another node
781 * who is doing DAD
782 * so fail our DAD process
783 */
784 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200785 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700786 } else {
787 /*
788 * This is not a dad solicitation.
789 * If we are an optimistic node,
790 * we should respond.
791 * Otherwise, we should ignore it.
792 */
793 if (!(ifp->flags & IFA_F_OPTIMISTIC))
794 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
797
798 idev = ifp->idev;
799 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700800 struct net *net = dev_net(dev);
801
David Ahernca254492015-10-12 11:47:10 -0700802 /* perhaps an address on the master device */
803 if (netif_is_l3_slave(dev)) {
804 struct net_device *mdev;
805
806 mdev = netdev_master_upper_dev_get_rcu(dev);
807 if (mdev) {
808 ifp = ipv6_get_ifaddr(net, &msg->target, mdev, 1);
809 if (ifp)
810 goto have_ifp;
811 }
812 }
813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 idev = in6_dev_get(dev);
815 if (!idev) {
816 /* XXX: count this drop? */
817 return;
818 }
819
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700820 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900821 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700822 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900823 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700824 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300826 inc &&
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100827 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 /*
829 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900830 * sender should delay its response
831 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 * MAX_ANYCAST_DELAY_TIME seconds.
833 * (RFC2461) -- yoshfuji
834 */
835 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
836 if (n)
837 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
838 goto out;
839 }
840 } else
841 goto out;
842 }
843
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900844 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000845 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (dad) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200848 ndisc_send_na(dev, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000849 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 goto out;
851 }
852
853 if (inc)
854 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
855 else
856 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
857
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900858 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 * update / create cache entry
860 * for the source address
861 */
862 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
863 !inc || lladdr || !dev->addr_len);
864 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900865 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 NEIGH_UPDATE_F_WEAK_OVERRIDE|
867 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700868 if (neigh || !dev->header_ops) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200869 ndisc_send_na(dev, saddr, &msg->target, !!is_router,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000870 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 if (neigh)
872 neigh_release(neigh);
873 }
874
875out:
876 if (ifp)
877 in6_ifa_put(ifp);
878 else
879 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880}
881
882static void ndisc_recv_na(struct sk_buff *skb)
883{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700884 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800885 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000886 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000888 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700889 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 struct ndisc_options ndopts;
891 struct net_device *dev = skb->dev;
Johannes Berg7a02bf82016-02-04 13:31:20 +0100892 struct inet6_dev *idev = __in6_dev_get(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 struct inet6_ifaddr *ifp;
894 struct neighbour *neigh;
895
896 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000897 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 return;
899 }
900
901 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000902 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 return;
904 }
905
906 if (ipv6_addr_is_multicast(daddr) &&
907 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000908 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return;
910 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900911
Johannes Berg7a02bf82016-02-04 13:31:20 +0100912 /* For some 802.11 wireless deployments (and possibly other networks),
913 * there will be a NA proxy and unsolicitd packets are attacks
914 * and thus should not be accepted.
915 */
916 if (!msg->icmph.icmp6_solicited && idev &&
917 idev->cnf.drop_unsolicited_na)
918 return;
919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000921 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 return;
923 }
924 if (ndopts.nd_opts_tgt_lladdr) {
925 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
926 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000927 ND_PRINTK(2, warn,
928 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 return;
930 }
931 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900932 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800933 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000934 if (skb->pkt_type != PACKET_LOOPBACK
935 && (ifp->flags & IFA_F_TENTATIVE)) {
936 addrconf_dad_failure(ifp);
937 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 }
939 /* What should we make now? The advertisement
940 is invalid, but ndisc specs say nothing
941 about it. It could be misconfiguration, or
942 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800943
944 We should not print the error if NA has been
945 received from loopback - it is just our own
946 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800948 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000949 ND_PRINTK(1, warn,
950 "NA: someone advertises our address %pI6 on %s!\n",
951 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 in6_ifa_put(ifp);
953 return;
954 }
955 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
956
957 if (neigh) {
958 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700959 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 if (neigh->nud_state & NUD_FAILED)
962 goto out;
963
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700964 /*
965 * Don't update the neighbor cache entry on a proxy NA from
966 * ourselves because either the proxied node is off link or it
967 * has already sent a NA to us.
968 */
969 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700970 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
971 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000972 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700973 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700974 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 neigh_update(neigh, lladdr,
977 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
978 NEIGH_UPDATE_F_WEAK_OVERRIDE|
979 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
980 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
981 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
982
983 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
984 /*
985 * Change: router to host
986 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800987 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 }
989
990out:
991 neigh_release(neigh);
992 }
993}
994
995static void ndisc_recv_rs(struct sk_buff *skb)
996{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700997 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
999 struct neighbour *neigh;
1000 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001001 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 struct ndisc_options ndopts;
1003 u8 *lladdr = NULL;
1004
1005 if (skb->len < sizeof(*rs_msg))
1006 return;
1007
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001008 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +00001010 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return;
1012 }
1013
1014 /* Don't accept RS if we're not in router mode */
1015 if (!idev->cnf.forwarding)
1016 goto out;
1017
1018 /*
1019 * Don't update NCE if src = ::;
1020 * this implies that the source node has no ip address assigned yet.
1021 */
1022 if (ipv6_addr_any(saddr))
1023 goto out;
1024
1025 /* Parse ND options */
1026 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001027 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 goto out;
1029 }
1030
1031 if (ndopts.nd_opts_src_lladdr) {
1032 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1033 skb->dev);
1034 if (!lladdr)
1035 goto out;
1036 }
1037
1038 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1039 if (neigh) {
1040 neigh_update(neigh, lladdr, NUD_STALE,
1041 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1042 NEIGH_UPDATE_F_OVERRIDE|
1043 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1044 neigh_release(neigh);
1045 }
1046out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001047 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048}
1049
Pierre Ynard31910572007-10-10 21:22:05 -07001050static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1051{
1052 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1053 struct sk_buff *skb;
1054 struct nlmsghdr *nlh;
1055 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001056 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001057 int err;
1058 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1059 + (opt->nd_opt_len << 3));
1060 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1061
1062 skb = nlmsg_new(msg_size, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01001063 if (!skb) {
Pierre Ynard31910572007-10-10 21:22:05 -07001064 err = -ENOBUFS;
1065 goto errout;
1066 }
1067
1068 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
Ian Morris63159f22015-03-29 14:00:04 +01001069 if (!nlh) {
Pierre Ynard31910572007-10-10 21:22:05 -07001070 goto nla_put_failure;
1071 }
1072
1073 ndmsg = nlmsg_data(nlh);
1074 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001075 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001076 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1077 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1078 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1079
1080 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1081
Jiri Benc930345e2015-03-29 16:59:25 +02001082 if (nla_put_in6_addr(skb, NDUSEROPT_SRCADDR, &ipv6_hdr(ra)->saddr))
David S. Millerc78679e2012-04-01 20:27:33 -04001083 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001084 nlmsg_end(skb, nlh);
1085
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001086 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001087 return;
1088
1089nla_put_failure:
1090 nlmsg_free(skb);
1091 err = -EMSGSIZE;
1092errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001093 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001094}
1095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096static void ndisc_router_discovery(struct sk_buff *skb)
1097{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001098 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 struct neighbour *neigh = NULL;
1100 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001101 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 int lifetime;
1103 struct ndisc_options ndopts;
1104 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001105 unsigned int pref = 0;
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001106 __u32 old_if_flags;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001107 bool send_ifinfo_notify = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Ian Morris67ba4152014-08-24 21:53:10 +01001109 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Simon Horman29a3cad2013-05-28 20:34:26 +00001111 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1112 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Ben Greearf2a762d2014-06-25 14:44:52 -07001114 ND_PRINTK(2, info,
1115 "RA: %s, dev: %s\n",
1116 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001117 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001118 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 return;
1120 }
1121 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001122 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 return;
1124 }
1125
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001126#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001127 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001128 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001129 return;
1130 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001131#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 /*
1134 * set the RA_RECV flag in the interface
1135 */
1136
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001137 in6_dev = __in6_dev_get(skb->dev);
Ian Morris63159f22015-03-29 14:00:04 +01001138 if (!in6_dev) {
Joe Perches675418d2012-05-16 19:28:38 +00001139 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1140 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 return;
1142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001145 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 return;
1147 }
1148
Ben Greearf2a762d2014-06-25 14:44:52 -07001149 if (!ipv6_accept_ra(in6_dev)) {
1150 ND_PRINTK(2, info,
1151 "RA: %s, did not accept ra for dev: %s\n",
1152 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001153 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001154 }
David Ward31ce8c72009-08-29 00:04:09 -07001155
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001156#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001157 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001158 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1159 ND_PRINTK(2, info,
1160 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1161 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001162 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001163 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001164#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001165
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 if (in6_dev->if_flags & IF_RS_SENT) {
1167 /*
1168 * flag that an RA was received after an RS was sent
1169 * out on this interface.
1170 */
1171 in6_dev->if_flags |= IF_RA_RCVD;
1172 }
1173
1174 /*
1175 * Remember the managed/otherconf flags from most recently
1176 * received RA message (RFC 2462) -- yoshfuji
1177 */
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001178 old_if_flags = in6_dev->if_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1180 IF_RA_OTHERCONF)) |
1181 (ra_msg->icmph.icmp6_addrconf_managed ?
1182 IF_RA_MANAGED : 0) |
1183 (ra_msg->icmph.icmp6_addrconf_other ?
1184 IF_RA_OTHERCONF : 0);
1185
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001186 if (old_if_flags != in6_dev->if_flags)
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001187 send_ifinfo_notify = true;
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001188
Ben Greearf2a762d2014-06-25 14:44:52 -07001189 if (!in6_dev->cnf.accept_ra_defrtr) {
1190 ND_PRINTK(2, info,
1191 "RA: %s, defrtr is false for dev: %s\n",
1192 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001193 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001194 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001195
Ben Greeard9333192014-06-25 14:44:53 -07001196 /* Do not accept RA with source-addr found on local machine unless
1197 * accept_ra_from_local is set to true.
1198 */
Li RongQingb6428812014-07-10 18:02:46 +08001199 if (!in6_dev->cnf.accept_ra_from_local &&
1200 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
Hannes Frederic Sowac1a9a292015-12-23 22:44:37 +01001201 in6_dev->dev, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001202 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001203 "RA from local address detected on dev: %s: default router ignored\n",
1204 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001205 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001206 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1209
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001210#ifdef CONFIG_IPV6_ROUTER_PREF
1211 pref = ra_msg->icmph.icmp6_router_pref;
1212 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001213 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001214 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001215 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1216#endif
1217
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001218 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
David S. Millereb857182012-01-27 15:07:56 -08001220 if (rt) {
1221 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1222 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001223 ND_PRINTK(0, err,
1224 "RA: %s got default router without neighbour\n",
1225 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001226 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001227 return;
1228 }
1229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001231 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 rt = NULL;
1233 }
1234
Ben Greearf2a762d2014-06-25 14:44:52 -07001235 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1236 rt, lifetime, skb->dev->name);
Ian Morris63159f22015-03-29 14:00:04 +01001237 if (!rt && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001238 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001240 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Ian Morris63159f22015-03-29 14:00:04 +01001241 if (!rt) {
Joe Perches675418d2012-05-16 19:28:38 +00001242 ND_PRINTK(0, err,
1243 "RA: %s failed to add default route\n",
1244 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 return;
1246 }
1247
David S. Millereb857182012-01-27 15:07:56 -08001248 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Ian Morris63159f22015-03-29 14:00:04 +01001249 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001250 ND_PRINTK(0, err,
1251 "RA: %s got default router without neighbour\n",
1252 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001253 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 return;
1255 }
1256 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001257 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001258 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260
1261 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001262 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001263 if (in6_dev->cnf.accept_ra_min_hop_limit < 256 &&
1264 ra_msg->icmph.icmp6_hop_limit) {
1265 if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) {
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001266 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001267 if (rt)
1268 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1269 ra_msg->icmph.icmp6_hop_limit);
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001270 } else {
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001271 ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than minimum\n");
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 }
1274
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001275skip_defrtr:
1276
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 /*
1278 * Update Reachable Time and Retrans Timer
1279 */
1280
1281 if (in6_dev->nd_parms) {
1282 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1283
1284 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1285 rtime = (rtime*HZ)/1000;
1286 if (rtime < HZ/10)
1287 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001288 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 in6_dev->tstamp = jiffies;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001290 send_ifinfo_notify = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 }
1292
1293 rtime = ntohl(ra_msg->reachable_time);
1294 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1295 rtime = (rtime*HZ)/1000;
1296
1297 if (rtime < HZ/10)
1298 rtime = HZ/10;
1299
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001300 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1301 NEIGH_VAR_SET(in6_dev->nd_parms,
1302 BASE_REACHABLE_TIME, rtime);
1303 NEIGH_VAR_SET(in6_dev->nd_parms,
1304 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1306 in6_dev->tstamp = jiffies;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001307 send_ifinfo_notify = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 }
1309 }
1310 }
1311
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001312 /*
1313 * Send a notify if RA changed managed/otherconf flags or timer settings
1314 */
1315 if (send_ifinfo_notify)
1316 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1317
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001318skip_linkparms:
1319
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 /*
1321 * Process options.
1322 */
1323
1324 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001325 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 skb->dev, 1);
1327 if (neigh) {
1328 u8 *lladdr = NULL;
1329 if (ndopts.nd_opts_src_lladdr) {
1330 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1331 skb->dev);
1332 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001333 ND_PRINTK(2, warn,
1334 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 goto out;
1336 }
1337 }
1338 neigh_update(neigh, lladdr, NUD_STALE,
1339 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1340 NEIGH_UPDATE_F_OVERRIDE|
1341 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1342 NEIGH_UPDATE_F_ISROUTER);
1343 }
1344
Ben Greearf2a762d2014-06-25 14:44:52 -07001345 if (!ipv6_accept_ra(in6_dev)) {
1346 ND_PRINTK(2, info,
1347 "RA: %s, accept_ra is false for dev: %s\n",
1348 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001349 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001350 }
David Ward31ce8c72009-08-29 00:04:09 -07001351
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001352#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001353 if (!in6_dev->cnf.accept_ra_from_local &&
1354 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
Hannes Frederic Sowac1a9a292015-12-23 22:44:37 +01001355 in6_dev->dev, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001356 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001357 "RA from local address detected on dev: %s: router info ignored.\n",
1358 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001359 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001360 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001361
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001362 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001363 struct nd_opt_hdr *p;
1364 for (p = ndopts.nd_opts_ri;
1365 p;
1366 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001367 struct route_info *ri = (struct route_info *)p;
1368#ifdef CONFIG_IPV6_NDISC_NODETYPE
1369 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1370 ri->prefix_len == 0)
1371 continue;
1372#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001373 if (ri->prefix_len == 0 &&
1374 !in6_dev->cnf.accept_ra_defrtr)
1375 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001376 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001377 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001378 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001379 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001380 }
1381 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001382
1383skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001384#endif
1385
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001386#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001387 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001388 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1389 ND_PRINTK(2, info,
1390 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1391 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001392 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001393 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001394#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001395
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001396 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 struct nd_opt_hdr *p;
1398 for (p = ndopts.nd_opts_pi;
1399 p;
1400 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001401 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1402 (p->nd_opt_len) << 3,
1403 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
1405 }
1406
Harout Hedeshianc2943f12015-01-20 10:06:05 -07001407 if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001408 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 u32 mtu;
1410
Ian Morris67ba4152014-08-24 21:53:10 +01001411 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4adc2006-11-14 20:56:00 -08001412 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
1414 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001415 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 } else if (in6_dev->cnf.mtu6 != mtu) {
1417 in6_dev->cnf.mtu6 = mtu;
1418
1419 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001420 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
1422 rt6_mtu_change(skb->dev, mtu);
1423 }
1424 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001425
Pierre Ynard31910572007-10-10 21:22:05 -07001426 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001427 struct nd_opt_hdr *p;
1428 for (p = ndopts.nd_useropts;
1429 p;
1430 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1431 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001432 }
1433 }
1434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001436 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 }
1438out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001439 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001440 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442}
1443
1444static void ndisc_redirect_rcv(struct sk_buff *skb)
1445{
Duan Jiong093d04d2012-12-14 02:59:59 +00001446 u8 *hdr;
1447 struct ndisc_options ndopts;
1448 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001449 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001450 offsetof(struct rd_msg, opt));
1451
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001452#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001453 switch (skb->ndisc_nodetype) {
1454 case NDISC_NODETYPE_HOST:
1455 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001456 ND_PRINTK(2, warn,
1457 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001458 return;
1459 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001460#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001461
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001462 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001463 ND_PRINTK(2, warn,
1464 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 return;
1466 }
1467
Duan Jiong093d04d2012-12-14 02:59:59 +00001468 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1469 return;
1470
Duan Jiongc92a59e2013-08-22 12:07:35 +08001471 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001472 ip6_redirect_no_header(skb, dev_net(skb->dev),
1473 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001474 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001475 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001476
1477 hdr = (u8 *)ndopts.nd_opts_rh;
1478 hdr += 8;
1479 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1480 return;
1481
David S. Millerb94f1c02012-07-12 00:33:37 -07001482 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483}
1484
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001485static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1486 struct sk_buff *orig_skb,
1487 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001488{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001489 u8 *opt = skb_put(skb, rd_len);
1490
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001491 memset(opt, 0, 8);
1492 *(opt++) = ND_OPT_REDIRECT_HDR;
1493 *(opt++) = (rd_len >> 3);
1494 opt += 6;
1495
1496 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001497}
1498
David S. Miller49919692012-01-27 15:30:48 -08001499void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001501 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001502 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001503 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001504 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001505 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001507 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 struct rt6_info *rt;
1510 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001511 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David Ahernca254492015-10-12 11:47:10 -07001514 int oif = l3mdev_fib_oif(dev);
David S. Miller1d861aa2012-07-10 03:58:16 -07001515 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
Neil Horman95c385b2007-04-25 17:08:10 -07001517 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001518 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1519 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001520 return;
1521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001523 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001524 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001525 ND_PRINTK(2, warn,
1526 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001527 return;
1528 }
1529
David S. Miller4c9483b2011-03-12 16:22:43 -05001530 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
David Ahernca254492015-10-12 11:47:10 -07001531 &saddr_buf, &ipv6_hdr(skb)->saddr, oif);
1532
1533 if (oif != skb->dev->ifindex)
1534 fl6.flowi6_flags |= FLOWI_FLAG_L3MDEV_SRC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
David S. Miller4c9483b2011-03-12 16:22:43 -05001536 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001537 if (dst->error) {
1538 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001540 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001541 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001542 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
1545 rt = (struct rt6_info *) dst;
1546
1547 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001548 ND_PRINTK(2, warn,
1549 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001550 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 }
Martin KaFai Laufd0273d2015-05-22 20:55:57 -07001552 peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1);
David S. Miller1d861aa2012-07-10 03:58:16 -07001553 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1554 if (peer)
1555 inet_putpeer(peer);
1556 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001557 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
1559 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001560 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1561 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001562 ND_PRINTK(2, warn,
1563 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001564 goto release;
1565 }
1566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 read_lock_bh(&neigh->lock);
1568 if (neigh->nud_state & NUD_VALID) {
1569 memcpy(ha_buf, neigh->ha, dev->addr_len);
1570 read_unlock_bh(&neigh->lock);
1571 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001572 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 } else
1574 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001575
1576 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
1578
1579 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001580 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1581 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001583 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001585 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001586 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001587 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001589 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1590 *msg = (struct rd_msg) {
1591 .icmph = {
1592 .icmp6_type = NDISC_REDIRECT,
1593 },
1594 .target = *target,
1595 .dest = ipv6_hdr(skb)->daddr,
1596 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 /*
1599 * include target_address option
1600 */
1601
1602 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001603 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
1605 /*
1606 * build redirect option and copy skb over to the new packet.
1607 */
1608
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001609 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001610 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
Eric Dumazetadf30902009-06-02 05:19:30 +00001612 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001613 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001614 return;
1615
1616release:
1617 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618}
1619
1620static void pndisc_redo(struct sk_buff *skb)
1621{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001622 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 kfree_skb(skb);
1624}
1625
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001626static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1627{
1628 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1629
1630 if (!idev)
1631 return true;
1632 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1633 idev->cnf.suppress_frag_ndisc) {
1634 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1635 return true;
1636 }
1637 return false;
1638}
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640int ndisc_rcv(struct sk_buff *skb)
1641{
1642 struct nd_msg *msg;
1643
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001644 if (ndisc_suppress_frag_ndisc(skb))
1645 return 0;
1646
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001647 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 return 0;
1649
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001650 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001652 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001654 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001655 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1656 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 return 0;
1658 }
1659
1660 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001661 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1662 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 return 0;
1664 }
1665
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001666 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 switch (msg->icmph.icmp6_type) {
1669 case NDISC_NEIGHBOUR_SOLICITATION:
1670 ndisc_recv_ns(skb);
1671 break;
1672
1673 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1674 ndisc_recv_na(skb);
1675 break;
1676
1677 case NDISC_ROUTER_SOLICITATION:
1678 ndisc_recv_rs(skb);
1679 break;
1680
1681 case NDISC_ROUTER_ADVERTISEMENT:
1682 ndisc_router_discovery(skb);
1683 break;
1684
1685 case NDISC_REDIRECT:
1686 ndisc_redirect_rcv(skb);
1687 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 return 0;
1691}
1692
1693static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1694{
Jiri Pirko351638e2013-05-28 01:30:21 +00001695 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazetc8507fb2015-07-29 12:01:41 +02001696 struct netdev_notifier_change_info *change_info;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001697 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001698 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 switch (event) {
1701 case NETDEV_CHANGEADDR:
1702 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001703 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001704 idev = in6_dev_get(dev);
1705 if (!idev)
1706 break;
1707 if (idev->cnf.ndisc_notify)
1708 ndisc_send_unsol_na(dev);
1709 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 break;
Eric Dumazetc8507fb2015-07-29 12:01:41 +02001711 case NETDEV_CHANGE:
1712 change_info = ptr;
1713 if (change_info->flags_changed & IFF_NOARP)
1714 neigh_changeaddr(&nd_tbl, dev);
1715 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 case NETDEV_DOWN:
1717 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001718 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001720 case NETDEV_NOTIFY_PEERS:
1721 ndisc_send_unsol_na(dev);
1722 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 default:
1724 break;
1725 }
1726
1727 return NOTIFY_DONE;
1728}
1729
1730static struct notifier_block ndisc_netdev_notifier = {
1731 .notifier_call = ndisc_netdev_event,
1732};
1733
1734#ifdef CONFIG_SYSCTL
1735static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1736 const char *func, const char *dev_name)
1737{
1738 static char warncomm[TASK_COMM_LEN];
1739 static int warned;
1740 if (strcmp(warncomm, current->comm) && warned < 5) {
1741 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001742 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 -07001743 warncomm, func,
1744 dev_name, ctl->procname,
1745 dev_name, ctl->procname);
1746 warned++;
1747 }
1748}
1749
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001750int 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 -07001751{
1752 struct net_device *dev = ctl->extra1;
1753 struct inet6_dev *idev;
1754 int ret;
1755
Eric W. Biedermand12af672007-10-18 03:05:25 -07001756 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1757 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1759
Eric W. Biedermand12af672007-10-18 03:05:25 -07001760 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001761 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001762
1763 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001764 ret = neigh_proc_dointvec_jiffies(ctl, write,
1765 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001766
1767 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001768 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001769 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1770 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001771 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001775 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1776 idev->nd_parms->reachable_time =
1777 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 idev->tstamp = jiffies;
1779 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1780 in6_dev_put(idev);
1781 }
1782 return ret;
1783}
1784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
1786#endif
1787
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001788static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
1790 struct ipv6_pinfo *np;
1791 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001792 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001794 err = inet_ctl_sock_create(&sk, PF_INET6,
1795 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001797 ND_PRINTK(0, err,
1798 "NDISC: Failed to initialize the control socket (err %d)\n",
1799 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 return err;
1801 }
1802
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001803 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 np->hop_limit = 255;
1807 /* Do not loopback ndisc messages */
1808 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001810 return 0;
1811}
1812
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001813static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001814{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001815 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001816}
1817
1818static struct pernet_operations ndisc_net_ops = {
1819 .init = ndisc_net_init,
1820 .exit = ndisc_net_exit,
1821};
1822
1823int __init ndisc_init(void)
1824{
1825 int err;
1826
1827 err = register_pernet_subsys(&ndisc_net_ops);
1828 if (err)
1829 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001830 /*
1831 * Initialize the neighbour table
1832 */
WANG Congd7480fd2014-11-10 15:59:36 -08001833 neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
1835#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001836 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301837 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001838 if (err)
1839 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001840out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001841#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001842 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001844#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001845out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001846 unregister_pernet_subsys(&ndisc_net_ops);
1847 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001848#endif
1849}
1850
1851int __init ndisc_late_init(void)
1852{
1853 return register_netdevice_notifier(&ndisc_netdev_notifier);
1854}
1855
1856void ndisc_late_cleanup(void)
1857{
1858 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859}
1860
1861void ndisc_cleanup(void)
1862{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863#ifdef CONFIG_SYSCTL
1864 neigh_sysctl_unregister(&nd_tbl.parms);
1865#endif
WANG Congd7480fd2014-11-10 15:59:36 -08001866 neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001867 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868}