blob: e363bbc2420d8dec7e4d3c4626ac089513d0a04e [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);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static int ndisc_constructor(struct neighbour *neigh);
88static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
89static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
90static int pndisc_constructor(struct pneigh_entry *n);
91static void pndisc_destructor(struct pneigh_entry *n);
92static void pndisc_redo(struct sk_buff *skb);
93
Stephen Hemminger89d69d22009-09-01 11:13:19 +000094static const struct neigh_ops ndisc_generic_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 .family = AF_INET6,
96 .solicit = ndisc_solicit,
97 .error_report = ndisc_error_report,
98 .output = neigh_resolve_output,
99 .connected_output = neigh_connected_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100};
101
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000102static const struct neigh_ops ndisc_hh_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 .family = AF_INET6,
104 .solicit = ndisc_solicit,
105 .error_report = ndisc_error_report,
106 .output = neigh_resolve_output,
107 .connected_output = neigh_resolve_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000111static const struct neigh_ops ndisc_direct_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .family = AF_INET6,
David S. Miller8f40b162011-07-17 13:34:11 -0700113 .output = neigh_direct_output,
114 .connected_output = neigh_direct_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115};
116
117struct neigh_table nd_tbl = {
118 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 .key_len = sizeof(struct in6_addr),
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -0600120 .protocol = cpu_to_be16(ETH_P_IPV6),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 .hash = ndisc_hash,
122 .constructor = ndisc_constructor,
123 .pconstructor = pndisc_constructor,
124 .pdestructor = pndisc_destructor,
125 .proxy_redo = pndisc_redo,
126 .id = "ndisc_cache",
127 .parms = {
Shan Weib6720832010-12-01 18:05:12 +0000128 .tbl = &nd_tbl,
Shan Weib6720832010-12-01 18:05:12 +0000129 .reachable_time = ND_REACHABLE_TIME,
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100130 .data = {
131 [NEIGH_VAR_MCAST_PROBES] = 3,
132 [NEIGH_VAR_UCAST_PROBES] = 3,
133 [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
134 [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
135 [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
136 [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
137 [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
138 [NEIGH_VAR_PROXY_QLEN] = 64,
139 [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
140 [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,
141 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 },
143 .gc_interval = 30 * HZ,
144 .gc_thresh1 = 128,
145 .gc_thresh2 = 512,
146 .gc_thresh3 = 1024,
147};
148
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000149static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000151 int pad = ndisc_addr_option_pad(skb->dev->type);
152 int data_len = skb->dev->addr_len;
153 int space = ndisc_opt_addr_space(skb->dev);
154 u8 *opt = skb_put(skb, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 opt[0] = type;
157 opt[1] = space>>3;
158
159 memset(opt + 2, 0, pad);
160 opt += pad;
161 space -= pad;
162
163 memcpy(opt+2, data, data_len);
164 data_len += 2;
165 opt += data_len;
Ian Morrise5d08d72014-11-23 21:28:43 +0000166 space -= data_len;
167 if (space > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169}
170
171static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
172 struct nd_opt_hdr *end)
173{
174 int type;
175 if (!cur || !end || cur >= end)
176 return NULL;
177 type = cur->nd_opt_type;
178 do {
179 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100180 } while (cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000181 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182}
183
Pierre Ynard31910572007-10-10 21:22:05 -0700184static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
185{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000186 return opt->nd_opt_type == ND_OPT_RDNSS ||
187 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700188}
189
190static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
191 struct nd_opt_hdr *end)
192{
193 if (!cur || !end || cur >= end)
194 return NULL;
195 do {
196 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100197 } while (cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000198 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700199}
200
David S. Miller30f2a5f2012-07-11 23:26:46 -0700201struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
202 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203{
204 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
205
206 if (!nd_opt || opt_len < 0 || !ndopts)
207 return NULL;
208 memset(ndopts, 0, sizeof(*ndopts));
209 while (opt_len) {
210 int l;
211 if (opt_len < sizeof(struct nd_opt_hdr))
212 return NULL;
213 l = nd_opt->nd_opt_len << 3;
214 if (opt_len < l || l == 0)
215 return NULL;
216 switch (nd_opt->nd_opt_type) {
217 case ND_OPT_SOURCE_LL_ADDR:
218 case ND_OPT_TARGET_LL_ADDR:
219 case ND_OPT_MTU:
220 case ND_OPT_REDIRECT_HDR:
221 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000222 ND_PRINTK(2, warn,
223 "%s: duplicated ND6 option found: type=%d\n",
224 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 } else {
226 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
227 }
228 break;
229 case ND_OPT_PREFIX_INFO:
230 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700231 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
233 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800234#ifdef CONFIG_IPV6_ROUTE_INFO
235 case ND_OPT_ROUTE_INFO:
236 ndopts->nd_opts_ri_end = nd_opt;
237 if (!ndopts->nd_opts_ri)
238 ndopts->nd_opts_ri = nd_opt;
239 break;
240#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700242 if (ndisc_is_useropt(nd_opt)) {
243 ndopts->nd_useropts_end = nd_opt;
244 if (!ndopts->nd_useropts)
245 ndopts->nd_useropts = nd_opt;
246 } else {
247 /*
248 * Unknown options must be silently ignored,
249 * to accommodate future extension to the
250 * protocol.
251 */
Joe Perches675418d2012-05-16 19:28:38 +0000252 ND_PRINTK(2, notice,
253 "%s: ignored unsupported option; type=%d, len=%d\n",
254 __func__,
255 nd_opt->nd_opt_type,
256 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
259 opt_len -= l;
260 nd_opt = ((void *)nd_opt) + l;
261 }
262 return ndopts;
263}
264
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000265int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
267 switch (dev->type) {
268 case ARPHRD_ETHER:
269 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
270 case ARPHRD_FDDI:
271 ipv6_eth_mc_map(addr, buf);
272 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 case ARPHRD_ARCNET:
274 ipv6_arcnet_mc_map(addr, buf);
275 return 0;
276 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700277 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000279 case ARPHRD_IPGRE:
280 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 default:
282 if (dir) {
283 memcpy(buf, dev->broadcast, dev->addr_len);
284 return 0;
285 }
286 }
287 return -EINVAL;
288}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900289EXPORT_SYMBOL(ndisc_mc_map);
290
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000291static u32 ndisc_hash(const void *pkey,
292 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500293 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
David S. Miller2c2aba62011-12-28 15:06:58 -0500295 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
298static int ndisc_constructor(struct neighbour *neigh)
299{
Ian Morris67ba4152014-08-24 21:53:10 +0100300 struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 struct net_device *dev = neigh->dev;
302 struct inet6_dev *in6_dev;
303 struct neigh_parms *parms;
Eric Dumazeta50feda2012-05-18 18:57:34 +0000304 bool is_multicast = ipv6_addr_is_multicast(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 in6_dev = in6_dev_get(dev);
307 if (in6_dev == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 return -EINVAL;
309 }
310
311 parms = in6_dev->nd_parms;
312 __neigh_parms_put(neigh->parms);
313 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700316 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 neigh->nud_state = NUD_NOARP;
318 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700319 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 } else {
321 if (is_multicast) {
322 neigh->nud_state = NUD_NOARP;
323 ndisc_mc_map(addr, neigh->ha, dev, 1);
324 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
325 neigh->nud_state = NUD_NOARP;
326 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
327 if (dev->flags&IFF_LOOPBACK)
328 neigh->type = RTN_LOCAL;
329 } else if (dev->flags&IFF_POINTOPOINT) {
330 neigh->nud_state = NUD_NOARP;
331 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
332 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700333 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 neigh->ops = &ndisc_hh_ops;
335 else
336 neigh->ops = &ndisc_generic_ops;
337 if (neigh->nud_state&NUD_VALID)
338 neigh->output = neigh->ops->connected_output;
339 else
340 neigh->output = neigh->ops->output;
341 }
342 in6_dev_put(in6_dev);
343 return 0;
344}
345
346static int pndisc_constructor(struct pneigh_entry *n)
347{
Ian Morris67ba4152014-08-24 21:53:10 +0100348 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 struct in6_addr maddr;
350 struct net_device *dev = n->dev;
351
352 if (dev == NULL || __in6_dev_get(dev) == NULL)
353 return -EINVAL;
354 addrconf_addr_solict_mult(addr, &maddr);
355 ipv6_dev_mc_inc(dev, &maddr);
356 return 0;
357}
358
359static void pndisc_destructor(struct pneigh_entry *n)
360{
Ian Morris67ba4152014-08-24 21:53:10 +0100361 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 struct in6_addr maddr;
363 struct net_device *dev = n->dev;
364
365 if (dev == NULL || __in6_dev_get(dev) == NULL)
366 return;
367 addrconf_addr_solict_mult(addr, &maddr);
368 ipv6_dev_mc_dec(dev, &maddr);
369}
370
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000371static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
372 int len)
373{
374 int hlen = LL_RESERVED_SPACE(dev);
375 int tlen = dev->needed_tailroom;
376 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
377 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000378
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200379 skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000380 if (!skb) {
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200381 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
382 __func__);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000383 return NULL;
384 }
385
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000386 skb->protocol = htons(ETH_P_IPV6);
387 skb->dev = dev;
388
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000389 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki / 吉藤英明5135e632013-01-21 06:48:44 +0000390 skb_reset_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000391
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200392 /* Manually assign socket ownership as we avoid calling
393 * sock_alloc_send_pskb() to bypass wmem buffer limits
394 */
395 skb_set_owner_w(skb, sk);
396
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000397 return skb;
398}
399
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000400static void ip6_nd_hdr(struct sk_buff *skb,
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000401 const struct in6_addr *saddr,
402 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000403 int hop_limit, int len)
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000404{
405 struct ipv6hdr *hdr;
406
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000407 skb_push(skb, sizeof(*hdr));
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000408 skb_reset_network_header(skb);
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000409 hdr = ipv6_hdr(skb);
410
411 ip6_flow_hdr(hdr, 0, 0);
412
413 hdr->payload_len = htons(len);
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000414 hdr->nexthdr = IPPROTO_ICMPV6;
415 hdr->hop_limit = hop_limit;
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000416
417 hdr->saddr = *saddr;
418 hdr->daddr = *daddr;
419}
420
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000421static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900422 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000423 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800424{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000425 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000426 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000427 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800428 struct inet6_dev *idev;
429 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000430 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800431 u8 type;
432
433 type = icmp6h->icmp6_type;
434
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000435 if (!dst) {
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000436 struct flowi6 fl6;
Brian Haley305d5522008-11-04 17:51:14 -0800437
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000438 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
439 dst = icmp6_dst_alloc(skb->dev, &fl6);
440 if (IS_ERR(dst)) {
441 kfree_skb(skb);
442 return;
443 }
444
445 skb_dst_set(skb, dst);
446 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900447
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000448 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
449 IPPROTO_ICMPV6,
450 csum_partial(icmp6h,
451 skb->len, 0));
452
453 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
454
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000455 rcu_read_lock();
456 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700457 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900458
Jan Engelhardtb2e0b382010-03-23 04:09:07 +0100459 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
Patrick McHardy6e23ae22007-11-19 18:53:30 -0800460 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900461 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700462 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700463 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900464 }
465
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000466 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900467}
468
Cong Wangf564f452013-08-31 13:44:36 +0800469void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
470 const struct in6_addr *daddr,
471 const struct in6_addr *solicited_addr,
472 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000474 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 struct in6_addr tmpaddr;
476 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900477 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000478 struct nd_msg *msg;
479 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
481 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900482 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900483 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700485 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300486 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000487 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 in6_ifa_put(ifp);
489 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700490 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900491 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900492 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 return;
494 src_addr = &tmpaddr;
495 }
496
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000497 if (!dev->addr_len)
498 inc_opt = 0;
499 if (inc_opt)
500 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000502 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000503 if (!skb)
504 return;
505
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000506 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
507 *msg = (struct nd_msg) {
508 .icmph = {
509 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
510 .icmp6_router = router,
511 .icmp6_solicited = solicited,
512 .icmp6_override = override,
513 },
514 .target = *solicited_addr,
515 };
516
517 if (inc_opt)
518 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
519 dev->dev_addr);
520
521
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000522 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900523}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000525static void ndisc_send_unsol_na(struct net_device *dev)
526{
527 struct inet6_dev *idev;
528 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000529
530 idev = in6_dev_get(dev);
531 if (!idev)
532 return;
533
534 read_lock_bh(&idev->lock);
535 list_for_each_entry(ifa, &idev->addr_list, if_list) {
YOSHIFUJI Hideaki / 吉藤英明9fafd652012-11-12 07:50:17 +0000536 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000537 /*router=*/ !!idev->cnf.forwarding,
538 /*solicited=*/ false, /*override=*/ true,
539 /*inc_opt=*/ true);
540 }
541 read_unlock_bh(&idev->lock);
542
543 in6_dev_put(idev);
544}
545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900547 const struct in6_addr *solicit,
548 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000550 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000552 int inc_opt = dev->addr_len;
553 int optlen = 0;
554 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 if (saddr == NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700557 if (ipv6_get_lladdr(dev, &addr_buf,
558 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 return;
560 saddr = &addr_buf;
561 }
562
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000563 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300564 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000565 if (inc_opt)
566 optlen += ndisc_opt_addr_space(dev);
567
568 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000569 if (!skb)
570 return;
571
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000572 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
573 *msg = (struct nd_msg) {
574 .icmph = {
575 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
576 },
577 .target = *solicit,
578 };
579
580 if (inc_opt)
581 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
582 dev->dev_addr);
583
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000584 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585}
586
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900587void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
588 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000590 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000591 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700592 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000593 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700594
595#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
596 /*
597 * According to section 2.2 of RFC 4429, we must not
598 * send router solicitations with a sllao from
599 * optimistic addresses, but we may send the solicitation
600 * if we don't include the sllao. So here we check
601 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800602 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700603 */
604 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900605 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800606 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700607 if (ifp) {
608 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900609 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700610 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900611 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700612 } else {
613 send_sllao = 0;
614 }
615 }
616#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000617 if (send_sllao)
618 optlen += ndisc_opt_addr_space(dev);
619
620 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000621 if (!skb)
622 return;
623
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000624 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
625 *msg = (struct rs_msg) {
626 .icmph = {
627 .icmp6_type = NDISC_ROUTER_SOLICITATION,
628 },
629 };
630
631 if (send_sllao)
632 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
633 dev->dev_addr);
634
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000635 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
640{
641 /*
642 * "The sender MUST return an ICMP
643 * destination unreachable"
644 */
645 dst_link_failure(skb);
646 kfree_skb(skb);
647}
648
649/* Called with locked neigh: either read or both */
650
651static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
652{
653 struct in6_addr *saddr = NULL;
654 struct in6_addr mcaddr;
655 struct net_device *dev = neigh->dev;
656 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
657 int probes = atomic_read(&neigh->probes);
658
Erik Klinec58da4c2015-02-04 20:01:23 +0900659 if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
660 dev, 1,
661 IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700662 saddr = &ipv6_hdr(skb)->saddr;
Ian Morrise5d08d72014-11-23 21:28:43 +0000663 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
664 if (probes < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000666 ND_PRINTK(1, dbg,
667 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
668 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
670 ndisc_send_ns(dev, neigh, target, target, saddr);
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100671 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 } else {
674 addrconf_addr_solict_mult(target, &mcaddr);
675 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
676 }
677}
678
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900679static int pndisc_is_router(const void *pkey,
680 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700681{
682 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900683 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700684
685 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900686 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
687 if (n)
688 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700689 read_unlock_bh(&nd_tbl.lock);
690
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900691 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700692}
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694static void ndisc_recv_ns(struct sk_buff *skb)
695{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700696 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000697 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
698 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000700 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700701 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 struct ndisc_options ndopts;
703 struct net_device *dev = skb->dev;
704 struct inet6_ifaddr *ifp;
705 struct inet6_dev *idev = NULL;
706 struct neighbour *neigh;
707 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000708 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900709 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000711 if (skb->len < sizeof(struct nd_msg)) {
712 ND_PRINTK(2, warn, "NS: packet too short\n");
713 return;
714 }
715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000717 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return;
719 }
720
721 /*
722 * RFC2461 7.1.1:
723 * DAD has to be destined for solicited node multicast address.
724 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000725 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000726 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return;
728 }
729
730 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000731 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return;
733 }
734
735 if (ndopts.nd_opts_src_lladdr) {
736 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
737 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000738 ND_PRINTK(2, warn,
739 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 return;
741 }
742
743 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900744 * If the IP source address is the unspecified address,
745 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 * in the message.
747 */
748 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000749 ND_PRINTK(2, warn,
750 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return;
752 }
753 }
754
755 inc = ipv6_addr_is_multicast(daddr);
756
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900757 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800758 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700759
760 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
761 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700762 /*
763 * We are colliding with another node
764 * who is doing DAD
765 * so fail our DAD process
766 */
767 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200768 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700769 } else {
770 /*
771 * This is not a dad solicitation.
772 * If we are an optimistic node,
773 * we should respond.
774 * Otherwise, we should ignore it.
775 */
776 if (!(ifp->flags & IFA_F_OPTIMISTIC))
777 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780
781 idev = ifp->idev;
782 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700783 struct net *net = dev_net(dev);
784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 idev = in6_dev_get(dev);
786 if (!idev) {
787 /* XXX: count this drop? */
788 return;
789 }
790
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700791 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900792 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700793 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900794 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700795 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300797 inc &&
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100798 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 /*
800 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900801 * sender should delay its response
802 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 * MAX_ANYCAST_DELAY_TIME seconds.
804 * (RFC2461) -- yoshfuji
805 */
806 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
807 if (n)
808 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
809 goto out;
810 }
811 } else
812 goto out;
813 }
814
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900815 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000816 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900819 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000820 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 goto out;
822 }
823
824 if (inc)
825 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
826 else
827 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
828
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900829 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 * update / create cache entry
831 * for the source address
832 */
833 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
834 !inc || lladdr || !dev->addr_len);
835 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900836 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 NEIGH_UPDATE_F_WEAK_OVERRIDE|
838 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700839 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 ndisc_send_na(dev, neigh, saddr, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000841 !!is_router,
842 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 if (neigh)
844 neigh_release(neigh);
845 }
846
847out:
848 if (ifp)
849 in6_ifa_put(ifp);
850 else
851 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852}
853
854static void ndisc_recv_na(struct sk_buff *skb)
855{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700856 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800857 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000858 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000860 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700861 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 struct ndisc_options ndopts;
863 struct net_device *dev = skb->dev;
864 struct inet6_ifaddr *ifp;
865 struct neighbour *neigh;
866
867 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000868 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 return;
870 }
871
872 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000873 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return;
875 }
876
877 if (ipv6_addr_is_multicast(daddr) &&
878 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000879 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 return;
881 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000884 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 return;
886 }
887 if (ndopts.nd_opts_tgt_lladdr) {
888 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
889 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000890 ND_PRINTK(2, warn,
891 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 return;
893 }
894 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900895 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800896 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000897 if (skb->pkt_type != PACKET_LOOPBACK
898 && (ifp->flags & IFA_F_TENTATIVE)) {
899 addrconf_dad_failure(ifp);
900 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 }
902 /* What should we make now? The advertisement
903 is invalid, but ndisc specs say nothing
904 about it. It could be misconfiguration, or
905 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800906
907 We should not print the error if NA has been
908 received from loopback - it is just our own
909 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800911 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000912 ND_PRINTK(1, warn,
913 "NA: someone advertises our address %pI6 on %s!\n",
914 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 in6_ifa_put(ifp);
916 return;
917 }
918 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
919
920 if (neigh) {
921 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700922 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 if (neigh->nud_state & NUD_FAILED)
925 goto out;
926
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700927 /*
928 * Don't update the neighbor cache entry on a proxy NA from
929 * ourselves because either the proxied node is off link or it
930 * has already sent a NA to us.
931 */
932 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700933 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
934 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000935 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700936 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700937 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 neigh_update(neigh, lladdr,
940 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
941 NEIGH_UPDATE_F_WEAK_OVERRIDE|
942 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
943 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
944 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
945
946 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
947 /*
948 * Change: router to host
949 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800950 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 }
952
953out:
954 neigh_release(neigh);
955 }
956}
957
958static void ndisc_recv_rs(struct sk_buff *skb)
959{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700960 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
962 struct neighbour *neigh;
963 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000964 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 struct ndisc_options ndopts;
966 u8 *lladdr = NULL;
967
968 if (skb->len < sizeof(*rs_msg))
969 return;
970
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000971 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000973 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return;
975 }
976
977 /* Don't accept RS if we're not in router mode */
978 if (!idev->cnf.forwarding)
979 goto out;
980
981 /*
982 * Don't update NCE if src = ::;
983 * this implies that the source node has no ip address assigned yet.
984 */
985 if (ipv6_addr_any(saddr))
986 goto out;
987
988 /* Parse ND options */
989 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000990 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 goto out;
992 }
993
994 if (ndopts.nd_opts_src_lladdr) {
995 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
996 skb->dev);
997 if (!lladdr)
998 goto out;
999 }
1000
1001 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1002 if (neigh) {
1003 neigh_update(neigh, lladdr, NUD_STALE,
1004 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1005 NEIGH_UPDATE_F_OVERRIDE|
1006 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1007 neigh_release(neigh);
1008 }
1009out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001010 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011}
1012
Pierre Ynard31910572007-10-10 21:22:05 -07001013static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1014{
1015 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1016 struct sk_buff *skb;
1017 struct nlmsghdr *nlh;
1018 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001019 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001020 int err;
1021 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1022 + (opt->nd_opt_len << 3));
1023 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1024
1025 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1026 if (skb == NULL) {
1027 err = -ENOBUFS;
1028 goto errout;
1029 }
1030
1031 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1032 if (nlh == NULL) {
1033 goto nla_put_failure;
1034 }
1035
1036 ndmsg = nlmsg_data(nlh);
1037 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001038 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001039 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1040 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1041 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1042
1043 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1044
David S. Millerc78679e2012-04-01 20:27:33 -04001045 if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1046 &ipv6_hdr(ra)->saddr))
1047 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001048 nlmsg_end(skb, nlh);
1049
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001050 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001051 return;
1052
1053nla_put_failure:
1054 nlmsg_free(skb);
1055 err = -EMSGSIZE;
1056errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001057 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001058}
1059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060static void ndisc_router_discovery(struct sk_buff *skb)
1061{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001062 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 struct neighbour *neigh = NULL;
1064 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001065 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 int lifetime;
1067 struct ndisc_options ndopts;
1068 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001069 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Ian Morris67ba4152014-08-24 21:53:10 +01001071 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Simon Horman29a3cad2013-05-28 20:34:26 +00001073 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1074 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Ben Greearf2a762d2014-06-25 14:44:52 -07001076 ND_PRINTK(2, info,
1077 "RA: %s, dev: %s\n",
1078 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001079 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001080 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 return;
1082 }
1083 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001084 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 return;
1086 }
1087
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001088#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001089 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001090 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001091 return;
1092 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001093#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 /*
1096 * set the RA_RECV flag in the interface
1097 */
1098
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001099 in6_dev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 if (in6_dev == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001101 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1102 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 return;
1104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001107 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return;
1109 }
1110
Ben Greearf2a762d2014-06-25 14:44:52 -07001111 if (!ipv6_accept_ra(in6_dev)) {
1112 ND_PRINTK(2, info,
1113 "RA: %s, did not accept ra for dev: %s\n",
1114 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001115 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001116 }
David Ward31ce8c72009-08-29 00:04:09 -07001117
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001118#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001119 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001120 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1121 ND_PRINTK(2, info,
1122 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1123 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001124 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001125 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001126#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 if (in6_dev->if_flags & IF_RS_SENT) {
1129 /*
1130 * flag that an RA was received after an RS was sent
1131 * out on this interface.
1132 */
1133 in6_dev->if_flags |= IF_RA_RCVD;
1134 }
1135
1136 /*
1137 * Remember the managed/otherconf flags from most recently
1138 * received RA message (RFC 2462) -- yoshfuji
1139 */
1140 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1141 IF_RA_OTHERCONF)) |
1142 (ra_msg->icmph.icmp6_addrconf_managed ?
1143 IF_RA_MANAGED : 0) |
1144 (ra_msg->icmph.icmp6_addrconf_other ?
1145 IF_RA_OTHERCONF : 0);
1146
Ben Greearf2a762d2014-06-25 14:44:52 -07001147 if (!in6_dev->cnf.accept_ra_defrtr) {
1148 ND_PRINTK(2, info,
1149 "RA: %s, defrtr is false for dev: %s\n",
1150 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001151 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001152 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001153
Ben Greeard9333192014-06-25 14:44:53 -07001154 /* Do not accept RA with source-addr found on local machine unless
1155 * accept_ra_from_local is set to true.
1156 */
Li RongQingb6428812014-07-10 18:02:46 +08001157 if (!in6_dev->cnf.accept_ra_from_local &&
1158 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1159 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001160 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001161 "RA from local address detected on dev: %s: default router ignored\n",
1162 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001163 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001164 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001165
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1167
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001168#ifdef CONFIG_IPV6_ROUTER_PREF
1169 pref = ra_msg->icmph.icmp6_router_pref;
1170 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001171 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001172 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001173 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1174#endif
1175
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001176 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
David S. Millereb857182012-01-27 15:07:56 -08001178 if (rt) {
1179 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1180 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001181 ND_PRINTK(0, err,
1182 "RA: %s got default router without neighbour\n",
1183 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001184 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001185 return;
1186 }
1187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001189 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 rt = NULL;
1191 }
1192
Ben Greearf2a762d2014-06-25 14:44:52 -07001193 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1194 rt, lifetime, skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (rt == NULL && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001196 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001198 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 if (rt == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001200 ND_PRINTK(0, err,
1201 "RA: %s failed to add default route\n",
1202 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 return;
1204 }
1205
David S. Millereb857182012-01-27 15:07:56 -08001206 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 if (neigh == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001208 ND_PRINTK(0, err,
1209 "RA: %s got default router without neighbour\n",
1210 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001211 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 return;
1213 }
1214 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001215 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001216 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 }
1218
1219 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001220 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 if (ra_msg->icmph.icmp6_hop_limit) {
1222 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1223 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001224 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1225 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 }
1227
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001228skip_defrtr:
1229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 /*
1231 * Update Reachable Time and Retrans Timer
1232 */
1233
1234 if (in6_dev->nd_parms) {
1235 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1236
1237 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1238 rtime = (rtime*HZ)/1000;
1239 if (rtime < HZ/10)
1240 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001241 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 in6_dev->tstamp = jiffies;
1243 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1244 }
1245
1246 rtime = ntohl(ra_msg->reachable_time);
1247 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1248 rtime = (rtime*HZ)/1000;
1249
1250 if (rtime < HZ/10)
1251 rtime = HZ/10;
1252
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001253 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1254 NEIGH_VAR_SET(in6_dev->nd_parms,
1255 BASE_REACHABLE_TIME, rtime);
1256 NEIGH_VAR_SET(in6_dev->nd_parms,
1257 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1259 in6_dev->tstamp = jiffies;
1260 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1261 }
1262 }
1263 }
1264
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001265skip_linkparms:
1266
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 /*
1268 * Process options.
1269 */
1270
1271 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001272 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 skb->dev, 1);
1274 if (neigh) {
1275 u8 *lladdr = NULL;
1276 if (ndopts.nd_opts_src_lladdr) {
1277 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1278 skb->dev);
1279 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001280 ND_PRINTK(2, warn,
1281 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 goto out;
1283 }
1284 }
1285 neigh_update(neigh, lladdr, NUD_STALE,
1286 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1287 NEIGH_UPDATE_F_OVERRIDE|
1288 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1289 NEIGH_UPDATE_F_ISROUTER);
1290 }
1291
Ben Greearf2a762d2014-06-25 14:44:52 -07001292 if (!ipv6_accept_ra(in6_dev)) {
1293 ND_PRINTK(2, info,
1294 "RA: %s, accept_ra is false for dev: %s\n",
1295 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001296 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001297 }
David Ward31ce8c72009-08-29 00:04:09 -07001298
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001299#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001300 if (!in6_dev->cnf.accept_ra_from_local &&
1301 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1302 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001303 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001304 "RA from local address detected on dev: %s: router info ignored.\n",
1305 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001306 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001307 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001308
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001309 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001310 struct nd_opt_hdr *p;
1311 for (p = ndopts.nd_opts_ri;
1312 p;
1313 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001314 struct route_info *ri = (struct route_info *)p;
1315#ifdef CONFIG_IPV6_NDISC_NODETYPE
1316 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1317 ri->prefix_len == 0)
1318 continue;
1319#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001320 if (ri->prefix_len == 0 &&
1321 !in6_dev->cnf.accept_ra_defrtr)
1322 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001323 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001324 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001325 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001326 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001327 }
1328 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001329
1330skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001331#endif
1332
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001333#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001334 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001335 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1336 ND_PRINTK(2, info,
1337 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1338 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001339 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001340 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001341#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001342
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001343 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 struct nd_opt_hdr *p;
1345 for (p = ndopts.nd_opts_pi;
1346 p;
1347 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001348 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1349 (p->nd_opt_len) << 3,
1350 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 }
1352 }
1353
Harout Hedeshianc2943f12015-01-20 10:06:05 -07001354 if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001355 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 u32 mtu;
1357
Ian Morris67ba4152014-08-24 21:53:10 +01001358 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4adc2006-11-14 20:56:00 -08001359 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001362 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 } else if (in6_dev->cnf.mtu6 != mtu) {
1364 in6_dev->cnf.mtu6 = mtu;
1365
1366 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001367 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369 rt6_mtu_change(skb->dev, mtu);
1370 }
1371 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001372
Pierre Ynard31910572007-10-10 21:22:05 -07001373 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001374 struct nd_opt_hdr *p;
1375 for (p = ndopts.nd_useropts;
1376 p;
1377 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1378 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001379 }
1380 }
1381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001383 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
1385out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001386 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001387 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389}
1390
1391static void ndisc_redirect_rcv(struct sk_buff *skb)
1392{
Duan Jiong093d04d2012-12-14 02:59:59 +00001393 u8 *hdr;
1394 struct ndisc_options ndopts;
1395 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001396 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001397 offsetof(struct rd_msg, opt));
1398
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001399#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001400 switch (skb->ndisc_nodetype) {
1401 case NDISC_NODETYPE_HOST:
1402 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001403 ND_PRINTK(2, warn,
1404 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001405 return;
1406 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001407#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001408
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001409 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001410 ND_PRINTK(2, warn,
1411 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 return;
1413 }
1414
Duan Jiong093d04d2012-12-14 02:59:59 +00001415 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1416 return;
1417
Duan Jiongc92a59e2013-08-22 12:07:35 +08001418 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001419 ip6_redirect_no_header(skb, dev_net(skb->dev),
1420 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001421 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001422 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001423
1424 hdr = (u8 *)ndopts.nd_opts_rh;
1425 hdr += 8;
1426 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1427 return;
1428
David S. Millerb94f1c02012-07-12 00:33:37 -07001429 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430}
1431
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001432static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1433 struct sk_buff *orig_skb,
1434 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001435{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001436 u8 *opt = skb_put(skb, rd_len);
1437
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001438 memset(opt, 0, 8);
1439 *(opt++) = ND_OPT_REDIRECT_HDR;
1440 *(opt++) = (rd_len >> 3);
1441 opt += 6;
1442
1443 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001444}
1445
David S. Miller49919692012-01-27 15:30:48 -08001446void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001448 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001449 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001450 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001451 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001452 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001454 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 struct rt6_info *rt;
1457 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001458 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001461 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
Neil Horman95c385b2007-04-25 17:08:10 -07001463 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001464 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1465 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001466 return;
1467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001469 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001470 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001471 ND_PRINTK(2, warn,
1472 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001473 return;
1474 }
1475
David S. Miller4c9483b2011-03-12 16:22:43 -05001476 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001477 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
David S. Miller4c9483b2011-03-12 16:22:43 -05001479 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001480 if (dst->error) {
1481 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001483 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001484 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001485 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488 rt = (struct rt6_info *) dst;
1489
1490 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001491 ND_PRINTK(2, warn,
1492 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001493 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001495 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1496 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1497 if (peer)
1498 inet_putpeer(peer);
1499 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001500 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
1502 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001503 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1504 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001505 ND_PRINTK(2, warn,
1506 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001507 goto release;
1508 }
1509
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 read_lock_bh(&neigh->lock);
1511 if (neigh->nud_state & NUD_VALID) {
1512 memcpy(ha_buf, neigh->ha, dev->addr_len);
1513 read_unlock_bh(&neigh->lock);
1514 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001515 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 } else
1517 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001518
1519 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 }
1521
1522 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001523 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1524 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001526 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001528 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001529 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001530 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001532 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1533 *msg = (struct rd_msg) {
1534 .icmph = {
1535 .icmp6_type = NDISC_REDIRECT,
1536 },
1537 .target = *target,
1538 .dest = ipv6_hdr(skb)->daddr,
1539 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 /*
1542 * include target_address option
1543 */
1544
1545 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001546 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 /*
1549 * build redirect option and copy skb over to the new packet.
1550 */
1551
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001552 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001553 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Eric Dumazetadf30902009-06-02 05:19:30 +00001555 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001556 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001557 return;
1558
1559release:
1560 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561}
1562
1563static void pndisc_redo(struct sk_buff *skb)
1564{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001565 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 kfree_skb(skb);
1567}
1568
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001569static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1570{
1571 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1572
1573 if (!idev)
1574 return true;
1575 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1576 idev->cnf.suppress_frag_ndisc) {
1577 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1578 return true;
1579 }
1580 return false;
1581}
1582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583int ndisc_rcv(struct sk_buff *skb)
1584{
1585 struct nd_msg *msg;
1586
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001587 if (ndisc_suppress_frag_ndisc(skb))
1588 return 0;
1589
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001590 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 return 0;
1592
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001593 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001595 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001597 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001598 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1599 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 return 0;
1601 }
1602
1603 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001604 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1605 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 return 0;
1607 }
1608
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001609 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 switch (msg->icmph.icmp6_type) {
1612 case NDISC_NEIGHBOUR_SOLICITATION:
1613 ndisc_recv_ns(skb);
1614 break;
1615
1616 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1617 ndisc_recv_na(skb);
1618 break;
1619
1620 case NDISC_ROUTER_SOLICITATION:
1621 ndisc_recv_rs(skb);
1622 break;
1623
1624 case NDISC_ROUTER_ADVERTISEMENT:
1625 ndisc_router_discovery(skb);
1626 break;
1627
1628 case NDISC_REDIRECT:
1629 ndisc_redirect_rcv(skb);
1630 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 return 0;
1634}
1635
1636static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1637{
Jiri Pirko351638e2013-05-28 01:30:21 +00001638 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001639 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001640 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
1642 switch (event) {
1643 case NETDEV_CHANGEADDR:
1644 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001645 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001646 idev = in6_dev_get(dev);
1647 if (!idev)
1648 break;
1649 if (idev->cnf.ndisc_notify)
1650 ndisc_send_unsol_na(dev);
1651 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 break;
1653 case NETDEV_DOWN:
1654 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001655 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001657 case NETDEV_NOTIFY_PEERS:
1658 ndisc_send_unsol_na(dev);
1659 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 default:
1661 break;
1662 }
1663
1664 return NOTIFY_DONE;
1665}
1666
1667static struct notifier_block ndisc_netdev_notifier = {
1668 .notifier_call = ndisc_netdev_event,
1669};
1670
1671#ifdef CONFIG_SYSCTL
1672static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1673 const char *func, const char *dev_name)
1674{
1675 static char warncomm[TASK_COMM_LEN];
1676 static int warned;
1677 if (strcmp(warncomm, current->comm) && warned < 5) {
1678 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001679 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 -07001680 warncomm, func,
1681 dev_name, ctl->procname,
1682 dev_name, ctl->procname);
1683 warned++;
1684 }
1685}
1686
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001687int 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 -07001688{
1689 struct net_device *dev = ctl->extra1;
1690 struct inet6_dev *idev;
1691 int ret;
1692
Eric W. Biedermand12af672007-10-18 03:05:25 -07001693 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1694 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1696
Eric W. Biedermand12af672007-10-18 03:05:25 -07001697 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001698 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001699
1700 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001701 ret = neigh_proc_dointvec_jiffies(ctl, write,
1702 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001703
1704 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001705 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001706 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1707 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001708 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
1711 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001712 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1713 idev->nd_parms->reachable_time =
1714 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 idev->tstamp = jiffies;
1716 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1717 in6_dev_put(idev);
1718 }
1719 return ret;
1720}
1721
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
1723#endif
1724
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001725static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726{
1727 struct ipv6_pinfo *np;
1728 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001729 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001731 err = inet_ctl_sock_create(&sk, PF_INET6,
1732 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001734 ND_PRINTK(0, err,
1735 "NDISC: Failed to initialize the control socket (err %d)\n",
1736 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 return err;
1738 }
1739
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001740 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001741
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 np->hop_limit = 255;
1744 /* Do not loopback ndisc messages */
1745 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001747 return 0;
1748}
1749
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001750static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001751{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001752 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001753}
1754
1755static struct pernet_operations ndisc_net_ops = {
1756 .init = ndisc_net_init,
1757 .exit = ndisc_net_exit,
1758};
1759
1760int __init ndisc_init(void)
1761{
1762 int err;
1763
1764 err = register_pernet_subsys(&ndisc_net_ops);
1765 if (err)
1766 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001767 /*
1768 * Initialize the neighbour table
1769 */
WANG Congd7480fd2014-11-10 15:59:36 -08001770 neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
1772#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001773 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301774 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001775 if (err)
1776 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001777out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001778#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001779 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001781#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001782out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001783 unregister_pernet_subsys(&ndisc_net_ops);
1784 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001785#endif
1786}
1787
1788int __init ndisc_late_init(void)
1789{
1790 return register_netdevice_notifier(&ndisc_netdev_notifier);
1791}
1792
1793void ndisc_late_cleanup(void)
1794{
1795 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796}
1797
1798void ndisc_cleanup(void)
1799{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800#ifdef CONFIG_SYSCTL
1801 neigh_sysctl_unregister(&nd_tbl.parms);
1802#endif
WANG Congd7480fd2014-11-10 15:59:36 -08001803 neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001804 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805}