blob: d6161e1c48c86f4a5dfa5cedc89d4b93f8e3d24a [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;
886 struct inet6_ifaddr *ifp;
887 struct neighbour *neigh;
888
889 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000890 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return;
892 }
893
894 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000895 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 return;
897 }
898
899 if (ipv6_addr_is_multicast(daddr) &&
900 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000901 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return;
903 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000906 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 return;
908 }
909 if (ndopts.nd_opts_tgt_lladdr) {
910 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
911 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000912 ND_PRINTK(2, warn,
913 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 return;
915 }
916 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900917 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800918 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000919 if (skb->pkt_type != PACKET_LOOPBACK
920 && (ifp->flags & IFA_F_TENTATIVE)) {
921 addrconf_dad_failure(ifp);
922 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 }
924 /* What should we make now? The advertisement
925 is invalid, but ndisc specs say nothing
926 about it. It could be misconfiguration, or
927 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800928
929 We should not print the error if NA has been
930 received from loopback - it is just our own
931 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800933 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000934 ND_PRINTK(1, warn,
935 "NA: someone advertises our address %pI6 on %s!\n",
936 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 in6_ifa_put(ifp);
938 return;
939 }
940 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
941
942 if (neigh) {
943 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700944 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 if (neigh->nud_state & NUD_FAILED)
947 goto out;
948
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700949 /*
950 * Don't update the neighbor cache entry on a proxy NA from
951 * ourselves because either the proxied node is off link or it
952 * has already sent a NA to us.
953 */
954 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700955 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
956 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000957 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700958 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700959 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 neigh_update(neigh, lladdr,
962 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
963 NEIGH_UPDATE_F_WEAK_OVERRIDE|
964 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
965 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
966 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
967
968 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
969 /*
970 * Change: router to host
971 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800972 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 }
974
975out:
976 neigh_release(neigh);
977 }
978}
979
980static void ndisc_recv_rs(struct sk_buff *skb)
981{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700982 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
984 struct neighbour *neigh;
985 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000986 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 struct ndisc_options ndopts;
988 u8 *lladdr = NULL;
989
990 if (skb->len < sizeof(*rs_msg))
991 return;
992
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000993 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000995 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return;
997 }
998
999 /* Don't accept RS if we're not in router mode */
1000 if (!idev->cnf.forwarding)
1001 goto out;
1002
1003 /*
1004 * Don't update NCE if src = ::;
1005 * this implies that the source node has no ip address assigned yet.
1006 */
1007 if (ipv6_addr_any(saddr))
1008 goto out;
1009
1010 /* Parse ND options */
1011 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001012 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 goto out;
1014 }
1015
1016 if (ndopts.nd_opts_src_lladdr) {
1017 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1018 skb->dev);
1019 if (!lladdr)
1020 goto out;
1021 }
1022
1023 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1024 if (neigh) {
1025 neigh_update(neigh, lladdr, NUD_STALE,
1026 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1027 NEIGH_UPDATE_F_OVERRIDE|
1028 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1029 neigh_release(neigh);
1030 }
1031out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001032 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
Pierre Ynard31910572007-10-10 21:22:05 -07001035static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1036{
1037 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1038 struct sk_buff *skb;
1039 struct nlmsghdr *nlh;
1040 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001041 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001042 int err;
1043 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1044 + (opt->nd_opt_len << 3));
1045 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1046
1047 skb = nlmsg_new(msg_size, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01001048 if (!skb) {
Pierre Ynard31910572007-10-10 21:22:05 -07001049 err = -ENOBUFS;
1050 goto errout;
1051 }
1052
1053 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
Ian Morris63159f22015-03-29 14:00:04 +01001054 if (!nlh) {
Pierre Ynard31910572007-10-10 21:22:05 -07001055 goto nla_put_failure;
1056 }
1057
1058 ndmsg = nlmsg_data(nlh);
1059 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001060 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001061 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1062 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1063 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1064
1065 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1066
Jiri Benc930345e2015-03-29 16:59:25 +02001067 if (nla_put_in6_addr(skb, NDUSEROPT_SRCADDR, &ipv6_hdr(ra)->saddr))
David S. Millerc78679e2012-04-01 20:27:33 -04001068 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001069 nlmsg_end(skb, nlh);
1070
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001071 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001072 return;
1073
1074nla_put_failure:
1075 nlmsg_free(skb);
1076 err = -EMSGSIZE;
1077errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001078 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001079}
1080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081static void ndisc_router_discovery(struct sk_buff *skb)
1082{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001083 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 struct neighbour *neigh = NULL;
1085 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001086 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 int lifetime;
1088 struct ndisc_options ndopts;
1089 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001090 unsigned int pref = 0;
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001091 __u32 old_if_flags;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001092 bool send_ifinfo_notify = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
Ian Morris67ba4152014-08-24 21:53:10 +01001094 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Simon Horman29a3cad2013-05-28 20:34:26 +00001096 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1097 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Ben Greearf2a762d2014-06-25 14:44:52 -07001099 ND_PRINTK(2, info,
1100 "RA: %s, dev: %s\n",
1101 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001102 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001103 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 return;
1105 }
1106 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001107 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return;
1109 }
1110
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001111#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001112 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001113 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001114 return;
1115 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001116#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 /*
1119 * set the RA_RECV flag in the interface
1120 */
1121
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001122 in6_dev = __in6_dev_get(skb->dev);
Ian Morris63159f22015-03-29 14:00:04 +01001123 if (!in6_dev) {
Joe Perches675418d2012-05-16 19:28:38 +00001124 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1125 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 return;
1127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001130 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 return;
1132 }
1133
Ben Greearf2a762d2014-06-25 14:44:52 -07001134 if (!ipv6_accept_ra(in6_dev)) {
1135 ND_PRINTK(2, info,
1136 "RA: %s, did not accept ra for dev: %s\n",
1137 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001138 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001139 }
David Ward31ce8c72009-08-29 00:04:09 -07001140
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001141#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001142 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001143 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1144 ND_PRINTK(2, info,
1145 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1146 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001147 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001148 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001149#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 if (in6_dev->if_flags & IF_RS_SENT) {
1152 /*
1153 * flag that an RA was received after an RS was sent
1154 * out on this interface.
1155 */
1156 in6_dev->if_flags |= IF_RA_RCVD;
1157 }
1158
1159 /*
1160 * Remember the managed/otherconf flags from most recently
1161 * received RA message (RFC 2462) -- yoshfuji
1162 */
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001163 old_if_flags = in6_dev->if_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1165 IF_RA_OTHERCONF)) |
1166 (ra_msg->icmph.icmp6_addrconf_managed ?
1167 IF_RA_MANAGED : 0) |
1168 (ra_msg->icmph.icmp6_addrconf_other ?
1169 IF_RA_OTHERCONF : 0);
1170
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001171 if (old_if_flags != in6_dev->if_flags)
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001172 send_ifinfo_notify = true;
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001173
Ben Greearf2a762d2014-06-25 14:44:52 -07001174 if (!in6_dev->cnf.accept_ra_defrtr) {
1175 ND_PRINTK(2, info,
1176 "RA: %s, defrtr is false for dev: %s\n",
1177 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001178 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001179 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001180
Ben Greeard9333192014-06-25 14:44:53 -07001181 /* Do not accept RA with source-addr found on local machine unless
1182 * accept_ra_from_local is set to true.
1183 */
Li RongQingb6428812014-07-10 18:02:46 +08001184 if (!in6_dev->cnf.accept_ra_from_local &&
1185 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1186 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001187 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001188 "RA from local address detected on dev: %s: default router ignored\n",
1189 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001190 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001191 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001192
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1194
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001195#ifdef CONFIG_IPV6_ROUTER_PREF
1196 pref = ra_msg->icmph.icmp6_router_pref;
1197 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001198 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001199 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001200 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1201#endif
1202
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001203 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
David S. Millereb857182012-01-27 15:07:56 -08001205 if (rt) {
1206 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1207 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001208 ND_PRINTK(0, err,
1209 "RA: %s got default router without neighbour\n",
1210 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001211 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001212 return;
1213 }
1214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001216 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 rt = NULL;
1218 }
1219
Ben Greearf2a762d2014-06-25 14:44:52 -07001220 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1221 rt, lifetime, skb->dev->name);
Ian Morris63159f22015-03-29 14:00:04 +01001222 if (!rt && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001223 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001225 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Ian Morris63159f22015-03-29 14:00:04 +01001226 if (!rt) {
Joe Perches675418d2012-05-16 19:28:38 +00001227 ND_PRINTK(0, err,
1228 "RA: %s failed to add default route\n",
1229 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 return;
1231 }
1232
David S. Millereb857182012-01-27 15:07:56 -08001233 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Ian Morris63159f22015-03-29 14:00:04 +01001234 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001235 ND_PRINTK(0, err,
1236 "RA: %s got default router without neighbour\n",
1237 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001238 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 return;
1240 }
1241 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001242 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001243 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
1245
1246 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001247 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001248 if (in6_dev->cnf.accept_ra_min_hop_limit < 256 &&
1249 ra_msg->icmph.icmp6_hop_limit) {
1250 if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) {
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001251 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001252 if (rt)
1253 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1254 ra_msg->icmph.icmp6_hop_limit);
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001255 } else {
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001256 ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than minimum\n");
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 }
1259
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001260skip_defrtr:
1261
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 /*
1263 * Update Reachable Time and Retrans Timer
1264 */
1265
1266 if (in6_dev->nd_parms) {
1267 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1268
1269 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1270 rtime = (rtime*HZ)/1000;
1271 if (rtime < HZ/10)
1272 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001273 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 in6_dev->tstamp = jiffies;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001275 send_ifinfo_notify = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 }
1277
1278 rtime = ntohl(ra_msg->reachable_time);
1279 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1280 rtime = (rtime*HZ)/1000;
1281
1282 if (rtime < HZ/10)
1283 rtime = HZ/10;
1284
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001285 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1286 NEIGH_VAR_SET(in6_dev->nd_parms,
1287 BASE_REACHABLE_TIME, rtime);
1288 NEIGH_VAR_SET(in6_dev->nd_parms,
1289 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1291 in6_dev->tstamp = jiffies;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001292 send_ifinfo_notify = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 }
1294 }
1295 }
1296
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001297 /*
1298 * Send a notify if RA changed managed/otherconf flags or timer settings
1299 */
1300 if (send_ifinfo_notify)
1301 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1302
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001303skip_linkparms:
1304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 /*
1306 * Process options.
1307 */
1308
1309 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001310 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 skb->dev, 1);
1312 if (neigh) {
1313 u8 *lladdr = NULL;
1314 if (ndopts.nd_opts_src_lladdr) {
1315 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1316 skb->dev);
1317 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001318 ND_PRINTK(2, warn,
1319 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 goto out;
1321 }
1322 }
1323 neigh_update(neigh, lladdr, NUD_STALE,
1324 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1325 NEIGH_UPDATE_F_OVERRIDE|
1326 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1327 NEIGH_UPDATE_F_ISROUTER);
1328 }
1329
Ben Greearf2a762d2014-06-25 14:44:52 -07001330 if (!ipv6_accept_ra(in6_dev)) {
1331 ND_PRINTK(2, info,
1332 "RA: %s, accept_ra is false for dev: %s\n",
1333 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001334 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001335 }
David Ward31ce8c72009-08-29 00:04:09 -07001336
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001337#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001338 if (!in6_dev->cnf.accept_ra_from_local &&
1339 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1340 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001341 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001342 "RA from local address detected on dev: %s: router info ignored.\n",
1343 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001344 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001345 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001346
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001347 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001348 struct nd_opt_hdr *p;
1349 for (p = ndopts.nd_opts_ri;
1350 p;
1351 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001352 struct route_info *ri = (struct route_info *)p;
1353#ifdef CONFIG_IPV6_NDISC_NODETYPE
1354 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1355 ri->prefix_len == 0)
1356 continue;
1357#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001358 if (ri->prefix_len == 0 &&
1359 !in6_dev->cnf.accept_ra_defrtr)
1360 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001361 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001362 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001363 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001364 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001365 }
1366 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001367
1368skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001369#endif
1370
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001371#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001372 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001373 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1374 ND_PRINTK(2, info,
1375 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1376 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001377 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001378 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001379#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001380
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001381 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 struct nd_opt_hdr *p;
1383 for (p = ndopts.nd_opts_pi;
1384 p;
1385 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001386 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1387 (p->nd_opt_len) << 3,
1388 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 }
1390 }
1391
Harout Hedeshianc2943f12015-01-20 10:06:05 -07001392 if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001393 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 u32 mtu;
1395
Ian Morris67ba4152014-08-24 21:53:10 +01001396 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4adc2006-11-14 20:56:00 -08001397 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001400 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 } else if (in6_dev->cnf.mtu6 != mtu) {
1402 in6_dev->cnf.mtu6 = mtu;
1403
1404 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001405 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
1407 rt6_mtu_change(skb->dev, mtu);
1408 }
1409 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001410
Pierre Ynard31910572007-10-10 21:22:05 -07001411 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001412 struct nd_opt_hdr *p;
1413 for (p = ndopts.nd_useropts;
1414 p;
1415 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1416 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001417 }
1418 }
1419
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001421 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 }
1423out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001424 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001425 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427}
1428
1429static void ndisc_redirect_rcv(struct sk_buff *skb)
1430{
Duan Jiong093d04d2012-12-14 02:59:59 +00001431 u8 *hdr;
1432 struct ndisc_options ndopts;
1433 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001434 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001435 offsetof(struct rd_msg, opt));
1436
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001437#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001438 switch (skb->ndisc_nodetype) {
1439 case NDISC_NODETYPE_HOST:
1440 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001441 ND_PRINTK(2, warn,
1442 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001443 return;
1444 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001445#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001446
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001447 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001448 ND_PRINTK(2, warn,
1449 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 return;
1451 }
1452
Duan Jiong093d04d2012-12-14 02:59:59 +00001453 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1454 return;
1455
Duan Jiongc92a59e2013-08-22 12:07:35 +08001456 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001457 ip6_redirect_no_header(skb, dev_net(skb->dev),
1458 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001459 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001460 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001461
1462 hdr = (u8 *)ndopts.nd_opts_rh;
1463 hdr += 8;
1464 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1465 return;
1466
David S. Millerb94f1c02012-07-12 00:33:37 -07001467 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468}
1469
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001470static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1471 struct sk_buff *orig_skb,
1472 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001473{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001474 u8 *opt = skb_put(skb, rd_len);
1475
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001476 memset(opt, 0, 8);
1477 *(opt++) = ND_OPT_REDIRECT_HDR;
1478 *(opt++) = (rd_len >> 3);
1479 opt += 6;
1480
1481 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001482}
1483
David S. Miller49919692012-01-27 15:30:48 -08001484void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001486 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001487 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001488 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001489 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001490 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001492 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 struct rt6_info *rt;
1495 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001496 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David Ahernca254492015-10-12 11:47:10 -07001499 int oif = l3mdev_fib_oif(dev);
David S. Miller1d861aa2012-07-10 03:58:16 -07001500 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Neil Horman95c385b2007-04-25 17:08:10 -07001502 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001503 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1504 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001505 return;
1506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001508 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001509 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001510 ND_PRINTK(2, warn,
1511 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001512 return;
1513 }
1514
David S. Miller4c9483b2011-03-12 16:22:43 -05001515 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
David Ahernca254492015-10-12 11:47:10 -07001516 &saddr_buf, &ipv6_hdr(skb)->saddr, oif);
1517
1518 if (oif != skb->dev->ifindex)
1519 fl6.flowi6_flags |= FLOWI_FLAG_L3MDEV_SRC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
David S. Miller4c9483b2011-03-12 16:22:43 -05001521 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001522 if (dst->error) {
1523 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001525 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001526 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001527 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
1530 rt = (struct rt6_info *) dst;
1531
1532 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001533 ND_PRINTK(2, warn,
1534 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001535 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 }
Martin KaFai Laufd0273d2015-05-22 20:55:57 -07001537 peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1);
David S. Miller1d861aa2012-07-10 03:58:16 -07001538 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1539 if (peer)
1540 inet_putpeer(peer);
1541 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001542 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
1544 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001545 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1546 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001547 ND_PRINTK(2, warn,
1548 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001549 goto release;
1550 }
1551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 read_lock_bh(&neigh->lock);
1553 if (neigh->nud_state & NUD_VALID) {
1554 memcpy(ha_buf, neigh->ha, dev->addr_len);
1555 read_unlock_bh(&neigh->lock);
1556 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001557 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 } else
1559 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001560
1561 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 }
1563
1564 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001565 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1566 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001568 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001570 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001571 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001572 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001574 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1575 *msg = (struct rd_msg) {
1576 .icmph = {
1577 .icmp6_type = NDISC_REDIRECT,
1578 },
1579 .target = *target,
1580 .dest = ipv6_hdr(skb)->daddr,
1581 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 /*
1584 * include target_address option
1585 */
1586
1587 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001588 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 /*
1591 * build redirect option and copy skb over to the new packet.
1592 */
1593
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001594 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001595 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Eric Dumazetadf30902009-06-02 05:19:30 +00001597 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001598 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001599 return;
1600
1601release:
1602 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603}
1604
1605static void pndisc_redo(struct sk_buff *skb)
1606{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001607 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 kfree_skb(skb);
1609}
1610
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001611static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1612{
1613 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1614
1615 if (!idev)
1616 return true;
1617 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1618 idev->cnf.suppress_frag_ndisc) {
1619 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1620 return true;
1621 }
1622 return false;
1623}
1624
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625int ndisc_rcv(struct sk_buff *skb)
1626{
1627 struct nd_msg *msg;
1628
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001629 if (ndisc_suppress_frag_ndisc(skb))
1630 return 0;
1631
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001632 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 return 0;
1634
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001635 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001637 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001639 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001640 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1641 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 return 0;
1643 }
1644
1645 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001646 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1647 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 return 0;
1649 }
1650
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001651 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1652
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 switch (msg->icmph.icmp6_type) {
1654 case NDISC_NEIGHBOUR_SOLICITATION:
1655 ndisc_recv_ns(skb);
1656 break;
1657
1658 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1659 ndisc_recv_na(skb);
1660 break;
1661
1662 case NDISC_ROUTER_SOLICITATION:
1663 ndisc_recv_rs(skb);
1664 break;
1665
1666 case NDISC_ROUTER_ADVERTISEMENT:
1667 ndisc_router_discovery(skb);
1668 break;
1669
1670 case NDISC_REDIRECT:
1671 ndisc_redirect_rcv(skb);
1672 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 return 0;
1676}
1677
1678static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1679{
Jiri Pirko351638e2013-05-28 01:30:21 +00001680 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazetc8507fb2015-07-29 12:01:41 +02001681 struct netdev_notifier_change_info *change_info;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001682 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001683 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
1685 switch (event) {
1686 case NETDEV_CHANGEADDR:
1687 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001688 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001689 idev = in6_dev_get(dev);
1690 if (!idev)
1691 break;
1692 if (idev->cnf.ndisc_notify)
1693 ndisc_send_unsol_na(dev);
1694 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 break;
Eric Dumazetc8507fb2015-07-29 12:01:41 +02001696 case NETDEV_CHANGE:
1697 change_info = ptr;
1698 if (change_info->flags_changed & IFF_NOARP)
1699 neigh_changeaddr(&nd_tbl, dev);
1700 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 case NETDEV_DOWN:
1702 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001703 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001705 case NETDEV_NOTIFY_PEERS:
1706 ndisc_send_unsol_na(dev);
1707 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 default:
1709 break;
1710 }
1711
1712 return NOTIFY_DONE;
1713}
1714
1715static struct notifier_block ndisc_netdev_notifier = {
1716 .notifier_call = ndisc_netdev_event,
1717};
1718
1719#ifdef CONFIG_SYSCTL
1720static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1721 const char *func, const char *dev_name)
1722{
1723 static char warncomm[TASK_COMM_LEN];
1724 static int warned;
1725 if (strcmp(warncomm, current->comm) && warned < 5) {
1726 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001727 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 -07001728 warncomm, func,
1729 dev_name, ctl->procname,
1730 dev_name, ctl->procname);
1731 warned++;
1732 }
1733}
1734
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001735int 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 -07001736{
1737 struct net_device *dev = ctl->extra1;
1738 struct inet6_dev *idev;
1739 int ret;
1740
Eric W. Biedermand12af672007-10-18 03:05:25 -07001741 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1742 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1744
Eric W. Biedermand12af672007-10-18 03:05:25 -07001745 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001746 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001747
1748 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001749 ret = neigh_proc_dointvec_jiffies(ctl, write,
1750 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001751
1752 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001753 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001754 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1755 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001756 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
1759 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001760 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1761 idev->nd_parms->reachable_time =
1762 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 idev->tstamp = jiffies;
1764 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1765 in6_dev_put(idev);
1766 }
1767 return ret;
1768}
1769
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
1771#endif
1772
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001773static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774{
1775 struct ipv6_pinfo *np;
1776 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001777 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001779 err = inet_ctl_sock_create(&sk, PF_INET6,
1780 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001782 ND_PRINTK(0, err,
1783 "NDISC: Failed to initialize the control socket (err %d)\n",
1784 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 return err;
1786 }
1787
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001788 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001789
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 np->hop_limit = 255;
1792 /* Do not loopback ndisc messages */
1793 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001795 return 0;
1796}
1797
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001798static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001799{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001800 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001801}
1802
1803static struct pernet_operations ndisc_net_ops = {
1804 .init = ndisc_net_init,
1805 .exit = ndisc_net_exit,
1806};
1807
1808int __init ndisc_init(void)
1809{
1810 int err;
1811
1812 err = register_pernet_subsys(&ndisc_net_ops);
1813 if (err)
1814 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001815 /*
1816 * Initialize the neighbour table
1817 */
WANG Congd7480fd2014-11-10 15:59:36 -08001818 neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
1820#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001821 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301822 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001823 if (err)
1824 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001825out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001826#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001827 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001829#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001830out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001831 unregister_pernet_subsys(&ndisc_net_ops);
1832 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001833#endif
1834}
1835
1836int __init ndisc_late_init(void)
1837{
1838 return register_netdevice_notifier(&ndisc_netdev_notifier);
1839}
1840
1841void ndisc_late_cleanup(void)
1842{
1843 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844}
1845
1846void ndisc_cleanup(void)
1847{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848#ifdef CONFIG_SYSCTL
1849 neigh_sysctl_unregister(&nd_tbl.parms);
1850#endif
WANG Congd7480fd2014-11-10 15:59:36 -08001851 neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001852 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853}