blob: 113fc6cd5a0c1ce9e8345f498efe9814139b38ae [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;
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
Erik Klinec58da4c2015-02-04 20:01:23 +0900658 if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
659 dev, 1,
660 IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700661 saddr = &ipv6_hdr(skb)->saddr;
Ian Morrise5d08d72014-11-23 21:28:43 +0000662 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
663 if (probes < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000665 ND_PRINTK(1, dbg,
666 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
667 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
669 ndisc_send_ns(dev, neigh, target, target, saddr);
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100670 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 } else {
673 addrconf_addr_solict_mult(target, &mcaddr);
674 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
675 }
676}
677
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900678static int pndisc_is_router(const void *pkey,
679 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700680{
681 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900682 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700683
684 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900685 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
686 if (n)
687 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700688 read_unlock_bh(&nd_tbl.lock);
689
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900690 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700691}
692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693static void ndisc_recv_ns(struct sk_buff *skb)
694{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700695 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000696 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
697 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000699 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700700 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 struct ndisc_options ndopts;
702 struct net_device *dev = skb->dev;
703 struct inet6_ifaddr *ifp;
704 struct inet6_dev *idev = NULL;
705 struct neighbour *neigh;
706 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000707 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900708 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000710 if (skb->len < sizeof(struct nd_msg)) {
711 ND_PRINTK(2, warn, "NS: packet too short\n");
712 return;
713 }
714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000716 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 return;
718 }
719
720 /*
721 * RFC2461 7.1.1:
722 * DAD has to be destined for solicited node multicast address.
723 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000724 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000725 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return;
727 }
728
729 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000730 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 return;
732 }
733
734 if (ndopts.nd_opts_src_lladdr) {
735 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
736 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000737 ND_PRINTK(2, warn,
738 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return;
740 }
741
742 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900743 * If the IP source address is the unspecified address,
744 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 * in the message.
746 */
747 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000748 ND_PRINTK(2, warn,
749 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 return;
751 }
752 }
753
754 inc = ipv6_addr_is_multicast(daddr);
755
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900756 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800757 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700758
759 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
760 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700761 /*
762 * We are colliding with another node
763 * who is doing DAD
764 * so fail our DAD process
765 */
766 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200767 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700768 } else {
769 /*
770 * This is not a dad solicitation.
771 * If we are an optimistic node,
772 * we should respond.
773 * Otherwise, we should ignore it.
774 */
775 if (!(ifp->flags & IFA_F_OPTIMISTIC))
776 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
779
780 idev = ifp->idev;
781 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700782 struct net *net = dev_net(dev);
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 idev = in6_dev_get(dev);
785 if (!idev) {
786 /* XXX: count this drop? */
787 return;
788 }
789
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700790 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900791 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700792 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900793 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700794 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300796 inc &&
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100797 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 /*
799 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900800 * sender should delay its response
801 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 * MAX_ANYCAST_DELAY_TIME seconds.
803 * (RFC2461) -- yoshfuji
804 */
805 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
806 if (n)
807 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
808 goto out;
809 }
810 } else
811 goto out;
812 }
813
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900814 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000815 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900818 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000819 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 goto out;
821 }
822
823 if (inc)
824 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
825 else
826 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
827
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900828 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 * update / create cache entry
830 * for the source address
831 */
832 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
833 !inc || lladdr || !dev->addr_len);
834 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900835 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 NEIGH_UPDATE_F_WEAK_OVERRIDE|
837 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700838 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 ndisc_send_na(dev, neigh, saddr, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000840 !!is_router,
841 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (neigh)
843 neigh_release(neigh);
844 }
845
846out:
847 if (ifp)
848 in6_ifa_put(ifp);
849 else
850 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851}
852
853static void ndisc_recv_na(struct sk_buff *skb)
854{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700855 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800856 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000857 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000859 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700860 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 struct ndisc_options ndopts;
862 struct net_device *dev = skb->dev;
863 struct inet6_ifaddr *ifp;
864 struct neighbour *neigh;
865
866 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000867 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 return;
869 }
870
871 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000872 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 return;
874 }
875
876 if (ipv6_addr_is_multicast(daddr) &&
877 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000878 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return;
880 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900881
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000883 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 return;
885 }
886 if (ndopts.nd_opts_tgt_lladdr) {
887 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
888 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000889 ND_PRINTK(2, warn,
890 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return;
892 }
893 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900894 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800895 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000896 if (skb->pkt_type != PACKET_LOOPBACK
897 && (ifp->flags & IFA_F_TENTATIVE)) {
898 addrconf_dad_failure(ifp);
899 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 }
901 /* What should we make now? The advertisement
902 is invalid, but ndisc specs say nothing
903 about it. It could be misconfiguration, or
904 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800905
906 We should not print the error if NA has been
907 received from loopback - it is just our own
908 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800910 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000911 ND_PRINTK(1, warn,
912 "NA: someone advertises our address %pI6 on %s!\n",
913 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 in6_ifa_put(ifp);
915 return;
916 }
917 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
918
919 if (neigh) {
920 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700921 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923 if (neigh->nud_state & NUD_FAILED)
924 goto out;
925
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700926 /*
927 * Don't update the neighbor cache entry on a proxy NA from
928 * ourselves because either the proxied node is off link or it
929 * has already sent a NA to us.
930 */
931 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700932 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
933 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000934 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700935 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700936 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700937
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 neigh_update(neigh, lladdr,
939 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
940 NEIGH_UPDATE_F_WEAK_OVERRIDE|
941 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
942 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
943 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
944
945 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
946 /*
947 * Change: router to host
948 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800949 rt6_clean_tohost(dev_net(dev), saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 }
951
952out:
953 neigh_release(neigh);
954 }
955}
956
957static void ndisc_recv_rs(struct sk_buff *skb)
958{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700959 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
961 struct neighbour *neigh;
962 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000963 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 struct ndisc_options ndopts;
965 u8 *lladdr = NULL;
966
967 if (skb->len < sizeof(*rs_msg))
968 return;
969
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000970 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000972 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return;
974 }
975
976 /* Don't accept RS if we're not in router mode */
977 if (!idev->cnf.forwarding)
978 goto out;
979
980 /*
981 * Don't update NCE if src = ::;
982 * this implies that the source node has no ip address assigned yet.
983 */
984 if (ipv6_addr_any(saddr))
985 goto out;
986
987 /* Parse ND options */
988 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000989 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 goto out;
991 }
992
993 if (ndopts.nd_opts_src_lladdr) {
994 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
995 skb->dev);
996 if (!lladdr)
997 goto out;
998 }
999
1000 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1001 if (neigh) {
1002 neigh_update(neigh, lladdr, NUD_STALE,
1003 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1004 NEIGH_UPDATE_F_OVERRIDE|
1005 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1006 neigh_release(neigh);
1007 }
1008out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001009 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010}
1011
Pierre Ynard31910572007-10-10 21:22:05 -07001012static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1013{
1014 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1015 struct sk_buff *skb;
1016 struct nlmsghdr *nlh;
1017 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001018 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001019 int err;
1020 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1021 + (opt->nd_opt_len << 3));
1022 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1023
1024 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1025 if (skb == NULL) {
1026 err = -ENOBUFS;
1027 goto errout;
1028 }
1029
1030 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1031 if (nlh == NULL) {
1032 goto nla_put_failure;
1033 }
1034
1035 ndmsg = nlmsg_data(nlh);
1036 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001037 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001038 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1039 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1040 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1041
1042 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1043
David S. Millerc78679e2012-04-01 20:27:33 -04001044 if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1045 &ipv6_hdr(ra)->saddr))
1046 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001047 nlmsg_end(skb, nlh);
1048
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001049 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001050 return;
1051
1052nla_put_failure:
1053 nlmsg_free(skb);
1054 err = -EMSGSIZE;
1055errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001056 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001057}
1058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059static void ndisc_router_discovery(struct sk_buff *skb)
1060{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001061 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 struct neighbour *neigh = NULL;
1063 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001064 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 int lifetime;
1066 struct ndisc_options ndopts;
1067 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001068 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Ian Morris67ba4152014-08-24 21:53:10 +01001070 __u8 *opt = (__u8 *)(ra_msg + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Simon Horman29a3cad2013-05-28 20:34:26 +00001072 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1073 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Ben Greearf2a762d2014-06-25 14:44:52 -07001075 ND_PRINTK(2, info,
1076 "RA: %s, dev: %s\n",
1077 __func__, skb->dev->name);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001078 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001079 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 return;
1081 }
1082 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001083 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 return;
1085 }
1086
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001087#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001088 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001089 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001090 return;
1091 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001092#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 /*
1095 * set the RA_RECV flag in the interface
1096 */
1097
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001098 in6_dev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 if (in6_dev == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001100 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1101 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return;
1103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001106 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 return;
1108 }
1109
Ben Greearf2a762d2014-06-25 14:44:52 -07001110 if (!ipv6_accept_ra(in6_dev)) {
1111 ND_PRINTK(2, info,
1112 "RA: %s, did not accept ra for dev: %s\n",
1113 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001114 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001115 }
David Ward31ce8c72009-08-29 00:04:09 -07001116
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001117#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001118 /* skip link-specific parameters from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001119 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1120 ND_PRINTK(2, info,
1121 "RA: %s, nodetype is NODEFAULT, dev: %s\n",
1122 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001123 goto skip_linkparms;
Ben Greearf2a762d2014-06-25 14:44:52 -07001124 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001125#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 if (in6_dev->if_flags & IF_RS_SENT) {
1128 /*
1129 * flag that an RA was received after an RS was sent
1130 * out on this interface.
1131 */
1132 in6_dev->if_flags |= IF_RA_RCVD;
1133 }
1134
1135 /*
1136 * Remember the managed/otherconf flags from most recently
1137 * received RA message (RFC 2462) -- yoshfuji
1138 */
1139 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1140 IF_RA_OTHERCONF)) |
1141 (ra_msg->icmph.icmp6_addrconf_managed ?
1142 IF_RA_MANAGED : 0) |
1143 (ra_msg->icmph.icmp6_addrconf_other ?
1144 IF_RA_OTHERCONF : 0);
1145
Ben Greearf2a762d2014-06-25 14:44:52 -07001146 if (!in6_dev->cnf.accept_ra_defrtr) {
1147 ND_PRINTK(2, info,
1148 "RA: %s, defrtr is false for dev: %s\n",
1149 __func__, skb->dev->name);
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001150 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001151 }
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001152
Ben Greeard9333192014-06-25 14:44:53 -07001153 /* Do not accept RA with source-addr found on local machine unless
1154 * accept_ra_from_local is set to true.
1155 */
Li RongQingb6428812014-07-10 18:02:46 +08001156 if (!in6_dev->cnf.accept_ra_from_local &&
1157 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1158 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001159 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001160 "RA from local address detected on dev: %s: default router ignored\n",
1161 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001162 goto skip_defrtr;
Ben Greearf2a762d2014-06-25 14:44:52 -07001163 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1166
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001167#ifdef CONFIG_IPV6_ROUTER_PREF
1168 pref = ra_msg->icmph.icmp6_router_pref;
1169 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001170 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001171 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001172 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1173#endif
1174
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001175 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
David S. Millereb857182012-01-27 15:07:56 -08001177 if (rt) {
1178 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1179 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001180 ND_PRINTK(0, err,
1181 "RA: %s got default router without neighbour\n",
1182 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001183 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001184 return;
1185 }
1186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001188 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 rt = NULL;
1190 }
1191
Ben Greearf2a762d2014-06-25 14:44:52 -07001192 ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
1193 rt, lifetime, skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 if (rt == NULL && lifetime) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001195 ND_PRINTK(3, info, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001197 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 if (rt == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001199 ND_PRINTK(0, err,
1200 "RA: %s failed to add default route\n",
1201 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 return;
1203 }
1204
David S. Millereb857182012-01-27 15:07:56 -08001205 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 if (neigh == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001207 ND_PRINTK(0, err,
1208 "RA: %s got default router without neighbour\n",
1209 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001210 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return;
1212 }
1213 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001214 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001215 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217
1218 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001219 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 if (ra_msg->icmph.icmp6_hop_limit) {
1221 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1222 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001223 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1224 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 }
1226
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001227skip_defrtr:
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 /*
1230 * Update Reachable Time and Retrans Timer
1231 */
1232
1233 if (in6_dev->nd_parms) {
1234 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1235
1236 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1237 rtime = (rtime*HZ)/1000;
1238 if (rtime < HZ/10)
1239 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001240 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 in6_dev->tstamp = jiffies;
1242 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1243 }
1244
1245 rtime = ntohl(ra_msg->reachable_time);
1246 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1247 rtime = (rtime*HZ)/1000;
1248
1249 if (rtime < HZ/10)
1250 rtime = HZ/10;
1251
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001252 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1253 NEIGH_VAR_SET(in6_dev->nd_parms,
1254 BASE_REACHABLE_TIME, rtime);
1255 NEIGH_VAR_SET(in6_dev->nd_parms,
1256 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1258 in6_dev->tstamp = jiffies;
1259 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1260 }
1261 }
1262 }
1263
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001264skip_linkparms:
1265
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 /*
1267 * Process options.
1268 */
1269
1270 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001271 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 skb->dev, 1);
1273 if (neigh) {
1274 u8 *lladdr = NULL;
1275 if (ndopts.nd_opts_src_lladdr) {
1276 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1277 skb->dev);
1278 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001279 ND_PRINTK(2, warn,
1280 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 goto out;
1282 }
1283 }
1284 neigh_update(neigh, lladdr, NUD_STALE,
1285 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1286 NEIGH_UPDATE_F_OVERRIDE|
1287 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1288 NEIGH_UPDATE_F_ISROUTER);
1289 }
1290
Ben Greearf2a762d2014-06-25 14:44:52 -07001291 if (!ipv6_accept_ra(in6_dev)) {
1292 ND_PRINTK(2, info,
1293 "RA: %s, accept_ra is false for dev: %s\n",
1294 __func__, skb->dev->name);
David Ward31ce8c72009-08-29 00:04:09 -07001295 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001296 }
David Ward31ce8c72009-08-29 00:04:09 -07001297
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001298#ifdef CONFIG_IPV6_ROUTE_INFO
Li RongQingb6428812014-07-10 18:02:46 +08001299 if (!in6_dev->cnf.accept_ra_from_local &&
1300 ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1301 NULL, 0)) {
Ben Greearf2a762d2014-06-25 14:44:52 -07001302 ND_PRINTK(2, info,
Ben Greeard9333192014-06-25 14:44:53 -07001303 "RA from local address detected on dev: %s: router info ignored.\n",
1304 skb->dev->name);
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001305 goto skip_routeinfo;
Ben Greearf2a762d2014-06-25 14:44:52 -07001306 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001307
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001308 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001309 struct nd_opt_hdr *p;
1310 for (p = ndopts.nd_opts_ri;
1311 p;
1312 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001313 struct route_info *ri = (struct route_info *)p;
1314#ifdef CONFIG_IPV6_NDISC_NODETYPE
1315 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1316 ri->prefix_len == 0)
1317 continue;
1318#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001319 if (ri->prefix_len == 0 &&
1320 !in6_dev->cnf.accept_ra_defrtr)
1321 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001322 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001323 continue;
Ian Morris67ba4152014-08-24 21:53:10 +01001324 rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001325 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001326 }
1327 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001328
1329skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001330#endif
1331
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001332#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001333 /* skip link-specific ndopts from interior routers */
Ben Greearf2a762d2014-06-25 14:44:52 -07001334 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1335 ND_PRINTK(2, info,
1336 "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1337 __func__, skb->dev->name);
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001338 goto out;
Ben Greearf2a762d2014-06-25 14:44:52 -07001339 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001340#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001341
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001342 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 struct nd_opt_hdr *p;
1344 for (p = ndopts.nd_opts_pi;
1345 p;
1346 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001347 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1348 (p->nd_opt_len) << 3,
1349 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 }
1351 }
1352
1353 if (ndopts.nd_opts_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001354 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 u32 mtu;
1356
Ian Morris67ba4152014-08-24 21:53:10 +01001357 memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
Al Viroe69a4adc2006-11-14 20:56:00 -08001358 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
1360 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001361 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 } else if (in6_dev->cnf.mtu6 != mtu) {
1363 in6_dev->cnf.mtu6 = mtu;
1364
1365 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001366 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 rt6_mtu_change(skb->dev, mtu);
1369 }
1370 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001371
Pierre Ynard31910572007-10-10 21:22:05 -07001372 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001373 struct nd_opt_hdr *p;
1374 for (p = ndopts.nd_useropts;
1375 p;
1376 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1377 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001378 }
1379 }
1380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001382 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 }
1384out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001385 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001386 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388}
1389
1390static void ndisc_redirect_rcv(struct sk_buff *skb)
1391{
Duan Jiong093d04d2012-12-14 02:59:59 +00001392 u8 *hdr;
1393 struct ndisc_options ndopts;
1394 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001395 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001396 offsetof(struct rd_msg, opt));
1397
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001398#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001399 switch (skb->ndisc_nodetype) {
1400 case NDISC_NODETYPE_HOST:
1401 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001402 ND_PRINTK(2, warn,
1403 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001404 return;
1405 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001406#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001407
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001408 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001409 ND_PRINTK(2, warn,
1410 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 return;
1412 }
1413
Duan Jiong093d04d2012-12-14 02:59:59 +00001414 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1415 return;
1416
Duan Jiongc92a59e2013-08-22 12:07:35 +08001417 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001418 ip6_redirect_no_header(skb, dev_net(skb->dev),
1419 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001420 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001421 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001422
1423 hdr = (u8 *)ndopts.nd_opts_rh;
1424 hdr += 8;
1425 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1426 return;
1427
David S. Millerb94f1c02012-07-12 00:33:37 -07001428 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429}
1430
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001431static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1432 struct sk_buff *orig_skb,
1433 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001434{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001435 u8 *opt = skb_put(skb, rd_len);
1436
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001437 memset(opt, 0, 8);
1438 *(opt++) = ND_OPT_REDIRECT_HDR;
1439 *(opt++) = (rd_len >> 3);
1440 opt += 6;
1441
1442 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001443}
1444
David S. Miller49919692012-01-27 15:30:48 -08001445void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001447 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001448 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001449 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001450 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001451 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001453 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 struct rt6_info *rt;
1456 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001457 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001460 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Neil Horman95c385b2007-04-25 17:08:10 -07001462 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001463 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1464 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001465 return;
1466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001468 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001469 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001470 ND_PRINTK(2, warn,
1471 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001472 return;
1473 }
1474
David S. Miller4c9483b2011-03-12 16:22:43 -05001475 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001476 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
David S. Miller4c9483b2011-03-12 16:22:43 -05001478 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001479 if (dst->error) {
1480 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001482 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001483 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001484 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
1487 rt = (struct rt6_info *) dst;
1488
1489 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001490 ND_PRINTK(2, warn,
1491 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001492 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001494 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1495 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1496 if (peer)
1497 inet_putpeer(peer);
1498 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001499 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001502 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1503 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001504 ND_PRINTK(2, warn,
1505 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001506 goto release;
1507 }
1508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 read_lock_bh(&neigh->lock);
1510 if (neigh->nud_state & NUD_VALID) {
1511 memcpy(ha_buf, neigh->ha, dev->addr_len);
1512 read_unlock_bh(&neigh->lock);
1513 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001514 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 } else
1516 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001517
1518 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 }
1520
1521 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001522 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1523 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001525 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001527 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001528 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001529 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001531 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1532 *msg = (struct rd_msg) {
1533 .icmph = {
1534 .icmp6_type = NDISC_REDIRECT,
1535 },
1536 .target = *target,
1537 .dest = ipv6_hdr(skb)->daddr,
1538 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 /*
1541 * include target_address option
1542 */
1543
1544 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001545 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
1547 /*
1548 * build redirect option and copy skb over to the new packet.
1549 */
1550
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001551 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001552 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
Eric Dumazetadf30902009-06-02 05:19:30 +00001554 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001555 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001556 return;
1557
1558release:
1559 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560}
1561
1562static void pndisc_redo(struct sk_buff *skb)
1563{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001564 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 kfree_skb(skb);
1566}
1567
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001568static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1569{
1570 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1571
1572 if (!idev)
1573 return true;
1574 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1575 idev->cnf.suppress_frag_ndisc) {
1576 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1577 return true;
1578 }
1579 return false;
1580}
1581
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582int ndisc_rcv(struct sk_buff *skb)
1583{
1584 struct nd_msg *msg;
1585
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001586 if (ndisc_suppress_frag_ndisc(skb))
1587 return 0;
1588
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001589 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 return 0;
1591
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001592 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001594 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001596 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001597 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1598 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 return 0;
1600 }
1601
1602 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001603 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1604 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 return 0;
1606 }
1607
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001608 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 switch (msg->icmph.icmp6_type) {
1611 case NDISC_NEIGHBOUR_SOLICITATION:
1612 ndisc_recv_ns(skb);
1613 break;
1614
1615 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1616 ndisc_recv_na(skb);
1617 break;
1618
1619 case NDISC_ROUTER_SOLICITATION:
1620 ndisc_recv_rs(skb);
1621 break;
1622
1623 case NDISC_ROUTER_ADVERTISEMENT:
1624 ndisc_router_discovery(skb);
1625 break;
1626
1627 case NDISC_REDIRECT:
1628 ndisc_redirect_rcv(skb);
1629 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001630 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
1632 return 0;
1633}
1634
1635static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1636{
Jiri Pirko351638e2013-05-28 01:30:21 +00001637 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001638 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001639 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
1641 switch (event) {
1642 case NETDEV_CHANGEADDR:
1643 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001644 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001645 idev = in6_dev_get(dev);
1646 if (!idev)
1647 break;
1648 if (idev->cnf.ndisc_notify)
1649 ndisc_send_unsol_na(dev);
1650 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 break;
1652 case NETDEV_DOWN:
1653 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001654 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001656 case NETDEV_NOTIFY_PEERS:
1657 ndisc_send_unsol_na(dev);
1658 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 default:
1660 break;
1661 }
1662
1663 return NOTIFY_DONE;
1664}
1665
1666static struct notifier_block ndisc_netdev_notifier = {
1667 .notifier_call = ndisc_netdev_event,
1668};
1669
1670#ifdef CONFIG_SYSCTL
1671static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1672 const char *func, const char *dev_name)
1673{
1674 static char warncomm[TASK_COMM_LEN];
1675 static int warned;
1676 if (strcmp(warncomm, current->comm) && warned < 5) {
1677 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001678 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 -07001679 warncomm, func,
1680 dev_name, ctl->procname,
1681 dev_name, ctl->procname);
1682 warned++;
1683 }
1684}
1685
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001686int 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 -07001687{
1688 struct net_device *dev = ctl->extra1;
1689 struct inet6_dev *idev;
1690 int ret;
1691
Eric W. Biedermand12af672007-10-18 03:05:25 -07001692 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1693 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1695
Eric W. Biedermand12af672007-10-18 03:05:25 -07001696 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001697 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001698
1699 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001700 ret = neigh_proc_dointvec_jiffies(ctl, write,
1701 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001702
1703 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001704 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001705 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1706 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001707 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
1710 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001711 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1712 idev->nd_parms->reachable_time =
1713 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 idev->tstamp = jiffies;
1715 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1716 in6_dev_put(idev);
1717 }
1718 return ret;
1719}
1720
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
1722#endif
1723
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001724static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725{
1726 struct ipv6_pinfo *np;
1727 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001728 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001730 err = inet_ctl_sock_create(&sk, PF_INET6,
1731 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001733 ND_PRINTK(0, err,
1734 "NDISC: Failed to initialize the control socket (err %d)\n",
1735 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 return err;
1737 }
1738
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001739 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001740
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 np->hop_limit = 255;
1743 /* Do not loopback ndisc messages */
1744 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001746 return 0;
1747}
1748
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001749static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001750{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001751 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001752}
1753
1754static struct pernet_operations ndisc_net_ops = {
1755 .init = ndisc_net_init,
1756 .exit = ndisc_net_exit,
1757};
1758
1759int __init ndisc_init(void)
1760{
1761 int err;
1762
1763 err = register_pernet_subsys(&ndisc_net_ops);
1764 if (err)
1765 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001766 /*
1767 * Initialize the neighbour table
1768 */
WANG Congd7480fd2014-11-10 15:59:36 -08001769 neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
1771#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001772 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Himangi Saraogi56ec0fb2014-07-25 01:49:37 +05301773 ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001774 if (err)
1775 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001776out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001777#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001778 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001780#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001781out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001782 unregister_pernet_subsys(&ndisc_net_ops);
1783 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001784#endif
1785}
1786
1787int __init ndisc_late_init(void)
1788{
1789 return register_netdevice_notifier(&ndisc_netdev_notifier);
1790}
1791
1792void ndisc_late_cleanup(void)
1793{
1794 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795}
1796
1797void ndisc_cleanup(void)
1798{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799#ifdef CONFIG_SYSCTL
1800 neigh_sysctl_unregister(&nd_tbl.parms);
1801#endif
WANG Congd7480fd2014-11-10 15:59:36 -08001802 neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001803 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804}