blob: 96f153c0846b7abcd9b1af995c49067efbe7064d [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include <linux/proc_fs.h>
71
72#include <linux/netfilter.h>
73#include <linux/netfilter_ipv6.h>
74
Joe Perches675418d2012-05-16 19:28:38 +000075/* Set to 3 to get tracing... */
76#define ND_DEBUG 1
77
78#define ND_PRINTK(val, level, fmt, ...) \
79do { \
80 if (val <= ND_DEBUG) \
81 net_##level##_ratelimited(fmt, ##__VA_ARGS__); \
82} while (0)
83
Eric Dumazetd6bf7812010-10-04 06:15:44 +000084static u32 ndisc_hash(const void *pkey,
85 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -050086 __u32 *hash_rnd);
Eric W. Biederman60395a22015-03-03 17:10:44 -060087static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static int ndisc_constructor(struct neighbour *neigh);
89static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
90static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
91static int pndisc_constructor(struct pneigh_entry *n);
92static void pndisc_destructor(struct pneigh_entry *n);
93static void pndisc_redo(struct sk_buff *skb);
94
Stephen Hemminger89d69d22009-09-01 11:13:19 +000095static const struct neigh_ops ndisc_generic_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 .family = AF_INET6,
97 .solicit = ndisc_solicit,
98 .error_report = ndisc_error_report,
99 .output = neigh_resolve_output,
100 .connected_output = neigh_connected_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101};
102
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000103static const struct neigh_ops ndisc_hh_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 .family = AF_INET6,
105 .solicit = ndisc_solicit,
106 .error_report = ndisc_error_report,
107 .output = neigh_resolve_output,
108 .connected_output = neigh_resolve_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109};
110
111
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000112static const struct neigh_ops ndisc_direct_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 .family = AF_INET6,
David S. Miller8f40b162011-07-17 13:34:11 -0700114 .output = neigh_direct_output,
115 .connected_output = neigh_direct_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116};
117
118struct neigh_table nd_tbl = {
119 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 .key_len = sizeof(struct in6_addr),
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -0600121 .protocol = cpu_to_be16(ETH_P_IPV6),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 .hash = ndisc_hash,
Eric W. Biederman60395a22015-03-03 17:10:44 -0600123 .key_eq = ndisc_key_eq,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 .constructor = ndisc_constructor,
125 .pconstructor = pndisc_constructor,
126 .pdestructor = pndisc_destructor,
127 .proxy_redo = pndisc_redo,
128 .id = "ndisc_cache",
129 .parms = {
Shan Weib6720832010-12-01 18:05:12 +0000130 .tbl = &nd_tbl,
Shan Weib6720832010-12-01 18:05:12 +0000131 .reachable_time = ND_REACHABLE_TIME,
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100132 .data = {
133 [NEIGH_VAR_MCAST_PROBES] = 3,
134 [NEIGH_VAR_UCAST_PROBES] = 3,
135 [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
136 [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
137 [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
138 [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
139 [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
140 [NEIGH_VAR_PROXY_QLEN] = 64,
141 [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
142 [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,
143 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 },
145 .gc_interval = 30 * HZ,
146 .gc_thresh1 = 128,
147 .gc_thresh2 = 512,
148 .gc_thresh3 = 1024,
149};
150
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000151static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000153 int pad = ndisc_addr_option_pad(skb->dev->type);
154 int data_len = skb->dev->addr_len;
155 int space = ndisc_opt_addr_space(skb->dev);
156 u8 *opt = skb_put(skb, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
158 opt[0] = type;
159 opt[1] = space>>3;
160
161 memset(opt + 2, 0, pad);
162 opt += pad;
163 space -= pad;
164
165 memcpy(opt+2, data, data_len);
166 data_len += 2;
167 opt += data_len;
Ian Morrise5d08d72014-11-23 21:28:43 +0000168 space -= data_len;
169 if (space > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
173static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
174 struct nd_opt_hdr *end)
175{
176 int type;
177 if (!cur || !end || cur >= end)
178 return NULL;
179 type = cur->nd_opt_type;
180 do {
181 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100182 } while (cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000183 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184}
185
Pierre Ynard31910572007-10-10 21:22:05 -0700186static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
187{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000188 return opt->nd_opt_type == ND_OPT_RDNSS ||
189 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700190}
191
192static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
193 struct nd_opt_hdr *end)
194{
195 if (!cur || !end || cur >= end)
196 return NULL;
197 do {
198 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100199 } while (cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000200 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700201}
202
David S. Miller30f2a5f2012-07-11 23:26:46 -0700203struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
204 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
206 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
207
208 if (!nd_opt || opt_len < 0 || !ndopts)
209 return NULL;
210 memset(ndopts, 0, sizeof(*ndopts));
211 while (opt_len) {
212 int l;
213 if (opt_len < sizeof(struct nd_opt_hdr))
214 return NULL;
215 l = nd_opt->nd_opt_len << 3;
216 if (opt_len < l || l == 0)
217 return NULL;
218 switch (nd_opt->nd_opt_type) {
219 case ND_OPT_SOURCE_LL_ADDR:
220 case ND_OPT_TARGET_LL_ADDR:
221 case ND_OPT_MTU:
222 case ND_OPT_REDIRECT_HDR:
223 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000224 ND_PRINTK(2, warn,
225 "%s: duplicated ND6 option found: type=%d\n",
226 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 } else {
228 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
229 }
230 break;
231 case ND_OPT_PREFIX_INFO:
232 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700233 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
235 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800236#ifdef CONFIG_IPV6_ROUTE_INFO
237 case ND_OPT_ROUTE_INFO:
238 ndopts->nd_opts_ri_end = nd_opt;
239 if (!ndopts->nd_opts_ri)
240 ndopts->nd_opts_ri = nd_opt;
241 break;
242#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700244 if (ndisc_is_useropt(nd_opt)) {
245 ndopts->nd_useropts_end = nd_opt;
246 if (!ndopts->nd_useropts)
247 ndopts->nd_useropts = nd_opt;
248 } else {
249 /*
250 * Unknown options must be silently ignored,
251 * to accommodate future extension to the
252 * protocol.
253 */
Joe Perches675418d2012-05-16 19:28:38 +0000254 ND_PRINTK(2, notice,
255 "%s: ignored unsupported option; type=%d, len=%d\n",
256 __func__,
257 nd_opt->nd_opt_type,
258 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 }
261 opt_len -= l;
262 nd_opt = ((void *)nd_opt) + l;
263 }
264 return ndopts;
265}
266
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000267int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
269 switch (dev->type) {
270 case ARPHRD_ETHER:
271 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
272 case ARPHRD_FDDI:
273 ipv6_eth_mc_map(addr, buf);
274 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 case ARPHRD_ARCNET:
276 ipv6_arcnet_mc_map(addr, buf);
277 return 0;
278 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700279 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000281 case ARPHRD_IPGRE:
282 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 default:
284 if (dir) {
285 memcpy(buf, dev->broadcast, dev->addr_len);
286 return 0;
287 }
288 }
289 return -EINVAL;
290}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900291EXPORT_SYMBOL(ndisc_mc_map);
292
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000293static u32 ndisc_hash(const void *pkey,
294 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500295 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
David S. Miller2c2aba62011-12-28 15:06:58 -0500297 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298}
299
Eric W. Biederman60395a22015-03-03 17:10:44 -0600300static bool ndisc_key_eq(const struct neighbour *n, const void *pkey)
301{
302 return neigh_key_eq128(n, pkey);
303}
304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305static int ndisc_constructor(struct neighbour *neigh)
306{
Ian Morris67ba4152014-08-24 21:53:10 +0100307 struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 struct net_device *dev = neigh->dev;
309 struct inet6_dev *in6_dev;
310 struct neigh_parms *parms;
Eric Dumazeta50feda2012-05-18 18:57:34 +0000311 bool is_multicast = ipv6_addr_is_multicast(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 in6_dev = in6_dev_get(dev);
Ian Morris63159f22015-03-29 14:00:04 +0100314 if (!in6_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 return -EINVAL;
316 }
317
318 parms = in6_dev->nd_parms;
319 __neigh_parms_put(neigh->parms);
320 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700323 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 neigh->nud_state = NUD_NOARP;
325 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700326 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 } else {
328 if (is_multicast) {
329 neigh->nud_state = NUD_NOARP;
330 ndisc_mc_map(addr, neigh->ha, dev, 1);
331 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
332 neigh->nud_state = NUD_NOARP;
333 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
334 if (dev->flags&IFF_LOOPBACK)
335 neigh->type = RTN_LOCAL;
336 } else if (dev->flags&IFF_POINTOPOINT) {
337 neigh->nud_state = NUD_NOARP;
338 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
339 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700340 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 neigh->ops = &ndisc_hh_ops;
342 else
343 neigh->ops = &ndisc_generic_ops;
344 if (neigh->nud_state&NUD_VALID)
345 neigh->output = neigh->ops->connected_output;
346 else
347 neigh->output = neigh->ops->output;
348 }
349 in6_dev_put(in6_dev);
350 return 0;
351}
352
353static int pndisc_constructor(struct pneigh_entry *n)
354{
Ian Morris67ba4152014-08-24 21:53:10 +0100355 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 struct in6_addr maddr;
357 struct net_device *dev = n->dev;
358
Ian Morris63159f22015-03-29 14:00:04 +0100359 if (!dev || !__in6_dev_get(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 return -EINVAL;
361 addrconf_addr_solict_mult(addr, &maddr);
362 ipv6_dev_mc_inc(dev, &maddr);
363 return 0;
364}
365
366static void pndisc_destructor(struct pneigh_entry *n)
367{
Ian Morris67ba4152014-08-24 21:53:10 +0100368 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 struct in6_addr maddr;
370 struct net_device *dev = n->dev;
371
Ian Morris63159f22015-03-29 14:00:04 +0100372 if (!dev || !__in6_dev_get(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return;
374 addrconf_addr_solict_mult(addr, &maddr);
375 ipv6_dev_mc_dec(dev, &maddr);
376}
377
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000378static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
379 int len)
380{
381 int hlen = LL_RESERVED_SPACE(dev);
382 int tlen = dev->needed_tailroom;
383 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
384 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000385
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200386 skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000387 if (!skb) {
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200388 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
389 __func__);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000390 return NULL;
391 }
392
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000393 skb->protocol = htons(ETH_P_IPV6);
394 skb->dev = dev;
395
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000396 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki / 吉藤英明5135e632013-01-21 06:48:44 +0000397 skb_reset_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000398
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200399 /* Manually assign socket ownership as we avoid calling
400 * sock_alloc_send_pskb() to bypass wmem buffer limits
401 */
402 skb_set_owner_w(skb, sk);
403
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000404 return skb;
405}
406
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000407static void ip6_nd_hdr(struct sk_buff *skb,
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000408 const struct in6_addr *saddr,
409 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000410 int hop_limit, int len)
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000411{
412 struct ipv6hdr *hdr;
413
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000414 skb_push(skb, sizeof(*hdr));
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000415 skb_reset_network_header(skb);
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000416 hdr = ipv6_hdr(skb);
417
418 ip6_flow_hdr(hdr, 0, 0);
419
420 hdr->payload_len = htons(len);
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000421 hdr->nexthdr = IPPROTO_ICMPV6;
422 hdr->hop_limit = hop_limit;
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000423
424 hdr->saddr = *saddr;
425 hdr->daddr = *daddr;
426}
427
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000428static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900429 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000430 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800431{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000432 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000433 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000434 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800435 struct inet6_dev *idev;
436 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000437 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800438 u8 type;
439
440 type = icmp6h->icmp6_type;
441
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000442 if (!dst) {
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000443 struct flowi6 fl6;
Brian Haley305d5522008-11-04 17:51:14 -0800444
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000445 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
446 dst = icmp6_dst_alloc(skb->dev, &fl6);
447 if (IS_ERR(dst)) {
448 kfree_skb(skb);
449 return;
450 }
451
452 skb_dst_set(skb, dst);
453 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900454
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000455 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
456 IPPROTO_ICMPV6,
457 csum_partial(icmp6h,
458 skb->len, 0));
459
460 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
461
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000462 rcu_read_lock();
463 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700464 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900465
David Miller7026b1d2015-04-05 22:19:04 -0400466 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb,
467 NULL, dst->dev,
468 dst_output_sk);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900469 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700470 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700471 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900472 }
473
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000474 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900475}
476
Cong Wangf564f452013-08-31 13:44:36 +0800477void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
478 const struct in6_addr *daddr,
479 const struct in6_addr *solicited_addr,
480 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000482 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 struct in6_addr tmpaddr;
484 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900485 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000486 struct nd_msg *msg;
487 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900490 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900491 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700493 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300494 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000495 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 in6_ifa_put(ifp);
497 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700498 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900499 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900500 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 return;
502 src_addr = &tmpaddr;
503 }
504
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000505 if (!dev->addr_len)
506 inc_opt = 0;
507 if (inc_opt)
508 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000510 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000511 if (!skb)
512 return;
513
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000514 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
515 *msg = (struct nd_msg) {
516 .icmph = {
517 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
518 .icmp6_router = router,
519 .icmp6_solicited = solicited,
520 .icmp6_override = override,
521 },
522 .target = *solicited_addr,
523 };
524
525 if (inc_opt)
526 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
527 dev->dev_addr);
528
529
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000530 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900531}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000533static void ndisc_send_unsol_na(struct net_device *dev)
534{
535 struct inet6_dev *idev;
536 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000537
538 idev = in6_dev_get(dev);
539 if (!idev)
540 return;
541
542 read_lock_bh(&idev->lock);
543 list_for_each_entry(ifa, &idev->addr_list, if_list) {
YOSHIFUJI Hideaki / 吉藤英明9fafd652012-11-12 07:50:17 +0000544 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000545 /*router=*/ !!idev->cnf.forwarding,
546 /*solicited=*/ false, /*override=*/ true,
547 /*inc_opt=*/ true);
548 }
549 read_unlock_bh(&idev->lock);
550
551 in6_dev_put(idev);
552}
553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900555 const struct in6_addr *solicit,
556 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000558 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000560 int inc_opt = dev->addr_len;
561 int optlen = 0;
562 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
Ian Morris63159f22015-03-29 14:00:04 +0100564 if (!saddr) {
Neil Horman95c385b2007-04-25 17:08:10 -0700565 if (ipv6_get_lladdr(dev, &addr_buf,
566 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 return;
568 saddr = &addr_buf;
569 }
570
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000571 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300572 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000573 if (inc_opt)
574 optlen += ndisc_opt_addr_space(dev);
575
576 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000577 if (!skb)
578 return;
579
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000580 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
581 *msg = (struct nd_msg) {
582 .icmph = {
583 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
584 },
585 .target = *solicit,
586 };
587
588 if (inc_opt)
589 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
590 dev->dev_addr);
591
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000592 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593}
594
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900595void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
596 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000598 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000599 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700600 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000601 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700602
603#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
604 /*
605 * According to section 2.2 of RFC 4429, we must not
606 * send router solicitations with a sllao from
607 * optimistic addresses, but we may send the solicitation
608 * if we don't include the sllao. So here we check
609 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800610 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700611 */
612 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900613 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800614 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700615 if (ifp) {
616 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900617 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700618 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900619 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700620 } else {
621 send_sllao = 0;
622 }
623 }
624#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000625 if (send_sllao)
626 optlen += ndisc_opt_addr_space(dev);
627
628 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000629 if (!skb)
630 return;
631
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000632 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
633 *msg = (struct rs_msg) {
634 .icmph = {
635 .icmp6_type = NDISC_ROUTER_SOLICITATION,
636 },
637 };
638
639 if (send_sllao)
640 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
641 dev->dev_addr);
642
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000643 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
648{
649 /*
650 * "The sender MUST return an ICMP
651 * destination unreachable"
652 */
653 dst_link_failure(skb);
654 kfree_skb(skb);
655}
656
657/* Called with locked neigh: either read or both */
658
659static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
660{
661 struct in6_addr *saddr = NULL;
662 struct in6_addr mcaddr;
663 struct net_device *dev = neigh->dev;
664 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
665 int probes = atomic_read(&neigh->probes);
666
Erik Klinec58da4c2015-02-04 20:01:23 +0900667 if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
668 dev, 1,
669 IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700670 saddr = &ipv6_hdr(skb)->saddr;
Ian Morrise5d08d72014-11-23 21:28:43 +0000671 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
672 if (probes < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000674 ND_PRINTK(1, dbg,
675 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
676 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
678 ndisc_send_ns(dev, neigh, target, target, saddr);
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100679 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 } else {
682 addrconf_addr_solict_mult(target, &mcaddr);
683 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
684 }
685}
686
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900687static int pndisc_is_router(const void *pkey,
688 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700689{
690 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900691 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700692
693 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900694 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
695 if (n)
696 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700697 read_unlock_bh(&nd_tbl.lock);
698
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900699 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700700}
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702static void ndisc_recv_ns(struct sk_buff *skb)
703{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700704 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000705 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
706 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000708 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700709 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 struct ndisc_options ndopts;
711 struct net_device *dev = skb->dev;
712 struct inet6_ifaddr *ifp;
713 struct inet6_dev *idev = NULL;
714 struct neighbour *neigh;
715 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000716 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900717 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000719 if (skb->len < sizeof(struct nd_msg)) {
720 ND_PRINTK(2, warn, "NS: packet too short\n");
721 return;
722 }
723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000725 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return;
727 }
728
729 /*
730 * RFC2461 7.1.1:
731 * DAD has to be destined for solicited node multicast address.
732 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000733 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000734 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return;
736 }
737
738 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000739 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 return;
741 }
742
743 if (ndopts.nd_opts_src_lladdr) {
744 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
745 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000746 ND_PRINTK(2, warn,
747 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return;
749 }
750
751 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900752 * If the IP source address is the unspecified address,
753 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 * in the message.
755 */
756 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000757 ND_PRINTK(2, warn,
758 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return;
760 }
761 }
762
763 inc = ipv6_addr_is_multicast(daddr);
764
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900765 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800766 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700767
768 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
769 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700770 /*
771 * We are colliding with another node
772 * who is doing DAD
773 * so fail our DAD process
774 */
775 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200776 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700777 } else {
778 /*
779 * This is not a dad solicitation.
780 * If we are an optimistic node,
781 * we should respond.
782 * Otherwise, we should ignore it.
783 */
784 if (!(ifp->flags & IFA_F_OPTIMISTIC))
785 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 }
788
789 idev = ifp->idev;
790 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700791 struct net *net = dev_net(dev);
792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 idev = in6_dev_get(dev);
794 if (!idev) {
795 /* XXX: count this drop? */
796 return;
797 }
798
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700799 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900800 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700801 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900802 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700803 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300805 inc &&
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100806 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 /*
808 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900809 * sender should delay its response
810 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 * MAX_ANYCAST_DELAY_TIME seconds.
812 * (RFC2461) -- yoshfuji
813 */
814 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
815 if (n)
816 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
817 goto out;
818 }
819 } else
820 goto out;
821 }
822
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900823 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000824 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900827 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000828 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 goto out;
830 }
831
832 if (inc)
833 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
834 else
835 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
836
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900837 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 * update / create cache entry
839 * for the source address
840 */
841 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
842 !inc || lladdr || !dev->addr_len);
843 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900844 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 NEIGH_UPDATE_F_WEAK_OVERRIDE|
846 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700847 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 ndisc_send_na(dev, neigh, saddr, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000849 !!is_router,
850 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (neigh)
852 neigh_release(neigh);
853 }
854
855out:
856 if (ifp)
857 in6_ifa_put(ifp);
858 else
859 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
862static void ndisc_recv_na(struct sk_buff *skb)
863{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700864 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800865 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000866 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000868 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700869 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 struct ndisc_options ndopts;
871 struct net_device *dev = skb->dev;
872 struct inet6_ifaddr *ifp;
873 struct neighbour *neigh;
874
875 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000876 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return;
878 }
879
880 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000881 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return;
883 }
884
885 if (ipv6_addr_is_multicast(daddr) &&
886 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000887 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return;
889 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000892 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 return;
894 }
895 if (ndopts.nd_opts_tgt_lladdr) {
896 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
897 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000898 ND_PRINTK(2, warn,
899 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 return;
901 }
902 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900903 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800904 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000905 if (skb->pkt_type != PACKET_LOOPBACK
906 && (ifp->flags & IFA_F_TENTATIVE)) {
907 addrconf_dad_failure(ifp);
908 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 }
910 /* What should we make now? The advertisement
911 is invalid, but ndisc specs say nothing
912 about it. It could be misconfiguration, or
913 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800914
915 We should not print the error if NA has been
916 received from loopback - it is just our own
917 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800919 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000920 ND_PRINTK(1, warn,
921 "NA: someone advertises our address %pI6 on %s!\n",
922 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 in6_ifa_put(ifp);
924 return;
925 }
926 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
927
928 if (neigh) {
929 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700930 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 if (neigh->nud_state & NUD_FAILED)
933 goto out;
934
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700935 /*
936 * Don't update the neighbor cache entry on a proxy NA from
937 * ourselves because either the proxied node is off link or it
938 * has already sent a NA to us.
939 */
940 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700941 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
942 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000943 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700944 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700945 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 neigh_update(neigh, lladdr,
948 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
949 NEIGH_UPDATE_F_WEAK_OVERRIDE|
950 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
951 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
952 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
953
954 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
955 /*
956 * Change: router to host
957 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800958 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 }
960
961out:
962 neigh_release(neigh);
963 }
964}
965
966static void ndisc_recv_rs(struct sk_buff *skb)
967{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700968 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
970 struct neighbour *neigh;
971 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000972 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 struct ndisc_options ndopts;
974 u8 *lladdr = NULL;
975
976 if (skb->len < sizeof(*rs_msg))
977 return;
978
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000979 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000981 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 return;
983 }
984
985 /* Don't accept RS if we're not in router mode */
986 if (!idev->cnf.forwarding)
987 goto out;
988
989 /*
990 * Don't update NCE if src = ::;
991 * this implies that the source node has no ip address assigned yet.
992 */
993 if (ipv6_addr_any(saddr))
994 goto out;
995
996 /* Parse ND options */
997 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000998 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 goto out;
1000 }
1001
1002 if (ndopts.nd_opts_src_lladdr) {
1003 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1004 skb->dev);
1005 if (!lladdr)
1006 goto out;
1007 }
1008
1009 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1010 if (neigh) {
1011 neigh_update(neigh, lladdr, NUD_STALE,
1012 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1013 NEIGH_UPDATE_F_OVERRIDE|
1014 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1015 neigh_release(neigh);
1016 }
1017out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001018 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019}
1020
Pierre Ynard31910572007-10-10 21:22:05 -07001021static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1022{
1023 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1024 struct sk_buff *skb;
1025 struct nlmsghdr *nlh;
1026 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001027 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001028 int err;
1029 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1030 + (opt->nd_opt_len << 3));
1031 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1032
1033 skb = nlmsg_new(msg_size, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01001034 if (!skb) {
Pierre Ynard31910572007-10-10 21:22:05 -07001035 err = -ENOBUFS;
1036 goto errout;
1037 }
1038
1039 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
Ian Morris63159f22015-03-29 14:00:04 +01001040 if (!nlh) {
Pierre Ynard31910572007-10-10 21:22:05 -07001041 goto nla_put_failure;
1042 }
1043
1044 ndmsg = nlmsg_data(nlh);
1045 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001046 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001047 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1048 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1049 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1050
1051 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1052
Jiri Benc930345e2015-03-29 16:59:25 +02001053 if (nla_put_in6_addr(skb, NDUSEROPT_SRCADDR, &ipv6_hdr(ra)->saddr))
David S. Millerc78679e2012-04-01 20:27:33 -04001054 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001055 nlmsg_end(skb, nlh);
1056
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001057 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001058 return;
1059
1060nla_put_failure:
1061 nlmsg_free(skb);
1062 err = -EMSGSIZE;
1063errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001064 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001065}
1066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067static void ndisc_router_discovery(struct sk_buff *skb)
1068{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001069 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 struct neighbour *neigh = NULL;
1071 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001072 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 int lifetime;
1074 struct ndisc_options ndopts;
1075 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001076 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Ian Morris67ba4152014-08-24 21:53:10 +01001078 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
Simon Horman29a3cad2013-05-28 20:34:26 +00001080 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1081 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Ben Greearf2a762d2014-06-25 14:44:52 -07001083 ND_PRINTK(2, info,
1084 "RA: %s, dev: %s\n",
1085 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001086 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001087 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 return;
1089 }
1090 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001091 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 return;
1093 }
1094
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001095#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001096 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001097 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001098 return;
1099 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001100#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 /*
1103 * set the RA_RECV flag in the interface
1104 */
1105
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001106 in6_dev = __in6_dev_get(skb->dev);
Ian Morris63159f22015-03-29 14:00:04 +01001107 if (!in6_dev) {
Joe Perches675418d2012-05-16 19:28:38 +00001108 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1109 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return;
1111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001114 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 return;
1116 }
1117
Ben Greearf2a762d2014-06-25 14:44:52 -07001118 if (!ipv6_accept_ra(in6_dev)) {
1119 ND_PRINTK(2, info,
1120 "RA: %s, did not accept ra for dev: %s\n",
1121 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001122 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001123 }
David Ward31ce8c72009-08-29 00:04:09 -07001124
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001125#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001126 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001127 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1128 ND_PRINTK(2, info,
1129 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1130 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001131 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001132 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001133#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001134
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 if (in6_dev->if_flags & IF_RS_SENT) {
1136 /*
1137 * flag that an RA was received after an RS was sent
1138 * out on this interface.
1139 */
1140 in6_dev->if_flags |= IF_RA_RCVD;
1141 }
1142
1143 /*
1144 * Remember the managed/otherconf flags from most recently
1145 * received RA message (RFC 2462) -- yoshfuji
1146 */
1147 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1148 IF_RA_OTHERCONF)) |
1149 (ra_msg->icmph.icmp6_addrconf_managed ?
1150 IF_RA_MANAGED : 0) |
1151 (ra_msg->icmph.icmp6_addrconf_other ?
1152 IF_RA_OTHERCONF : 0);
1153
Ben Greearf2a762d2014-06-25 14:44:52 -07001154 if (!in6_dev->cnf.accept_ra_defrtr) {
1155 ND_PRINTK(2, info,
1156 "RA: %s, defrtr is false for dev: %s\n",
1157 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001158 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001159 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001160
Ben Greeard9333192014-06-25 14:44:53 -07001161 /* Do not accept RA with source-addr found on local machine unless
1162 * accept_ra_from_local is set to true.
1163 */
Li RongQingb6428812014-07-10 18:02:46 +08001164 if (!in6_dev->cnf.accept_ra_from_local &&
1165 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1166 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001167 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001168 "RA from local address detected on dev: %s: default router ignored\n",
1169 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001170 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001171 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1174
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001175#ifdef CONFIG_IPV6_ROUTER_PREF
1176 pref = ra_msg->icmph.icmp6_router_pref;
1177 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001178 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001179 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001180 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1181#endif
1182
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001183 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
David S. Millereb857182012-01-27 15:07:56 -08001185 if (rt) {
1186 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1187 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001188 ND_PRINTK(0, err,
1189 "RA: %s got default router without neighbour\n",
1190 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001191 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001192 return;
1193 }
1194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001196 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 rt = NULL;
1198 }
1199
Ben Greearf2a762d2014-06-25 14:44:52 -07001200 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1201 rt, lifetime, skb->dev->name);
Ian Morris63159f22015-03-29 14:00:04 +01001202 if (!rt && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001203 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001205 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Ian Morris63159f22015-03-29 14:00:04 +01001206 if (!rt) {
Joe Perches675418d2012-05-16 19:28:38 +00001207 ND_PRINTK(0, err,
1208 "RA: %s failed to add default route\n",
1209 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 return;
1211 }
1212
David S. Millereb857182012-01-27 15:07:56 -08001213 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Ian Morris63159f22015-03-29 14:00:04 +01001214 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001215 ND_PRINTK(0, err,
1216 "RA: %s got default router without neighbour\n",
1217 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001218 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 return;
1220 }
1221 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001222 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001223 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 }
1225
1226 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001227 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 if (ra_msg->icmph.icmp6_hop_limit) {
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001229 /* Only set hop_limit on the interface if it is higher than
1230 * the current hop_limit.
1231 */
1232 if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) {
1233 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1234 } else {
1235 ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n");
1236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001238 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1239 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 }
1241
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001242skip_defrtr:
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 /*
1245 * Update Reachable Time and Retrans Timer
1246 */
1247
1248 if (in6_dev->nd_parms) {
1249 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1250
1251 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1252 rtime = (rtime*HZ)/1000;
1253 if (rtime < HZ/10)
1254 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001255 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 in6_dev->tstamp = jiffies;
1257 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1258 }
1259
1260 rtime = ntohl(ra_msg->reachable_time);
1261 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1262 rtime = (rtime*HZ)/1000;
1263
1264 if (rtime < HZ/10)
1265 rtime = HZ/10;
1266
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001267 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1268 NEIGH_VAR_SET(in6_dev->nd_parms,
1269 BASE_REACHABLE_TIME, rtime);
1270 NEIGH_VAR_SET(in6_dev->nd_parms,
1271 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1273 in6_dev->tstamp = jiffies;
1274 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1275 }
1276 }
1277 }
1278
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001279skip_linkparms:
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 /*
1282 * Process options.
1283 */
1284
1285 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001286 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 skb->dev, 1);
1288 if (neigh) {
1289 u8 *lladdr = NULL;
1290 if (ndopts.nd_opts_src_lladdr) {
1291 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1292 skb->dev);
1293 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001294 ND_PRINTK(2, warn,
1295 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 goto out;
1297 }
1298 }
1299 neigh_update(neigh, lladdr, NUD_STALE,
1300 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1301 NEIGH_UPDATE_F_OVERRIDE|
1302 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1303 NEIGH_UPDATE_F_ISROUTER);
1304 }
1305
Ben Greearf2a762d2014-06-25 14:44:52 -07001306 if (!ipv6_accept_ra(in6_dev)) {
1307 ND_PRINTK(2, info,
1308 "RA: %s, accept_ra is false for dev: %s\n",
1309 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001310 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001311 }
David Ward31ce8c72009-08-29 00:04:09 -07001312
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001313#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001314 if (!in6_dev->cnf.accept_ra_from_local &&
1315 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1316 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001317 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001318 "RA from local address detected on dev: %s: router info ignored.\n",
1319 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001320 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001321 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001322
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001323 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001324 struct nd_opt_hdr *p;
1325 for (p = ndopts.nd_opts_ri;
1326 p;
1327 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001328 struct route_info *ri = (struct route_info *)p;
1329#ifdef CONFIG_IPV6_NDISC_NODETYPE
1330 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1331 ri->prefix_len == 0)
1332 continue;
1333#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001334 if (ri->prefix_len == 0 &&
1335 !in6_dev->cnf.accept_ra_defrtr)
1336 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001337 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001338 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001339 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001340 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001341 }
1342 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001343
1344skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001345#endif
1346
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001347#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001348 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001349 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1350 ND_PRINTK(2, info,
1351 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1352 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001353 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001354 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001355#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001356
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001357 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 struct nd_opt_hdr *p;
1359 for (p = ndopts.nd_opts_pi;
1360 p;
1361 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001362 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1363 (p->nd_opt_len) << 3,
1364 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 }
1366 }
1367
Harout Hedeshianc2943f12015-01-20 10:06:05 -07001368 if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001369 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 u32 mtu;
1371
Ian Morris67ba4152014-08-24 21:53:10 +01001372 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4adc2006-11-14 20:56:00 -08001373 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
1375 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001376 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 } else if (in6_dev->cnf.mtu6 != mtu) {
1378 in6_dev->cnf.mtu6 = mtu;
1379
1380 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001381 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 rt6_mtu_change(skb->dev, mtu);
1384 }
1385 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001386
Pierre Ynard31910572007-10-10 21:22:05 -07001387 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001388 struct nd_opt_hdr *p;
1389 for (p = ndopts.nd_useropts;
1390 p;
1391 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1392 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001393 }
1394 }
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001397 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 }
1399out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001400 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001401 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403}
1404
1405static void ndisc_redirect_rcv(struct sk_buff *skb)
1406{
Duan Jiong093d04d2012-12-14 02:59:59 +00001407 u8 *hdr;
1408 struct ndisc_options ndopts;
1409 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001410 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001411 offsetof(struct rd_msg, opt));
1412
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001413#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001414 switch (skb->ndisc_nodetype) {
1415 case NDISC_NODETYPE_HOST:
1416 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001417 ND_PRINTK(2, warn,
1418 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001419 return;
1420 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001421#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001422
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001423 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001424 ND_PRINTK(2, warn,
1425 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 return;
1427 }
1428
Duan Jiong093d04d2012-12-14 02:59:59 +00001429 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1430 return;
1431
Duan Jiongc92a59e2013-08-22 12:07:35 +08001432 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001433 ip6_redirect_no_header(skb, dev_net(skb->dev),
1434 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001435 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001436 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001437
1438 hdr = (u8 *)ndopts.nd_opts_rh;
1439 hdr += 8;
1440 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1441 return;
1442
David S. Millerb94f1c02012-07-12 00:33:37 -07001443 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444}
1445
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001446static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1447 struct sk_buff *orig_skb,
1448 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001449{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001450 u8 *opt = skb_put(skb, rd_len);
1451
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001452 memset(opt, 0, 8);
1453 *(opt++) = ND_OPT_REDIRECT_HDR;
1454 *(opt++) = (rd_len >> 3);
1455 opt += 6;
1456
1457 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001458}
1459
David S. Miller49919692012-01-27 15:30:48 -08001460void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001462 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001463 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001464 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001465 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001466 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001468 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 struct rt6_info *rt;
1471 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001472 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001475 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Neil Horman95c385b2007-04-25 17:08:10 -07001477 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001478 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1479 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001480 return;
1481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001483 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001484 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001485 ND_PRINTK(2, warn,
1486 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001487 return;
1488 }
1489
David S. Miller4c9483b2011-03-12 16:22:43 -05001490 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001491 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
David S. Miller4c9483b2011-03-12 16:22:43 -05001493 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001494 if (dst->error) {
1495 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001497 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001498 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001499 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
1502 rt = (struct rt6_info *) dst;
1503
1504 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001505 ND_PRINTK(2, warn,
1506 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001507 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001509 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1510 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1511 if (peer)
1512 inet_putpeer(peer);
1513 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001514 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
1516 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001517 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1518 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001519 ND_PRINTK(2, warn,
1520 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001521 goto release;
1522 }
1523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 read_lock_bh(&neigh->lock);
1525 if (neigh->nud_state & NUD_VALID) {
1526 memcpy(ha_buf, neigh->ha, dev->addr_len);
1527 read_unlock_bh(&neigh->lock);
1528 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001529 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 } else
1531 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001532
1533 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 }
1535
1536 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001537 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1538 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001540 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001542 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001543 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001544 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001546 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1547 *msg = (struct rd_msg) {
1548 .icmph = {
1549 .icmp6_type = NDISC_REDIRECT,
1550 },
1551 .target = *target,
1552 .dest = ipv6_hdr(skb)->daddr,
1553 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 /*
1556 * include target_address option
1557 */
1558
1559 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001560 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 /*
1563 * build redirect option and copy skb over to the new packet.
1564 */
1565
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001566 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001567 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
Eric Dumazetadf30902009-06-02 05:19:30 +00001569 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001570 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001571 return;
1572
1573release:
1574 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575}
1576
1577static void pndisc_redo(struct sk_buff *skb)
1578{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001579 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 kfree_skb(skb);
1581}
1582
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001583static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1584{
1585 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1586
1587 if (!idev)
1588 return true;
1589 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1590 idev->cnf.suppress_frag_ndisc) {
1591 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1592 return true;
1593 }
1594 return false;
1595}
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597int ndisc_rcv(struct sk_buff *skb)
1598{
1599 struct nd_msg *msg;
1600
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001601 if (ndisc_suppress_frag_ndisc(skb))
1602 return 0;
1603
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001604 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 return 0;
1606
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001607 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001609 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001611 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001612 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1613 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 return 0;
1615 }
1616
1617 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001618 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1619 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 return 0;
1621 }
1622
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001623 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1624
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 switch (msg->icmph.icmp6_type) {
1626 case NDISC_NEIGHBOUR_SOLICITATION:
1627 ndisc_recv_ns(skb);
1628 break;
1629
1630 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1631 ndisc_recv_na(skb);
1632 break;
1633
1634 case NDISC_ROUTER_SOLICITATION:
1635 ndisc_recv_rs(skb);
1636 break;
1637
1638 case NDISC_ROUTER_ADVERTISEMENT:
1639 ndisc_router_discovery(skb);
1640 break;
1641
1642 case NDISC_REDIRECT:
1643 ndisc_redirect_rcv(skb);
1644 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 return 0;
1648}
1649
1650static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1651{
Jiri Pirko351638e2013-05-28 01:30:21 +00001652 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001653 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001654 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 switch (event) {
1657 case NETDEV_CHANGEADDR:
1658 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001659 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001660 idev = in6_dev_get(dev);
1661 if (!idev)
1662 break;
1663 if (idev->cnf.ndisc_notify)
1664 ndisc_send_unsol_na(dev);
1665 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 break;
1667 case NETDEV_DOWN:
1668 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001669 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001671 case NETDEV_NOTIFY_PEERS:
1672 ndisc_send_unsol_na(dev);
1673 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 default:
1675 break;
1676 }
1677
1678 return NOTIFY_DONE;
1679}
1680
1681static struct notifier_block ndisc_netdev_notifier = {
1682 .notifier_call = ndisc_netdev_event,
1683};
1684
1685#ifdef CONFIG_SYSCTL
1686static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1687 const char *func, const char *dev_name)
1688{
1689 static char warncomm[TASK_COMM_LEN];
1690 static int warned;
1691 if (strcmp(warncomm, current->comm) && warned < 5) {
1692 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001693 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 -07001694 warncomm, func,
1695 dev_name, ctl->procname,
1696 dev_name, ctl->procname);
1697 warned++;
1698 }
1699}
1700
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001701int 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 -07001702{
1703 struct net_device *dev = ctl->extra1;
1704 struct inet6_dev *idev;
1705 int ret;
1706
Eric W. Biedermand12af672007-10-18 03:05:25 -07001707 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1708 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1710
Eric W. Biedermand12af672007-10-18 03:05:25 -07001711 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001712 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001713
1714 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001715 ret = neigh_proc_dointvec_jiffies(ctl, write,
1716 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001717
1718 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001719 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001720 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1721 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001722 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001726 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1727 idev->nd_parms->reachable_time =
1728 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 idev->tstamp = jiffies;
1730 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1731 in6_dev_put(idev);
1732 }
1733 return ret;
1734}
1735
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
1737#endif
1738
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001739static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740{
1741 struct ipv6_pinfo *np;
1742 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001743 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001745 err = inet_ctl_sock_create(&sk, PF_INET6,
1746 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001748 ND_PRINTK(0, err,
1749 "NDISC: Failed to initialize the control socket (err %d)\n",
1750 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 return err;
1752 }
1753
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001754 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 np->hop_limit = 255;
1758 /* Do not loopback ndisc messages */
1759 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001761 return 0;
1762}
1763
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001764static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001765{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001766 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001767}
1768
1769static struct pernet_operations ndisc_net_ops = {
1770 .init = ndisc_net_init,
1771 .exit = ndisc_net_exit,
1772};
1773
1774int __init ndisc_init(void)
1775{
1776 int err;
1777
1778 err = register_pernet_subsys(&ndisc_net_ops);
1779 if (err)
1780 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001781 /*
1782 * Initialize the neighbour table
1783 */
WANG Congd7480fd2014-11-10 15:59:36 -08001784 neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
1786#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001787 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301788 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001789 if (err)
1790 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001791out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001792#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001793 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001795#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001796out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001797 unregister_pernet_subsys(&ndisc_net_ops);
1798 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001799#endif
1800}
1801
1802int __init ndisc_late_init(void)
1803{
1804 return register_netdevice_notifier(&ndisc_netdev_notifier);
1805}
1806
1807void ndisc_late_cleanup(void)
1808{
1809 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810}
1811
1812void ndisc_cleanup(void)
1813{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814#ifdef CONFIG_SYSCTL
1815 neigh_sysctl_unregister(&nd_tbl.parms);
1816#endif
WANG Congd7480fd2014-11-10 15:59:36 -08001817 neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001818 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819}