blob: 7cb236e8e261e0620070273fabaa2a1673b043a0 [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
30/* Set to 3 to get tracing... */
31#define ND_DEBUG 1
32
33#define ND_PRINTK(fmt, args...) do { if (net_ratelimit()) { printk(fmt, ## args); } } while(0)
34#define ND_NOPRINTK(x...) do { ; } while(0)
35#define ND_PRINTK0 ND_PRINTK
36#define ND_PRINTK1 ND_NOPRINTK
37#define ND_PRINTK2 ND_NOPRINTK
38#define ND_PRINTK3 ND_NOPRINTK
39#if ND_DEBUG >= 1
40#undef ND_PRINTK1
41#define ND_PRINTK1 ND_PRINTK
42#endif
43#if ND_DEBUG >= 2
44#undef ND_PRINTK2
45#define ND_PRINTK2 ND_PRINTK
46#endif
47#if ND_DEBUG >= 3
48#undef ND_PRINTK3
49#define ND_PRINTK3 ND_PRINTK
50#endif
51
52#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <linux/errno.h>
54#include <linux/types.h>
55#include <linux/socket.h>
56#include <linux/sockios.h>
57#include <linux/sched.h>
58#include <linux/net.h>
59#include <linux/in6.h>
60#include <linux/route.h>
61#include <linux/init.h>
62#include <linux/rcupdate.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090063#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#ifdef CONFIG_SYSCTL
65#include <linux/sysctl.h>
66#endif
67
Thomas Graf18237302006-08-04 23:04:54 -070068#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#include <linux/if_arp.h>
70#include <linux/ipv6.h>
71#include <linux/icmpv6.h>
72#include <linux/jhash.h>
73
74#include <net/sock.h>
75#include <net/snmp.h>
76
77#include <net/ipv6.h>
78#include <net/protocol.h>
79#include <net/ndisc.h>
80#include <net/ip6_route.h>
81#include <net/addrconf.h>
82#include <net/icmp.h>
83
Pierre Ynard31910572007-10-10 21:22:05 -070084#include <net/netlink.h>
85#include <linux/rtnetlink.h>
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#include <net/flow.h>
88#include <net/ip6_checksum.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070089#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#include <linux/proc_fs.h>
91
92#include <linux/netfilter.h>
93#include <linux/netfilter_ipv6.h>
94
Eric Dumazetd6bf7812010-10-04 06:15:44 +000095static u32 ndisc_hash(const void *pkey,
96 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -050097 __u32 *hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static int ndisc_constructor(struct neighbour *neigh);
99static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
100static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
101static int pndisc_constructor(struct pneigh_entry *n);
102static void pndisc_destructor(struct pneigh_entry *n);
103static void pndisc_redo(struct sk_buff *skb);
104
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000105static const struct neigh_ops ndisc_generic_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 .family = AF_INET6,
107 .solicit = ndisc_solicit,
108 .error_report = ndisc_error_report,
109 .output = neigh_resolve_output,
110 .connected_output = neigh_connected_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000113static const struct neigh_ops ndisc_hh_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 .family = AF_INET6,
115 .solicit = ndisc_solicit,
116 .error_report = ndisc_error_report,
117 .output = neigh_resolve_output,
118 .connected_output = neigh_resolve_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119};
120
121
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000122static const struct neigh_ops ndisc_direct_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 .family = AF_INET6,
David S. Miller8f40b162011-07-17 13:34:11 -0700124 .output = neigh_direct_output,
125 .connected_output = neigh_direct_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126};
127
128struct neigh_table nd_tbl = {
129 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 .key_len = sizeof(struct in6_addr),
131 .hash = ndisc_hash,
132 .constructor = ndisc_constructor,
133 .pconstructor = pndisc_constructor,
134 .pdestructor = pndisc_destructor,
135 .proxy_redo = pndisc_redo,
136 .id = "ndisc_cache",
137 .parms = {
Shan Weib6720832010-12-01 18:05:12 +0000138 .tbl = &nd_tbl,
139 .base_reachable_time = ND_REACHABLE_TIME,
140 .retrans_time = ND_RETRANS_TIMER,
141 .gc_staletime = 60 * HZ,
142 .reachable_time = ND_REACHABLE_TIME,
143 .delay_probe_time = 5 * HZ,
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000144 .queue_len_bytes = 64*1024,
Shan Weib6720832010-12-01 18:05:12 +0000145 .ucast_probes = 3,
146 .mcast_probes = 3,
147 .anycast_delay = 1 * HZ,
148 .proxy_delay = (8 * HZ) / 10,
149 .proxy_qlen = 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 },
151 .gc_interval = 30 * HZ,
152 .gc_thresh1 = 128,
153 .gc_thresh2 = 512,
154 .gc_thresh3 = 1024,
155};
156
157/* ND options */
158struct ndisc_options {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800159 struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
160#ifdef CONFIG_IPV6_ROUTE_INFO
161 struct nd_opt_hdr *nd_opts_ri;
162 struct nd_opt_hdr *nd_opts_ri_end;
163#endif
Pierre Ynard31910572007-10-10 21:22:05 -0700164 struct nd_opt_hdr *nd_useropts;
165 struct nd_opt_hdr *nd_useropts_end;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166};
167
168#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
169#define nd_opts_tgt_lladdr nd_opt_array[ND_OPT_TARGET_LL_ADDR]
170#define nd_opts_pi nd_opt_array[ND_OPT_PREFIX_INFO]
171#define nd_opts_pi_end nd_opt_array[__ND_OPT_PREFIX_INFO_END]
172#define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR]
173#define nd_opts_mtu nd_opt_array[ND_OPT_MTU]
174
175#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
176
177/*
178 * Return the padding between the option length and the start of the
179 * link addr. Currently only IP-over-InfiniBand needs this, although
180 * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may
181 * also need a pad of 2.
182 */
183static int ndisc_addr_option_pad(unsigned short type)
184{
185 switch (type) {
186 case ARPHRD_INFINIBAND: return 2;
187 default: return 0;
188 }
189}
190
191static inline int ndisc_opt_addr_space(struct net_device *dev)
192{
193 return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
194}
195
196static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
197 unsigned short addr_type)
198{
199 int space = NDISC_OPT_SPACE(data_len);
200 int pad = ndisc_addr_option_pad(addr_type);
201
202 opt[0] = type;
203 opt[1] = space>>3;
204
205 memset(opt + 2, 0, pad);
206 opt += pad;
207 space -= pad;
208
209 memcpy(opt+2, data, data_len);
210 data_len += 2;
211 opt += data_len;
212 if ((space -= data_len) > 0)
213 memset(opt, 0, space);
214 return opt + space;
215}
216
217static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
218 struct nd_opt_hdr *end)
219{
220 int type;
221 if (!cur || !end || cur >= end)
222 return NULL;
223 type = cur->nd_opt_type;
224 do {
225 cur = ((void *)cur) + (cur->nd_opt_len << 3);
226 } while(cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000227 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228}
229
Pierre Ynard31910572007-10-10 21:22:05 -0700230static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
231{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000232 return opt->nd_opt_type == ND_OPT_RDNSS ||
233 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700234}
235
236static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
237 struct nd_opt_hdr *end)
238{
239 if (!cur || !end || cur >= end)
240 return NULL;
241 do {
242 cur = ((void *)cur) + (cur->nd_opt_len << 3);
243 } while(cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000244 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700245}
246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
248 struct ndisc_options *ndopts)
249{
250 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
251
252 if (!nd_opt || opt_len < 0 || !ndopts)
253 return NULL;
254 memset(ndopts, 0, sizeof(*ndopts));
255 while (opt_len) {
256 int l;
257 if (opt_len < sizeof(struct nd_opt_hdr))
258 return NULL;
259 l = nd_opt->nd_opt_len << 3;
260 if (opt_len < l || l == 0)
261 return NULL;
262 switch (nd_opt->nd_opt_type) {
263 case ND_OPT_SOURCE_LL_ADDR:
264 case ND_OPT_TARGET_LL_ADDR:
265 case ND_OPT_MTU:
266 case ND_OPT_REDIRECT_HDR:
267 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
268 ND_PRINTK2(KERN_WARNING
269 "%s(): duplicated ND6 option found: type=%d\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800270 __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 nd_opt->nd_opt_type);
272 } else {
273 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
274 }
275 break;
276 case ND_OPT_PREFIX_INFO:
277 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700278 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
280 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800281#ifdef CONFIG_IPV6_ROUTE_INFO
282 case ND_OPT_ROUTE_INFO:
283 ndopts->nd_opts_ri_end = nd_opt;
284 if (!ndopts->nd_opts_ri)
285 ndopts->nd_opts_ri = nd_opt;
286 break;
287#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700289 if (ndisc_is_useropt(nd_opt)) {
290 ndopts->nd_useropts_end = nd_opt;
291 if (!ndopts->nd_useropts)
292 ndopts->nd_useropts = nd_opt;
293 } else {
294 /*
295 * Unknown options must be silently ignored,
296 * to accommodate future extension to the
297 * protocol.
298 */
299 ND_PRINTK2(KERN_NOTICE
300 "%s(): ignored unsupported option; type=%d, len=%d\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800301 __func__,
Pierre Ynard31910572007-10-10 21:22:05 -0700302 nd_opt->nd_opt_type, nd_opt->nd_opt_len);
303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 }
305 opt_len -= l;
306 nd_opt = ((void *)nd_opt) + l;
307 }
308 return ndopts;
309}
310
311static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
312 struct net_device *dev)
313{
314 u8 *lladdr = (u8 *)(p + 1);
315 int lladdrlen = p->nd_opt_len << 3;
316 int prepad = ndisc_addr_option_pad(dev->type);
317 if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad))
318 return NULL;
Eric Dumazeta02cec22010-09-22 20:43:57 +0000319 return lladdr + prepad;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000322int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
324 switch (dev->type) {
325 case ARPHRD_ETHER:
326 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
327 case ARPHRD_FDDI:
328 ipv6_eth_mc_map(addr, buf);
329 return 0;
330 case ARPHRD_IEEE802_TR:
331 ipv6_tr_mc_map(addr,buf);
332 return 0;
333 case ARPHRD_ARCNET:
334 ipv6_arcnet_mc_map(addr, buf);
335 return 0;
336 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700337 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000339 case ARPHRD_IPGRE:
340 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 default:
342 if (dir) {
343 memcpy(buf, dev->broadcast, dev->addr_len);
344 return 0;
345 }
346 }
347 return -EINVAL;
348}
349
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900350EXPORT_SYMBOL(ndisc_mc_map);
351
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000352static u32 ndisc_hash(const void *pkey,
353 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500354 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
David S. Miller2c2aba62011-12-28 15:06:58 -0500356 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357}
358
359static int ndisc_constructor(struct neighbour *neigh)
360{
361 struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
362 struct net_device *dev = neigh->dev;
363 struct inet6_dev *in6_dev;
364 struct neigh_parms *parms;
365 int is_multicast = ipv6_addr_is_multicast(addr);
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 in6_dev = in6_dev_get(dev);
368 if (in6_dev == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 return -EINVAL;
370 }
371
372 parms = in6_dev->nd_parms;
373 __neigh_parms_put(neigh->parms);
374 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700377 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 neigh->nud_state = NUD_NOARP;
379 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700380 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 } else {
382 if (is_multicast) {
383 neigh->nud_state = NUD_NOARP;
384 ndisc_mc_map(addr, neigh->ha, dev, 1);
385 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
386 neigh->nud_state = NUD_NOARP;
387 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
388 if (dev->flags&IFF_LOOPBACK)
389 neigh->type = RTN_LOCAL;
390 } else if (dev->flags&IFF_POINTOPOINT) {
391 neigh->nud_state = NUD_NOARP;
392 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
393 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700394 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 neigh->ops = &ndisc_hh_ops;
396 else
397 neigh->ops = &ndisc_generic_ops;
398 if (neigh->nud_state&NUD_VALID)
399 neigh->output = neigh->ops->connected_output;
400 else
401 neigh->output = neigh->ops->output;
402 }
403 in6_dev_put(in6_dev);
404 return 0;
405}
406
407static int pndisc_constructor(struct pneigh_entry *n)
408{
409 struct in6_addr *addr = (struct in6_addr*)&n->key;
410 struct in6_addr maddr;
411 struct net_device *dev = n->dev;
412
413 if (dev == NULL || __in6_dev_get(dev) == NULL)
414 return -EINVAL;
415 addrconf_addr_solict_mult(addr, &maddr);
416 ipv6_dev_mc_inc(dev, &maddr);
417 return 0;
418}
419
420static void pndisc_destructor(struct pneigh_entry *n)
421{
422 struct in6_addr *addr = (struct in6_addr*)&n->key;
423 struct in6_addr maddr;
424 struct net_device *dev = n->dev;
425
426 if (dev == NULL || __in6_dev_get(dev) == NULL)
427 return;
428 addrconf_addr_solict_mult(addr, &maddr);
429 ipv6_dev_mc_dec(dev, &maddr);
430}
431
Brian Haley305d5522008-11-04 17:51:14 -0800432struct sk_buff *ndisc_build_skb(struct net_device *dev,
433 const struct in6_addr *daddr,
434 const struct in6_addr *saddr,
435 struct icmp6hdr *icmp6h,
436 const struct in6_addr *target,
437 int llinfo)
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900438{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900439 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -0800440 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900441 struct sk_buff *skb;
442 struct icmp6hdr *hdr;
Herbert Xua7ae1992011-11-18 02:20:04 +0000443 int hlen = LL_RESERVED_SPACE(dev);
444 int tlen = dev->needed_tailroom;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900445 int len;
446 int err;
Brian Haley305d5522008-11-04 17:51:14 -0800447 u8 *opt;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900448
449 if (!dev->addr_len)
450 llinfo = 0;
451
452 len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
453 if (llinfo)
454 len += ndisc_opt_addr_space(dev);
455
456 skb = sock_alloc_send_skb(sk,
457 (MAX_HEADER + sizeof(struct ipv6hdr) +
Herbert Xua7ae1992011-11-18 02:20:04 +0000458 len + hlen + tlen),
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900459 1, &err);
460 if (!skb) {
461 ND_PRINTK0(KERN_ERR
Brian Haleydae9de82009-06-02 00:20:26 -0700462 "ICMPv6 ND: %s() failed to allocate an skb, err=%d.\n",
463 __func__, err);
Brian Haley305d5522008-11-04 17:51:14 -0800464 return NULL;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900465 }
466
Herbert Xua7ae1992011-11-18 02:20:04 +0000467 skb_reserve(skb, hlen);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900468 ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
469
470 skb->transport_header = skb->tail;
471 skb_put(skb, len);
472
473 hdr = (struct icmp6hdr *)skb_transport_header(skb);
474 memcpy(hdr, icmp6h, sizeof(*hdr));
475
476 opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
477 if (target) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000478 *(struct in6_addr *)opt = *target;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900479 opt += sizeof(*target);
480 }
481
482 if (llinfo)
483 ndisc_fill_addr_option(opt, llinfo, dev->dev_addr,
484 dev->addr_len, dev->type);
485
486 hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
487 IPPROTO_ICMPV6,
Joe Perches07f07572008-11-19 15:44:53 -0800488 csum_partial(hdr,
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900489 len, 0));
490
Brian Haley305d5522008-11-04 17:51:14 -0800491 return skb;
492}
493
494EXPORT_SYMBOL(ndisc_build_skb);
495
496void ndisc_send_skb(struct sk_buff *skb,
497 struct net_device *dev,
498 struct neighbour *neigh,
499 const struct in6_addr *daddr,
500 const struct in6_addr *saddr,
501 struct icmp6hdr *icmp6h)
502{
David S. Miller4c9483b2011-03-12 16:22:43 -0500503 struct flowi6 fl6;
Brian Haley305d5522008-11-04 17:51:14 -0800504 struct dst_entry *dst;
505 struct net *net = dev_net(dev);
506 struct sock *sk = net->ipv6.ndisc_sk;
507 struct inet6_dev *idev;
508 int err;
509 u8 type;
510
511 type = icmp6h->icmp6_type;
512
David S. Miller4c9483b2011-03-12 16:22:43 -0500513 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex);
David S. Miller87a11572011-12-06 17:04:13 -0500514 dst = icmp6_dst_alloc(dev, neigh, &fl6);
David S. Miller452edd52011-03-02 13:27:41 -0800515 if (IS_ERR(dst)) {
Brian Haley305d5522008-11-04 17:51:14 -0800516 kfree_skb(skb);
517 return;
518 }
519
Eric Dumazetadf30902009-06-02 05:19:30 +0000520 skb_dst_set(skb, dst);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900521
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000522 rcu_read_lock();
523 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700524 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900525
Jan Engelhardtb2e0b382010-03-23 04:09:07 +0100526 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
Patrick McHardy6e23ae22007-11-19 18:53:30 -0800527 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900528 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700529 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700530 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900531 }
532
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000533 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900534}
535
Brian Haley305d5522008-11-04 17:51:14 -0800536EXPORT_SYMBOL(ndisc_send_skb);
537
538/*
539 * Send a Neighbour Discover packet
540 */
541static void __ndisc_send(struct net_device *dev,
542 struct neighbour *neigh,
543 const struct in6_addr *daddr,
544 const struct in6_addr *saddr,
545 struct icmp6hdr *icmp6h, const struct in6_addr *target,
546 int llinfo)
547{
548 struct sk_buff *skb;
549
550 skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo);
551 if (!skb)
552 return;
553
554 ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
555}
556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900558 const struct in6_addr *daddr,
559 const struct in6_addr *solicited_addr,
560 int router, int solicited, int override, int inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
562 struct in6_addr tmpaddr;
563 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900564 const struct in6_addr *src_addr;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900565 struct icmp6hdr icmp6h = {
566 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
567 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900570 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900571 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700573 if (ifp->flags & IFA_F_OPTIMISTIC)
574 override = 0;
stephen hemminger9f888162010-06-21 11:00:13 +0000575 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 in6_ifa_put(ifp);
577 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700578 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900579 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900580 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 return;
582 src_addr = &tmpaddr;
583 }
584
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900585 icmp6h.icmp6_router = router;
586 icmp6h.icmp6_solicited = solicited;
587 icmp6h.icmp6_override = override;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900589 __ndisc_send(dev, neigh, daddr, src_addr,
590 &icmp6h, solicited_addr,
David L Stevens14878f72007-09-16 16:52:35 -0700591 inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900592}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000594static void ndisc_send_unsol_na(struct net_device *dev)
595{
596 struct inet6_dev *idev;
597 struct inet6_ifaddr *ifa;
598 struct in6_addr mcaddr;
599
600 idev = in6_dev_get(dev);
601 if (!idev)
602 return;
603
604 read_lock_bh(&idev->lock);
605 list_for_each_entry(ifa, &idev->addr_list, if_list) {
606 addrconf_addr_solict_mult(&ifa->addr, &mcaddr);
607 ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr,
608 /*router=*/ !!idev->cnf.forwarding,
609 /*solicited=*/ false, /*override=*/ true,
610 /*inc_opt=*/ true);
611 }
612 read_unlock_bh(&idev->lock);
613
614 in6_dev_put(idev);
615}
616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900618 const struct in6_addr *solicit,
619 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 struct in6_addr addr_buf;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900622 struct icmp6hdr icmp6h = {
623 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
624 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 if (saddr == NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700627 if (ipv6_get_lladdr(dev, &addr_buf,
628 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 return;
630 saddr = &addr_buf;
631 }
632
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900633 __ndisc_send(dev, neigh, daddr, saddr,
634 &icmp6h, solicit,
David L Stevens14878f72007-09-16 16:52:35 -0700635 !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636}
637
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900638void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
639 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900641 struct icmp6hdr icmp6h = {
642 .icmp6_type = NDISC_ROUTER_SOLICITATION,
643 };
Neil Horman95c385b2007-04-25 17:08:10 -0700644 int send_sllao = dev->addr_len;
Neil Horman95c385b2007-04-25 17:08:10 -0700645
646#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
647 /*
648 * According to section 2.2 of RFC 4429, we must not
649 * send router solicitations with a sllao from
650 * optimistic addresses, but we may send the solicitation
651 * if we don't include the sllao. So here we check
652 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800653 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700654 */
655 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900656 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800657 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700658 if (ifp) {
659 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900660 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700661 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900662 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700663 } else {
664 send_sllao = 0;
665 }
666 }
667#endif
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900668 __ndisc_send(dev, NULL, daddr, saddr,
669 &icmp6h, NULL,
David L Stevens14878f72007-09-16 16:52:35 -0700670 send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
675{
676 /*
677 * "The sender MUST return an ICMP
678 * destination unreachable"
679 */
680 dst_link_failure(skb);
681 kfree_skb(skb);
682}
683
684/* Called with locked neigh: either read or both */
685
686static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
687{
688 struct in6_addr *saddr = NULL;
689 struct in6_addr mcaddr;
690 struct net_device *dev = neigh->dev;
691 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
692 int probes = atomic_read(&neigh->probes);
693
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900694 if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700695 saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697 if ((probes -= neigh->parms->ucast_probes) < 0) {
698 if (!(neigh->nud_state & NUD_VALID)) {
Harvey Harrison5b095d9892008-10-29 12:52:50 -0700699 ND_PRINTK1(KERN_DEBUG "%s(): trying to ucast probe in NUD_INVALID: %pI6\n",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700700 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 }
702 ndisc_send_ns(dev, neigh, target, target, saddr);
703 } else if ((probes -= neigh->parms->app_probes) < 0) {
704#ifdef CONFIG_ARPD
705 neigh_app_ns(neigh);
706#endif
707 } else {
708 addrconf_addr_solict_mult(target, &mcaddr);
709 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
710 }
711}
712
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900713static int pndisc_is_router(const void *pkey,
714 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700715{
716 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900717 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700718
719 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900720 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
721 if (n)
722 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700723 read_unlock_bh(&nd_tbl.lock);
724
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900725 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700726}
727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728static void ndisc_recv_ns(struct sk_buff *skb)
729{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700730 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000731 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
732 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 u8 *lladdr = NULL;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700734 u32 ndoptlen = skb->tail - (skb->transport_header +
735 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 struct ndisc_options ndopts;
737 struct net_device *dev = skb->dev;
738 struct inet6_ifaddr *ifp;
739 struct inet6_dev *idev = NULL;
740 struct neighbour *neigh;
741 int dad = ipv6_addr_any(saddr);
742 int inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900743 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745 if (ipv6_addr_is_multicast(&msg->target)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900746 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 "ICMPv6 NS: multicast target address");
748 return;
749 }
750
751 /*
752 * RFC2461 7.1.1:
753 * DAD has to be destined for solicited node multicast address.
754 */
755 if (dad &&
756 !(daddr->s6_addr32[0] == htonl(0xff020000) &&
757 daddr->s6_addr32[1] == htonl(0x00000000) &&
758 daddr->s6_addr32[2] == htonl(0x00000001) &&
759 daddr->s6_addr [12] == 0xff )) {
760 ND_PRINTK2(KERN_WARNING
761 "ICMPv6 NS: bad DAD packet (wrong destination)\n");
762 return;
763 }
764
765 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900766 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 "ICMPv6 NS: invalid ND options\n");
768 return;
769 }
770
771 if (ndopts.nd_opts_src_lladdr) {
772 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
773 if (!lladdr) {
774 ND_PRINTK2(KERN_WARNING
775 "ICMPv6 NS: invalid link-layer address length\n");
776 return;
777 }
778
779 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900780 * If the IP source address is the unspecified address,
781 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 * in the message.
783 */
784 if (dad) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900785 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 "ICMPv6 NS: bad DAD packet (link-layer address option)\n");
787 return;
788 }
789 }
790
791 inc = ipv6_addr_is_multicast(daddr);
792
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900793 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800794 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700795
796 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
797 if (dad) {
798 if (dev->type == ARPHRD_IEEE802_TR) {
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700799 const unsigned char *sadr;
800 sadr = skb_mac_header(skb);
Neil Horman95c385b2007-04-25 17:08:10 -0700801 if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
802 sadr[9] == dev->dev_addr[1] &&
803 sadr[10] == dev->dev_addr[2] &&
804 sadr[11] == dev->dev_addr[3] &&
805 sadr[12] == dev->dev_addr[4] &&
806 sadr[13] == dev->dev_addr[5]) {
807 /* looped-back to us */
808 goto out;
809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 }
Neil Horman95c385b2007-04-25 17:08:10 -0700811
812 /*
813 * We are colliding with another node
814 * who is doing DAD
815 * so fail our DAD process
816 */
817 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200818 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700819 } else {
820 /*
821 * This is not a dad solicitation.
822 * If we are an optimistic node,
823 * we should respond.
824 * Otherwise, we should ignore it.
825 */
826 if (!(ifp->flags & IFA_F_OPTIMISTIC))
827 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
830
831 idev = ifp->idev;
832 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700833 struct net *net = dev_net(dev);
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 idev = in6_dev_get(dev);
836 if (!idev) {
837 /* XXX: count this drop? */
838 return;
839 }
840
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700841 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900842 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700843 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900844 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700845 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 skb->pkt_type != PACKET_HOST &&
847 inc != 0 &&
848 idev->nd_parms->proxy_delay != 0) {
849 /*
850 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900851 * sender should delay its response
852 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 * MAX_ANYCAST_DELAY_TIME seconds.
854 * (RFC2461) -- yoshfuji
855 */
856 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
857 if (n)
858 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
859 goto out;
860 }
861 } else
862 goto out;
863 }
864
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900865 if (is_router < 0)
866 is_router = !!idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900869 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700870 is_router, 0, (ifp != NULL), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 goto out;
872 }
873
874 if (inc)
875 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
876 else
877 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
878
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900879 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 * update / create cache entry
881 * for the source address
882 */
883 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
884 !inc || lladdr || !dev->addr_len);
885 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900886 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 NEIGH_UPDATE_F_WEAK_OVERRIDE|
888 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700889 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 ndisc_send_na(dev, neigh, saddr, &msg->target,
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700891 is_router,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 1, (ifp != NULL && inc), inc);
893 if (neigh)
894 neigh_release(neigh);
895 }
896
897out:
898 if (ifp)
899 in6_ifa_put(ifp);
900 else
901 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902}
903
904static void ndisc_recv_na(struct sk_buff *skb)
905{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700906 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000907 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
908 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 u8 *lladdr = NULL;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700910 u32 ndoptlen = skb->tail - (skb->transport_header +
911 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 struct ndisc_options ndopts;
913 struct net_device *dev = skb->dev;
914 struct inet6_ifaddr *ifp;
915 struct neighbour *neigh;
916
917 if (skb->len < sizeof(struct nd_msg)) {
918 ND_PRINTK2(KERN_WARNING
919 "ICMPv6 NA: packet too short\n");
920 return;
921 }
922
923 if (ipv6_addr_is_multicast(&msg->target)) {
924 ND_PRINTK2(KERN_WARNING
925 "ICMPv6 NA: target address is multicast.\n");
926 return;
927 }
928
929 if (ipv6_addr_is_multicast(daddr) &&
930 msg->icmph.icmp6_solicited) {
931 ND_PRINTK2(KERN_WARNING
932 "ICMPv6 NA: solicited NA is multicasted.\n");
933 return;
934 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
937 ND_PRINTK2(KERN_WARNING
938 "ICMPv6 NS: invalid ND option\n");
939 return;
940 }
941 if (ndopts.nd_opts_tgt_lladdr) {
942 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
943 if (!lladdr) {
944 ND_PRINTK2(KERN_WARNING
945 "ICMPv6 NA: invalid link-layer address length\n");
946 return;
947 }
948 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900949 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800950 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000951 if (skb->pkt_type != PACKET_LOOPBACK
952 && (ifp->flags & IFA_F_TENTATIVE)) {
953 addrconf_dad_failure(ifp);
954 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 }
956 /* What should we make now? The advertisement
957 is invalid, but ndisc specs say nothing
958 about it. It could be misconfiguration, or
959 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800960
961 We should not print the error if NA has been
962 received from loopback - it is just our own
963 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800965 if (skb->pkt_type != PACKET_LOOPBACK)
966 ND_PRINTK1(KERN_WARNING
Jens Rosenbooma6fa3282009-08-12 22:16:04 +0000967 "ICMPv6 NA: someone advertises our address %pI6 on %s!\n",
968 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 in6_ifa_put(ifp);
970 return;
971 }
972 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
973
974 if (neigh) {
975 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700976 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 if (neigh->nud_state & NUD_FAILED)
979 goto out;
980
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700981 /*
982 * Don't update the neighbor cache entry on a proxy NA from
983 * ourselves because either the proxied node is off link or it
984 * has already sent a NA to us.
985 */
986 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700987 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
988 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700989 /* XXX: idev->cnf.prixy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700990 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700991 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 neigh_update(neigh, lladdr,
994 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
995 NEIGH_UPDATE_F_WEAK_OVERRIDE|
996 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
997 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
998 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
999
1000 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
1001 /*
1002 * Change: router to host
1003 */
1004 struct rt6_info *rt;
1005 rt = rt6_get_dflt_router(saddr, dev);
1006 if (rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001007 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 }
1009
1010out:
1011 neigh_release(neigh);
1012 }
1013}
1014
1015static void ndisc_recv_rs(struct sk_buff *skb)
1016{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001017 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
1019 struct neighbour *neigh;
1020 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001021 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 struct ndisc_options ndopts;
1023 u8 *lladdr = NULL;
1024
1025 if (skb->len < sizeof(*rs_msg))
1026 return;
1027
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001028 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (!idev) {
1030 if (net_ratelimit())
1031 ND_PRINTK1("ICMP6 RS: can't find in6 device\n");
1032 return;
1033 }
1034
1035 /* Don't accept RS if we're not in router mode */
1036 if (!idev->cnf.forwarding)
1037 goto out;
1038
1039 /*
1040 * Don't update NCE if src = ::;
1041 * this implies that the source node has no ip address assigned yet.
1042 */
1043 if (ipv6_addr_any(saddr))
1044 goto out;
1045
1046 /* Parse ND options */
1047 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
1048 if (net_ratelimit())
1049 ND_PRINTK2("ICMP6 NS: invalid ND option, ignored\n");
1050 goto out;
1051 }
1052
1053 if (ndopts.nd_opts_src_lladdr) {
1054 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1055 skb->dev);
1056 if (!lladdr)
1057 goto out;
1058 }
1059
1060 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1061 if (neigh) {
1062 neigh_update(neigh, lladdr, NUD_STALE,
1063 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1064 NEIGH_UPDATE_F_OVERRIDE|
1065 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1066 neigh_release(neigh);
1067 }
1068out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001069 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070}
1071
Pierre Ynard31910572007-10-10 21:22:05 -07001072static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1073{
1074 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1075 struct sk_buff *skb;
1076 struct nlmsghdr *nlh;
1077 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001078 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001079 int err;
1080 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1081 + (opt->nd_opt_len << 3));
1082 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1083
1084 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1085 if (skb == NULL) {
1086 err = -ENOBUFS;
1087 goto errout;
1088 }
1089
1090 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1091 if (nlh == NULL) {
1092 goto nla_put_failure;
1093 }
1094
1095 ndmsg = nlmsg_data(nlh);
1096 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001097 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001098 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1099 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1100 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1101
1102 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1103
David S. Millerc78679e2012-04-01 20:27:33 -04001104 if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1105 &ipv6_hdr(ra)->saddr))
1106 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001107 nlmsg_end(skb, nlh);
1108
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001109 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001110 return;
1111
1112nla_put_failure:
1113 nlmsg_free(skb);
1114 err = -EMSGSIZE;
1115errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001116 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001117}
1118
Thomas Graf65e9b622010-09-03 02:59:14 +00001119static inline int accept_ra(struct inet6_dev *in6_dev)
1120{
1121 /*
1122 * If forwarding is enabled, RA are not accepted unless the special
1123 * hybrid mode (accept_ra=2) is enabled.
1124 */
1125 if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2)
1126 return 0;
1127
1128 return in6_dev->cnf.accept_ra;
1129}
1130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131static void ndisc_router_discovery(struct sk_buff *skb)
1132{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001133 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 struct neighbour *neigh = NULL;
1135 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001136 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 int lifetime;
1138 struct ndisc_options ndopts;
1139 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001140 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142 __u8 * opt = (__u8 *)(ra_msg + 1);
1143
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001144 optlen = (skb->tail - skb->transport_header) - sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001146 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 ND_PRINTK2(KERN_WARNING
1148 "ICMPv6 RA: source address is not link-local.\n");
1149 return;
1150 }
1151 if (optlen < 0) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001152 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 "ICMPv6 RA: packet too short\n");
1154 return;
1155 }
1156
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001157#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001158 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
1159 ND_PRINTK2(KERN_WARNING
1160 "ICMPv6 RA: from host or unauthorized router\n");
1161 return;
1162 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001163#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 /*
1166 * set the RA_RECV flag in the interface
1167 */
1168
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001169 in6_dev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 if (in6_dev == NULL) {
1171 ND_PRINTK0(KERN_ERR
1172 "ICMPv6 RA: can't find inet6 device for %s.\n",
1173 skb->dev->name);
1174 return;
1175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 ND_PRINTK2(KERN_WARNING
1179 "ICMP6 RA: invalid ND options\n");
1180 return;
1181 }
1182
Thomas Graf65e9b622010-09-03 02:59:14 +00001183 if (!accept_ra(in6_dev))
David Ward31ce8c72009-08-29 00:04:09 -07001184 goto skip_linkparms;
1185
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001186#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001187 /* skip link-specific parameters from interior routers */
1188 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
1189 goto skip_linkparms;
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001190#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001191
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 if (in6_dev->if_flags & IF_RS_SENT) {
1193 /*
1194 * flag that an RA was received after an RS was sent
1195 * out on this interface.
1196 */
1197 in6_dev->if_flags |= IF_RA_RCVD;
1198 }
1199
1200 /*
1201 * Remember the managed/otherconf flags from most recently
1202 * received RA message (RFC 2462) -- yoshfuji
1203 */
1204 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1205 IF_RA_OTHERCONF)) |
1206 (ra_msg->icmph.icmp6_addrconf_managed ?
1207 IF_RA_MANAGED : 0) |
1208 (ra_msg->icmph.icmp6_addrconf_other ?
1209 IF_RA_OTHERCONF : 0);
1210
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001211 if (!in6_dev->cnf.accept_ra_defrtr)
1212 goto skip_defrtr;
1213
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001214 if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
1215 goto skip_defrtr;
1216
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1218
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001219#ifdef CONFIG_IPV6_ROUTER_PREF
1220 pref = ra_msg->icmph.icmp6_router_pref;
1221 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001222 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001223 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001224 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1225#endif
1226
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001227 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
David S. Millereb857182012-01-27 15:07:56 -08001229 if (rt) {
1230 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1231 if (!neigh) {
1232 ND_PRINTK0(KERN_ERR
1233 "ICMPv6 RA: %s() got default router without neighbour.\n",
1234 __func__);
1235 dst_release(&rt->dst);
1236 return;
1237 }
1238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001240 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 rt = NULL;
1242 }
1243
1244 if (rt == NULL && lifetime) {
1245 ND_PRINTK3(KERN_DEBUG
1246 "ICMPv6 RA: adding default router.\n");
1247
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001248 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 if (rt == NULL) {
1250 ND_PRINTK0(KERN_ERR
1251 "ICMPv6 RA: %s() failed to add default route.\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -08001252 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 return;
1254 }
1255
David S. Millereb857182012-01-27 15:07:56 -08001256 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 if (neigh == NULL) {
1258 ND_PRINTK0(KERN_ERR
1259 "ICMPv6 RA: %s() got default router without neighbour.\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -08001260 __func__);
Changli Gaod8d1f302010-06-10 23:31:35 -07001261 dst_release(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 return;
1263 }
1264 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001265 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001266 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 }
1268
1269 if (rt)
David S. Millerd1918542011-12-28 20:19:20 -05001270 rt->dst.expires = jiffies + (HZ * lifetime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
1272 if (ra_msg->icmph.icmp6_hop_limit) {
1273 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1274 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001275 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1276 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 }
1278
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001279skip_defrtr:
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 /*
1282 * Update Reachable Time and Retrans Timer
1283 */
1284
1285 if (in6_dev->nd_parms) {
1286 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1287
1288 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1289 rtime = (rtime*HZ)/1000;
1290 if (rtime < HZ/10)
1291 rtime = HZ/10;
1292 in6_dev->nd_parms->retrans_time = rtime;
1293 in6_dev->tstamp = jiffies;
1294 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1295 }
1296
1297 rtime = ntohl(ra_msg->reachable_time);
1298 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1299 rtime = (rtime*HZ)/1000;
1300
1301 if (rtime < HZ/10)
1302 rtime = HZ/10;
1303
1304 if (rtime != in6_dev->nd_parms->base_reachable_time) {
1305 in6_dev->nd_parms->base_reachable_time = rtime;
1306 in6_dev->nd_parms->gc_staletime = 3 * rtime;
1307 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1308 in6_dev->tstamp = jiffies;
1309 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1310 }
1311 }
1312 }
1313
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001314skip_linkparms:
1315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 /*
1317 * Process options.
1318 */
1319
1320 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001321 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 skb->dev, 1);
1323 if (neigh) {
1324 u8 *lladdr = NULL;
1325 if (ndopts.nd_opts_src_lladdr) {
1326 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1327 skb->dev);
1328 if (!lladdr) {
1329 ND_PRINTK2(KERN_WARNING
1330 "ICMPv6 RA: invalid link-layer address length\n");
1331 goto out;
1332 }
1333 }
1334 neigh_update(neigh, lladdr, NUD_STALE,
1335 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1336 NEIGH_UPDATE_F_OVERRIDE|
1337 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1338 NEIGH_UPDATE_F_ISROUTER);
1339 }
1340
Thomas Graf65e9b622010-09-03 02:59:14 +00001341 if (!accept_ra(in6_dev))
David Ward31ce8c72009-08-29 00:04:09 -07001342 goto out;
1343
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001344#ifdef CONFIG_IPV6_ROUTE_INFO
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001345 if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
1346 goto skip_routeinfo;
1347
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001348 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001349 struct nd_opt_hdr *p;
1350 for (p = ndopts.nd_opts_ri;
1351 p;
1352 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001353 struct route_info *ri = (struct route_info *)p;
1354#ifdef CONFIG_IPV6_NDISC_NODETYPE
1355 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1356 ri->prefix_len == 0)
1357 continue;
1358#endif
1359 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001360 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001361 rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001362 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001363 }
1364 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001365
1366skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001367#endif
1368
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001369#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001370 /* skip link-specific ndopts from interior routers */
1371 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
1372 goto out;
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001373#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001374
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001375 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 struct nd_opt_hdr *p;
1377 for (p = ndopts.nd_opts_pi;
1378 p;
1379 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001380 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1381 (p->nd_opt_len) << 3,
1382 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 }
1384 }
1385
1386 if (ndopts.nd_opts_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001387 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 u32 mtu;
1389
Al Viroe69a4adc2006-11-14 20:56:00 -08001390 memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
1391 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
1394 ND_PRINTK2(KERN_WARNING
1395 "ICMPv6 RA: invalid mtu: %d\n",
1396 mtu);
1397 } else if (in6_dev->cnf.mtu6 != mtu) {
1398 in6_dev->cnf.mtu6 = mtu;
1399
1400 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001401 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 rt6_mtu_change(skb->dev, mtu);
1404 }
1405 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001406
Pierre Ynard31910572007-10-10 21:22:05 -07001407 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001408 struct nd_opt_hdr *p;
1409 for (p = ndopts.nd_useropts;
1410 p;
1411 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1412 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001413 }
1414 }
1415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
1417 ND_PRINTK2(KERN_WARNING
1418 "ICMPv6 RA: invalid RA options");
1419 }
1420out:
1421 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001422 dst_release(&rt->dst);
David S. Millereb857182012-01-27 15:07:56 -08001423 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425}
1426
1427static void ndisc_redirect_rcv(struct sk_buff *skb)
1428{
1429 struct inet6_dev *in6_dev;
1430 struct icmp6hdr *icmph;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001431 const struct in6_addr *dest;
1432 const struct in6_addr *target; /* new first hop to destination */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 struct neighbour *neigh;
1434 int on_link = 0;
1435 struct ndisc_options ndopts;
1436 int optlen;
1437 u8 *lladdr = NULL;
1438
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001439#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001440 switch (skb->ndisc_nodetype) {
1441 case NDISC_NODETYPE_HOST:
1442 case NDISC_NODETYPE_NODEFAULT:
1443 ND_PRINTK2(KERN_WARNING
1444 "ICMPv6 Redirect: from host or unauthorized router\n");
1445 return;
1446 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001447#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001448
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001449 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 ND_PRINTK2(KERN_WARNING
1451 "ICMPv6 Redirect: source address is not link-local.\n");
1452 return;
1453 }
1454
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001455 optlen = skb->tail - skb->transport_header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1457
1458 if (optlen < 0) {
1459 ND_PRINTK2(KERN_WARNING
1460 "ICMPv6 Redirect: packet too short\n");
1461 return;
1462 }
1463
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -03001464 icmph = icmp6_hdr(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001465 target = (const struct in6_addr *) (icmph + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 dest = target + 1;
1467
1468 if (ipv6_addr_is_multicast(dest)) {
1469 ND_PRINTK2(KERN_WARNING
1470 "ICMPv6 Redirect: destination address is multicast.\n");
1471 return;
1472 }
1473
1474 if (ipv6_addr_equal(dest, target)) {
1475 on_link = 1;
Brian Haleybf0b48d2007-10-08 00:12:05 -07001476 } else if (ipv6_addr_type(target) !=
1477 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001478 ND_PRINTK2(KERN_WARNING
Brian Haleybf0b48d2007-10-08 00:12:05 -07001479 "ICMPv6 Redirect: target address is not link-local unicast.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 return;
1481 }
1482
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001483 in6_dev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 if (!in6_dev)
1485 return;
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001486 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001489 /* RFC2461 8.1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 * The IP source address of the Redirect MUST be the same as the current
1491 * first-hop router for the specified ICMP Destination Address.
1492 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001493
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
1495 ND_PRINTK2(KERN_WARNING
1496 "ICMPv6 Redirect: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 return;
1498 }
1499 if (ndopts.nd_opts_tgt_lladdr) {
1500 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1501 skb->dev);
1502 if (!lladdr) {
1503 ND_PRINTK2(KERN_WARNING
1504 "ICMPv6 Redirect: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return;
1506 }
1507 }
1508
1509 neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
1510 if (neigh) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001511 rt6_redirect(dest, &ipv6_hdr(skb)->daddr,
1512 &ipv6_hdr(skb)->saddr, neigh, lladdr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 on_link);
1514 neigh_release(neigh);
1515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516}
1517
David S. Miller49919692012-01-27 15:30:48 -08001518void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001520 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001521 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001522 struct sock *sk = net->ipv6.ndisc_sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1524 struct sk_buff *buff;
1525 struct icmp6hdr *icmph;
1526 struct in6_addr saddr_buf;
1527 struct in6_addr *addrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 struct rt6_info *rt;
1529 struct dst_entry *dst;
1530 struct inet6_dev *idev;
David S. Miller4c9483b2011-03-12 16:22:43 -05001531 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 u8 *opt;
Herbert Xua7ae1992011-11-18 02:20:04 +00001533 int hlen, tlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 int rd_len;
1535 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
1537
Neil Horman95c385b2007-04-25 17:08:10 -07001538 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 ND_PRINTK2(KERN_WARNING
1540 "ICMPv6 Redirect: no link-local address on %s\n",
1541 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001542 return;
1543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001545 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001546 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Li Yewang29556522007-01-30 14:33:20 -08001547 ND_PRINTK2(KERN_WARNING
Brian Haleybf0b48d2007-10-08 00:12:05 -07001548 "ICMPv6 Redirect: target address is not link-local unicast.\n");
Li Yewang29556522007-01-30 14:33:20 -08001549 return;
1550 }
1551
David S. Miller4c9483b2011-03-12 16:22:43 -05001552 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001553 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
David S. Miller4c9483b2011-03-12 16:22:43 -05001555 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001556 if (dst->error) {
1557 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001559 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001560 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001561 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
1564 rt = (struct rt6_info *) dst;
1565
1566 if (rt->rt6i_flags & RTF_GATEWAY) {
1567 ND_PRINTK2(KERN_WARNING
1568 "ICMPv6 Redirect: destination is not a neighbour.\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001569 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 }
David S. Miller92d86822011-02-04 15:55:25 -08001571 if (!rt->rt6i_peer)
1572 rt6_bind_peer(rt, 1);
Li Wei4d65a242011-11-23 03:51:54 -05001573 if (!inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ))
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001574 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001577 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1578 if (!neigh) {
1579 ND_PRINTK2(KERN_WARNING
1580 "ICMPv6 Redirect: no neigh for target address\n");
1581 goto release;
1582 }
1583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 read_lock_bh(&neigh->lock);
1585 if (neigh->nud_state & NUD_VALID) {
1586 memcpy(ha_buf, neigh->ha, dev->addr_len);
1587 read_unlock_bh(&neigh->lock);
1588 ha = ha_buf;
1589 len += ndisc_opt_addr_space(dev);
1590 } else
1591 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001592
1593 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 }
1595
1596 rd_len = min_t(unsigned int,
1597 IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8);
1598 rd_len &= ~0x7;
1599 len += rd_len;
1600
Herbert Xua7ae1992011-11-18 02:20:04 +00001601 hlen = LL_RESERVED_SPACE(dev);
1602 tlen = dev->needed_tailroom;
David S. Millerd54a81d2006-12-02 21:00:06 -08001603 buff = sock_alloc_send_skb(sk,
1604 (MAX_HEADER + sizeof(struct ipv6hdr) +
Herbert Xua7ae1992011-11-18 02:20:04 +00001605 len + hlen + tlen),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 1, &err);
1607 if (buff == NULL) {
1608 ND_PRINTK0(KERN_ERR
Brian Haleydae9de82009-06-02 00:20:26 -07001609 "ICMPv6 Redirect: %s() failed to allocate an skb, err=%d.\n",
1610 __func__, err);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001611 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 }
1613
Herbert Xua7ae1992011-11-18 02:20:04 +00001614 skb_reserve(buff, hlen);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001615 ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 IPPROTO_ICMPV6, len);
1617
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001618 skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
Arnaldo Carvalho de Melod10ba342007-03-14 21:05:37 -03001619 skb_put(buff, len);
1620 icmph = icmp6_hdr(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
1622 memset(icmph, 0, sizeof(struct icmp6hdr));
1623 icmph->icmp6_type = NDISC_REDIRECT;
1624
1625 /*
1626 * copy target and destination addresses
1627 */
1628
1629 addrp = (struct in6_addr *)(icmph + 1);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001630 *addrp = *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 addrp++;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001632 *addrp = ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
1634 opt = (u8*) (addrp + 1);
1635
1636 /*
1637 * include target_address option
1638 */
1639
1640 if (ha)
1641 opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
1642 dev->addr_len, dev->type);
1643
1644 /*
1645 * build redirect option and copy skb over to the new packet.
1646 */
1647
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001648 memset(opt, 0, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 *(opt++) = ND_OPT_REDIRECT_HDR;
1650 *(opt++) = (rd_len >> 3);
1651 opt += 6;
1652
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001653 memcpy(opt, ipv6_hdr(skb), rd_len - 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001655 icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 len, IPPROTO_ICMPV6,
Joe Perches07f07572008-11-19 15:44:53 -08001657 csum_partial(icmph, len, 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
Eric Dumazetadf30902009-06-02 05:19:30 +00001659 skb_dst_set(buff, dst);
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001660 rcu_read_lock();
1661 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -07001662 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
Jan Engelhardtb2e0b382010-03-23 04:09:07 +01001663 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
Patrick McHardy6e23ae22007-11-19 18:53:30 -08001664 dst_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -07001666 ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT);
Denis V. Luneva862f6a2008-10-08 10:33:06 -07001667 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 }
1669
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001670 rcu_read_unlock();
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001671 return;
1672
1673release:
1674 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675}
1676
1677static void pndisc_redo(struct sk_buff *skb)
1678{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001679 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 kfree_skb(skb);
1681}
1682
1683int ndisc_rcv(struct sk_buff *skb)
1684{
1685 struct nd_msg *msg;
1686
1687 if (!pskb_may_pull(skb, skb->len))
1688 return 0;
1689
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001690 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001692 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001694 if (ipv6_hdr(skb)->hop_limit != 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 ND_PRINTK2(KERN_WARNING
1696 "ICMPv6 NDISC: invalid hop-limit: %d\n",
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001697 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 return 0;
1699 }
1700
1701 if (msg->icmph.icmp6_code != 0) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001702 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 "ICMPv6 NDISC: invalid ICMPv6 code: %d\n",
1704 msg->icmph.icmp6_code);
1705 return 0;
1706 }
1707
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001708 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 switch (msg->icmph.icmp6_type) {
1711 case NDISC_NEIGHBOUR_SOLICITATION:
1712 ndisc_recv_ns(skb);
1713 break;
1714
1715 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1716 ndisc_recv_na(skb);
1717 break;
1718
1719 case NDISC_ROUTER_SOLICITATION:
1720 ndisc_recv_rs(skb);
1721 break;
1722
1723 case NDISC_ROUTER_ADVERTISEMENT:
1724 ndisc_router_discovery(skb);
1725 break;
1726
1727 case NDISC_REDIRECT:
1728 ndisc_redirect_rcv(skb);
1729 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731
1732 return 0;
1733}
1734
1735static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1736{
1737 struct net_device *dev = ptr;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001738 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
1740 switch (event) {
1741 case NETDEV_CHANGEADDR:
1742 neigh_changeaddr(&nd_tbl, dev);
Daniel Lezcano5b7c9312008-03-03 23:28:58 -08001743 fib6_run_gc(~0UL, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 break;
1745 case NETDEV_DOWN:
1746 neigh_ifdown(&nd_tbl, dev);
Daniel Lezcano5b7c9312008-03-03 23:28:58 -08001747 fib6_run_gc(~0UL, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001749 case NETDEV_NOTIFY_PEERS:
1750 ndisc_send_unsol_na(dev);
1751 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 default:
1753 break;
1754 }
1755
1756 return NOTIFY_DONE;
1757}
1758
1759static struct notifier_block ndisc_netdev_notifier = {
1760 .notifier_call = ndisc_netdev_event,
1761};
1762
1763#ifdef CONFIG_SYSCTL
1764static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1765 const char *func, const char *dev_name)
1766{
1767 static char warncomm[TASK_COMM_LEN];
1768 static int warned;
1769 if (strcmp(warncomm, current->comm) && warned < 5) {
1770 strcpy(warncomm, current->comm);
1771 printk(KERN_WARNING
1772 "process `%s' is using deprecated sysctl (%s) "
1773 "net.ipv6.neigh.%s.%s; "
1774 "Use net.ipv6.neigh.%s.%s_ms "
1775 "instead.\n",
1776 warncomm, func,
1777 dev_name, ctl->procname,
1778 dev_name, ctl->procname);
1779 warned++;
1780 }
1781}
1782
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001783int 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 -07001784{
1785 struct net_device *dev = ctl->extra1;
1786 struct inet6_dev *idev;
1787 int ret;
1788
Eric W. Biedermand12af672007-10-18 03:05:25 -07001789 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1790 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1792
Eric W. Biedermand12af672007-10-18 03:05:25 -07001793 if (strcmp(ctl->procname, "retrans_time") == 0)
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001794 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001795
1796 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 ret = proc_dointvec_jiffies(ctl, write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001798 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001799
1800 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001801 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 ret = proc_dointvec_ms_jiffies(ctl, write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001803 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001804 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
1807 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Eric W. Biedermand12af672007-10-18 03:05:25 -07001808 if (ctl->data == &idev->nd_parms->base_reachable_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
1810 idev->tstamp = jiffies;
1811 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1812 in6_dev_put(idev);
1813 }
1814 return ret;
1815}
1816
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
1818#endif
1819
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001820static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821{
1822 struct ipv6_pinfo *np;
1823 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001824 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001826 err = inet_ctl_sock_create(&sk, PF_INET6,
1827 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if (err < 0) {
1829 ND_PRINTK0(KERN_ERR
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001830 "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 return err;
1833 }
1834
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001835 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 np->hop_limit = 255;
1839 /* Do not loopback ndisc messages */
1840 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001842 return 0;
1843}
1844
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001845static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001846{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001847 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001848}
1849
1850static struct pernet_operations ndisc_net_ops = {
1851 .init = ndisc_net_init,
1852 .exit = ndisc_net_exit,
1853};
1854
1855int __init ndisc_init(void)
1856{
1857 int err;
1858
1859 err = register_pernet_subsys(&ndisc_net_ops);
1860 if (err)
1861 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001862 /*
1863 * Initialize the neighbour table
1864 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 neigh_table_init(&nd_tbl);
1866
1867#ifdef CONFIG_SYSCTL
Eric W. Biederman54716e32010-02-14 03:27:03 +00001868 err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001869 &ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001870 if (err)
1871 goto out_unregister_pernet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001873 err = register_netdevice_notifier(&ndisc_netdev_notifier);
1874 if (err)
1875 goto out_unregister_sysctl;
1876out:
1877 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001879out_unregister_sysctl:
1880#ifdef CONFIG_SYSCTL
1881 neigh_sysctl_unregister(&nd_tbl.parms);
1882out_unregister_pernet:
1883#endif
1884 unregister_pernet_subsys(&ndisc_net_ops);
1885 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886}
1887
1888void ndisc_cleanup(void)
1889{
Dmitry Mishin36f73d02006-11-03 16:08:19 -08001890 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891#ifdef CONFIG_SYSCTL
1892 neigh_sysctl_unregister(&nd_tbl.parms);
1893#endif
1894 neigh_table_clear(&nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001895 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896}