blob: 4cb45c1079a29f4b7b59201e829905a5c65ac9fe [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),
120 .hash = ndisc_hash,
121 .constructor = ndisc_constructor,
122 .pconstructor = pndisc_constructor,
123 .pdestructor = pndisc_destructor,
124 .proxy_redo = pndisc_redo,
125 .id = "ndisc_cache",
126 .parms = {
Shan Weib6720832010-12-01 18:05:12 +0000127 .tbl = &nd_tbl,
Shan Weib6720832010-12-01 18:05:12 +0000128 .reachable_time = ND_REACHABLE_TIME,
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100129 .data = {
130 [NEIGH_VAR_MCAST_PROBES] = 3,
131 [NEIGH_VAR_UCAST_PROBES] = 3,
132 [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
133 [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
134 [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
135 [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
136 [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
137 [NEIGH_VAR_PROXY_QLEN] = 64,
138 [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
139 [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,
140 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 },
142 .gc_interval = 30 * HZ,
143 .gc_thresh1 = 128,
144 .gc_thresh2 = 512,
145 .gc_thresh3 = 1024,
146};
147
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000148static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000150 int pad = ndisc_addr_option_pad(skb->dev->type);
151 int data_len = skb->dev->addr_len;
152 int space = ndisc_opt_addr_space(skb->dev);
153 u8 *opt = skb_put(skb, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155 opt[0] = type;
156 opt[1] = space>>3;
157
158 memset(opt + 2, 0, pad);
159 opt += pad;
160 space -= pad;
161
162 memcpy(opt+2, data, data_len);
163 data_len += 2;
164 opt += data_len;
165 if ((space -= data_len) > 0)
166 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167}
168
169static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
170 struct nd_opt_hdr *end)
171{
172 int type;
173 if (!cur || !end || cur >= end)
174 return NULL;
175 type = cur->nd_opt_type;
176 do {
177 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100178 } while (cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000179 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180}
181
Pierre Ynard31910572007-10-10 21:22:05 -0700182static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
183{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000184 return opt->nd_opt_type == ND_OPT_RDNSS ||
185 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700186}
187
188static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
189 struct nd_opt_hdr *end)
190{
191 if (!cur || !end || cur >= end)
192 return NULL;
193 do {
194 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100195 } while (cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000196 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700197}
198
David S. Miller30f2a5f2012-07-11 23:26:46 -0700199struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
200 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201{
202 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
203
204 if (!nd_opt || opt_len < 0 || !ndopts)
205 return NULL;
206 memset(ndopts, 0, sizeof(*ndopts));
207 while (opt_len) {
208 int l;
209 if (opt_len < sizeof(struct nd_opt_hdr))
210 return NULL;
211 l = nd_opt->nd_opt_len << 3;
212 if (opt_len < l || l == 0)
213 return NULL;
214 switch (nd_opt->nd_opt_type) {
215 case ND_OPT_SOURCE_LL_ADDR:
216 case ND_OPT_TARGET_LL_ADDR:
217 case ND_OPT_MTU:
218 case ND_OPT_REDIRECT_HDR:
219 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000220 ND_PRINTK(2, warn,
221 "%s: duplicated ND6 option found: type=%d\n",
222 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 } else {
224 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
225 }
226 break;
227 case ND_OPT_PREFIX_INFO:
228 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700229 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
231 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800232#ifdef CONFIG_IPV6_ROUTE_INFO
233 case ND_OPT_ROUTE_INFO:
234 ndopts->nd_opts_ri_end = nd_opt;
235 if (!ndopts->nd_opts_ri)
236 ndopts->nd_opts_ri = nd_opt;
237 break;
238#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700240 if (ndisc_is_useropt(nd_opt)) {
241 ndopts->nd_useropts_end = nd_opt;
242 if (!ndopts->nd_useropts)
243 ndopts->nd_useropts = nd_opt;
244 } else {
245 /*
246 * Unknown options must be silently ignored,
247 * to accommodate future extension to the
248 * protocol.
249 */
Joe Perches675418d2012-05-16 19:28:38 +0000250 ND_PRINTK(2, notice,
251 "%s: ignored unsupported option; type=%d, len=%d\n",
252 __func__,
253 nd_opt->nd_opt_type,
254 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 }
257 opt_len -= l;
258 nd_opt = ((void *)nd_opt) + l;
259 }
260 return ndopts;
261}
262
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000263int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 switch (dev->type) {
266 case ARPHRD_ETHER:
267 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
268 case ARPHRD_FDDI:
269 ipv6_eth_mc_map(addr, buf);
270 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 case ARPHRD_ARCNET:
272 ipv6_arcnet_mc_map(addr, buf);
273 return 0;
274 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700275 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000277 case ARPHRD_IPGRE:
278 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 default:
280 if (dir) {
281 memcpy(buf, dev->broadcast, dev->addr_len);
282 return 0;
283 }
284 }
285 return -EINVAL;
286}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900287EXPORT_SYMBOL(ndisc_mc_map);
288
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000289static u32 ndisc_hash(const void *pkey,
290 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500291 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
David S. Miller2c2aba62011-12-28 15:06:58 -0500293 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
296static int ndisc_constructor(struct neighbour *neigh)
297{
Ian Morris67ba4152014-08-24 21:53:10 +0100298 struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 struct net_device *dev = neigh->dev;
300 struct inet6_dev *in6_dev;
301 struct neigh_parms *parms;
Eric Dumazeta50feda2012-05-18 18:57:34 +0000302 bool is_multicast = ipv6_addr_is_multicast(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 in6_dev = in6_dev_get(dev);
305 if (in6_dev == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 return -EINVAL;
307 }
308
309 parms = in6_dev->nd_parms;
310 __neigh_parms_put(neigh->parms);
311 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700314 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 neigh->nud_state = NUD_NOARP;
316 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700317 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 } else {
319 if (is_multicast) {
320 neigh->nud_state = NUD_NOARP;
321 ndisc_mc_map(addr, neigh->ha, dev, 1);
322 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
323 neigh->nud_state = NUD_NOARP;
324 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
325 if (dev->flags&IFF_LOOPBACK)
326 neigh->type = RTN_LOCAL;
327 } else if (dev->flags&IFF_POINTOPOINT) {
328 neigh->nud_state = NUD_NOARP;
329 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
330 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700331 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 neigh->ops = &ndisc_hh_ops;
333 else
334 neigh->ops = &ndisc_generic_ops;
335 if (neigh->nud_state&NUD_VALID)
336 neigh->output = neigh->ops->connected_output;
337 else
338 neigh->output = neigh->ops->output;
339 }
340 in6_dev_put(in6_dev);
341 return 0;
342}
343
344static int pndisc_constructor(struct pneigh_entry *n)
345{
Ian Morris67ba4152014-08-24 21:53:10 +0100346 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 struct in6_addr maddr;
348 struct net_device *dev = n->dev;
349
350 if (dev == NULL || __in6_dev_get(dev) == NULL)
351 return -EINVAL;
352 addrconf_addr_solict_mult(addr, &maddr);
353 ipv6_dev_mc_inc(dev, &maddr);
354 return 0;
355}
356
357static void pndisc_destructor(struct pneigh_entry *n)
358{
Ian Morris67ba4152014-08-24 21:53:10 +0100359 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 struct in6_addr maddr;
361 struct net_device *dev = n->dev;
362
363 if (dev == NULL || __in6_dev_get(dev) == NULL)
364 return;
365 addrconf_addr_solict_mult(addr, &maddr);
366 ipv6_dev_mc_dec(dev, &maddr);
367}
368
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000369static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
370 int len)
371{
372 int hlen = LL_RESERVED_SPACE(dev);
373 int tlen = dev->needed_tailroom;
374 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
375 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000376
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200377 skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000378 if (!skb) {
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200379 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
380 __func__);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000381 return NULL;
382 }
383
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000384 skb->protocol = htons(ETH_P_IPV6);
385 skb->dev = dev;
386
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000387 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki / 吉藤英明5135e632013-01-21 06:48:44 +0000388 skb_reset_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000389
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200390 /* Manually assign socket ownership as we avoid calling
391 * sock_alloc_send_pskb() to bypass wmem buffer limits
392 */
393 skb_set_owner_w(skb, sk);
394
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000395 return skb;
396}
397
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000398static void ip6_nd_hdr(struct sk_buff *skb,
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000399 const struct in6_addr *saddr,
400 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000401 int hop_limit, int len)
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000402{
403 struct ipv6hdr *hdr;
404
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000405 skb_push(skb, sizeof(*hdr));
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000406 skb_reset_network_header(skb);
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000407 hdr = ipv6_hdr(skb);
408
409 ip6_flow_hdr(hdr, 0, 0);
410
411 hdr->payload_len = htons(len);
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000412 hdr->nexthdr = IPPROTO_ICMPV6;
413 hdr->hop_limit = hop_limit;
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000414
415 hdr->saddr = *saddr;
416 hdr->daddr = *daddr;
417}
418
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000419static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900420 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000421 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800422{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000423 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000424 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000425 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800426 struct inet6_dev *idev;
427 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000428 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800429 u8 type;
430
431 type = icmp6h->icmp6_type;
432
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000433 if (!dst) {
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000434 struct flowi6 fl6;
Brian Haley305d5522008-11-04 17:51:14 -0800435
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000436 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
437 dst = icmp6_dst_alloc(skb->dev, &fl6);
438 if (IS_ERR(dst)) {
439 kfree_skb(skb);
440 return;
441 }
442
443 skb_dst_set(skb, dst);
444 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900445
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000446 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
447 IPPROTO_ICMPV6,
448 csum_partial(icmp6h,
449 skb->len, 0));
450
451 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
452
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000453 rcu_read_lock();
454 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700455 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900456
Jan Engelhardtb2e0b382010-03-23 04:09:07 +0100457 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
Patrick McHardy6e23ae22007-11-19 18:53:30 -0800458 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900459 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700460 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700461 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900462 }
463
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000464 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900465}
466
Cong Wangf564f452013-08-31 13:44:36 +0800467void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
468 const struct in6_addr *daddr,
469 const struct in6_addr *solicited_addr,
470 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000472 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 struct in6_addr tmpaddr;
474 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900475 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000476 struct nd_msg *msg;
477 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900480 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900481 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700483 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300484 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000485 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 in6_ifa_put(ifp);
487 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700488 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900489 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900490 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 return;
492 src_addr = &tmpaddr;
493 }
494
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000495 if (!dev->addr_len)
496 inc_opt = 0;
497 if (inc_opt)
498 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000500 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000501 if (!skb)
502 return;
503
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000504 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
505 *msg = (struct nd_msg) {
506 .icmph = {
507 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
508 .icmp6_router = router,
509 .icmp6_solicited = solicited,
510 .icmp6_override = override,
511 },
512 .target = *solicited_addr,
513 };
514
515 if (inc_opt)
516 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
517 dev->dev_addr);
518
519
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000520 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900521}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000523static void ndisc_send_unsol_na(struct net_device *dev)
524{
525 struct inet6_dev *idev;
526 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000527
528 idev = in6_dev_get(dev);
529 if (!idev)
530 return;
531
532 read_lock_bh(&idev->lock);
533 list_for_each_entry(ifa, &idev->addr_list, if_list) {
YOSHIFUJI Hideaki / 吉藤英明9fafd652012-11-12 07:50:17 +0000534 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000535 /*router=*/ !!idev->cnf.forwarding,
536 /*solicited=*/ false, /*override=*/ true,
537 /*inc_opt=*/ true);
538 }
539 read_unlock_bh(&idev->lock);
540
541 in6_dev_put(idev);
542}
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900545 const struct in6_addr *solicit,
546 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000548 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000550 int inc_opt = dev->addr_len;
551 int optlen = 0;
552 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 if (saddr == NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700555 if (ipv6_get_lladdr(dev, &addr_buf,
556 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 return;
558 saddr = &addr_buf;
559 }
560
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000561 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300562 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000563 if (inc_opt)
564 optlen += ndisc_opt_addr_space(dev);
565
566 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000567 if (!skb)
568 return;
569
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000570 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
571 *msg = (struct nd_msg) {
572 .icmph = {
573 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
574 },
575 .target = *solicit,
576 };
577
578 if (inc_opt)
579 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
580 dev->dev_addr);
581
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000582 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583}
584
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900585void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
586 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000588 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000589 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700590 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000591 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700592
593#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
594 /*
595 * According to section 2.2 of RFC 4429, we must not
596 * send router solicitations with a sllao from
597 * optimistic addresses, but we may send the solicitation
598 * if we don't include the sllao. So here we check
599 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800600 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700601 */
602 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900603 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800604 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700605 if (ifp) {
606 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900607 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700608 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900609 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700610 } else {
611 send_sllao = 0;
612 }
613 }
614#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000615 if (send_sllao)
616 optlen += ndisc_opt_addr_space(dev);
617
618 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000619 if (!skb)
620 return;
621
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000622 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
623 *msg = (struct rs_msg) {
624 .icmph = {
625 .icmp6_type = NDISC_ROUTER_SOLICITATION,
626 },
627 };
628
629 if (send_sllao)
630 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
631 dev->dev_addr);
632
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000633 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
638{
639 /*
640 * "The sender MUST return an ICMP
641 * destination unreachable"
642 */
643 dst_link_failure(skb);
644 kfree_skb(skb);
645}
646
647/* Called with locked neigh: either read or both */
648
649static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
650{
651 struct in6_addr *saddr = NULL;
652 struct in6_addr mcaddr;
653 struct net_device *dev = neigh->dev;
654 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
655 int probes = atomic_read(&neigh->probes);
656
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900657 if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700658 saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100660 if ((probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000662 ND_PRINTK(1, dbg,
663 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
664 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
666 ndisc_send_ns(dev, neigh, target, target, saddr);
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100667 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 } else {
670 addrconf_addr_solict_mult(target, &mcaddr);
671 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
672 }
673}
674
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900675static int pndisc_is_router(const void *pkey,
676 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700677{
678 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900679 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700680
681 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900682 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
683 if (n)
684 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700685 read_unlock_bh(&nd_tbl.lock);
686
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900687 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700688}
689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690static void ndisc_recv_ns(struct sk_buff *skb)
691{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700692 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000693 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
694 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000696 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700697 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 struct ndisc_options ndopts;
699 struct net_device *dev = skb->dev;
700 struct inet6_ifaddr *ifp;
701 struct inet6_dev *idev = NULL;
702 struct neighbour *neigh;
703 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000704 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900705 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000707 if (skb->len < sizeof(struct nd_msg)) {
708 ND_PRINTK(2, warn, "NS: packet too short\n");
709 return;
710 }
711
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000713 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 return;
715 }
716
717 /*
718 * RFC2461 7.1.1:
719 * DAD has to be destined for solicited node multicast address.
720 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000721 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000722 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return;
724 }
725
726 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000727 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return;
729 }
730
731 if (ndopts.nd_opts_src_lladdr) {
732 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
733 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000734 ND_PRINTK(2, warn,
735 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return;
737 }
738
739 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900740 * If the IP source address is the unspecified address,
741 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 * in the message.
743 */
744 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000745 ND_PRINTK(2, warn,
746 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 return;
748 }
749 }
750
751 inc = ipv6_addr_is_multicast(daddr);
752
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900753 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800754 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700755
756 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
757 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700758 /*
759 * We are colliding with another node
760 * who is doing DAD
761 * so fail our DAD process
762 */
763 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200764 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700765 } else {
766 /*
767 * This is not a dad solicitation.
768 * If we are an optimistic node,
769 * we should respond.
770 * Otherwise, we should ignore it.
771 */
772 if (!(ifp->flags & IFA_F_OPTIMISTIC))
773 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776
777 idev = ifp->idev;
778 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700779 struct net *net = dev_net(dev);
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 idev = in6_dev_get(dev);
782 if (!idev) {
783 /* XXX: count this drop? */
784 return;
785 }
786
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700787 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900788 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700789 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900790 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700791 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300793 inc &&
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100794 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 /*
796 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900797 * sender should delay its response
798 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 * MAX_ANYCAST_DELAY_TIME seconds.
800 * (RFC2461) -- yoshfuji
801 */
802 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
803 if (n)
804 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
805 goto out;
806 }
807 } else
808 goto out;
809 }
810
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900811 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000812 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900815 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000816 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 goto out;
818 }
819
820 if (inc)
821 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
822 else
823 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
824
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900825 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 * update / create cache entry
827 * for the source address
828 */
829 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
830 !inc || lladdr || !dev->addr_len);
831 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900832 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 NEIGH_UPDATE_F_WEAK_OVERRIDE|
834 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700835 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 ndisc_send_na(dev, neigh, saddr, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000837 !!is_router,
838 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (neigh)
840 neigh_release(neigh);
841 }
842
843out:
844 if (ifp)
845 in6_ifa_put(ifp);
846 else
847 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848}
849
850static void ndisc_recv_na(struct sk_buff *skb)
851{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700852 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800853 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000854 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000856 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700857 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 struct ndisc_options ndopts;
859 struct net_device *dev = skb->dev;
860 struct inet6_ifaddr *ifp;
861 struct neighbour *neigh;
862
863 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000864 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 return;
866 }
867
868 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000869 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 return;
871 }
872
873 if (ipv6_addr_is_multicast(daddr) &&
874 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000875 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 return;
877 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000880 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 return;
882 }
883 if (ndopts.nd_opts_tgt_lladdr) {
884 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
885 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000886 ND_PRINTK(2, warn,
887 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return;
889 }
890 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900891 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800892 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000893 if (skb->pkt_type != PACKET_LOOPBACK
894 && (ifp->flags & IFA_F_TENTATIVE)) {
895 addrconf_dad_failure(ifp);
896 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 }
898 /* What should we make now? The advertisement
899 is invalid, but ndisc specs say nothing
900 about it. It could be misconfiguration, or
901 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800902
903 We should not print the error if NA has been
904 received from loopback - it is just our own
905 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800907 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000908 ND_PRINTK(1, warn,
909 "NA: someone advertises our address %pI6 on %s!\n",
910 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 in6_ifa_put(ifp);
912 return;
913 }
914 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
915
916 if (neigh) {
917 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700918 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920 if (neigh->nud_state & NUD_FAILED)
921 goto out;
922
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700923 /*
924 * Don't update the neighbor cache entry on a proxy NA from
925 * ourselves because either the proxied node is off link or it
926 * has already sent a NA to us.
927 */
928 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700929 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
930 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000931 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700932 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700933 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 neigh_update(neigh, lladdr,
936 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
937 NEIGH_UPDATE_F_WEAK_OVERRIDE|
938 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
939 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
940 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
941
942 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
943 /*
944 * Change: router to host
945 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800946 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 }
948
949out:
950 neigh_release(neigh);
951 }
952}
953
954static void ndisc_recv_rs(struct sk_buff *skb)
955{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700956 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
958 struct neighbour *neigh;
959 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000960 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 struct ndisc_options ndopts;
962 u8 *lladdr = NULL;
963
964 if (skb->len < sizeof(*rs_msg))
965 return;
966
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000967 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000969 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 return;
971 }
972
973 /* Don't accept RS if we're not in router mode */
974 if (!idev->cnf.forwarding)
975 goto out;
976
977 /*
978 * Don't update NCE if src = ::;
979 * this implies that the source node has no ip address assigned yet.
980 */
981 if (ipv6_addr_any(saddr))
982 goto out;
983
984 /* Parse ND options */
985 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000986 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 goto out;
988 }
989
990 if (ndopts.nd_opts_src_lladdr) {
991 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
992 skb->dev);
993 if (!lladdr)
994 goto out;
995 }
996
997 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
998 if (neigh) {
999 neigh_update(neigh, lladdr, NUD_STALE,
1000 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1001 NEIGH_UPDATE_F_OVERRIDE|
1002 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1003 neigh_release(neigh);
1004 }
1005out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001006 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007}
1008
Pierre Ynard31910572007-10-10 21:22:05 -07001009static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1010{
1011 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1012 struct sk_buff *skb;
1013 struct nlmsghdr *nlh;
1014 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001015 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001016 int err;
1017 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1018 + (opt->nd_opt_len << 3));
1019 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1020
1021 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1022 if (skb == NULL) {
1023 err = -ENOBUFS;
1024 goto errout;
1025 }
1026
1027 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1028 if (nlh == NULL) {
1029 goto nla_put_failure;
1030 }
1031
1032 ndmsg = nlmsg_data(nlh);
1033 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001034 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001035 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1036 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1037 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1038
1039 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1040
David S. Millerc78679e2012-04-01 20:27:33 -04001041 if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1042 &ipv6_hdr(ra)->saddr))
1043 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001044 nlmsg_end(skb, nlh);
1045
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001046 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001047 return;
1048
1049nla_put_failure:
1050 nlmsg_free(skb);
1051 err = -EMSGSIZE;
1052errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001053 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001054}
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056static void ndisc_router_discovery(struct sk_buff *skb)
1057{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001058 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 struct neighbour *neigh = NULL;
1060 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001061 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 int lifetime;
1063 struct ndisc_options ndopts;
1064 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001065 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Ian Morris67ba4152014-08-24 21:53:10 +01001067 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
Simon Horman29a3cad2013-05-28 20:34:26 +00001069 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1070 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Ben Greearf2a762d2014-06-25 14:44:52 -07001072 ND_PRINTK(2, info,
1073 "RA: %s, dev: %s\n",
1074 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001075 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001076 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 return;
1078 }
1079 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001080 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 return;
1082 }
1083
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001084#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001085 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001086 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001087 return;
1088 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001089#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 /*
1092 * set the RA_RECV flag in the interface
1093 */
1094
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001095 in6_dev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 if (in6_dev == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001097 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1098 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return;
1100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
1102 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001103 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 return;
1105 }
1106
Ben Greearf2a762d2014-06-25 14:44:52 -07001107 if (!ipv6_accept_ra(in6_dev)) {
1108 ND_PRINTK(2, info,
1109 "RA: %s, did not accept ra for dev: %s\n",
1110 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001111 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001112 }
David Ward31ce8c72009-08-29 00:04:09 -07001113
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001114#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001115 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001116 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1117 ND_PRINTK(2, info,
1118 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1119 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001120 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001121 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001122#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 if (in6_dev->if_flags & IF_RS_SENT) {
1125 /*
1126 * flag that an RA was received after an RS was sent
1127 * out on this interface.
1128 */
1129 in6_dev->if_flags |= IF_RA_RCVD;
1130 }
1131
1132 /*
1133 * Remember the managed/otherconf flags from most recently
1134 * received RA message (RFC 2462) -- yoshfuji
1135 */
1136 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1137 IF_RA_OTHERCONF)) |
1138 (ra_msg->icmph.icmp6_addrconf_managed ?
1139 IF_RA_MANAGED : 0) |
1140 (ra_msg->icmph.icmp6_addrconf_other ?
1141 IF_RA_OTHERCONF : 0);
1142
Ben Greearf2a762d2014-06-25 14:44:52 -07001143 if (!in6_dev->cnf.accept_ra_defrtr) {
1144 ND_PRINTK(2, info,
1145 "RA: %s, defrtr is false for dev: %s\n",
1146 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001147 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001148 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001149
Ben Greeard9333192014-06-25 14:44:53 -07001150 /* Do not accept RA with source-addr found on local machine unless
1151 * accept_ra_from_local is set to true.
1152 */
Li RongQingb6428812014-07-10 18:02:46 +08001153 if (!in6_dev->cnf.accept_ra_from_local &&
1154 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1155 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001156 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001157 "RA from local address detected on dev: %s: default router ignored\n",
1158 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001159 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001160 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1163
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001164#ifdef CONFIG_IPV6_ROUTER_PREF
1165 pref = ra_msg->icmph.icmp6_router_pref;
1166 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001167 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001168 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001169 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1170#endif
1171
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001172 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
David S. Millereb857182012-01-27 15:07:56 -08001174 if (rt) {
1175 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1176 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001177 ND_PRINTK(0, err,
1178 "RA: %s got default router without neighbour\n",
1179 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001180 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001181 return;
1182 }
1183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001185 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 rt = NULL;
1187 }
1188
Ben Greearf2a762d2014-06-25 14:44:52 -07001189 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1190 rt, lifetime, skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 if (rt == NULL && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001192 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001194 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (rt == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001196 ND_PRINTK(0, err,
1197 "RA: %s failed to add default route\n",
1198 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 return;
1200 }
1201
David S. Millereb857182012-01-27 15:07:56 -08001202 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 if (neigh == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001204 ND_PRINTK(0, err,
1205 "RA: %s got default router without neighbour\n",
1206 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001207 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 return;
1209 }
1210 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001211 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001212 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 }
1214
1215 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001216 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 if (ra_msg->icmph.icmp6_hop_limit) {
1218 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1219 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001220 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1221 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 }
1223
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001224skip_defrtr:
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 /*
1227 * Update Reachable Time and Retrans Timer
1228 */
1229
1230 if (in6_dev->nd_parms) {
1231 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1232
1233 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1234 rtime = (rtime*HZ)/1000;
1235 if (rtime < HZ/10)
1236 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001237 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 in6_dev->tstamp = jiffies;
1239 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1240 }
1241
1242 rtime = ntohl(ra_msg->reachable_time);
1243 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1244 rtime = (rtime*HZ)/1000;
1245
1246 if (rtime < HZ/10)
1247 rtime = HZ/10;
1248
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001249 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1250 NEIGH_VAR_SET(in6_dev->nd_parms,
1251 BASE_REACHABLE_TIME, rtime);
1252 NEIGH_VAR_SET(in6_dev->nd_parms,
1253 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1255 in6_dev->tstamp = jiffies;
1256 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1257 }
1258 }
1259 }
1260
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001261skip_linkparms:
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 /*
1264 * Process options.
1265 */
1266
1267 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001268 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 skb->dev, 1);
1270 if (neigh) {
1271 u8 *lladdr = NULL;
1272 if (ndopts.nd_opts_src_lladdr) {
1273 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1274 skb->dev);
1275 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001276 ND_PRINTK(2, warn,
1277 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 goto out;
1279 }
1280 }
1281 neigh_update(neigh, lladdr, NUD_STALE,
1282 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1283 NEIGH_UPDATE_F_OVERRIDE|
1284 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1285 NEIGH_UPDATE_F_ISROUTER);
1286 }
1287
Ben Greearf2a762d2014-06-25 14:44:52 -07001288 if (!ipv6_accept_ra(in6_dev)) {
1289 ND_PRINTK(2, info,
1290 "RA: %s, accept_ra is false for dev: %s\n",
1291 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001292 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001293 }
David Ward31ce8c72009-08-29 00:04:09 -07001294
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001295#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001296 if (!in6_dev->cnf.accept_ra_from_local &&
1297 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1298 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001299 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001300 "RA from local address detected on dev: %s: router info ignored.\n",
1301 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001302 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001303 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001304
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001305 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001306 struct nd_opt_hdr *p;
1307 for (p = ndopts.nd_opts_ri;
1308 p;
1309 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001310 struct route_info *ri = (struct route_info *)p;
1311#ifdef CONFIG_IPV6_NDISC_NODETYPE
1312 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1313 ri->prefix_len == 0)
1314 continue;
1315#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001316 if (ri->prefix_len == 0 &&
1317 !in6_dev->cnf.accept_ra_defrtr)
1318 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001319 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001320 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001321 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001322 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001323 }
1324 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001325
1326skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001327#endif
1328
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001329#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001330 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001331 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1332 ND_PRINTK(2, info,
1333 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1334 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001335 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001336 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001337#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001338
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001339 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 struct nd_opt_hdr *p;
1341 for (p = ndopts.nd_opts_pi;
1342 p;
1343 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001344 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1345 (p->nd_opt_len) << 3,
1346 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 }
1348 }
1349
1350 if (ndopts.nd_opts_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001351 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 u32 mtu;
1353
Ian Morris67ba4152014-08-24 21:53:10 +01001354 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4adc2006-11-14 20:56:00 -08001355 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
1357 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001358 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 } else if (in6_dev->cnf.mtu6 != mtu) {
1360 in6_dev->cnf.mtu6 = mtu;
1361
1362 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001363 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
1365 rt6_mtu_change(skb->dev, mtu);
1366 }
1367 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001368
Pierre Ynard31910572007-10-10 21:22:05 -07001369 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001370 struct nd_opt_hdr *p;
1371 for (p = ndopts.nd_useropts;
1372 p;
1373 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1374 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001375 }
1376 }
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001379 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
1381out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001382 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001383 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385}
1386
1387static void ndisc_redirect_rcv(struct sk_buff *skb)
1388{
Duan Jiong093d04d2012-12-14 02:59:59 +00001389 u8 *hdr;
1390 struct ndisc_options ndopts;
1391 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001392 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001393 offsetof(struct rd_msg, opt));
1394
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001395#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001396 switch (skb->ndisc_nodetype) {
1397 case NDISC_NODETYPE_HOST:
1398 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001399 ND_PRINTK(2, warn,
1400 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001401 return;
1402 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001403#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001404
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001405 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001406 ND_PRINTK(2, warn,
1407 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 return;
1409 }
1410
Duan Jiong093d04d2012-12-14 02:59:59 +00001411 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1412 return;
1413
Duan Jiongc92a59e2013-08-22 12:07:35 +08001414 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001415 ip6_redirect_no_header(skb, dev_net(skb->dev),
1416 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001417 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001418 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001419
1420 hdr = (u8 *)ndopts.nd_opts_rh;
1421 hdr += 8;
1422 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1423 return;
1424
David S. Millerb94f1c02012-07-12 00:33:37 -07001425 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426}
1427
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001428static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1429 struct sk_buff *orig_skb,
1430 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001431{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001432 u8 *opt = skb_put(skb, rd_len);
1433
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001434 memset(opt, 0, 8);
1435 *(opt++) = ND_OPT_REDIRECT_HDR;
1436 *(opt++) = (rd_len >> 3);
1437 opt += 6;
1438
1439 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001440}
1441
David S. Miller49919692012-01-27 15:30:48 -08001442void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001444 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001445 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001446 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001447 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001448 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001450 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 struct rt6_info *rt;
1453 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001454 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001457 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Neil Horman95c385b2007-04-25 17:08:10 -07001459 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001460 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1461 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001462 return;
1463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001465 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001466 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001467 ND_PRINTK(2, warn,
1468 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001469 return;
1470 }
1471
David S. Miller4c9483b2011-03-12 16:22:43 -05001472 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001473 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
David S. Miller4c9483b2011-03-12 16:22:43 -05001475 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001476 if (dst->error) {
1477 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001479 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001480 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001481 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
1484 rt = (struct rt6_info *) dst;
1485
1486 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001487 ND_PRINTK(2, warn,
1488 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001489 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001491 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1492 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1493 if (peer)
1494 inet_putpeer(peer);
1495 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001496 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
1498 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001499 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1500 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001501 ND_PRINTK(2, warn,
1502 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001503 goto release;
1504 }
1505
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 read_lock_bh(&neigh->lock);
1507 if (neigh->nud_state & NUD_VALID) {
1508 memcpy(ha_buf, neigh->ha, dev->addr_len);
1509 read_unlock_bh(&neigh->lock);
1510 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001511 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 } else
1513 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001514
1515 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 }
1517
1518 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001519 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1520 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001522 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001524 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001525 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001526 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001528 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1529 *msg = (struct rd_msg) {
1530 .icmph = {
1531 .icmp6_type = NDISC_REDIRECT,
1532 },
1533 .target = *target,
1534 .dest = ipv6_hdr(skb)->daddr,
1535 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 /*
1538 * include target_address option
1539 */
1540
1541 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001542 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
1544 /*
1545 * build redirect option and copy skb over to the new packet.
1546 */
1547
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001548 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001549 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Eric Dumazetadf30902009-06-02 05:19:30 +00001551 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001552 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001553 return;
1554
1555release:
1556 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557}
1558
1559static void pndisc_redo(struct sk_buff *skb)
1560{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001561 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 kfree_skb(skb);
1563}
1564
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001565static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1566{
1567 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1568
1569 if (!idev)
1570 return true;
1571 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1572 idev->cnf.suppress_frag_ndisc) {
1573 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1574 return true;
1575 }
1576 return false;
1577}
1578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579int ndisc_rcv(struct sk_buff *skb)
1580{
1581 struct nd_msg *msg;
1582
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001583 if (ndisc_suppress_frag_ndisc(skb))
1584 return 0;
1585
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001586 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 return 0;
1588
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001589 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001591 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001593 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001594 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1595 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 return 0;
1597 }
1598
1599 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001600 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1601 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 return 0;
1603 }
1604
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001605 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 switch (msg->icmph.icmp6_type) {
1608 case NDISC_NEIGHBOUR_SOLICITATION:
1609 ndisc_recv_ns(skb);
1610 break;
1611
1612 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1613 ndisc_recv_na(skb);
1614 break;
1615
1616 case NDISC_ROUTER_SOLICITATION:
1617 ndisc_recv_rs(skb);
1618 break;
1619
1620 case NDISC_ROUTER_ADVERTISEMENT:
1621 ndisc_router_discovery(skb);
1622 break;
1623
1624 case NDISC_REDIRECT:
1625 ndisc_redirect_rcv(skb);
1626 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
1629 return 0;
1630}
1631
1632static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1633{
Jiri Pirko351638e2013-05-28 01:30:21 +00001634 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001635 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001636 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
1638 switch (event) {
1639 case NETDEV_CHANGEADDR:
1640 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001641 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001642 idev = in6_dev_get(dev);
1643 if (!idev)
1644 break;
1645 if (idev->cnf.ndisc_notify)
1646 ndisc_send_unsol_na(dev);
1647 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 break;
1649 case NETDEV_DOWN:
1650 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001651 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001653 case NETDEV_NOTIFY_PEERS:
1654 ndisc_send_unsol_na(dev);
1655 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 default:
1657 break;
1658 }
1659
1660 return NOTIFY_DONE;
1661}
1662
1663static struct notifier_block ndisc_netdev_notifier = {
1664 .notifier_call = ndisc_netdev_event,
1665};
1666
1667#ifdef CONFIG_SYSCTL
1668static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1669 const char *func, const char *dev_name)
1670{
1671 static char warncomm[TASK_COMM_LEN];
1672 static int warned;
1673 if (strcmp(warncomm, current->comm) && warned < 5) {
1674 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001675 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 -07001676 warncomm, func,
1677 dev_name, ctl->procname,
1678 dev_name, ctl->procname);
1679 warned++;
1680 }
1681}
1682
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001683int 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 -07001684{
1685 struct net_device *dev = ctl->extra1;
1686 struct inet6_dev *idev;
1687 int ret;
1688
Eric W. Biedermand12af672007-10-18 03:05:25 -07001689 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1690 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1692
Eric W. Biedermand12af672007-10-18 03:05:25 -07001693 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001694 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001695
1696 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001697 ret = neigh_proc_dointvec_jiffies(ctl, write,
1698 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001699
1700 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001701 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001702 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1703 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001704 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
1707 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001708 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1709 idev->nd_parms->reachable_time =
1710 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 idev->tstamp = jiffies;
1712 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1713 in6_dev_put(idev);
1714 }
1715 return ret;
1716}
1717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719#endif
1720
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001721static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722{
1723 struct ipv6_pinfo *np;
1724 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001725 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001727 err = inet_ctl_sock_create(&sk, PF_INET6,
1728 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001730 ND_PRINTK(0, err,
1731 "NDISC: Failed to initialize the control socket (err %d)\n",
1732 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 return err;
1734 }
1735
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001736 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001737
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 np->hop_limit = 255;
1740 /* Do not loopback ndisc messages */
1741 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001743 return 0;
1744}
1745
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001746static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001747{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001748 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001749}
1750
1751static struct pernet_operations ndisc_net_ops = {
1752 .init = ndisc_net_init,
1753 .exit = ndisc_net_exit,
1754};
1755
1756int __init ndisc_init(void)
1757{
1758 int err;
1759
1760 err = register_pernet_subsys(&ndisc_net_ops);
1761 if (err)
1762 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001763 /*
1764 * Initialize the neighbour table
1765 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 neigh_table_init(&nd_tbl);
1767
1768#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001769 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301770 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001771 if (err)
1772 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001773out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001774#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001775 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001777#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001778out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001779 unregister_pernet_subsys(&ndisc_net_ops);
1780 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001781#endif
1782}
1783
1784int __init ndisc_late_init(void)
1785{
1786 return register_netdevice_notifier(&ndisc_netdev_notifier);
1787}
1788
1789void ndisc_late_cleanup(void)
1790{
1791 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792}
1793
1794void ndisc_cleanup(void)
1795{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796#ifdef CONFIG_SYSCTL
1797 neigh_sysctl_unregister(&nd_tbl.parms);
1798#endif
1799 neigh_table_clear(&nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001800 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801}