blob: 7089c305245c81f7aa28af5141f2b64d9812e693 [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
Eric W. Biederman29a26a52015-09-15 20:04:16 -0500466 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
467 net, sk, skb, NULL, dst->dev,
Eric W. Biederman0c4b51f2015-09-15 20:04:18 -0500468 dst_output_okfn);
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
Jiri Benc38cf5952015-09-22 18:57:13 +0200477void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
Cong Wangf564f452013-08-31 13:44:36 +0800478 const struct in6_addr *solicited_addr,
479 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000481 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 struct in6_addr tmpaddr;
483 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900484 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000485 struct nd_msg *msg;
486 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900489 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900490 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700492 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300493 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000494 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 in6_ifa_put(ifp);
496 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700497 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900498 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900499 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 return;
501 src_addr = &tmpaddr;
502 }
503
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000504 if (!dev->addr_len)
505 inc_opt = 0;
506 if (inc_opt)
507 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000509 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000510 if (!skb)
511 return;
512
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000513 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
514 *msg = (struct nd_msg) {
515 .icmph = {
516 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
517 .icmp6_router = router,
518 .icmp6_solicited = solicited,
519 .icmp6_override = override,
520 },
521 .target = *solicited_addr,
522 };
523
524 if (inc_opt)
525 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
526 dev->dev_addr);
527
528
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000529 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900530}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000532static void ndisc_send_unsol_na(struct net_device *dev)
533{
534 struct inet6_dev *idev;
535 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000536
537 idev = in6_dev_get(dev);
538 if (!idev)
539 return;
540
541 read_lock_bh(&idev->lock);
542 list_for_each_entry(ifa, &idev->addr_list, if_list) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200543 ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000544 /*router=*/ !!idev->cnf.forwarding,
545 /*solicited=*/ false, /*override=*/ true,
546 /*inc_opt=*/ true);
547 }
548 read_unlock_bh(&idev->lock);
549
550 in6_dev_put(idev);
551}
552
Jiri Benc38cf5952015-09-22 18:57:13 +0200553void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
Jiri Bencab450602015-08-20 13:56:27 +0200554 const struct in6_addr *daddr, const struct in6_addr *saddr,
555 struct sk_buff *oskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000557 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000559 int inc_opt = dev->addr_len;
560 int optlen = 0;
561 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Ian Morris63159f22015-03-29 14:00:04 +0100563 if (!saddr) {
Neil Horman95c385b2007-04-25 17:08:10 -0700564 if (ipv6_get_lladdr(dev, &addr_buf,
565 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 return;
567 saddr = &addr_buf;
568 }
569
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000570 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300571 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000572 if (inc_opt)
573 optlen += ndisc_opt_addr_space(dev);
574
575 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000576 if (!skb)
577 return;
578
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000579 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
580 *msg = (struct nd_msg) {
581 .icmph = {
582 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
583 },
584 .target = *solicit,
585 };
586
587 if (inc_opt)
588 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
589 dev->dev_addr);
590
Jiri Bencab450602015-08-20 13:56:27 +0200591 if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE) && oskb)
592 skb_dst_copy(skb, oskb);
593
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000594 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595}
596
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900597void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
598 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000600 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000601 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700602 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000603 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700604
605#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
606 /*
607 * According to section 2.2 of RFC 4429, we must not
608 * send router solicitations with a sllao from
609 * optimistic addresses, but we may send the solicitation
610 * if we don't include the sllao. So here we check
611 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800612 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700613 */
614 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900615 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800616 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700617 if (ifp) {
618 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900619 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700620 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900621 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700622 } else {
623 send_sllao = 0;
624 }
625 }
626#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000627 if (send_sllao)
628 optlen += ndisc_opt_addr_space(dev);
629
630 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000631 if (!skb)
632 return;
633
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000634 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
635 *msg = (struct rs_msg) {
636 .icmph = {
637 .icmp6_type = NDISC_ROUTER_SOLICITATION,
638 },
639 };
640
641 if (send_sllao)
642 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
643 dev->dev_addr);
644
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000645 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
650{
651 /*
652 * "The sender MUST return an ICMP
653 * destination unreachable"
654 */
655 dst_link_failure(skb);
656 kfree_skb(skb);
657}
658
659/* Called with locked neigh: either read or both */
660
661static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
662{
663 struct in6_addr *saddr = NULL;
664 struct in6_addr mcaddr;
665 struct net_device *dev = neigh->dev;
666 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
667 int probes = atomic_read(&neigh->probes);
668
Erik Klinec58da4c2015-02-04 20:01:23 +0900669 if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
670 dev, 1,
671 IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700672 saddr = &ipv6_hdr(skb)->saddr;
Ian Morrise5d08d72014-11-23 21:28:43 +0000673 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
674 if (probes < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000676 ND_PRINTK(1, dbg,
677 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
678 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 }
Jiri Benc38cf5952015-09-22 18:57:13 +0200680 ndisc_send_ns(dev, target, target, saddr, skb);
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100681 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 } else {
684 addrconf_addr_solict_mult(target, &mcaddr);
Jiri Benc38cf5952015-09-22 18:57:13 +0200685 ndisc_send_ns(dev, target, &mcaddr, saddr, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
687}
688
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900689static int pndisc_is_router(const void *pkey,
690 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700691{
692 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900693 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700694
695 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900696 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
697 if (n)
698 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700699 read_unlock_bh(&nd_tbl.lock);
700
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900701 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700702}
703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704static void ndisc_recv_ns(struct sk_buff *skb)
705{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700706 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000707 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
708 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000710 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700711 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 struct ndisc_options ndopts;
713 struct net_device *dev = skb->dev;
714 struct inet6_ifaddr *ifp;
715 struct inet6_dev *idev = NULL;
716 struct neighbour *neigh;
717 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000718 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900719 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000721 if (skb->len < sizeof(struct nd_msg)) {
722 ND_PRINTK(2, warn, "NS: packet too short\n");
723 return;
724 }
725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000727 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return;
729 }
730
731 /*
732 * RFC2461 7.1.1:
733 * DAD has to be destined for solicited node multicast address.
734 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000735 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000736 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return;
738 }
739
740 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000741 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 return;
743 }
744
745 if (ndopts.nd_opts_src_lladdr) {
746 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
747 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000748 ND_PRINTK(2, warn,
749 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 return;
751 }
752
753 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900754 * If the IP source address is the unspecified address,
755 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 * in the message.
757 */
758 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000759 ND_PRINTK(2, warn,
760 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return;
762 }
763 }
764
765 inc = ipv6_addr_is_multicast(daddr);
766
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900767 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800768 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700769
770 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
771 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700772 /*
773 * We are colliding with another node
774 * who is doing DAD
775 * so fail our DAD process
776 */
777 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200778 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700779 } else {
780 /*
781 * This is not a dad solicitation.
782 * If we are an optimistic node,
783 * we should respond.
784 * Otherwise, we should ignore it.
785 */
786 if (!(ifp->flags & IFA_F_OPTIMISTIC))
787 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790
791 idev = ifp->idev;
792 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700793 struct net *net = dev_net(dev);
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 idev = in6_dev_get(dev);
796 if (!idev) {
797 /* XXX: count this drop? */
798 return;
799 }
800
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700801 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900802 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700803 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900804 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700805 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300807 inc &&
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100808 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 /*
810 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900811 * sender should delay its response
812 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 * MAX_ANYCAST_DELAY_TIME seconds.
814 * (RFC2461) -- yoshfuji
815 */
816 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
817 if (n)
818 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
819 goto out;
820 }
821 } else
822 goto out;
823 }
824
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900825 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000826 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700827
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (dad) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200829 ndisc_send_na(dev, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000830 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 goto out;
832 }
833
834 if (inc)
835 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
836 else
837 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
838
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900839 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 * update / create cache entry
841 * for the source address
842 */
843 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
844 !inc || lladdr || !dev->addr_len);
845 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900846 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 NEIGH_UPDATE_F_WEAK_OVERRIDE|
848 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700849 if (neigh || !dev->header_ops) {
Jiri Benc38cf5952015-09-22 18:57:13 +0200850 ndisc_send_na(dev, saddr, &msg->target, !!is_router,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000851 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (neigh)
853 neigh_release(neigh);
854 }
855
856out:
857 if (ifp)
858 in6_ifa_put(ifp);
859 else
860 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861}
862
863static void ndisc_recv_na(struct sk_buff *skb)
864{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700865 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800866 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000867 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000869 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700870 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 struct ndisc_options ndopts;
872 struct net_device *dev = skb->dev;
873 struct inet6_ifaddr *ifp;
874 struct neighbour *neigh;
875
876 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000877 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return;
879 }
880
881 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000882 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 return;
884 }
885
886 if (ipv6_addr_is_multicast(daddr) &&
887 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000888 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return;
890 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900891
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000893 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 return;
895 }
896 if (ndopts.nd_opts_tgt_lladdr) {
897 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
898 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000899 ND_PRINTK(2, warn,
900 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return;
902 }
903 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900904 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800905 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000906 if (skb->pkt_type != PACKET_LOOPBACK
907 && (ifp->flags & IFA_F_TENTATIVE)) {
908 addrconf_dad_failure(ifp);
909 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 }
911 /* What should we make now? The advertisement
912 is invalid, but ndisc specs say nothing
913 about it. It could be misconfiguration, or
914 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800915
916 We should not print the error if NA has been
917 received from loopback - it is just our own
918 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800920 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000921 ND_PRINTK(1, warn,
922 "NA: someone advertises our address %pI6 on %s!\n",
923 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 in6_ifa_put(ifp);
925 return;
926 }
927 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
928
929 if (neigh) {
930 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700931 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
933 if (neigh->nud_state & NUD_FAILED)
934 goto out;
935
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700936 /*
937 * Don't update the neighbor cache entry on a proxy NA from
938 * ourselves because either the proxied node is off link or it
939 * has already sent a NA to us.
940 */
941 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700942 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
943 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000944 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700945 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700946 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 neigh_update(neigh, lladdr,
949 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
950 NEIGH_UPDATE_F_WEAK_OVERRIDE|
951 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
952 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
953 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
954
955 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
956 /*
957 * Change: router to host
958 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800959 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 }
961
962out:
963 neigh_release(neigh);
964 }
965}
966
967static void ndisc_recv_rs(struct sk_buff *skb)
968{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700969 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
971 struct neighbour *neigh;
972 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000973 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 struct ndisc_options ndopts;
975 u8 *lladdr = NULL;
976
977 if (skb->len < sizeof(*rs_msg))
978 return;
979
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000980 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000982 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return;
984 }
985
986 /* Don't accept RS if we're not in router mode */
987 if (!idev->cnf.forwarding)
988 goto out;
989
990 /*
991 * Don't update NCE if src = ::;
992 * this implies that the source node has no ip address assigned yet.
993 */
994 if (ipv6_addr_any(saddr))
995 goto out;
996
997 /* Parse ND options */
998 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000999 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 goto out;
1001 }
1002
1003 if (ndopts.nd_opts_src_lladdr) {
1004 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1005 skb->dev);
1006 if (!lladdr)
1007 goto out;
1008 }
1009
1010 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1011 if (neigh) {
1012 neigh_update(neigh, lladdr, NUD_STALE,
1013 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1014 NEIGH_UPDATE_F_OVERRIDE|
1015 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1016 neigh_release(neigh);
1017 }
1018out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001019 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020}
1021
Pierre Ynard31910572007-10-10 21:22:05 -07001022static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1023{
1024 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1025 struct sk_buff *skb;
1026 struct nlmsghdr *nlh;
1027 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001028 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001029 int err;
1030 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1031 + (opt->nd_opt_len << 3));
1032 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1033
1034 skb = nlmsg_new(msg_size, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01001035 if (!skb) {
Pierre Ynard31910572007-10-10 21:22:05 -07001036 err = -ENOBUFS;
1037 goto errout;
1038 }
1039
1040 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
Ian Morris63159f22015-03-29 14:00:04 +01001041 if (!nlh) {
Pierre Ynard31910572007-10-10 21:22:05 -07001042 goto nla_put_failure;
1043 }
1044
1045 ndmsg = nlmsg_data(nlh);
1046 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001047 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001048 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1049 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1050 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1051
1052 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1053
Jiri Benc930345e2015-03-29 16:59:25 +02001054 if (nla_put_in6_addr(skb, NDUSEROPT_SRCADDR, &ipv6_hdr(ra)->saddr))
David S. Millerc78679e2012-04-01 20:27:33 -04001055 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001056 nlmsg_end(skb, nlh);
1057
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001058 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001059 return;
1060
1061nla_put_failure:
1062 nlmsg_free(skb);
1063 err = -EMSGSIZE;
1064errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001065 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001066}
1067
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068static void ndisc_router_discovery(struct sk_buff *skb)
1069{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001070 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 struct neighbour *neigh = NULL;
1072 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001073 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 int lifetime;
1075 struct ndisc_options ndopts;
1076 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001077 unsigned int pref = 0;
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001078 __u32 old_if_flags;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001079 bool send_ifinfo_notify = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Ian Morris67ba4152014-08-24 21:53:10 +01001081 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Simon Horman29a3cad2013-05-28 20:34:26 +00001083 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1084 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
Ben Greearf2a762d2014-06-25 14:44:52 -07001086 ND_PRINTK(2, info,
1087 "RA: %s, dev: %s\n",
1088 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001089 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001090 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 return;
1092 }
1093 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001094 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 return;
1096 }
1097
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001098#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001099 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001100 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001101 return;
1102 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001103#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001104
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 /*
1106 * set the RA_RECV flag in the interface
1107 */
1108
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001109 in6_dev = __in6_dev_get(skb->dev);
Ian Morris63159f22015-03-29 14:00:04 +01001110 if (!in6_dev) {
Joe Perches675418d2012-05-16 19:28:38 +00001111 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1112 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 return;
1114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
1116 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001117 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 return;
1119 }
1120
Ben Greearf2a762d2014-06-25 14:44:52 -07001121 if (!ipv6_accept_ra(in6_dev)) {
1122 ND_PRINTK(2, info,
1123 "RA: %s, did not accept ra for dev: %s\n",
1124 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001125 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001126 }
David Ward31ce8c72009-08-29 00:04:09 -07001127
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001128#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001129 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001130 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1131 ND_PRINTK(2, info,
1132 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1133 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001134 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001135 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001136#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 if (in6_dev->if_flags & IF_RS_SENT) {
1139 /*
1140 * flag that an RA was received after an RS was sent
1141 * out on this interface.
1142 */
1143 in6_dev->if_flags |= IF_RA_RCVD;
1144 }
1145
1146 /*
1147 * Remember the managed/otherconf flags from most recently
1148 * received RA message (RFC 2462) -- yoshfuji
1149 */
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001150 old_if_flags = in6_dev->if_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1152 IF_RA_OTHERCONF)) |
1153 (ra_msg->icmph.icmp6_addrconf_managed ?
1154 IF_RA_MANAGED : 0) |
1155 (ra_msg->icmph.icmp6_addrconf_other ?
1156 IF_RA_OTHERCONF : 0);
1157
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001158 if (old_if_flags != in6_dev->if_flags)
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001159 send_ifinfo_notify = true;
Marius Tomaschewskia394eef2015-08-31 15:59:22 +02001160
Ben Greearf2a762d2014-06-25 14:44:52 -07001161 if (!in6_dev->cnf.accept_ra_defrtr) {
1162 ND_PRINTK(2, info,
1163 "RA: %s, defrtr is false for dev: %s\n",
1164 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001165 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001166 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001167
Ben Greeard9333192014-06-25 14:44:53 -07001168 /* Do not accept RA with source-addr found on local machine unless
1169 * accept_ra_from_local is set to true.
1170 */
Li RongQingb6428812014-07-10 18:02:46 +08001171 if (!in6_dev->cnf.accept_ra_from_local &&
1172 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1173 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001174 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001175 "RA from local address detected on dev: %s: default router ignored\n",
1176 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001177 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001178 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1181
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001182#ifdef CONFIG_IPV6_ROUTER_PREF
1183 pref = ra_msg->icmph.icmp6_router_pref;
1184 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001185 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001186 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001187 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1188#endif
1189
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001190 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
David S. Millereb857182012-01-27 15:07:56 -08001192 if (rt) {
1193 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1194 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001195 ND_PRINTK(0, err,
1196 "RA: %s got default router without neighbour\n",
1197 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001198 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001199 return;
1200 }
1201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001203 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 rt = NULL;
1205 }
1206
Ben Greearf2a762d2014-06-25 14:44:52 -07001207 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1208 rt, lifetime, skb->dev->name);
Ian Morris63159f22015-03-29 14:00:04 +01001209 if (!rt && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001210 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001212 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Ian Morris63159f22015-03-29 14:00:04 +01001213 if (!rt) {
Joe Perches675418d2012-05-16 19:28:38 +00001214 ND_PRINTK(0, err,
1215 "RA: %s failed to add default route\n",
1216 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 return;
1218 }
1219
David S. Millereb857182012-01-27 15:07:56 -08001220 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Ian Morris63159f22015-03-29 14:00:04 +01001221 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001222 ND_PRINTK(0, err,
1223 "RA: %s got default router without neighbour\n",
1224 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001225 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 return;
1227 }
1228 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001229 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001230 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 }
1232
1233 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001234 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001235 if (in6_dev->cnf.accept_ra_min_hop_limit < 256 &&
1236 ra_msg->icmph.icmp6_hop_limit) {
1237 if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) {
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001238 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001239 if (rt)
1240 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1241 ra_msg->icmph.icmp6_hop_limit);
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001242 } else {
Hangbin Liu8013d1d2015-07-30 14:28:42 +08001243 ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than minimum\n");
D.S. Ljungmark6fd99092015-03-25 09:28:15 +01001244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 }
1246
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001247skip_defrtr:
1248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 /*
1250 * Update Reachable Time and Retrans Timer
1251 */
1252
1253 if (in6_dev->nd_parms) {
1254 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1255
1256 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1257 rtime = (rtime*HZ)/1000;
1258 if (rtime < HZ/10)
1259 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001260 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 in6_dev->tstamp = jiffies;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001262 send_ifinfo_notify = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 }
1264
1265 rtime = ntohl(ra_msg->reachable_time);
1266 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1267 rtime = (rtime*HZ)/1000;
1268
1269 if (rtime < HZ/10)
1270 rtime = HZ/10;
1271
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001272 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1273 NEIGH_VAR_SET(in6_dev->nd_parms,
1274 BASE_REACHABLE_TIME, rtime);
1275 NEIGH_VAR_SET(in6_dev->nd_parms,
1276 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1278 in6_dev->tstamp = jiffies;
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001279 send_ifinfo_notify = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 }
1281 }
1282 }
1283
Marius Tomaschewski2053aeb2015-09-01 01:57:30 +02001284 /*
1285 * Send a notify if RA changed managed/otherconf flags or timer settings
1286 */
1287 if (send_ifinfo_notify)
1288 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1289
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001290skip_linkparms:
1291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 /*
1293 * Process options.
1294 */
1295
1296 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001297 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 skb->dev, 1);
1299 if (neigh) {
1300 u8 *lladdr = NULL;
1301 if (ndopts.nd_opts_src_lladdr) {
1302 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1303 skb->dev);
1304 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001305 ND_PRINTK(2, warn,
1306 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 goto out;
1308 }
1309 }
1310 neigh_update(neigh, lladdr, NUD_STALE,
1311 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1312 NEIGH_UPDATE_F_OVERRIDE|
1313 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1314 NEIGH_UPDATE_F_ISROUTER);
1315 }
1316
Ben Greearf2a762d2014-06-25 14:44:52 -07001317 if (!ipv6_accept_ra(in6_dev)) {
1318 ND_PRINTK(2, info,
1319 "RA: %s, accept_ra is false for dev: %s\n",
1320 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001321 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001322 }
David Ward31ce8c72009-08-29 00:04:09 -07001323
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001324#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001325 if (!in6_dev->cnf.accept_ra_from_local &&
1326 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1327 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001328 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001329 "RA from local address detected on dev: %s: router info ignored.\n",
1330 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001331 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001332 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001333
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001334 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001335 struct nd_opt_hdr *p;
1336 for (p = ndopts.nd_opts_ri;
1337 p;
1338 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001339 struct route_info *ri = (struct route_info *)p;
1340#ifdef CONFIG_IPV6_NDISC_NODETYPE
1341 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1342 ri->prefix_len == 0)
1343 continue;
1344#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001345 if (ri->prefix_len == 0 &&
1346 !in6_dev->cnf.accept_ra_defrtr)
1347 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001348 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001349 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001350 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001351 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001352 }
1353 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001354
1355skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001356#endif
1357
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001358#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001359 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001360 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1361 ND_PRINTK(2, info,
1362 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1363 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001364 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001365 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001366#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001367
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001368 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 struct nd_opt_hdr *p;
1370 for (p = ndopts.nd_opts_pi;
1371 p;
1372 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001373 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1374 (p->nd_opt_len) << 3,
1375 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
1377 }
1378
Harout Hedeshianc2943f12015-01-20 10:06:05 -07001379 if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001380 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 u32 mtu;
1382
Ian Morris67ba4152014-08-24 21:53:10 +01001383 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4adc2006-11-14 20:56:00 -08001384 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
1386 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001387 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 } else if (in6_dev->cnf.mtu6 != mtu) {
1389 in6_dev->cnf.mtu6 = mtu;
1390
1391 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001392 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 rt6_mtu_change(skb->dev, mtu);
1395 }
1396 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001397
Pierre Ynard31910572007-10-10 21:22:05 -07001398 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001399 struct nd_opt_hdr *p;
1400 for (p = ndopts.nd_useropts;
1401 p;
1402 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1403 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001404 }
1405 }
1406
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001408 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 }
1410out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001411 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001412 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414}
1415
1416static void ndisc_redirect_rcv(struct sk_buff *skb)
1417{
Duan Jiong093d04d2012-12-14 02:59:59 +00001418 u8 *hdr;
1419 struct ndisc_options ndopts;
1420 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001421 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001422 offsetof(struct rd_msg, opt));
1423
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001424#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001425 switch (skb->ndisc_nodetype) {
1426 case NDISC_NODETYPE_HOST:
1427 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001428 ND_PRINTK(2, warn,
1429 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001430 return;
1431 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001432#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001433
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001434 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001435 ND_PRINTK(2, warn,
1436 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 return;
1438 }
1439
Duan Jiong093d04d2012-12-14 02:59:59 +00001440 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1441 return;
1442
Duan Jiongc92a59e2013-08-22 12:07:35 +08001443 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001444 ip6_redirect_no_header(skb, dev_net(skb->dev),
1445 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001446 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001447 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001448
1449 hdr = (u8 *)ndopts.nd_opts_rh;
1450 hdr += 8;
1451 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1452 return;
1453
David S. Millerb94f1c02012-07-12 00:33:37 -07001454 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455}
1456
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001457static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1458 struct sk_buff *orig_skb,
1459 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001460{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001461 u8 *opt = skb_put(skb, rd_len);
1462
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001463 memset(opt, 0, 8);
1464 *(opt++) = ND_OPT_REDIRECT_HDR;
1465 *(opt++) = (rd_len >> 3);
1466 opt += 6;
1467
1468 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001469}
1470
David S. Miller49919692012-01-27 15:30:48 -08001471void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001473 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001474 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001475 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001476 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001477 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001479 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 struct rt6_info *rt;
1482 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001483 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001486 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
Neil Horman95c385b2007-04-25 17:08:10 -07001488 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001489 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1490 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001491 return;
1492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001494 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001495 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001496 ND_PRINTK(2, warn,
1497 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001498 return;
1499 }
1500
David S. Miller4c9483b2011-03-12 16:22:43 -05001501 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001502 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
David S. Miller4c9483b2011-03-12 16:22:43 -05001504 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001505 if (dst->error) {
1506 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001508 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001509 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001510 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
1513 rt = (struct rt6_info *) dst;
1514
1515 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001516 ND_PRINTK(2, warn,
1517 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001518 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 }
Martin KaFai Laufd0273d2015-05-22 20:55:57 -07001520 peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1);
David S. Miller1d861aa2012-07-10 03:58:16 -07001521 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1522 if (peer)
1523 inet_putpeer(peer);
1524 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001525 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001528 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1529 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001530 ND_PRINTK(2, warn,
1531 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001532 goto release;
1533 }
1534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 read_lock_bh(&neigh->lock);
1536 if (neigh->nud_state & NUD_VALID) {
1537 memcpy(ha_buf, neigh->ha, dev->addr_len);
1538 read_unlock_bh(&neigh->lock);
1539 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001540 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 } else
1542 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001543
1544 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 }
1546
1547 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001548 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1549 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001551 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001553 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001554 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001555 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001557 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1558 *msg = (struct rd_msg) {
1559 .icmph = {
1560 .icmp6_type = NDISC_REDIRECT,
1561 },
1562 .target = *target,
1563 .dest = ipv6_hdr(skb)->daddr,
1564 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 /*
1567 * include target_address option
1568 */
1569
1570 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001571 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
1573 /*
1574 * build redirect option and copy skb over to the new packet.
1575 */
1576
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001577 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001578 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Eric Dumazetadf30902009-06-02 05:19:30 +00001580 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001581 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001582 return;
1583
1584release:
1585 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586}
1587
1588static void pndisc_redo(struct sk_buff *skb)
1589{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001590 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 kfree_skb(skb);
1592}
1593
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001594static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1595{
1596 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1597
1598 if (!idev)
1599 return true;
1600 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1601 idev->cnf.suppress_frag_ndisc) {
1602 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1603 return true;
1604 }
1605 return false;
1606}
1607
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608int ndisc_rcv(struct sk_buff *skb)
1609{
1610 struct nd_msg *msg;
1611
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001612 if (ndisc_suppress_frag_ndisc(skb))
1613 return 0;
1614
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001615 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 return 0;
1617
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001618 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001620 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001622 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001623 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1624 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 return 0;
1626 }
1627
1628 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001629 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1630 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 return 0;
1632 }
1633
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001634 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1635
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 switch (msg->icmph.icmp6_type) {
1637 case NDISC_NEIGHBOUR_SOLICITATION:
1638 ndisc_recv_ns(skb);
1639 break;
1640
1641 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1642 ndisc_recv_na(skb);
1643 break;
1644
1645 case NDISC_ROUTER_SOLICITATION:
1646 ndisc_recv_rs(skb);
1647 break;
1648
1649 case NDISC_ROUTER_ADVERTISEMENT:
1650 ndisc_router_discovery(skb);
1651 break;
1652
1653 case NDISC_REDIRECT:
1654 ndisc_redirect_rcv(skb);
1655 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657
1658 return 0;
1659}
1660
1661static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1662{
Jiri Pirko351638e2013-05-28 01:30:21 +00001663 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazetc8507fb2015-07-29 12:01:41 +02001664 struct netdev_notifier_change_info *change_info;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001665 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001666 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668 switch (event) {
1669 case NETDEV_CHANGEADDR:
1670 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001671 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001672 idev = in6_dev_get(dev);
1673 if (!idev)
1674 break;
1675 if (idev->cnf.ndisc_notify)
1676 ndisc_send_unsol_na(dev);
1677 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 break;
Eric Dumazetc8507fb2015-07-29 12:01:41 +02001679 case NETDEV_CHANGE:
1680 change_info = ptr;
1681 if (change_info->flags_changed & IFF_NOARP)
1682 neigh_changeaddr(&nd_tbl, dev);
1683 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 case NETDEV_DOWN:
1685 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001686 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001688 case NETDEV_NOTIFY_PEERS:
1689 ndisc_send_unsol_na(dev);
1690 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 default:
1692 break;
1693 }
1694
1695 return NOTIFY_DONE;
1696}
1697
1698static struct notifier_block ndisc_netdev_notifier = {
1699 .notifier_call = ndisc_netdev_event,
1700};
1701
1702#ifdef CONFIG_SYSCTL
1703static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1704 const char *func, const char *dev_name)
1705{
1706 static char warncomm[TASK_COMM_LEN];
1707 static int warned;
1708 if (strcmp(warncomm, current->comm) && warned < 5) {
1709 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001710 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 -07001711 warncomm, func,
1712 dev_name, ctl->procname,
1713 dev_name, ctl->procname);
1714 warned++;
1715 }
1716}
1717
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001718int 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 -07001719{
1720 struct net_device *dev = ctl->extra1;
1721 struct inet6_dev *idev;
1722 int ret;
1723
Eric W. Biedermand12af672007-10-18 03:05:25 -07001724 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1725 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1727
Eric W. Biedermand12af672007-10-18 03:05:25 -07001728 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001729 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001730
1731 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001732 ret = neigh_proc_dointvec_jiffies(ctl, write,
1733 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001734
1735 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001736 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001737 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1738 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001739 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
1742 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001743 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1744 idev->nd_parms->reachable_time =
1745 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 idev->tstamp = jiffies;
1747 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1748 in6_dev_put(idev);
1749 }
1750 return ret;
1751}
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
1754#endif
1755
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001756static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757{
1758 struct ipv6_pinfo *np;
1759 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001760 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001762 err = inet_ctl_sock_create(&sk, PF_INET6,
1763 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001765 ND_PRINTK(0, err,
1766 "NDISC: Failed to initialize the control socket (err %d)\n",
1767 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 return err;
1769 }
1770
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001771 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 np->hop_limit = 255;
1775 /* Do not loopback ndisc messages */
1776 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001778 return 0;
1779}
1780
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001781static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001782{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001783 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001784}
1785
1786static struct pernet_operations ndisc_net_ops = {
1787 .init = ndisc_net_init,
1788 .exit = ndisc_net_exit,
1789};
1790
1791int __init ndisc_init(void)
1792{
1793 int err;
1794
1795 err = register_pernet_subsys(&ndisc_net_ops);
1796 if (err)
1797 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001798 /*
1799 * Initialize the neighbour table
1800 */
WANG Congd7480fd2014-11-10 15:59:36 -08001801 neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
1803#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001804 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301805 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001806 if (err)
1807 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001808out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001809#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001810 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001812#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001813out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001814 unregister_pernet_subsys(&ndisc_net_ops);
1815 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001816#endif
1817}
1818
1819int __init ndisc_late_init(void)
1820{
1821 return register_netdevice_notifier(&ndisc_netdev_notifier);
1822}
1823
1824void ndisc_late_cleanup(void)
1825{
1826 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827}
1828
1829void ndisc_cleanup(void)
1830{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831#ifdef CONFIG_SYSCTL
1832 neigh_sysctl_unregister(&nd_tbl.parms);
1833#endif
WANG Congd7480fd2014-11-10 15:59:36 -08001834 neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001835 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836}