blob: 682866777d5383dabaf6e3ae2f6f2deef261f557 [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 Pirko1f9248e2013-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;
Ian Morrise5d08d72014-11-23 21:28:43 +0000165 space -= data_len;
166 if (space > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
170static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
171 struct nd_opt_hdr *end)
172{
173 int type;
174 if (!cur || !end || cur >= end)
175 return NULL;
176 type = cur->nd_opt_type;
177 do {
178 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100179 } while (cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000180 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181}
182
Pierre Ynard31910572007-10-10 21:22:05 -0700183static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
184{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000185 return opt->nd_opt_type == ND_OPT_RDNSS ||
186 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700187}
188
189static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
190 struct nd_opt_hdr *end)
191{
192 if (!cur || !end || cur >= end)
193 return NULL;
194 do {
195 cur = ((void *)cur) + (cur->nd_opt_len << 3);
Ian Morris67ba4152014-08-24 21:53:10 +0100196 } while (cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000197 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700198}
199
David S. Miller30f2a5f2012-07-11 23:26:46 -0700200struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
201 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
203 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
204
205 if (!nd_opt || opt_len < 0 || !ndopts)
206 return NULL;
207 memset(ndopts, 0, sizeof(*ndopts));
208 while (opt_len) {
209 int l;
210 if (opt_len < sizeof(struct nd_opt_hdr))
211 return NULL;
212 l = nd_opt->nd_opt_len << 3;
213 if (opt_len < l || l == 0)
214 return NULL;
215 switch (nd_opt->nd_opt_type) {
216 case ND_OPT_SOURCE_LL_ADDR:
217 case ND_OPT_TARGET_LL_ADDR:
218 case ND_OPT_MTU:
219 case ND_OPT_REDIRECT_HDR:
220 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000221 ND_PRINTK(2, warn,
222 "%s: duplicated ND6 option found: type=%d\n",
223 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 } else {
225 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
226 }
227 break;
228 case ND_OPT_PREFIX_INFO:
229 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700230 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
232 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800233#ifdef CONFIG_IPV6_ROUTE_INFO
234 case ND_OPT_ROUTE_INFO:
235 ndopts->nd_opts_ri_end = nd_opt;
236 if (!ndopts->nd_opts_ri)
237 ndopts->nd_opts_ri = nd_opt;
238 break;
239#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700241 if (ndisc_is_useropt(nd_opt)) {
242 ndopts->nd_useropts_end = nd_opt;
243 if (!ndopts->nd_useropts)
244 ndopts->nd_useropts = nd_opt;
245 } else {
246 /*
247 * Unknown options must be silently ignored,
248 * to accommodate future extension to the
249 * protocol.
250 */
Joe Perches675418d2012-05-16 19:28:38 +0000251 ND_PRINTK(2, notice,
252 "%s: ignored unsupported option; type=%d, len=%d\n",
253 __func__,
254 nd_opt->nd_opt_type,
255 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 }
258 opt_len -= l;
259 nd_opt = ((void *)nd_opt) + l;
260 }
261 return ndopts;
262}
263
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000264int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 switch (dev->type) {
267 case ARPHRD_ETHER:
268 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
269 case ARPHRD_FDDI:
270 ipv6_eth_mc_map(addr, buf);
271 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 case ARPHRD_ARCNET:
273 ipv6_arcnet_mc_map(addr, buf);
274 return 0;
275 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700276 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000278 case ARPHRD_IPGRE:
279 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 default:
281 if (dir) {
282 memcpy(buf, dev->broadcast, dev->addr_len);
283 return 0;
284 }
285 }
286 return -EINVAL;
287}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900288EXPORT_SYMBOL(ndisc_mc_map);
289
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000290static u32 ndisc_hash(const void *pkey,
291 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500292 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
David S. Miller2c2aba62011-12-28 15:06:58 -0500294 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
297static int ndisc_constructor(struct neighbour *neigh)
298{
Ian Morris67ba4152014-08-24 21:53:10 +0100299 struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 struct net_device *dev = neigh->dev;
301 struct inet6_dev *in6_dev;
302 struct neigh_parms *parms;
Eric Dumazeta50feda2012-05-18 18:57:34 +0000303 bool is_multicast = ipv6_addr_is_multicast(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 in6_dev = in6_dev_get(dev);
306 if (in6_dev == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 return -EINVAL;
308 }
309
310 parms = in6_dev->nd_parms;
311 __neigh_parms_put(neigh->parms);
312 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700315 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 neigh->nud_state = NUD_NOARP;
317 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700318 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 } else {
320 if (is_multicast) {
321 neigh->nud_state = NUD_NOARP;
322 ndisc_mc_map(addr, neigh->ha, dev, 1);
323 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
324 neigh->nud_state = NUD_NOARP;
325 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
326 if (dev->flags&IFF_LOOPBACK)
327 neigh->type = RTN_LOCAL;
328 } else if (dev->flags&IFF_POINTOPOINT) {
329 neigh->nud_state = NUD_NOARP;
330 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
331 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700332 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 neigh->ops = &ndisc_hh_ops;
334 else
335 neigh->ops = &ndisc_generic_ops;
336 if (neigh->nud_state&NUD_VALID)
337 neigh->output = neigh->ops->connected_output;
338 else
339 neigh->output = neigh->ops->output;
340 }
341 in6_dev_put(in6_dev);
342 return 0;
343}
344
345static int pndisc_constructor(struct pneigh_entry *n)
346{
Ian Morris67ba4152014-08-24 21:53:10 +0100347 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 struct in6_addr maddr;
349 struct net_device *dev = n->dev;
350
351 if (dev == NULL || __in6_dev_get(dev) == NULL)
352 return -EINVAL;
353 addrconf_addr_solict_mult(addr, &maddr);
354 ipv6_dev_mc_inc(dev, &maddr);
355 return 0;
356}
357
358static void pndisc_destructor(struct pneigh_entry *n)
359{
Ian Morris67ba4152014-08-24 21:53:10 +0100360 struct in6_addr *addr = (struct in6_addr *)&n->key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 struct in6_addr maddr;
362 struct net_device *dev = n->dev;
363
364 if (dev == NULL || __in6_dev_get(dev) == NULL)
365 return;
366 addrconf_addr_solict_mult(addr, &maddr);
367 ipv6_dev_mc_dec(dev, &maddr);
368}
369
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000370static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
371 int len)
372{
373 int hlen = LL_RESERVED_SPACE(dev);
374 int tlen = dev->needed_tailroom;
375 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
376 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000377
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200378 skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000379 if (!skb) {
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200380 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
381 __func__);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000382 return NULL;
383 }
384
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000385 skb->protocol = htons(ETH_P_IPV6);
386 skb->dev = dev;
387
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000388 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki / 吉藤英明5135e632013-01-21 06:48:44 +0000389 skb_reset_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000390
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200391 /* Manually assign socket ownership as we avoid calling
392 * sock_alloc_send_pskb() to bypass wmem buffer limits
393 */
394 skb_set_owner_w(skb, sk);
395
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000396 return skb;
397}
398
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000399static void ip6_nd_hdr(struct sk_buff *skb,
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000400 const struct in6_addr *saddr,
401 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000402 int hop_limit, int len)
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000403{
404 struct ipv6hdr *hdr;
405
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000406 skb_push(skb, sizeof(*hdr));
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000407 skb_reset_network_header(skb);
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000408 hdr = ipv6_hdr(skb);
409
410 ip6_flow_hdr(hdr, 0, 0);
411
412 hdr->payload_len = htons(len);
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000413 hdr->nexthdr = IPPROTO_ICMPV6;
414 hdr->hop_limit = hop_limit;
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000415
416 hdr->saddr = *saddr;
417 hdr->daddr = *daddr;
418}
419
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000420static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900421 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000422 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800423{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000424 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000425 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000426 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800427 struct inet6_dev *idev;
428 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000429 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800430 u8 type;
431
432 type = icmp6h->icmp6_type;
433
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000434 if (!dst) {
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000435 struct flowi6 fl6;
Brian Haley305d5522008-11-04 17:51:14 -0800436
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000437 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
438 dst = icmp6_dst_alloc(skb->dev, &fl6);
439 if (IS_ERR(dst)) {
440 kfree_skb(skb);
441 return;
442 }
443
444 skb_dst_set(skb, dst);
445 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900446
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000447 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
448 IPPROTO_ICMPV6,
449 csum_partial(icmp6h,
450 skb->len, 0));
451
452 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
453
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000454 rcu_read_lock();
455 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700456 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900457
Jan Engelhardtb2e0b382010-03-23 04:09:07 +0100458 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
Patrick McHardy6e23ae22007-11-19 18:53:30 -0800459 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900460 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700461 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700462 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900463 }
464
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000465 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900466}
467
Cong Wangf564f452013-08-31 13:44:36 +0800468void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
469 const struct in6_addr *daddr,
470 const struct in6_addr *solicited_addr,
471 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000473 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 struct in6_addr tmpaddr;
475 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900476 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000477 struct nd_msg *msg;
478 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900481 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900482 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700484 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300485 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000486 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 in6_ifa_put(ifp);
488 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700489 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900490 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900491 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 return;
493 src_addr = &tmpaddr;
494 }
495
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000496 if (!dev->addr_len)
497 inc_opt = 0;
498 if (inc_opt)
499 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000501 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000502 if (!skb)
503 return;
504
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000505 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
506 *msg = (struct nd_msg) {
507 .icmph = {
508 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
509 .icmp6_router = router,
510 .icmp6_solicited = solicited,
511 .icmp6_override = override,
512 },
513 .target = *solicited_addr,
514 };
515
516 if (inc_opt)
517 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
518 dev->dev_addr);
519
520
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000521 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900522}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000524static void ndisc_send_unsol_na(struct net_device *dev)
525{
526 struct inet6_dev *idev;
527 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000528
529 idev = in6_dev_get(dev);
530 if (!idev)
531 return;
532
533 read_lock_bh(&idev->lock);
534 list_for_each_entry(ifa, &idev->addr_list, if_list) {
YOSHIFUJI Hideaki / 吉藤英明9fafd652012-11-12 07:50:17 +0000535 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000536 /*router=*/ !!idev->cnf.forwarding,
537 /*solicited=*/ false, /*override=*/ true,
538 /*inc_opt=*/ true);
539 }
540 read_unlock_bh(&idev->lock);
541
542 in6_dev_put(idev);
543}
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900546 const struct in6_addr *solicit,
547 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000549 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000551 int inc_opt = dev->addr_len;
552 int optlen = 0;
553 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 if (saddr == NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700556 if (ipv6_get_lladdr(dev, &addr_buf,
557 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 return;
559 saddr = &addr_buf;
560 }
561
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000562 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300563 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000564 if (inc_opt)
565 optlen += ndisc_opt_addr_space(dev);
566
567 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000568 if (!skb)
569 return;
570
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000571 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
572 *msg = (struct nd_msg) {
573 .icmph = {
574 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
575 },
576 .target = *solicit,
577 };
578
579 if (inc_opt)
580 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
581 dev->dev_addr);
582
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000583 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900586void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
587 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000589 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000590 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700591 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000592 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700593
594#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
595 /*
596 * According to section 2.2 of RFC 4429, we must not
597 * send router solicitations with a sllao from
598 * optimistic addresses, but we may send the solicitation
599 * if we don't include the sllao. So here we check
600 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800601 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700602 */
603 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900604 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800605 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700606 if (ifp) {
607 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900608 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700609 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900610 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700611 } else {
612 send_sllao = 0;
613 }
614 }
615#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000616 if (send_sllao)
617 optlen += ndisc_opt_addr_space(dev);
618
619 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000620 if (!skb)
621 return;
622
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000623 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
624 *msg = (struct rs_msg) {
625 .icmph = {
626 .icmp6_type = NDISC_ROUTER_SOLICITATION,
627 },
628 };
629
630 if (send_sllao)
631 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
632 dev->dev_addr);
633
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000634 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
639{
640 /*
641 * "The sender MUST return an ICMP
642 * destination unreachable"
643 */
644 dst_link_failure(skb);
645 kfree_skb(skb);
646}
647
648/* Called with locked neigh: either read or both */
649
650static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
651{
652 struct in6_addr *saddr = NULL;
653 struct in6_addr mcaddr;
654 struct net_device *dev = neigh->dev;
655 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
656 int probes = atomic_read(&neigh->probes);
657
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900658 if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700659 saddr = &ipv6_hdr(skb)->saddr;
Ian Morrise5d08d72014-11-23 21:28:43 +0000660 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
661 if (probes < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000663 ND_PRINTK(1, dbg,
664 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
665 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 }
667 ndisc_send_ns(dev, neigh, target, target, saddr);
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100668 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 } else {
671 addrconf_addr_solict_mult(target, &mcaddr);
672 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
673 }
674}
675
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900676static int pndisc_is_router(const void *pkey,
677 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700678{
679 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900680 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700681
682 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900683 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
684 if (n)
685 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700686 read_unlock_bh(&nd_tbl.lock);
687
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900688 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700689}
690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691static void ndisc_recv_ns(struct sk_buff *skb)
692{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700693 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000694 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
695 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000697 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700698 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 struct ndisc_options ndopts;
700 struct net_device *dev = skb->dev;
701 struct inet6_ifaddr *ifp;
702 struct inet6_dev *idev = NULL;
703 struct neighbour *neigh;
704 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000705 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900706 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000708 if (skb->len < sizeof(struct nd_msg)) {
709 ND_PRINTK(2, warn, "NS: packet too short\n");
710 return;
711 }
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000714 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return;
716 }
717
718 /*
719 * RFC2461 7.1.1:
720 * DAD has to be destined for solicited node multicast address.
721 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000722 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000723 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return;
725 }
726
727 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000728 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 return;
730 }
731
732 if (ndopts.nd_opts_src_lladdr) {
733 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
734 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000735 ND_PRINTK(2, warn,
736 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return;
738 }
739
740 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900741 * If the IP source address is the unspecified address,
742 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 * in the message.
744 */
745 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000746 ND_PRINTK(2, warn,
747 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return;
749 }
750 }
751
752 inc = ipv6_addr_is_multicast(daddr);
753
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900754 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800755 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700756
757 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
758 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700759 /*
760 * We are colliding with another node
761 * who is doing DAD
762 * so fail our DAD process
763 */
764 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200765 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700766 } else {
767 /*
768 * This is not a dad solicitation.
769 * If we are an optimistic node,
770 * we should respond.
771 * Otherwise, we should ignore it.
772 */
773 if (!(ifp->flags & IFA_F_OPTIMISTIC))
774 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
777
778 idev = ifp->idev;
779 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700780 struct net *net = dev_net(dev);
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 idev = in6_dev_get(dev);
783 if (!idev) {
784 /* XXX: count this drop? */
785 return;
786 }
787
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700788 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900789 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700790 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900791 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700792 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300794 inc &&
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100795 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 /*
797 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900798 * sender should delay its response
799 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 * MAX_ANYCAST_DELAY_TIME seconds.
801 * (RFC2461) -- yoshfuji
802 */
803 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
804 if (n)
805 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
806 goto out;
807 }
808 } else
809 goto out;
810 }
811
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900812 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000813 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900816 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000817 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 goto out;
819 }
820
821 if (inc)
822 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
823 else
824 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
825
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900826 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 * update / create cache entry
828 * for the source address
829 */
830 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
831 !inc || lladdr || !dev->addr_len);
832 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900833 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 NEIGH_UPDATE_F_WEAK_OVERRIDE|
835 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700836 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 ndisc_send_na(dev, neigh, saddr, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000838 !!is_router,
839 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (neigh)
841 neigh_release(neigh);
842 }
843
844out:
845 if (ifp)
846 in6_ifa_put(ifp);
847 else
848 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849}
850
851static void ndisc_recv_na(struct sk_buff *skb)
852{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700853 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800854 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000855 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000857 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700858 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 struct ndisc_options ndopts;
860 struct net_device *dev = skb->dev;
861 struct inet6_ifaddr *ifp;
862 struct neighbour *neigh;
863
864 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000865 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 return;
867 }
868
869 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000870 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return;
872 }
873
874 if (ipv6_addr_is_multicast(daddr) &&
875 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000876 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return;
878 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000881 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return;
883 }
884 if (ndopts.nd_opts_tgt_lladdr) {
885 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
886 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000887 ND_PRINTK(2, warn,
888 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return;
890 }
891 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900892 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800893 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000894 if (skb->pkt_type != PACKET_LOOPBACK
895 && (ifp->flags & IFA_F_TENTATIVE)) {
896 addrconf_dad_failure(ifp);
897 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
899 /* What should we make now? The advertisement
900 is invalid, but ndisc specs say nothing
901 about it. It could be misconfiguration, or
902 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800903
904 We should not print the error if NA has been
905 received from loopback - it is just our own
906 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800908 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000909 ND_PRINTK(1, warn,
910 "NA: someone advertises our address %pI6 on %s!\n",
911 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 in6_ifa_put(ifp);
913 return;
914 }
915 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
916
917 if (neigh) {
918 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700919 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 if (neigh->nud_state & NUD_FAILED)
922 goto out;
923
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700924 /*
925 * Don't update the neighbor cache entry on a proxy NA from
926 * ourselves because either the proxied node is off link or it
927 * has already sent a NA to us.
928 */
929 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700930 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
931 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000932 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700933 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700934 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 neigh_update(neigh, lladdr,
937 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
938 NEIGH_UPDATE_F_WEAK_OVERRIDE|
939 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
940 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
941 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
942
943 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
944 /*
945 * Change: router to host
946 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800947 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 }
949
950out:
951 neigh_release(neigh);
952 }
953}
954
955static void ndisc_recv_rs(struct sk_buff *skb)
956{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700957 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
959 struct neighbour *neigh;
960 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000961 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 struct ndisc_options ndopts;
963 u8 *lladdr = NULL;
964
965 if (skb->len < sizeof(*rs_msg))
966 return;
967
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000968 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000970 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 return;
972 }
973
974 /* Don't accept RS if we're not in router mode */
975 if (!idev->cnf.forwarding)
976 goto out;
977
978 /*
979 * Don't update NCE if src = ::;
980 * this implies that the source node has no ip address assigned yet.
981 */
982 if (ipv6_addr_any(saddr))
983 goto out;
984
985 /* Parse ND options */
986 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000987 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 goto out;
989 }
990
991 if (ndopts.nd_opts_src_lladdr) {
992 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
993 skb->dev);
994 if (!lladdr)
995 goto out;
996 }
997
998 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
999 if (neigh) {
1000 neigh_update(neigh, lladdr, NUD_STALE,
1001 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1002 NEIGH_UPDATE_F_OVERRIDE|
1003 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1004 neigh_release(neigh);
1005 }
1006out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001007 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008}
1009
Pierre Ynard31910572007-10-10 21:22:05 -07001010static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1011{
1012 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1013 struct sk_buff *skb;
1014 struct nlmsghdr *nlh;
1015 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001016 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001017 int err;
1018 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1019 + (opt->nd_opt_len << 3));
1020 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1021
1022 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1023 if (skb == NULL) {
1024 err = -ENOBUFS;
1025 goto errout;
1026 }
1027
1028 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1029 if (nlh == NULL) {
1030 goto nla_put_failure;
1031 }
1032
1033 ndmsg = nlmsg_data(nlh);
1034 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001035 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001036 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1037 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1038 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1039
1040 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1041
David S. Millerc78679e2012-04-01 20:27:33 -04001042 if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1043 &ipv6_hdr(ra)->saddr))
1044 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001045 nlmsg_end(skb, nlh);
1046
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001047 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001048 return;
1049
1050nla_put_failure:
1051 nlmsg_free(skb);
1052 err = -EMSGSIZE;
1053errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001054 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001055}
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057static void ndisc_router_discovery(struct sk_buff *skb)
1058{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001059 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 struct neighbour *neigh = NULL;
1061 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001062 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 int lifetime;
1064 struct ndisc_options ndopts;
1065 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001066 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
Ian Morris67ba4152014-08-24 21:53:10 +01001068 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Simon Horman29a3cad2013-05-28 20:34:26 +00001070 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1071 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Ben Greearf2a762d2014-06-25 14:44:52 -07001073 ND_PRINTK(2, info,
1074 "RA: %s, dev: %s\n",
1075 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001076 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001077 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 return;
1079 }
1080 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001081 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 return;
1083 }
1084
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001085#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001086 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001087 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001088 return;
1089 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001090#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 /*
1093 * set the RA_RECV flag in the interface
1094 */
1095
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001096 in6_dev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 if (in6_dev == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001098 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1099 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 return;
1101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001104 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 return;
1106 }
1107
Ben Greearf2a762d2014-06-25 14:44:52 -07001108 if (!ipv6_accept_ra(in6_dev)) {
1109 ND_PRINTK(2, info,
1110 "RA: %s, did not accept ra for dev: %s\n",
1111 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001112 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001113 }
David Ward31ce8c72009-08-29 00:04:09 -07001114
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001115#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001116 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001117 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1118 ND_PRINTK(2, info,
1119 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1120 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001121 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001122 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001123#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 if (in6_dev->if_flags & IF_RS_SENT) {
1126 /*
1127 * flag that an RA was received after an RS was sent
1128 * out on this interface.
1129 */
1130 in6_dev->if_flags |= IF_RA_RCVD;
1131 }
1132
1133 /*
1134 * Remember the managed/otherconf flags from most recently
1135 * received RA message (RFC 2462) -- yoshfuji
1136 */
1137 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1138 IF_RA_OTHERCONF)) |
1139 (ra_msg->icmph.icmp6_addrconf_managed ?
1140 IF_RA_MANAGED : 0) |
1141 (ra_msg->icmph.icmp6_addrconf_other ?
1142 IF_RA_OTHERCONF : 0);
1143
Ben Greearf2a762d2014-06-25 14:44:52 -07001144 if (!in6_dev->cnf.accept_ra_defrtr) {
1145 ND_PRINTK(2, info,
1146 "RA: %s, defrtr is false for dev: %s\n",
1147 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001148 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001149 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001150
Ben Greeard9333192014-06-25 14:44:53 -07001151 /* Do not accept RA with source-addr found on local machine unless
1152 * accept_ra_from_local is set to true.
1153 */
Li RongQingb6428812014-07-10 18:02:46 +08001154 if (!in6_dev->cnf.accept_ra_from_local &&
1155 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1156 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001157 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001158 "RA from local address detected on dev: %s: default router ignored\n",
1159 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001160 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001161 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1164
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001165#ifdef CONFIG_IPV6_ROUTER_PREF
1166 pref = ra_msg->icmph.icmp6_router_pref;
1167 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001168 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001169 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001170 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1171#endif
1172
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001173 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
David S. Millereb857182012-01-27 15:07:56 -08001175 if (rt) {
1176 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1177 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001178 ND_PRINTK(0, err,
1179 "RA: %s got default router without neighbour\n",
1180 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001181 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001182 return;
1183 }
1184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001186 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 rt = NULL;
1188 }
1189
Ben Greearf2a762d2014-06-25 14:44:52 -07001190 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1191 rt, lifetime, skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 if (rt == NULL && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001193 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001195 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 if (rt == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001197 ND_PRINTK(0, err,
1198 "RA: %s failed to add default route\n",
1199 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 return;
1201 }
1202
David S. Millereb857182012-01-27 15:07:56 -08001203 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 if (neigh == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001205 ND_PRINTK(0, err,
1206 "RA: %s got default router without neighbour\n",
1207 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001208 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 return;
1210 }
1211 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001212 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001213 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 }
1215
1216 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001217 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if (ra_msg->icmph.icmp6_hop_limit) {
1219 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1220 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001221 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1222 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 }
1224
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001225skip_defrtr:
1226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 /*
1228 * Update Reachable Time and Retrans Timer
1229 */
1230
1231 if (in6_dev->nd_parms) {
1232 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1233
1234 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1235 rtime = (rtime*HZ)/1000;
1236 if (rtime < HZ/10)
1237 rtime = HZ/10;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001238 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 in6_dev->tstamp = jiffies;
1240 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1241 }
1242
1243 rtime = ntohl(ra_msg->reachable_time);
1244 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1245 rtime = (rtime*HZ)/1000;
1246
1247 if (rtime < HZ/10)
1248 rtime = HZ/10;
1249
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001250 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1251 NEIGH_VAR_SET(in6_dev->nd_parms,
1252 BASE_REACHABLE_TIME, rtime);
1253 NEIGH_VAR_SET(in6_dev->nd_parms,
1254 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1256 in6_dev->tstamp = jiffies;
1257 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1258 }
1259 }
1260 }
1261
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001262skip_linkparms:
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 /*
1265 * Process options.
1266 */
1267
1268 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001269 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 skb->dev, 1);
1271 if (neigh) {
1272 u8 *lladdr = NULL;
1273 if (ndopts.nd_opts_src_lladdr) {
1274 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1275 skb->dev);
1276 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001277 ND_PRINTK(2, warn,
1278 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 goto out;
1280 }
1281 }
1282 neigh_update(neigh, lladdr, NUD_STALE,
1283 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1284 NEIGH_UPDATE_F_OVERRIDE|
1285 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1286 NEIGH_UPDATE_F_ISROUTER);
1287 }
1288
Ben Greearf2a762d2014-06-25 14:44:52 -07001289 if (!ipv6_accept_ra(in6_dev)) {
1290 ND_PRINTK(2, info,
1291 "RA: %s, accept_ra is false for dev: %s\n",
1292 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001293 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001294 }
David Ward31ce8c72009-08-29 00:04:09 -07001295
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001296#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001297 if (!in6_dev->cnf.accept_ra_from_local &&
1298 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1299 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001300 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001301 "RA from local address detected on dev: %s: router info ignored.\n",
1302 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001303 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001304 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001305
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001306 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001307 struct nd_opt_hdr *p;
1308 for (p = ndopts.nd_opts_ri;
1309 p;
1310 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001311 struct route_info *ri = (struct route_info *)p;
1312#ifdef CONFIG_IPV6_NDISC_NODETYPE
1313 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1314 ri->prefix_len == 0)
1315 continue;
1316#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001317 if (ri->prefix_len == 0 &&
1318 !in6_dev->cnf.accept_ra_defrtr)
1319 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001320 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001321 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001322 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001323 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001324 }
1325 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001326
1327skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001328#endif
1329
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001330#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001331 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001332 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1333 ND_PRINTK(2, info,
1334 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1335 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001336 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001337 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001338#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001339
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001340 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 struct nd_opt_hdr *p;
1342 for (p = ndopts.nd_opts_pi;
1343 p;
1344 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001345 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1346 (p->nd_opt_len) << 3,
1347 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 }
1349 }
1350
1351 if (ndopts.nd_opts_mtu) {
Al Viroe69a4ad2006-11-14 20:56:00 -08001352 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 u32 mtu;
1354
Ian Morris67ba4152014-08-24 21:53:10 +01001355 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4ad2006-11-14 20:56:00 -08001356 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001359 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 } else if (in6_dev->cnf.mtu6 != mtu) {
1361 in6_dev->cnf.mtu6 = mtu;
1362
1363 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001364 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366 rt6_mtu_change(skb->dev, mtu);
1367 }
1368 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001369
Pierre Ynard31910572007-10-10 21:22:05 -07001370 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001371 struct nd_opt_hdr *p;
1372 for (p = ndopts.nd_useropts;
1373 p;
1374 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1375 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001376 }
1377 }
1378
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001380 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
1382out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001383 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001384 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386}
1387
1388static void ndisc_redirect_rcv(struct sk_buff *skb)
1389{
Duan Jiong093d04d2012-12-14 02:59:59 +00001390 u8 *hdr;
1391 struct ndisc_options ndopts;
1392 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001393 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001394 offsetof(struct rd_msg, opt));
1395
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001396#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001397 switch (skb->ndisc_nodetype) {
1398 case NDISC_NODETYPE_HOST:
1399 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001400 ND_PRINTK(2, warn,
1401 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001402 return;
1403 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001404#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001405
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001406 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001407 ND_PRINTK(2, warn,
1408 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 return;
1410 }
1411
Duan Jiong093d04d2012-12-14 02:59:59 +00001412 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1413 return;
1414
Duan Jiongc92a59e2013-08-22 12:07:35 +08001415 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001416 ip6_redirect_no_header(skb, dev_net(skb->dev),
1417 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001418 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001419 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001420
1421 hdr = (u8 *)ndopts.nd_opts_rh;
1422 hdr += 8;
1423 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1424 return;
1425
David S. Millerb94f1c02012-07-12 00:33:37 -07001426 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427}
1428
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001429static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1430 struct sk_buff *orig_skb,
1431 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001432{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001433 u8 *opt = skb_put(skb, rd_len);
1434
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001435 memset(opt, 0, 8);
1436 *(opt++) = ND_OPT_REDIRECT_HDR;
1437 *(opt++) = (rd_len >> 3);
1438 opt += 6;
1439
1440 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001441}
1442
David S. Miller49919692012-01-27 15:30:48 -08001443void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001445 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001446 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001447 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001448 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001449 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001451 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 struct rt6_info *rt;
1454 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001455 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001458 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
Neil Horman95c385b2007-04-25 17:08:10 -07001460 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001461 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1462 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001463 return;
1464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001466 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001467 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001468 ND_PRINTK(2, warn,
1469 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001470 return;
1471 }
1472
David S. Miller4c9483b2011-03-12 16:22:43 -05001473 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001474 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
David S. Miller4c9483b2011-03-12 16:22:43 -05001476 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001477 if (dst->error) {
1478 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001480 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001481 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001482 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484
1485 rt = (struct rt6_info *) dst;
1486
1487 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001488 ND_PRINTK(2, warn,
1489 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001490 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001492 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1493 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1494 if (peer)
1495 inet_putpeer(peer);
1496 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001497 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
1499 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001500 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1501 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001502 ND_PRINTK(2, warn,
1503 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001504 goto release;
1505 }
1506
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 read_lock_bh(&neigh->lock);
1508 if (neigh->nud_state & NUD_VALID) {
1509 memcpy(ha_buf, neigh->ha, dev->addr_len);
1510 read_unlock_bh(&neigh->lock);
1511 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001512 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 } else
1514 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001515
1516 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 }
1518
1519 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001520 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1521 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001523 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001525 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001526 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001527 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001529 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1530 *msg = (struct rd_msg) {
1531 .icmph = {
1532 .icmp6_type = NDISC_REDIRECT,
1533 },
1534 .target = *target,
1535 .dest = ipv6_hdr(skb)->daddr,
1536 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 /*
1539 * include target_address option
1540 */
1541
1542 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001543 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
1545 /*
1546 * build redirect option and copy skb over to the new packet.
1547 */
1548
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001549 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001550 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
Eric Dumazetadf30902009-06-02 05:19:30 +00001552 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001553 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001554 return;
1555
1556release:
1557 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558}
1559
1560static void pndisc_redo(struct sk_buff *skb)
1561{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001562 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 kfree_skb(skb);
1564}
1565
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001566static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1567{
1568 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1569
1570 if (!idev)
1571 return true;
1572 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1573 idev->cnf.suppress_frag_ndisc) {
1574 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1575 return true;
1576 }
1577 return false;
1578}
1579
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580int ndisc_rcv(struct sk_buff *skb)
1581{
1582 struct nd_msg *msg;
1583
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001584 if (ndisc_suppress_frag_ndisc(skb))
1585 return 0;
1586
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001587 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 return 0;
1589
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001590 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001592 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001594 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001595 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1596 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 return 0;
1598 }
1599
1600 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001601 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1602 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 return 0;
1604 }
1605
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001606 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1607
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 switch (msg->icmph.icmp6_type) {
1609 case NDISC_NEIGHBOUR_SOLICITATION:
1610 ndisc_recv_ns(skb);
1611 break;
1612
1613 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1614 ndisc_recv_na(skb);
1615 break;
1616
1617 case NDISC_ROUTER_SOLICITATION:
1618 ndisc_recv_rs(skb);
1619 break;
1620
1621 case NDISC_ROUTER_ADVERTISEMENT:
1622 ndisc_router_discovery(skb);
1623 break;
1624
1625 case NDISC_REDIRECT:
1626 ndisc_redirect_rcv(skb);
1627 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
1630 return 0;
1631}
1632
1633static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1634{
Jiri Pirko351638e2013-05-28 01:30:21 +00001635 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001636 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001637 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
1639 switch (event) {
1640 case NETDEV_CHANGEADDR:
1641 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001642 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001643 idev = in6_dev_get(dev);
1644 if (!idev)
1645 break;
1646 if (idev->cnf.ndisc_notify)
1647 ndisc_send_unsol_na(dev);
1648 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 break;
1650 case NETDEV_DOWN:
1651 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001652 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001654 case NETDEV_NOTIFY_PEERS:
1655 ndisc_send_unsol_na(dev);
1656 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 default:
1658 break;
1659 }
1660
1661 return NOTIFY_DONE;
1662}
1663
1664static struct notifier_block ndisc_netdev_notifier = {
1665 .notifier_call = ndisc_netdev_event,
1666};
1667
1668#ifdef CONFIG_SYSCTL
1669static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1670 const char *func, const char *dev_name)
1671{
1672 static char warncomm[TASK_COMM_LEN];
1673 static int warned;
1674 if (strcmp(warncomm, current->comm) && warned < 5) {
1675 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001676 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 -07001677 warncomm, func,
1678 dev_name, ctl->procname,
1679 dev_name, ctl->procname);
1680 warned++;
1681 }
1682}
1683
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001684int 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 -07001685{
1686 struct net_device *dev = ctl->extra1;
1687 struct inet6_dev *idev;
1688 int ret;
1689
Eric W. Biedermand12af672007-10-18 03:05:25 -07001690 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1691 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1693
Eric W. Biedermand12af672007-10-18 03:05:25 -07001694 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001695 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001696
1697 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001698 ret = neigh_proc_dointvec_jiffies(ctl, write,
1699 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001700
1701 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001702 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001703 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1704 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001705 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001709 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1710 idev->nd_parms->reachable_time =
1711 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 idev->tstamp = jiffies;
1713 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1714 in6_dev_put(idev);
1715 }
1716 return ret;
1717}
1718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
1720#endif
1721
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001722static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723{
1724 struct ipv6_pinfo *np;
1725 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001726 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001728 err = inet_ctl_sock_create(&sk, PF_INET6,
1729 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001731 ND_PRINTK(0, err,
1732 "NDISC: Failed to initialize the control socket (err %d)\n",
1733 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 return err;
1735 }
1736
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001737 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001738
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 np->hop_limit = 255;
1741 /* Do not loopback ndisc messages */
1742 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001744 return 0;
1745}
1746
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001747static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001748{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001749 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001750}
1751
1752static struct pernet_operations ndisc_net_ops = {
1753 .init = ndisc_net_init,
1754 .exit = ndisc_net_exit,
1755};
1756
1757int __init ndisc_init(void)
1758{
1759 int err;
1760
1761 err = register_pernet_subsys(&ndisc_net_ops);
1762 if (err)
1763 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001764 /*
1765 * Initialize the neighbour table
1766 */
WANG Congd7480fd2014-11-10 15:59:36 -08001767 neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
1769#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001770 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301771 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001772 if (err)
1773 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001774out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001775#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001776 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001778#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001779out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001780 unregister_pernet_subsys(&ndisc_net_ops);
1781 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001782#endif
1783}
1784
1785int __init ndisc_late_init(void)
1786{
1787 return register_netdevice_notifier(&ndisc_netdev_notifier);
1788}
1789
1790void ndisc_late_cleanup(void)
1791{
1792 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793}
1794
1795void ndisc_cleanup(void)
1796{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797#ifdef CONFIG_SYSCTL
1798 neigh_sysctl_unregister(&nd_tbl.parms);
1799#endif
WANG Congd7480fd2014-11-10 15:59:36 -08001800 neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001801 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802}