blob: 09a22f4f36c9e069c6dfb3074909691ef2c82399 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Neighbour Discovery for IPv6
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003 * Linux INET6 implementation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Mike Shaver <shaver@ingenia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
15/*
16 * Changes:
17 *
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +000018 * Alexey I. Froloff : RFC6106 (DNSSL) support
Pierre Ynard31910572007-10-10 21:22:05 -070019 * Pierre Ynard : export userland ND options
20 * through netlink (RDNSS support)
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 * Lars Fenneberg : fixed MTU setting on receipt
22 * of an RA.
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 * Janos Farkas : kmalloc failure checks
24 * Alexey Kuznetsov : state machine reworked
25 * and moved to net/core.
26 * Pekka Savola : RFC2461 validation
27 * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
28 */
29
Joe Perches675418d2012-05-16 19:28:38 +000030#define pr_fmt(fmt) "ICMPv6: " fmt
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/types.h>
35#include <linux/socket.h>
36#include <linux/sockios.h>
37#include <linux/sched.h>
38#include <linux/net.h>
39#include <linux/in6.h>
40#include <linux/route.h>
41#include <linux/init.h>
42#include <linux/rcupdate.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090043#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#ifdef CONFIG_SYSCTL
45#include <linux/sysctl.h>
46#endif
47
Thomas Graf18237302006-08-04 23:04:54 -070048#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/if_arp.h>
50#include <linux/ipv6.h>
51#include <linux/icmpv6.h>
52#include <linux/jhash.h>
53
54#include <net/sock.h>
55#include <net/snmp.h>
56
57#include <net/ipv6.h>
58#include <net/protocol.h>
59#include <net/ndisc.h>
60#include <net/ip6_route.h>
61#include <net/addrconf.h>
62#include <net/icmp.h>
63
Pierre Ynard31910572007-10-10 21:22:05 -070064#include <net/netlink.h>
65#include <linux/rtnetlink.h>
66
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <net/flow.h>
68#include <net/ip6_checksum.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070069#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include <linux/proc_fs.h>
71
72#include <linux/netfilter.h>
73#include <linux/netfilter_ipv6.h>
74
Joe Perches675418d2012-05-16 19:28:38 +000075/* Set to 3 to get tracing... */
76#define ND_DEBUG 1
77
78#define ND_PRINTK(val, level, fmt, ...) \
79do { \
80 if (val <= ND_DEBUG) \
81 net_##level##_ratelimited(fmt, ##__VA_ARGS__); \
82} while (0)
83
Eric Dumazetd6bf7812010-10-04 06:15:44 +000084static u32 ndisc_hash(const void *pkey,
85 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -050086 __u32 *hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static int ndisc_constructor(struct neighbour *neigh);
88static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
89static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
90static int pndisc_constructor(struct pneigh_entry *n);
91static void pndisc_destructor(struct pneigh_entry *n);
92static void pndisc_redo(struct sk_buff *skb);
93
Stephen Hemminger89d69d22009-09-01 11:13:19 +000094static const struct neigh_ops ndisc_generic_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 .family = AF_INET6,
96 .solicit = ndisc_solicit,
97 .error_report = ndisc_error_report,
98 .output = neigh_resolve_output,
99 .connected_output = neigh_connected_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100};
101
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000102static const struct neigh_ops ndisc_hh_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 .family = AF_INET6,
104 .solicit = ndisc_solicit,
105 .error_report = ndisc_error_report,
106 .output = neigh_resolve_output,
107 .connected_output = neigh_resolve_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000111static const struct neigh_ops ndisc_direct_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .family = AF_INET6,
David S. Miller8f40b162011-07-17 13:34:11 -0700113 .output = neigh_direct_output,
114 .connected_output = neigh_direct_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115};
116
117struct neigh_table nd_tbl = {
118 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 .key_len = sizeof(struct in6_addr),
120 .hash = ndisc_hash,
121 .constructor = ndisc_constructor,
122 .pconstructor = pndisc_constructor,
123 .pdestructor = pndisc_destructor,
124 .proxy_redo = pndisc_redo,
125 .id = "ndisc_cache",
126 .parms = {
Shan Weib6720832010-12-01 18:05:12 +0000127 .tbl = &nd_tbl,
Shan Weib6720832010-12-01 18:05:12 +0000128 .reachable_time = ND_REACHABLE_TIME,
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100129 .data = {
130 [NEIGH_VAR_MCAST_PROBES] = 3,
131 [NEIGH_VAR_UCAST_PROBES] = 3,
132 [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
133 [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
134 [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
135 [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
136 [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
137 [NEIGH_VAR_PROXY_QLEN] = 64,
138 [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
139 [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,
140 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 },
142 .gc_interval = 30 * HZ,
143 .gc_thresh1 = 128,
144 .gc_thresh2 = 512,
145 .gc_thresh3 = 1024,
146};
147
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000148static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000150 int pad = ndisc_addr_option_pad(skb->dev->type);
151 int data_len = skb->dev->addr_len;
152 int space = ndisc_opt_addr_space(skb->dev);
153 u8 *opt = skb_put(skb, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155 opt[0] = type;
156 opt[1] = space>>3;
157
158 memset(opt + 2, 0, pad);
159 opt += pad;
160 space -= pad;
161
162 memcpy(opt+2, data, data_len);
163 data_len += 2;
164 opt += data_len;
165 if ((space -= data_len) > 0)
166 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167}
168
169static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
170 struct nd_opt_hdr *end)
171{
172 int type;
173 if (!cur || !end || cur >= end)
174 return NULL;
175 type = cur->nd_opt_type;
176 do {
177 cur = ((void *)cur) + (cur->nd_opt_len << 3);
178 } while(cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000179 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180}
181
Pierre Ynard31910572007-10-10 21:22:05 -0700182static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
183{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000184 return opt->nd_opt_type == ND_OPT_RDNSS ||
185 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700186}
187
188static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
189 struct nd_opt_hdr *end)
190{
191 if (!cur || !end || cur >= end)
192 return NULL;
193 do {
194 cur = ((void *)cur) + (cur->nd_opt_len << 3);
195 } while(cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000196 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700197}
198
David S. Miller30f2a5f2012-07-11 23:26:46 -0700199struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
200 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201{
202 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
203
204 if (!nd_opt || opt_len < 0 || !ndopts)
205 return NULL;
206 memset(ndopts, 0, sizeof(*ndopts));
207 while (opt_len) {
208 int l;
209 if (opt_len < sizeof(struct nd_opt_hdr))
210 return NULL;
211 l = nd_opt->nd_opt_len << 3;
212 if (opt_len < l || l == 0)
213 return NULL;
214 switch (nd_opt->nd_opt_type) {
215 case ND_OPT_SOURCE_LL_ADDR:
216 case ND_OPT_TARGET_LL_ADDR:
217 case ND_OPT_MTU:
218 case ND_OPT_REDIRECT_HDR:
219 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000220 ND_PRINTK(2, warn,
221 "%s: duplicated ND6 option found: type=%d\n",
222 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 } else {
224 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
225 }
226 break;
227 case ND_OPT_PREFIX_INFO:
228 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700229 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
231 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800232#ifdef CONFIG_IPV6_ROUTE_INFO
233 case ND_OPT_ROUTE_INFO:
234 ndopts->nd_opts_ri_end = nd_opt;
235 if (!ndopts->nd_opts_ri)
236 ndopts->nd_opts_ri = nd_opt;
237 break;
238#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700240 if (ndisc_is_useropt(nd_opt)) {
241 ndopts->nd_useropts_end = nd_opt;
242 if (!ndopts->nd_useropts)
243 ndopts->nd_useropts = nd_opt;
244 } else {
245 /*
246 * Unknown options must be silently ignored,
247 * to accommodate future extension to the
248 * protocol.
249 */
Joe Perches675418d2012-05-16 19:28:38 +0000250 ND_PRINTK(2, notice,
251 "%s: ignored unsupported option; type=%d, len=%d\n",
252 __func__,
253 nd_opt->nd_opt_type,
254 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 }
257 opt_len -= l;
258 nd_opt = ((void *)nd_opt) + l;
259 }
260 return ndopts;
261}
262
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000263int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 switch (dev->type) {
266 case ARPHRD_ETHER:
267 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
268 case ARPHRD_FDDI:
269 ipv6_eth_mc_map(addr, buf);
270 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 case ARPHRD_ARCNET:
272 ipv6_arcnet_mc_map(addr, buf);
273 return 0;
274 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700275 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000277 case ARPHRD_IPGRE:
278 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 default:
280 if (dir) {
281 memcpy(buf, dev->broadcast, dev->addr_len);
282 return 0;
283 }
284 }
285 return -EINVAL;
286}
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{
299 struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
300 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{
347 struct in6_addr *addr = (struct in6_addr*)&n->key;
348 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{
360 struct in6_addr *addr = (struct in6_addr*)&n->key;
361 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100661 if ((probes -= NEIGH_VAR(neigh->parms, UCAST_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 Pirko1f9248e52013-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 Pirko1f9248e52013-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);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000854 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
855 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 */
947 struct rt6_info *rt;
948 rt = rt6_get_dflt_router(saddr, dev);
949 if (rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700950 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 }
952
953out:
954 neigh_release(neigh);
955 }
956}
957
958static void ndisc_recv_rs(struct sk_buff *skb)
959{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700960 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
962 struct neighbour *neigh;
963 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000964 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 struct ndisc_options ndopts;
966 u8 *lladdr = NULL;
967
968 if (skb->len < sizeof(*rs_msg))
969 return;
970
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000971 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000973 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return;
975 }
976
977 /* Don't accept RS if we're not in router mode */
978 if (!idev->cnf.forwarding)
979 goto out;
980
981 /*
982 * Don't update NCE if src = ::;
983 * this implies that the source node has no ip address assigned yet.
984 */
985 if (ipv6_addr_any(saddr))
986 goto out;
987
988 /* Parse ND options */
989 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000990 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 goto out;
992 }
993
994 if (ndopts.nd_opts_src_lladdr) {
995 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
996 skb->dev);
997 if (!lladdr)
998 goto out;
999 }
1000
1001 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1002 if (neigh) {
1003 neigh_update(neigh, lladdr, NUD_STALE,
1004 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1005 NEIGH_UPDATE_F_OVERRIDE|
1006 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1007 neigh_release(neigh);
1008 }
1009out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001010 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011}
1012
Pierre Ynard31910572007-10-10 21:22:05 -07001013static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1014{
1015 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1016 struct sk_buff *skb;
1017 struct nlmsghdr *nlh;
1018 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001019 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001020 int err;
1021 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1022 + (opt->nd_opt_len << 3));
1023 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1024
1025 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1026 if (skb == NULL) {
1027 err = -ENOBUFS;
1028 goto errout;
1029 }
1030
1031 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1032 if (nlh == NULL) {
1033 goto nla_put_failure;
1034 }
1035
1036 ndmsg = nlmsg_data(nlh);
1037 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001038 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001039 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1040 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1041 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1042
1043 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1044
David S. Millerc78679e2012-04-01 20:27:33 -04001045 if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1046 &ipv6_hdr(ra)->saddr))
1047 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001048 nlmsg_end(skb, nlh);
1049
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001050 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001051 return;
1052
1053nla_put_failure:
1054 nlmsg_free(skb);
1055 err = -EMSGSIZE;
1056errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001057 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001058}
1059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060static void ndisc_router_discovery(struct sk_buff *skb)
1061{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001062 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 struct neighbour *neigh = NULL;
1064 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001065 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 int lifetime;
1067 struct ndisc_options ndopts;
1068 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001069 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
1071 __u8 * opt = (__u8 *)(ra_msg + 1);
1072
Simon Horman29a3cad2013-05-28 20:34:26 +00001073 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1074 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
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
Shmulik Ladkaniaeaf6e92012-11-30 10:25:59 +00001108 if (!ipv6_accept_ra(in6_dev))
David Ward31ce8c72009-08-29 00:04:09 -07001109 goto skip_linkparms;
1110
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001111#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001112 /* skip link-specific parameters from interior routers */
1113 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
1114 goto skip_linkparms;
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001115#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 if (in6_dev->if_flags & IF_RS_SENT) {
1118 /*
1119 * flag that an RA was received after an RS was sent
1120 * out on this interface.
1121 */
1122 in6_dev->if_flags |= IF_RA_RCVD;
1123 }
1124
1125 /*
1126 * Remember the managed/otherconf flags from most recently
1127 * received RA message (RFC 2462) -- yoshfuji
1128 */
1129 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1130 IF_RA_OTHERCONF)) |
1131 (ra_msg->icmph.icmp6_addrconf_managed ?
1132 IF_RA_MANAGED : 0) |
1133 (ra_msg->icmph.icmp6_addrconf_other ?
1134 IF_RA_OTHERCONF : 0);
1135
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001136 if (!in6_dev->cnf.accept_ra_defrtr)
1137 goto skip_defrtr;
1138
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001139 if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
1140 goto skip_defrtr;
1141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1143
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001144#ifdef CONFIG_IPV6_ROUTER_PREF
1145 pref = ra_msg->icmph.icmp6_router_pref;
1146 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001147 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001148 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001149 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1150#endif
1151
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001152 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
David S. Millereb857182012-01-27 15:07:56 -08001154 if (rt) {
1155 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1156 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001157 ND_PRINTK(0, err,
1158 "RA: %s got default router without neighbour\n",
1159 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001160 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001161 return;
1162 }
1163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001165 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 rt = NULL;
1167 }
1168
1169 if (rt == NULL && lifetime) {
Joe Perches675418d2012-05-16 19:28:38 +00001170 ND_PRINTK(3, dbg, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001172 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 if (rt == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001174 ND_PRINTK(0, err,
1175 "RA: %s failed to add default route\n",
1176 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return;
1178 }
1179
David S. Millereb857182012-01-27 15:07:56 -08001180 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 if (neigh == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001182 ND_PRINTK(0, err,
1183 "RA: %s got default router without neighbour\n",
1184 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001185 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 return;
1187 }
1188 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001189 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001190 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
1192
1193 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001194 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (ra_msg->icmph.icmp6_hop_limit) {
1196 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1197 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001198 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1199 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 }
1201
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001202skip_defrtr:
1203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 /*
1205 * Update Reachable Time and Retrans Timer
1206 */
1207
1208 if (in6_dev->nd_parms) {
1209 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1210
1211 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1212 rtime = (rtime*HZ)/1000;
1213 if (rtime < HZ/10)
1214 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001215 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 in6_dev->tstamp = jiffies;
1217 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1218 }
1219
1220 rtime = ntohl(ra_msg->reachable_time);
1221 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1222 rtime = (rtime*HZ)/1000;
1223
1224 if (rtime < HZ/10)
1225 rtime = HZ/10;
1226
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001227 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1228 NEIGH_VAR_SET(in6_dev->nd_parms,
1229 BASE_REACHABLE_TIME, rtime);
1230 NEIGH_VAR_SET(in6_dev->nd_parms,
1231 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1233 in6_dev->tstamp = jiffies;
1234 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1235 }
1236 }
1237 }
1238
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001239skip_linkparms:
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 /*
1242 * Process options.
1243 */
1244
1245 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001246 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 skb->dev, 1);
1248 if (neigh) {
1249 u8 *lladdr = NULL;
1250 if (ndopts.nd_opts_src_lladdr) {
1251 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1252 skb->dev);
1253 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001254 ND_PRINTK(2, warn,
1255 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 goto out;
1257 }
1258 }
1259 neigh_update(neigh, lladdr, NUD_STALE,
1260 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1261 NEIGH_UPDATE_F_OVERRIDE|
1262 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1263 NEIGH_UPDATE_F_ISROUTER);
1264 }
1265
Shmulik Ladkaniaeaf6e92012-11-30 10:25:59 +00001266 if (!ipv6_accept_ra(in6_dev))
David Ward31ce8c72009-08-29 00:04:09 -07001267 goto out;
1268
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001269#ifdef CONFIG_IPV6_ROUTE_INFO
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001270 if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
1271 goto skip_routeinfo;
1272
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001273 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001274 struct nd_opt_hdr *p;
1275 for (p = ndopts.nd_opts_ri;
1276 p;
1277 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001278 struct route_info *ri = (struct route_info *)p;
1279#ifdef CONFIG_IPV6_NDISC_NODETYPE
1280 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1281 ri->prefix_len == 0)
1282 continue;
1283#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001284 if (ri->prefix_len == 0 &&
1285 !in6_dev->cnf.accept_ra_defrtr)
1286 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001287 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001288 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001289 rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001290 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001291 }
1292 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001293
1294skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001295#endif
1296
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001297#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001298 /* skip link-specific ndopts from interior routers */
1299 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
1300 goto out;
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001301#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001302
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001303 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 struct nd_opt_hdr *p;
1305 for (p = ndopts.nd_opts_pi;
1306 p;
1307 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001308 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1309 (p->nd_opt_len) << 3,
1310 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 }
1312 }
1313
1314 if (ndopts.nd_opts_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001315 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 u32 mtu;
1317
Al Viroe69a4adc2006-11-14 20:56:00 -08001318 memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
1319 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
1321 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001322 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 } else if (in6_dev->cnf.mtu6 != mtu) {
1324 in6_dev->cnf.mtu6 = mtu;
1325
1326 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001327 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329 rt6_mtu_change(skb->dev, mtu);
1330 }
1331 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001332
Pierre Ynard31910572007-10-10 21:22:05 -07001333 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001334 struct nd_opt_hdr *p;
1335 for (p = ndopts.nd_useropts;
1336 p;
1337 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1338 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001339 }
1340 }
1341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001343 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 }
1345out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001346 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001347 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349}
1350
1351static void ndisc_redirect_rcv(struct sk_buff *skb)
1352{
Duan Jiong093d04d2012-12-14 02:59:59 +00001353 u8 *hdr;
1354 struct ndisc_options ndopts;
1355 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001356 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001357 offsetof(struct rd_msg, opt));
1358
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001359#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001360 switch (skb->ndisc_nodetype) {
1361 case NDISC_NODETYPE_HOST:
1362 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001363 ND_PRINTK(2, warn,
1364 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001365 return;
1366 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001367#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001368
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001369 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001370 ND_PRINTK(2, warn,
1371 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 return;
1373 }
1374
Duan Jiong093d04d2012-12-14 02:59:59 +00001375 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1376 return;
1377
Duan Jiongc92a59e2013-08-22 12:07:35 +08001378 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001379 ip6_redirect_no_header(skb, dev_net(skb->dev),
1380 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001381 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001382 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001383
1384 hdr = (u8 *)ndopts.nd_opts_rh;
1385 hdr += 8;
1386 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1387 return;
1388
David S. Millerb94f1c02012-07-12 00:33:37 -07001389 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390}
1391
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001392static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1393 struct sk_buff *orig_skb,
1394 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001395{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001396 u8 *opt = skb_put(skb, rd_len);
1397
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001398 memset(opt, 0, 8);
1399 *(opt++) = ND_OPT_REDIRECT_HDR;
1400 *(opt++) = (rd_len >> 3);
1401 opt += 6;
1402
1403 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001404}
1405
David S. Miller49919692012-01-27 15:30:48 -08001406void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001408 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001409 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001410 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001411 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001412 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001414 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 struct rt6_info *rt;
1417 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001418 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001421 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Neil Horman95c385b2007-04-25 17:08:10 -07001423 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001424 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1425 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001426 return;
1427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001429 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001430 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001431 ND_PRINTK(2, warn,
1432 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001433 return;
1434 }
1435
David S. Miller4c9483b2011-03-12 16:22:43 -05001436 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001437 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
David S. Miller4c9483b2011-03-12 16:22:43 -05001439 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001440 if (dst->error) {
1441 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001443 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001444 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001445 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
1448 rt = (struct rt6_info *) dst;
1449
1450 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001451 ND_PRINTK(2, warn,
1452 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001453 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001455 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1456 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1457 if (peer)
1458 inet_putpeer(peer);
1459 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001460 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
1462 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001463 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1464 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001465 ND_PRINTK(2, warn,
1466 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001467 goto release;
1468 }
1469
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 read_lock_bh(&neigh->lock);
1471 if (neigh->nud_state & NUD_VALID) {
1472 memcpy(ha_buf, neigh->ha, dev->addr_len);
1473 read_unlock_bh(&neigh->lock);
1474 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001475 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 } else
1477 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001478
1479 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 }
1481
1482 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001483 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1484 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001486 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001488 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001489 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001490 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001492 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1493 *msg = (struct rd_msg) {
1494 .icmph = {
1495 .icmp6_type = NDISC_REDIRECT,
1496 },
1497 .target = *target,
1498 .dest = ipv6_hdr(skb)->daddr,
1499 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 /*
1502 * include target_address option
1503 */
1504
1505 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001506 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
1508 /*
1509 * build redirect option and copy skb over to the new packet.
1510 */
1511
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001512 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001513 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
Eric Dumazetadf30902009-06-02 05:19:30 +00001515 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001516 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001517 return;
1518
1519release:
1520 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521}
1522
1523static void pndisc_redo(struct sk_buff *skb)
1524{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001525 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 kfree_skb(skb);
1527}
1528
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001529static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1530{
1531 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1532
1533 if (!idev)
1534 return true;
1535 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1536 idev->cnf.suppress_frag_ndisc) {
1537 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1538 return true;
1539 }
1540 return false;
1541}
1542
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543int ndisc_rcv(struct sk_buff *skb)
1544{
1545 struct nd_msg *msg;
1546
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001547 if (ndisc_suppress_frag_ndisc(skb))
1548 return 0;
1549
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001550 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 return 0;
1552
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001553 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001555 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001557 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001558 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1559 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 return 0;
1561 }
1562
1563 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001564 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1565 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 return 0;
1567 }
1568
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001569 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1570
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 switch (msg->icmph.icmp6_type) {
1572 case NDISC_NEIGHBOUR_SOLICITATION:
1573 ndisc_recv_ns(skb);
1574 break;
1575
1576 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1577 ndisc_recv_na(skb);
1578 break;
1579
1580 case NDISC_ROUTER_SOLICITATION:
1581 ndisc_recv_rs(skb);
1582 break;
1583
1584 case NDISC_ROUTER_ADVERTISEMENT:
1585 ndisc_router_discovery(skb);
1586 break;
1587
1588 case NDISC_REDIRECT:
1589 ndisc_redirect_rcv(skb);
1590 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
1593 return 0;
1594}
1595
1596static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1597{
Jiri Pirko351638e2013-05-28 01:30:21 +00001598 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001599 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001600 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 switch (event) {
1603 case NETDEV_CHANGEADDR:
1604 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001605 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001606 idev = in6_dev_get(dev);
1607 if (!idev)
1608 break;
1609 if (idev->cnf.ndisc_notify)
1610 ndisc_send_unsol_na(dev);
1611 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 break;
1613 case NETDEV_DOWN:
1614 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001615 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001617 case NETDEV_NOTIFY_PEERS:
1618 ndisc_send_unsol_na(dev);
1619 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 default:
1621 break;
1622 }
1623
1624 return NOTIFY_DONE;
1625}
1626
1627static struct notifier_block ndisc_netdev_notifier = {
1628 .notifier_call = ndisc_netdev_event,
1629};
1630
1631#ifdef CONFIG_SYSCTL
1632static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1633 const char *func, const char *dev_name)
1634{
1635 static char warncomm[TASK_COMM_LEN];
1636 static int warned;
1637 if (strcmp(warncomm, current->comm) && warned < 5) {
1638 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001639 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 -07001640 warncomm, func,
1641 dev_name, ctl->procname,
1642 dev_name, ctl->procname);
1643 warned++;
1644 }
1645}
1646
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001647int 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 -07001648{
1649 struct net_device *dev = ctl->extra1;
1650 struct inet6_dev *idev;
1651 int ret;
1652
Eric W. Biedermand12af672007-10-18 03:05:25 -07001653 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1654 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1656
Eric W. Biedermand12af672007-10-18 03:05:25 -07001657 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001658 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001659
1660 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001661 ret = neigh_proc_dointvec_jiffies(ctl, write,
1662 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001663
1664 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001665 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001666 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1667 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001668 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001672 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1673 idev->nd_parms->reachable_time =
1674 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 idev->tstamp = jiffies;
1676 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1677 in6_dev_put(idev);
1678 }
1679 return ret;
1680}
1681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683#endif
1684
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001685static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686{
1687 struct ipv6_pinfo *np;
1688 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001689 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001691 err = inet_ctl_sock_create(&sk, PF_INET6,
1692 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001694 ND_PRINTK(0, err,
1695 "NDISC: Failed to initialize the control socket (err %d)\n",
1696 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 return err;
1698 }
1699
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001700 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 np->hop_limit = 255;
1704 /* Do not loopback ndisc messages */
1705 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001707 return 0;
1708}
1709
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001710static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001711{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001712 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001713}
1714
1715static struct pernet_operations ndisc_net_ops = {
1716 .init = ndisc_net_init,
1717 .exit = ndisc_net_exit,
1718};
1719
1720int __init ndisc_init(void)
1721{
1722 int err;
1723
1724 err = register_pernet_subsys(&ndisc_net_ops);
1725 if (err)
1726 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001727 /*
1728 * Initialize the neighbour table
1729 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 neigh_table_init(&nd_tbl);
1731
1732#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001733 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001734 &ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001735 if (err)
1736 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001737out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001738#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001739 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001741#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001742out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001743 unregister_pernet_subsys(&ndisc_net_ops);
1744 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001745#endif
1746}
1747
1748int __init ndisc_late_init(void)
1749{
1750 return register_netdevice_notifier(&ndisc_netdev_notifier);
1751}
1752
1753void ndisc_late_cleanup(void)
1754{
1755 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756}
1757
1758void ndisc_cleanup(void)
1759{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760#ifdef CONFIG_SYSCTL
1761 neigh_sysctl_unregister(&nd_tbl.parms);
1762#endif
1763 neigh_table_clear(&nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001764 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765}